Notifications
Clear all

[Closed] Axis order and IK: how do I make them cooperate?

I’ve got a bit of a puzzler here. I have a function that I want to use to change the axis order of a bone, without changing the keyframe transforms of the existing animation. The functions works fine for FK bones, but as soon as you throw an IK chain into the mix all bets are off.

I should clarify that I am trying to use the function on an IK chain that has IK disabled, so I had hoped that would make it behave like an FK chain, but no dice. The same thing happens when I try to do this manually: FK bones can be aligned after their axis order has been changed using the align tool, but a disabled IK bone will not.

Is there anything I can add or change in the following script that will make it work with the lines between the /****/ markers un-commented?

----
 -- FUNCTIONS TO MAKE THE OTHER STUFF WORK
 ----
fn getKnotPoints obj s:1 k: =(
	case(classOf k)of(
		array: try(for i in k collect(getKnotPoint obj s i))catch()
		integer: #(getKnotPoint obj s k)
		unsuppliedClass: for i=1 to(numKnots obj s)collect(getKnotPoint obj s i)
	)
)
fn getAxis p1 p2 p3=(x1=normalize(p2-p1);x2=normalize(p3-p2);normalize(cross x1 x2))
fn makeTipBone b=(
	local tip=boneSys.createBone b.transform.translation(b.transform.translation-6)b.dir
	tip.name=b.name+"_Tip";tip.parent=b;tip.taper=100;tip.transform=b.transform;tip.wireColor=b.wireColor;tip.backFin=tip.frontFin=tip.sideFins=false;tip.height=tip.length=tip.width=aMin #(b.width,b.height)
	in coordsys local move tip [b.length,0,0]
	setTransformLockFlags tip #all;tip
)
 fn BCFL lin=(--Bone Chain From Line
 	local boneChain=#(),LP=getKnotPoints lin,segCount=(numKnots lin 1)- 1
 	for i=1 to segCount do(
 		local p1=LP[i],p2=LP[i+1]
 		local a=(if LP.count>2 then(if i==1 then getAxis LP[3]LP[2]LP[1]else getAxis LP[i-1]LP[i]LP[i+1])else(matrixFromNormal(normalize(p1-p2)))[2])
 		local b=boneSys.createBone p1 p2 a;append boneChain b;if i!=1 then b.parent=boneChain[i-1]
 	)
 	for b in boneChain do(b.height=b.width=(b.length*.2);b.backFin=true;b.frontFin=b.sideFins=false;b.backFinSize=b.height/4;b.taper=50)
 	append boneChain(tip=makeTipBone boneChain[boneChain.count])
 )
 fn collectObjKeys a sel:false cf: =(--collect Object Keys
 	local fa=#()
 	fn getKeys &fa t sel:sel=(
 		if isController t.controller do(
 			if sel==true then join fa(for k in t.controller.keys where k.selected collect k.time.frame as integer)else join fa(for k in t.controller.keys collect k.time.frame as integer)
 			fa=sort(makeUniqueArray fa);for i=1 to t.numSubs do try(getKeys &fa t[i]sel:sel)catch()
 		)
 	)
 	if(not classOf a==array)and(not classOf a==objectSet)do a=#(a);
 	for n in a do (getKeys &fa n sel:sel;for i=1 to n.baseObject.custAttributes.count do if n.baseObject.custAttributes[i].name=="IKFK" do getKeys &fa n.baseObject.custAttributes[i][1] sel:sel)
 	fa
 )
 ----
 
 
 fn setAxisOrder obj ao =
 (
 	-- Collect keys and object transforms at keys
 	objKeys = collectObjKeys obj
 	keyTMs = for k in objKeys collect at time k obj.transform
 
 	-- Switch axis order
 	try(obj.rotation.controller.axisOrder=ao)catch(obj[3][2][2].controller.axisorder=ao)
 
 	-- Fix rotations
 	for k = 1 to objKeys.count do
 		with animate on at time objKeys[k] obj.Transform = keyTMs[k]
 )
 
 
 delete objects 
 
 
 -- Random bone chains
 ----
 pointArray = (for p = 1 to 6 collect random [0,0,0] [200,200,200])
 lin = SplineShape pos:pointArray[1]; addNewSpline lin; for p in pointArray do addKnot lin 1 #corner #line p; updateShape lin
 bc1 = BCFL lin
 bc2 = BCFL lin
 for bc in #(bc1, bc2) do (wc = color (random 0 255) (random 0 255) (random 0 255); for b in bc do b.wireColor = wc)
 ----
 
 
 /*/
 -- IKHI=IKSys.ikChain bc1[1]bc1[3]"IKHISolver"
 -- IKHI.controller.enabled = 0
 /*/
 
 
 -- Random animation
 ----
 keys = #(0) + (sort (for k = 1 to 5 collect random 0 100))
 
 for k = 2 to 5 do with animate on at time keys[k]
 (
 	for b = 1 to 4 do
 	(
 		rot = (eulerAngles (random -180 180) (random -180 180) (random -180 180))
 		rotate bc1[b] rot
 		rotate bc2[b] rot
 	)
 )
 ----
 
 for b = 1 to 2 do setAxisOrder bc1[b] (random 2 9)
