PDA

View Full Version : Homebrew splineIK (not using Maya's)


StephG
06-14-2006, 07:52 PM
OK, I'm pretty annoyed with the way Maya's splineIK works. The fact that there's no option to turn off the roll control so you can just input it directly into the bones via constraints or other connections is infuriating, and getting arbitrary roll data into it even with advanced twist is a bodge of trial and error that never works the same way twice. Think using splineIK with mocap data.

So, what I'd like to do, is create a curve, and attach the joints to the curve without roll restrictions. So I set out to make a "homebrew splineIK".

The approach I've tried so far, is to create a pointOnCurveInfo node for each joint. I found a brute force way to find the percentage of the curve that corresponds to the joint's current location (approximately, but very very close).

This is where things get ugly. I tried to connect the position (output) from the POCI node to the joint's translate. This would be neat if it works, because then the joints move stretchy IKspline style. Bad news. The joint's translate info is local, while the POCI output is world space. It flings the joint across the screen.

The roll vector on the joints is the y-axis. I prefer keeping my axes oriented approximately to the world axis direction they're pointing whenever possible, and this is a spine.

OK, so turn off "inherit transforms". Now I can get the joints into the right place, but the joints no longer point at each other. More bad news. Also, their represention now points into space like porcupine quills. So I set up aim constraints with no up-vector, which seems to work. The joints are still super long and pointing beyond the "child" joints, but at least they're pointing in the right direction.

So far so...well if not good, at least it's promising. So I try breaking the connection on the joints' y-axis. This should work. Nope. The y-axis isn't the roll vector, because the parent of the joint is the "world" when the inherit transforms are turned off, and the rotation axis doesn't seem to pick up the resulting transform from aiming the x-z vectors. WTF?

Ideally, I'd be able to find a way to keep the inherit transforms on, and get the data out of the pointOnCurveInfo node onto the joints while they still work like a joint chain. I'm not married to the way I'm doing this, it's just all I've thought of so far.

Very frustrating. It's like Maya has one and only one way it wants you to do something, and they've thought of a way to defeat you at every turn should you get any uppity notions of circumventing their tool.

Any suggestions or tutorials out there for making a homebrewed splineIK that doesn't use Maya's overly restrictive splineIK handles? Or, for that matter, coming up with a way to make this methodology work?

Oh, and this is my brute force method of finding the POCI percentage that corresponds to the joint location (where the CVs were placed at the joint location to draw the curve, not the most accurate method but accurate enough, and I'm open to suggestions for more elegant ways of getting the info):

string $listCV[] = `ls -fl ($curveName + ".cv
")`;
int $count = 0;
float $percentage[];
for ($lc in $listCV)
{
float $pos[] = `xform -q -r -t $lc`;
for ($countFloat = 0.0;$countFloat<1.0; $countFloat+=0.00015)
{
float $pocPos[] = `pointOnCurve -top 1 -pr $countFloat "tempCurve"`;
$pos[1] = `roundoff $pos[1] 3`;
$pocPos[1] = `roundoff $pocPos[1] 3`;
if ($pocPos[1] != $pos[1])continue;
print ($lc + " " + $countFloat + "\n");
$percentage[$count] = $countFloat;
$count++;
}
}

Andimation
06-14-2006, 09:52 PM
I have to say i think API is the only way forward for writing a solver like this. I dont think a hack will work. I know Judd Simantov has wrote ik solvers including a modified spline ik one in the past.

Just my 2 cents

Andy

StephG
06-14-2006, 11:13 PM
Yeah, I just want the part that attaches the bones to the spline without the rest of the black box foofaraw. Is that asking too much? It's not so much asking to put something in as make it so we can take something out.

Learning the API is a good suggestion (working on it) but I'm a looooong way from equivalent expertise in MEL. Not particularly useful for what is an immediate need.

Does anyone know if I can get the results I seek by pathing the joints?

darkjedi1929
06-15-2006, 07:18 AM
Correct me if I am wrong here...but I thinkSpline IK does nothing to the joints translations, it modifies joint rotations. In fact Spline IK has almost nothing to do with stretchy spines, as all we use is the curve's length to match the stretch to....so maybe this is what you are doing wrong, i.e., piping in the percentages to the translate. Maybe you ought to be finding a way to Rotate your joints to the specific target....:shrug: . Just my 0.02

StephG
06-15-2006, 07:47 AM
Correct me if I am wrong here...but I thinkSpline IK does nothing to the joints translations, it modifies joint rotations. In fact Spline IK has almost nothing to do with stretchy spines, as all we use is the curve's length to match the stretch to....so maybe this is what you are doing wrong, i.e., piping in the percentages to the translate. Maybe you ought to be finding a way to Rotate your joints to the specific target....:shrug: . Just my 0.02

The piping of translations is a technique to avoid using splineIK, which is insufficiently flexible in the way it can be used.

Well, splineIK rotates/translates the joints so they stay on the spline and move with the spline. Stretchy is what I want to end up with, and the techniques for that are well known. But it doesn't have to start out with stretchy. It does have to be free to roll with the character's rotation, and straightforward to align with arbitrary rotational data (i.e. taken from motion capture that is turned into translations).

I want joints to track a spline. Doesn't matter how it does it. Spline IK almost works.
It's just too time consuming getting it tuned to work with a large number of various characters.

I've got something that almost works. Make the spline. Get the percentages for the position of the joints on the spline. Add transforms and connect the position of the POCI to the transform's translate attribute. Point constrain the joints to the corresponding transform. Aim constrain the parent joints to the child joints. In my case with ry as the roll vector, delete the ry connection to the constraint. Because I'm using ry as the roll, set the rotation order to xyz, yxz or yzx.

It works. Pretty well, actually. But...not quite ready for prime time. The evaluation precision is a problem, especially if you use undo. I'm working on fixing that. But if someone has an actual technique to share, it would be greatly appreciated.

animationrigs
06-15-2006, 05:20 PM
Isn't this going to be a fun one. If you want to try to continue with the curve then perhaps rather then disconnecting the ry, add in another offset transform between your poci transform and the joints. Maybe then you can connect your "extra" info for ry to the offset OR connect into the tangent inputs of the aimConstraint with whatever you are trying to drive the twist of the spine.......BUT

Have you tried using a surface instead of a spline. The problem with a spline is always going to be stability/flipping potential. How do you know which way is up? With a surface and using a pointOnSurface info you can get the surface tangent at the point and use that to drive your aimConstraint's up vector. IT depends on requirements, but it might work out for you.

StephG
06-15-2006, 08:10 PM
Isn't this going to be a fun one. If you want to try to continue with the curve then perhaps rather then disconnecting the ry, add in another offset transform between your poci transform and the joints. Maybe then you can connect your "extra" info for ry to the offset OR connect into the tangent inputs of the aimConstraint with whatever you are trying to drive the twist of the spine.......BUT

Have you tried using a surface instead of a spline. The problem with a spline is always going to be stability/flipping potential. How do you know which way is up? With a surface and using a pointOnSurface info you can get the surface tangent at the point and use that to drive your aimConstraint's up vector. IT depends on requirements, but it might work out for you.

Ah, now we're getting somewhere. I think the spline should be fine (not flipping, but I'll watch for that now), because the whole goal of this is to be able to control the roll of the joints with external controllers. So flipping shouldn't be an issue. The only info I really want the joint to get from the spline is the position of the rotate axes, and then to have the joints properly point at one another when the child joint is moved.

Now I haven't tried adding the extra transform yet, but the problem I see with that is that the joints have to remain in their original hierarchy. I can't see where I can add an extra transform without adding it between the joints in the hierarchy. And I tried using the jointOrient attribute, but it's really whacked in this situation.

I notice some weird imprecision with the technique I outlined above. So I turned cycleCheck on and lo and behold, it regards the aim constraints as cyclic. But they still work moderately reliably. I think I can fix this by aiming at the transforms on the curve instead of the child joint. Probably a better way to do it anyway.

But I can't get around the issue of having to decouple the y rotation from the aim constraint, though a blend might work. I'll report back on that as soon as I get a chance.

EDIT:
OK, I got it working...Using the transforms I created as the aim target did it. I still have to break the ry connection, but I haven't seen any ill effects in my tests.

I have one thing left to resolve, and that's finding a better and faster way to find the percentage of the spline that corresponds to the position of the joint. Right now, I'm using iterative brute force (see the code in my first post) which is slow, and if I want improved accuracy, even slower. If someone had a way of doing that, I could reduce the curve (instead of a point at every joint) without the joints jumping (since I could recalculate the percentage). When I get this last bit figured out, I'll post the code on HighEnd so people can use it in their own scripts instead a stretchy splineIKSolver.

NolanSW
06-15-2006, 10:17 PM
Hey Steph,
Take a look at Aaron Holly's ribbon spine (http://www.fahrenheitdigital.com/) setup he's got . I have a slightly modified version on my blog (video demo) of what he does but I added Fk. It's not prefect and was kind of thrown together. It uses the apporach of using a nurbsSurface as a way to drive joints using maya's hair system but could be used with pointOnSurface nodes. Basically you would have floating bones that would drive the a slaved joint hiearchy. I've used on a few characters here at work and the system could be used for both film or games. If using mocap it could be a bit more setup. But I love the flexiblity of the "IK" part but it's not IK. You get really nice twist and roll. If you buy the DVD you'll see how that can all be adjusted.

-Sean

CGTalk Moderation
06-15-2006, 10:17 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.