View Full Version : Soft IK & Non-snapping IK

 Sebastianimator01 January 2008, 07:25 AMHi all, I'm trying to extend upon an idea oulined by Andy Nicholas here (http://xsi-blog.com/archives/108) and here (http://xsi-blog.com/archives/109). I'm basically trying to achieve soft-blended stretchy IK in max for future rigs at our company. I'm not huge on maths so it took me a while to sit down and decipher the equation listed at his site and this is what i've come up with: ds(1-exp(-(x-da)/ds))+da where ds is the falloff of the soft IK effect, da is full stretch distance minus ds and x is the current distance between the two points. I've set up a simple 2-bone IK system to get the smooth blending working before I move onto the stretchy blending and am getting very mixed results. I made the distance between the bones 20 and wanted the falloff to be 5. I'm working purely off the x axis at the moment in order to better understand the concept. I have 2 point helpers which i'm using to measure the distance, one of which is the soft IK control. I've attached the following script to the X position track of the IK controller: if \$point06.pos.x > 15 then 5*(1-exp(-((\$point06.pos.x)-15)/5))+15 else \$point06.pos.xAfter animating point06 in X it appears to work with a subtle falloff until about 99% and then it seems to pop to 100%. I'm not entirely sure if this is a bug with max (which wouldn't surprise me) and I need to simply limit it to 99% of the effect, or if there's something wrong with my maths. The curves in the curve editor do look perfectly exponential so I'm leaning more towards it simply being a limitation of max. I'd also like someone to explain how the equation that I've derived works because I'm a little baffled as to the maths behind it. I'm yet to work out a way to make the falloff distance shorter so it has a more accelerated curve too because currently the control point has to travel a long way for it to reach the full extension of the bones. Anyways, thanks in advance for any guidance in this area. Once I understand this concept, I'll continue on to make it work with stretchy bones and eventually post a script to enable automated creation. Cheers, Sebastian
djlane
01 January 2008, 03:37 PM
Hi, had a go myself check this file.

Cheers

Dan

