Calculate rotation of target object based on source

Calculate rotation of target object based on source

Anonymous
Not applicable
940 Views
6 Replies
Message 1 of 7

Calculate rotation of target object based on source

Anonymous
Not applicable

Lets assume you have 3 identical doors in a max file. Due to Xform, the doors have lost their rotation information.

 

I want a MaxScript which can figure and rotate the pivots of door B and C using A as reference. In other words, door A should be selected as the master object and the rotation of object B and C should be calculated using face normal of a poly for example.

 

Think of this as using object A as source for transformation and rotation for object B, C. How much would you have to rotate object A if it was placed exactly the same way object B and C are.

 

Attaching a file with several doors. I want one of the doors to become the master object and the rest of them should have a pivot rotation in relation to the source object. 

 

I have a semi working max script for this but it has bugs. Especially if there is an X form on the target objects then its rather difficult to even use face normal of poly.

 

(
  local geoToUV = (for o in selection where (isKindOf o GeometryClass and canConvertTo o Editable_Mesh) collect o)
  local MasterObject = null
  local MasterObjectLargestFaceArea = 0
  local MasterObjectLargestFaceIndex = 0
  local MasterObjectLargestFace = null
  local MasterObjectFaceNormal = null --polyop.getFaceNormal
  
  local poGetFaceNormal = polyop.getFaceNormal
  
  if geoToUV.count == 0 then messagebox "No suitable geometry selected!"
  else
  (
   clearSelection() -- clears selection once original selection has been saved as geoToUV array

   for i in 1 to geoToUV.count do -- loops through array of suitable geometry
   (
    obj = geoToUV[i]    
    select geoToUV[i]
    
    -- convert selected object to Editable Poly if it not already is
    if (classOf obj != Editable_Poly)
     then (convertToPoly obj)
    
    if(i == 1) then
    (
     selectedFaces = polyop.GetFaceSelection selection[1]
     if selectedFaces.isEmpty == false then
     (
      if(selectedFaces.numberSet == 1) then
      (
       MasterObject = obj
       MasterObjectLargestFaceIndex = MasterObject.selectedFaces[1].index
       MasterObjectFaceNormal = poGetFaceNormal MasterObject MasterObjectLargestFaceIndex
       local selectedIndex = MasterObjectLargestFaceIndex as string
       --MasterObjectLargestFaceIndex = selectedFaces[1].index
      )else
      (
       MessageBox "Too many faces slected on the first object"
      )
     )
     else
     (
      MessageBox "No face selected"
     )
      
    ) else
    (
     
     local currentFaceNormal = poGetFaceNormal Obj MasterObjectLargestFaceIndex
     OffsetAngleForPivot = acos (dot MasterObjectFaceNormal currentFaceNormal)
      
     currentMatrix = matrixFromNormal (currentFaceNormal) as eulerAngles
     masterMatrix = matrixFromNormal (MasterObjectFaceNormal) as eulerAngles
     
     AngleMatrixMaster = "X:" + ((masterMatrix.x as string) + " Y:" + (masterMatrix.y as string) + " Z:" + (masterMatrix.z as string)) as string
     AngleMatrixCurrent = "X:" + ((currentMatrix.x as string) + " Y:" + (currentMatrix.y as string) + " Z:" + (currentMatrix.z as string)) as string
     
     masterMatrixX   = masterMatrix.x
     masterMatrixY   = masterMatrix.y
     masterMatrixZ   = masterMatrix.z
     
     currentMatrixX = currentMatrix.x
     currentMatrixY = currentMatrix.y
     currentMatrixZ = currentMatrix.z
     
     Xdiff = amax #(masterMatrixX, currentMatrixX) - amin #(masterMatrixX, currentMatrixX)
     if (Xdiff > 180) then
     (
      Xdiff = 360 - Xdiff
     )
     
     Ydiff = amax #(masterMatrixY, currentMatrixY) - amin #(masterMatrixY, currentMatrixY)
     if (Ydiff > 180) then
     (
      Ydiff = 360 - Ydiff
     )
     
     Zdiff = amax #(masterMatrixZ, currentMatrixZ) - amin #(masterMatrixZ, currentMatrixZ)
     if (Zdiff > 180) then
     (
      Zdiff = 360 - Zdiff
     )
     
     --Negative values......
     if(masterMatrix.z > 0 and currentMatrix.z < 0) then
     (
      Zdiff = Zdiff *-1 
     )
     
     print ("AngleMatrixMaster:" + (AngleMatrixMaster as string))
     print ("AngleMatrixCurrent:" + (AngleMatrixCurrent as string))
     print ("Zdiff:" + (Zdiff as string))
     print ("Ydiff:" + (Ydiff as string))
     print ("Xdiff:" + (Xdiff as string))
     
      --Call to function for sorting the pivot
     --RotatePivotOnly obj (EulerAngles 0 0 Zdiff)
     
    )
    
     clearSelection()
   )
   
   select geoToUV
   Messagebox ("Done")
  )
  
 )

 

 

 