13 Replies
  • Bake the IK controller/solver keys on to a point.
  • delete the curent IK.
  • Change bone axis order.
  • re-create the IK.
  • bake the keys from the point to the IK control.

That is what I think I have done in the past.

I was looking at something along those lines for a possible solution. Unfortunately, when working with an IK-disabled IK chain, matching transformations directly using x.transform = y.transform, or even the “align selection” tool, simply does not work.

I have something that works for FK bones but not IK-disabled IK bones. I checked this a bunch of times to make sure I wasn’t going crazy, and finally realized that the problem only occurs with an axis order between 2 and 6. (Things work fine with XYZ, XYX, YZY, and ZXZ; the “default” and “two axis” configurations.)

To demonstrate, the bone is this scene named $2_1 will not match up with the desired transformations, and fails to even hold the correct bone length:


fn getKnotPoints obj s:1 k: =(
	case(classOf k)of(
		array: try(for i in k collect(getKnotPoint obj s i))catch()
		integer: #(getKnotPoint obj s k)
		unsuppliedClass: for i=1 to(numKnots obj s)collect(getKnotPoint obj s i)
	)
)
fn getAxis p1 p2 p3=(x1=normalize(p2-p1);x2=normalize(p3-p2);normalize(cross x1 x2))
fn makeTipBone b=(
	local tip=boneSys.createBone b.transform.translation(b.transform.translation-6)b.dir
	tip.name=b.name+"_Tip";tip.parent=b;tip.taper=100;tip.transform=b.transform;tip.wireColor=b.wireColor;tip.backFin=tip.frontFin=tip.sideFins=false;tip.height=tip.length=tip.width=aMin #(b.width,b.height)
	in coordsys local move tip [b.length,0,0]
	setTransformLockFlags tip #all;tip
)
fn BCFL lin=(--Bone Chain From Line
  	local boneChain=#(),LP=getKnotPoints lin,segCount=(numKnots lin 1)- 1
  	for i=1 to segCount do(
  		local p1=LP[i],p2=LP[i+1]
  		local a=(if LP.count>2 then(if i==1 then getAxis LP[3]LP[2]LP[1]else getAxis LP[i-1]LP[i]LP[i+1])else(matrixFromNormal(normalize(p1-p2)))[2])
  		local b=boneSys.createBone p1 p2 a;append boneChain b;if i!=1 then b.parent=boneChain[i-1]
  	)
  	for b in boneChain do(b.height=b.width=(b.length*.2);b.backFin=true;b.frontFin=b.sideFins=false;b.backFinSize=b.height/4;b.taper=50)
  	append boneChain(tip=makeTipBone boneChain[boneChain.count])
  )
  
  
  -- Set up scene
  ----
  sliderTime = 0
  delete objects
  
  pointArray = #(random [-200,-200,-200] [200,200,200])
  for i = 1 to 2 do append pointArray (pointArray[pointArray.count] + random [-200,-200,-200]  [200,200,200])
  lin = SplineShape pos:pointArray[1]; addNewSpline lin; for p in pointArray do addKnot lin 1 #corner #line p; updateShape lin
  
  bc1 = BCFL lin; bc2 = BCFL lin
  bc3 = BCFL lin; move bc3[1] [300,300,300]; bc4 = BCFL lin; move bc4[1] [300,300,300]
  
  bcArray = #(bc1, bc2, bc3, bc4)
  for a = 1 to 4 do
  (
  	bc = bcArray[a]
  	wc = color (random 0 255) (random 0 255) (random 0 255); for b in bc where isValidNode b do b.wireColor = wc
  
  	for b = 1 to bc.count do
  	(
  		bc[b].name = a as string + "_" + b as string
  	)
  )
  
  bc2_Chain = IKSys.ikChain bc2[1] bc2[3] "IKHISolver"; bc2_Chain.controller.enabled = 0
  bc4_Chain = IKSys.ikChain bc4[1] bc4[3] "IKHISolver"; bc4_Chain.controller.enabled = 0
  ----
  
  
  -- Switch axis order
  bc2[1].rotation.controller.axisOrder = bc3[1].rotation.controller.axisOrder = random 2 6
  
  
  -- Randomized animation
  ----
  keys = (sort (for k = 1 to 5 collect random 0 100))
  
  for k = 1 to 5 do with animate on at time keys[k]
  (
  	for b = 1 to 2 do--2 do
  	(
  		rot = (eulerAngles (random -180 180) (random -180 180) (random -180 180))
  		rotate bc1[b] rot; rotate bc4[b] rot
  
  		bc2[b].transform = bc1[b].transform
  		bc3[b].transform = bc4[b].transform
  	)
  	bc2_Chain.pos = bc2[3].pos; bc4_Chain.pos = bc4[3].pos
  )
  ----

