[Closed] Aligning bones and getting inverted scales
Hey all.
I’ve got a function which basically takes 3 bones and then effectively adjusts their twists so the rotations are planar.
Unfortunately, although these now look ok from a rotation perspective, the first and final bones get their scales inverted which obviously is bad. I’m sure I’m overlooking something really obvious here, but I can’t figure out what it is! So any suggestions would be very welcome!
My script is as follws (the bones in bonelist are parented from top to bottom)
boneList = #(
$bone1,
$bone2,
$bone3
)
axisorder = #(“x”,“y”,“z”)
/
Take 3 bones and create a plane between them
Use cross products to align the bones to that plane
/
fn alignBoneToPlane bonelist axisOrder =
(
theProjPlaneCoords = #(bonelist[1].pos, bonelist[2].pos, bonelist[3].pos)
initialTransforms = #(bonelist[1].transform, bonelist[2].transform, bonelist[3].transform)
-- Create a visible trimesh for this
(
vismesh = mesh vertices:theProjPlaneCoords faces:#([1,2,3]) materialIDS:#(1)
vismesh.name = ("VISMESH_"+boneList[1].name+"_"+boneList[2].name+"_"+boneList[3].name)
)
-- Get alignment of first bone.
-- ASSUMING X, Y, Z FOR NOW!
-- X DOWN!
-- Y INTO THE PLANE!
-- Get a vector from bone 1 to bone 2.
xVector = bonelist[2].pos - bonelist[1].pos
xVector = normalize (xVector)
-- Get a temp plane vector from bone 1 to bone 3.
-- Use this to find a cross vector that we'll discard
-- With that temp vector we find a proper 3rd vector, plus the correct second vector
tempVector = bonelist[3].pos - bonelist[1].pos
tempVector = normalize (tempVector)
zVector = normalize (cross xVector tempVector)
yVector = normalize (cross xVector zVector)
finalTransform = matrix3 xVector yVector zVector bonelist[1].pos
bonelist[1].transform = finalTransform
bonelist[2].transform = initialTransforms[2]
-- Get a vector from bone 2 to bone 3.
xVector = bonelist[3].pos - bonelist[2].pos
xVector = normalize (xVector)
zVector = normalize (cross xVector tempVector)
yVector = normalize (cross xVector zVector)
finalTransform = matrix3 xVector yVector zVector bonelist[2].pos
bonelist[2].transform = finalTransform
bonelist[3].transform = initialTransforms[3]
)
[i]– Take 3 bones and create a plane between them…
[/i]hmm… 3 bones means 4 points. how can they be on the same plane for sure?
i think you want to align bones to their common plane… here is a solution. hopefully i didn’t forget anything
the function…
fn planarPairBones bones =
(
tm1 = bones[1].transform
tm2 = bones[2].transform
v1 = normalize tm1[1]
v2 = normalize tm2[1]
up = normalize (cross v1 v2)
bones[1].transform = prescale (matrix3 v1 (cross v1 up) up tm1.pos) tm1.scale
bones[2].transform = prescale (matrix3 v2 (cross v2 up) up tm2.pos) tm2.scale
ok
)
an example…
delete objects
(
b1 = boneSys.createBone (random [-40,-40,-40] [40,40,40]) (v2 = random [-40,-40,-40] [40,40,40]) z_axis
b2 = boneSys.createBone v2 (random [-40,-40,-40] [40,40,40]) z_axis
b1.wirecolor = yellow
b2.wirecolor = green
b2.parent = b1
planarPairBones #(b1,b2)
)
Are you coming from a Maya bone orienting/rigging paradigm?
Max bones != Maya bones, and certain “crucial” things about bone orientation in Maya do not necessarily apply in Max. I spent a lot of time fighting Max’s bones to try to accomplish Maya style orienting and in the end I abandoned it (because of wacky scale inversions.)
Paul Neale has a deep understanding of this issue.
Hrm… I’m not consciously coming from a ‘Maya centric’ approach. I can’t really say if I am inadvertantly though as its about 12 years since I last used it!
All I’m trying to do is orient my joint so that it is aligned with its parent, so that when i rotate it, it is not introducing twist – effectively I’m wanting to ensure my joint works like a hinge.
transforms and Matrix 3 values are tricky…
perhaps you can store the tranform.scalepart of each and reapply after the operation, to reset the scale back .
it seems like a complex method to get what you want -if i understand the problem.
if you hinge-like behavior always on, why not just lock the rotation on all axes but y or z?
if you want bones 2 and 3 to match bone1’s x and z (or x and y) rotation you can just convert .rotation too euler values and swap x and z (or x and y, which ever you are seeking)
--change quaternion to euler to get at xyz angles
bone1EulerRot=$Bone001.rotation as eulerangles
bone2EulerRot=$Bone002.rotation as eulerangles
--make new euler rotation using bone 1 x and y, bone2 z
bone2EulerNewRot=eulerAngles bone1EulerRot.x bone1EulerRot.y bone2EulerRot.z
--convert the new euler rotation to a quaternion
bone2QuatRot= eulerToQuat bone2EulerNewRot
--set the rotation of$ bone002
$Bone002.rotation = bone2QuatRot