eek
01 January 2008, 03:43 PM
[
The equation is similar to linear interpolation usings exp (2.81) as the value 't'. Standard linear equations work by setting the range your working in:

(1 minusing the t value) * the inital value plus the end value times t. So - (1-t)*p0 + p1 *t

Whats happening in the equation is your setting the value '15' as your limit, and then the chain is exponentially slowing down by a factor of '5'. You need the '(-((\$point06.pos.x)-15)/5))+15' because you need to keep it in its original position and not to pop at the start of it slowing down.

This equation:
http://xsi-blog.com/userContent/anicholas/softik/Equation.gif
http://xsi-blog.com/userContent/anicholas/softik/Equation.gif

Uses a clause, its infact very similar to a basis function found in bspline curves:

if x > 0 then (x) else (if x < da then (x) else (ds*(1-exp(-(x-da)/ds))+da))

Sebastianimator
01 January 2008, 12:02 AM
Thanks heaps for the replies guys. Took me a while to dig through the logic of your posts as my Maths sucks but I think I understand the majority of it now.

Eek: I believe there's a bit of a flaw in your logic in the first part of the statement that states if x > 0 then (x). Due to the equation on the blog shouldn't it be if x > 0 and x < da? Currently x will always be > 0 so it will always just take the x value. After further dissemination of the formula you posted, I realised it's effectively the same as mine just ordered differently. I used your ordering and got exactly the same result as my previous attempt whereby there was a definite exponential falloff but then a pop at the end. I'm really not sure why this is happening :(

Dan: Your solution works but unfortunately I'm baffled as to how. I can follow up to the NewPos line at which point I get a bit lost.NewPos = (( transMatrix ((normalize offsetTrans.row4) * Limit)) * root.transform).row4 I'm not really sure why you are multiplying the normalized offset transform matrix with the limit value (which was derived from the same expression on the blog) and then why are you multiplying the resultant with the original root point's transform?

If someone can explain the theories behind this I'd be very appreciative. I'd also be very keen on hearing if there's any "Maths for TDs" type training books/DVDs as it's an area that I'd like to break into.

djlane
01 January 2008, 10:26 AM
Hi
Its probably pretty obvious but maths is not my strong point so maybe I went around the houses to get the final result, but my logic was:

Create a unit vector which gives me the direction of the Control handle from the root, and use the blog formula to calculate a magnitude. I multiply the unit vector by the magnitude and create a new matrix by feeding the result into a Transmatrix constructor.

As the root is not at the origin I have to do some matrix concatenation by multiplying the new matrix by the root transform matrix to create a third matrix. As I am only after the position I only use the 4th row of the final matrix.

offsetTrans = (cnt.transform * inverse root.transform)

-- This bit speakes for itself but this gives me the spatial offset of the control handle relative

-- to the chain root

NewPos = (( transMatrix ((normalize offsetTrans.row4) * Limit)) * root.transform).row4

-- the Limit variable contains the result of the Blog formula
-- I normalized offsetTrans.row4 and then multiply it with the Limit
-- this gives me a vector with the right direction and magnitude
-- I push that into a Transmatrix which is then multiplyed by the root transform so everything is offset from the root and not the origin.

I am pretty sure there is a much easier way to do it so I am hoping a maths and script dude will enlighten me to how it should be done.

Cheers

Dan

Chinwagon
01 January 2008, 12:44 PM
There is an easier way of doing this without using any maths.

Create a point, position it at and link it to the root, add a lookat constraint to the new object, point it at the controlling object and link the end effector point to the lookat constrained one.
Create an expose transform helper and use the root as one reference object and the controlling object as the other. Wire the distance output by the exposeTM to the position axis that will control how far away from the root the end effector point will be. Turn that position axis' controller of the wired point to a limit controller and for the upper limit, set it to be the length of the bone chain. From there you can adjust the smoothing buffer and it'll smooth out the snapping in the IK solution.

Easier still, here's the file that does it.
:¬)

djlane
01 January 2008, 12:51 PM
Thanks Brad, not looked at the limit controller before.

Cheers

Dan

PEN
01 January 2008, 02:04 PM
I had something similar to that brad but I as using a simple hermite curve I think to drive the math as the limit controller wasn't implimented at the time. But it was just that simple. I like the idea of the limit controller as that make for a very stright forward setup.

PEN
01 January 2008, 02:30 PM
I just gave it a shot with the limit controller and it works great.

I did a two bone chain setup just to see what it would do. So I have two chains, one is the driver that has the solver on it. The second is wired to ExTm helpers that are exposing the rotation of the driver bones. The I limit the wires.

I'm not sure how you are going to do it with positions with the limit controller as the range of motion needs to be given for the upper and lower limit. Since that position value is relative to a parent object you don't know what it will be. Unless I have missed something about what you have said Brad.

PEN
01 January 2008, 02:37 PM
Never mind, I didn't look at your file, clever, that works great. It is better then what I played with. I will have to go back and see what I did before, I think it was about Max 6 so who knows what I was up to.

eek
01 January 2008, 02:52 PM
There is an easier way of doing this without using any maths.

Create a point, position it at and link it to the root, add a lookat constraint to the new object, point it at the controlling object and link the end effector point to the lookat constrained one.
Create an expose transform helper and use the root as one reference object and the controlling object as the other. Wire the distance output by the exposeTM to the position axis that will control how far away from the root the end effector point will be. Turn that position axis' controller of the wired point to a limit controller and for the upper limit, set it to be the length of the bone chain. From there you can adjust the smoothing buffer and it'll smooth out the snapping in the IK solution.

Easier still, here's the file that does it.
:¬)

Paul,

ExposeTM the distance of two objects, one parented to the root bone looking at another at the end, (the ik goal is parented and i guess orientated in the same direction as this root point). Then you drive the ik goal with this distance along im guessing its x axis - and further adding a limit controller to soften it.

I do similar things, but completely written with 3 lines of code. Essentially all I do is, get the distance of two points 'd1'. Build that direction with (p1.pos - p0.pos)+p1.pos 'n1' and use the exact same equation (with some tweaking to factor in the direction) if d1 > 0 and d1 < da (combined lengths - the soft value) I call n1, if not I use the equation.

Pretty neat when you have softStretch. :) (with this you just wire the ratio to a multipler of the bones original length, and parent the ik goal directly to your control object, XSI's goal is based on the length of the bones)

cheers,

CGTalk Moderation
01 January 2008, 02:52 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.

1