I’m thinking it /might/ be possible to get the desired effect with IK enabled? (Through the positioning of the goal and use of a vh target.) I don’t even know if that would work, and even if it did, what happens if IK is subsequently disabled?

i don’t understand why you need to change axis order at all. i’ve never changed it… never in many years of my rigging practice.

Hi Denis,

If you look at chains 3 and 4 in my scene, you can see how much of a difference the axis order can make. A limb can be posed exactly how I want it on a series of keyframes, but on the in between frames be behaving very differently. I’ve had luck with switching to ZXZ in the past (which is fortunately not one of the setups that causes problems for this sort of thing), though that can also lead to some of its own problems. Beyond that, I guess I just like having options available?

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

there is no axis order that magically solves all problems. there is no really difference.

for me the changing axis order as animation option is the same as change a car from left-wheel to right on the road.

What if you want to drive it in a different country?

And it LOOKS like it might really just be as simple as adding this line:

for k = 1 to 5 do with animate on at time keys[k]
(
	for b = 1 to 2 do
	(
		rot = (eulerAngles (random -180 180) (random -180 180) (random -180 180))
		rotate bc1[b] rot; rotate bc4[b] rot

		bc2[b].transform = bc1[b].transform
		bc2[b].transform = bc2[b].objectTransform

		bc3[b].transform = bc4[b].transform
	)
	bc2_Chain.pos = bc2[3].pos; bc4_Chain.pos = bc4[3].pos
)

…or not?

I must have tested it a couple dozen times earlier and it was working. Now it isn’t. :surprised

To clarify, it still works if the axisorder is 6, but apparently only then. I could have sworn that earlier it was working for everything, but apparently I’m on crack.

in coordSys local $2_1.rotation == (quat 0 0 0 1)
  false

And that seems to be at the heart of the problem.

Page 1 / 2