Joint IK with Irrlicht

Post those lines of code you feel like sharing or find what you require for your project here; or simply use them as tutorials.
Post Reply
PaperCutDoom
Posts: 6
Joined: Sun Apr 03, 2011 3:06 am
Location: Hawaii

Joint IK with Irrlicht

Post by PaperCutDoom »

Hey, I couldn't find anything on joint IK with irrlicht, so I'm pretty sure there is nothing publicly available, but if I'm wrong I guess this post is worthless. Anyways, here's a function to position joints using the CCD IK algorithm. It's pretty fast and you can implement it pretty easily into whatever you want. I myself have it in a joint controller class as an IK option. There are three arguments, the first is the boneNode that you want to put at the target vector. The rootBoneNode is the parent joint that the function will solve up to (useful if you don't want the entire body to move to grab a gun). Finally, there is the target, which is a vector3df that hold the position of your target location in 3D space. Hopefully you could all get that without reading my explanation, but I just thought I'd explain just incase.... anyways, thanks for taking a look at it and do whatever you want with the code and I hope this is helpful.

Code: Select all

bool Compute(IBoneSceneNode* boneNode, IBoneSceneNode* rootBoneNode, vector3df target)
{
    vector3df	    rootPos, curEnd, targetVector, desiredEnd, curVector, crossResult, endPos = target;
    double		    cosAngle,turnAngle;
    IBoneSceneNode* link;
    IBoneSceneNode* end;

    // start at the last link in the chain
    end = boneNode;
    link = (IBoneSceneNode*)end->getParent();
    int tries = 0;
    double norm = 2;

    int maxTries = 1000;
    double error = 0.1;
    double maxAngleChange = PI / 12;

    while (++tries < maxTries && norm > 0.1)
    {
        link->updateAbsolutePosition();
        end->updateAbsolutePosition();

        rootPos = link->getAbsolutePosition();
        curEnd = end->getAbsolutePosition();
        desiredEnd = endPos;
        norm = curEnd.getDistanceFromSQ(desiredEnd);

        //std::cout << norm << std::endl;

        // see if i'm already close enough
        if (norm > error)
        {
            // create the vector to the current effector pos
            curVector = curEnd - rootPos;
            // create the desired effector position vector
            targetVector = endPos - rootPos;

            // normalize the vectors (expensive, requires a sqrt)
            curVector.normalize();
            targetVector.normalize();

            // the dot product gives me the cosine of the desired angle
            cosAngle = curVector.dotProduct(targetVector);
            // if the dot product returns 1.0, i don't need to rotate as it is 0 degrees
            if (cosAngle < 0.9999999)
            {
                // use the cross product to check which way to rotate
                crossResult = curVector.crossProduct(targetVector);

                crossResult.normalize();
                turnAngle = acos(cosAngle);	// get the angle

                if(turnAngle < maxAngleChange)
                {
                    turnAngle = maxAngleChange;
                }

                quaternion rotation;
                rotation = rotation.fromAngleAxis(turnAngle, crossResult);
                rotation.normalize();
                vector3df euRotation;
                rotation.toEuler(euRotation);
                link->setRotation(link->getRotation()+vector3df(euRotation.Z, euRotation.X, euRotation.Y));

                //TODO: check DOF restrictions for link joint here.
            }

            if (link == rootBoneNode)
            {
                link = (IBoneSceneNode*)end->getParent();	// start of the chain, restart
            }
            else
            {
                link = (IBoneSceneNode*)link->getParent();
            }
        }
    }

    if (tries == maxTries)
    {
        return false;
    }

    return true;
}
There are 10 kinds of people in this world, the ones who understand binary and those who don't.
Adler1337
Posts: 471
Joined: Sat Aug 09, 2008 6:10 pm
Location: In your base.

Post by Adler1337 »

Very useful thanks for posting :D I was working on IrrIK a long time ago but it was supposed to do per bone animations as well as IK and i never finished it. Maybe with this I can bring it back to life.
multum in parvo
PaperCutDoom
Posts: 6
Joined: Sun Apr 03, 2011 3:06 am
Location: Hawaii

Post by PaperCutDoom »

No problem :) Glad it was actually useful XD But yeah, the maxTries variable is something that should be played with a bit more, and there's no constraint checking. A speed issue is the max tries. When you use animateJoints() the skeleton gets reset, so you need more iterations for it to find a good solution, but if you're not using an animated skeleton, 100 would be a good number for it and it would be much faster. But yeah just play around with the code to make it fit :P
There are 10 kinds of people in this world, the ones who understand binary and those who don't.
Mel
Competition winner
Posts: 2292
Joined: Wed May 07, 2008 11:40 am
Location: Granada, Spain

Post by Mel »

Definately something Irrlicht should have included.
"There is nothing truly useless, it always serves as a bad example". Arthur A. Schmitt
thanhle
Posts: 325
Joined: Wed Jun 12, 2013 8:09 am

Re: Joint IK with Irrlicht

Post by thanhle »

In version 1.81 the rotation euRotation can be used directly.

However I have found a bug in the rotation. When I create a robot arm using node addchild method.
The links face +X.

At angle 90 to 270 degree the rotation seems to flip.
This happens when the target point x, z is less than the rootnode x and z coordinate.

Even using matrix multiplication to obtain the orientation.

I think there is a bug in the matrix calculation somewhere.

Regards
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Re: Joint IK with Irrlicht

Post by christianclavet »

Wow! Really good stuff! :shock: I might use this! :D
At angle 90 to 270 degree the rotation seems to flip.
Too bad I don't have time to create a demo with my goblins going backward when the transition where used on them. (This affect how the interpolation is done when animating the bones, and here you manipulate the bones. Probable chance of having them related to this problem is great.)
Post Reply