0 Likes
941 Views
6 Replies
Replies (6)
Message 2 of 7

denisT.MaxDoctor
Advisor
Advisor
fn isPolyNode node = (iskindof node Editable_Poly)
mapped fn resetNodeBBox node = if isPolyNode node do 
(
	rot = node.rotation
	pos = node.position
	node.rotation = quat 1
	resetxform node
	converttopoly node
	node.rotation = rot
	node.position = pos
)

fn getFaceTM node face:1 = if isPolyNode node do 
(
	normal = polyop.getfacenormal node face
	center = polyop.getfacecenter node face
	
	verts = for v in (polyop.getfaceverts node face) collect (polyop.getvert node v)
	
	front = normalize (verts[2] - verts[1])
	right = cross front normal
	
	matrix3 right front normal center
)

fn alignPivotToTM node tm = 
(
	itm = tm * (inverse node.transform)
	node.transform = tm
	node.objectOffsetPos *= inverse itm
	node.objectOffsetRot *= inverse itm.rotation
	node.transform
)

mapped fn alignPivotToTargetUsingFace source target face:1 = if isPolyNode source and isPolyNode target do
(
	target_face_tm = getFaceTM target face:face
	source_face_tm = getFaceTM source face:face
	
	tm = target.transform * (inverse target_face_tm) * source_face_tm
	
	alignPivotToTM source tm
)

/******************************
we will use the fact that all your doors have the same topology
that means pivots of all doors have the same transform relativly to any specified by index face

#1 pick any door and set its pivot to the right transform
#2 name this door for example "Doors_ID__master"  
#3 run the script
...
#4 at the end the script resets node's BBox to match the pivot 
*******************************/

/************ run to fix ******************
(
	target = getnodebyname "Doors_ID__master" 
	sources = for node in geometry where node != target and isPolyNode node and matchpattern node.name pattern:"doors_*" collect node 
	alignPivotToTargetUsingFace sources target
	resetNodeBBox (append sources target)
)
*******************************************/
Message 3 of 7

Anonymous
Not applicable

Denis, thank you for looking in to my align question. I have tested your script and it aligns the pivot for all objects, the required rotation offset however is not there. I have corresponded with some friends and we are working on a solution.

 

Once again thank you for your time.

0 Likes
Message 4 of 7

denisT.MaxDoctor
Advisor
Advisor

you didn't say anything about "required offset"

 

 

0 Likes
Message 5 of 7

Anonymous
Not applicable

In order to  reuse the same door at a different location there has to be a pivot offset when compared to the “Master” object. I have a sent you a PM with detailed explanation.

 

Thanks

0 Likes
Message 6 of 7

Anonymous
Not applicable

Did some further testing on your solution Denis. It does rotate the pivot as desired. The discrepancies I was witnessing was caused by slight differences in topology. So one area of improvement would be to relocate the poly index based on known information about the selection.

 

In any case, thanks 😊

0 Likes
Message 7 of 7

denisT.MaxDoctor
Advisor
Advisor

so did you have a solution? 

if the solution is different than mine please post it

0 Likes