Hey guys,
As we all know when we use normal IK rp solver, it pops when it reaches a straight position. Can anyone guide me how to achieve soft ik, below is video link for people who dont know soft IK.
thank you.
Hey guys,
As we all know when we use normal IK rp solver, it pops when it reaches a straight position. Can anyone guide me how to achieve soft ik, below is video link for people who dont know soft IK.
thank you.
Fortunately for me, there are some really helpful 3ds Max riggers over on CGSociety who have provided blueprints for implementing soft IK and stretchy soft IK using the Limit Controller and Script Control (respectively).
Here’s some links which you might find helpful:
http://www.softimageblog.com/archives/108
http://forums.cgsociety.org/showthread.php?f=54&t=738420&page=1&pp=15
-Harry
I keep nagging Autodesk to add this by default to the solvers, they really need a bit of an update. It’s also something I have on my future plans for Red9, just a case of getting round to writing it!
Yes, IK solver upgrade across all Autodesk Software would be and should be pushed for.
Here is a snipped of code that will help you implement a soft ik solver as a node. I have only copy/pasted the compute method, but you can see all the parameters that are needed from that. The node has inputs for the default lengths, as well as additional length parameters, then a softIK parameter to determine how soft you want it to be. We then take the upper bone worldspace matrix and our target bone/effector world space matrix to get the distances. I am sure it can be optimised much more, but it does the trick…
//-------------------------------------------
// This is the caluclation method
MStatus stretchIK::compute(const MPlug& plug, MDataBlock& dataBlock)
{
// Regardless of the stretch, these will always be
// added to the output result
double upperAddition = dataBlock.inputValue(stretchIK::aUpperStretch).asDouble();
double lowerAddition = dataBlock.inputValue(stretchIK::aLowerStretch).asDouble();
// Regardless of whether or not we will actually
// stretch we will need the default bone length
// values
double defaultUpperLen = (dataBlock.inputValue(stretchIK::aDefaultUpperLength).asDouble()) + upperAddition;
double defaultLowerLen = (dataBlock.inputValue(stretchIK::aDefaultLowerLength).asDouble()) + lowerAddition;
// Determine what the maximum length is without any
// stretch incurred
double maximumLength = defaultUpperLen + defaultLowerLen;
// Determine the factors between the default lengths
double upperFactor = defaultUpperLen/maximumLength;
double lowerFactor = defaultLowerLen/maximumLength;
// Get the stretch factor. If this is zero then
// then there is no point doing anything more
double stretchFactor = dataBlock.inputValue(stretchIK::aStretch).asDouble();
// The fact that we're here means that the stretch is active,
// so in order to prevent any over-calculation we should start
// by checking if the distance between our two points is more
// than the combined bone lengths
MMatrix upperBoneWS = dataBlock.inputValue(stretchIK::aWSUpperBone).asMatrix();
MMatrix targetWS = dataBlock.inputValue(stretchIK::aWSTarget ).asMatrix();
// Get the locations as vectors
MVector upperBoneVec(upperBoneWS[3][0], upperBoneWS[3][1], upperBoneWS[3][2]);
MVector targetVec ( targetWS[3][0], targetWS[3][1], targetWS[3][2]);
// Get the distance between the two
MVector relativeVec = upperBoneVec - targetVec;
double actualDistance = relativeVec.length();
// Add Soft IK
double softDist = dataBlock.inputValue(stretchIK::aSoftDist).asDouble();
double daU = maximumLength - softDist;
if ( actualDistance > daU )
{
double shortd = softDist * ( 1.0 - exp( -(actualDistance-daU)/softDist)) + daU;
double scale = actualDistance/shortd;
upperAddition += ((defaultUpperLen * scale) - defaultUpperLen) * stretchFactor;
lowerAddition += ((defaultLowerLen * scale) - defaultLowerLen) * stretchFactor;
}
dataBlock.outputValue(stretchIK::aOutUpperLength).set(defaultUpperLen + upperAddition);
dataBlock.outputValue(stretchIK::aOutLowerLength).set(defaultLowerLen + lowerAddition);
return MStatus::kSuccess;
}