My invention of inverse kinematics for Unity.

Hello,
I had posted a topic earlier on this form about how to make it so that I can make something like a hand from a character move to a specific vector spot in world space, and make all the other connecting limbs from that character re-attach themselves accordingly so that no limbs would stretch outside the proper boundaries of that character.

I was told that it was called “inverse kinematics” and that it can’t be done in Unity without a high cost, so I developed a script of my own that does exactly what I wanted. I place my script on the parent of the hip and when ran, the scripts then automatically duplicate themselves onto the children, then the grand children, etc. all the way up to the ‘leaves’ of each objects.

Where I originally put my scripts, I have 3 reference variables I need to set, (LimbObj, StopObj and GoalObj). LimbObj is the part I want to move (like the right hand). StopObj is where the connections stop (if I am using the right hand, the stop object should be the right shoulder so that the abdomen, hips, neck and head along the upper hierarchy don’t also move along with the shoulder). GoalObj is where the limb tries their best to meet up with the goal object’s position. If it is not within reach, the limbs stretch as close as they can to the object. If within reach, the other limbs will bend in a way so that the limb object’s position will approximately equal the goal object’s position in world space.

Here is the code I’ve written so far. How would I publish it so that I can be the author and get good references so I can get my foot in the door in this economy we’re in with no work experience and minimal education in the computer field?

class ik extends MonoBehaviour {
public var posArray;
public var rotArray;
public var posDiff;
public var rotDiff;
public var pRoot;
public static var pLimbObj;
public static var pStopObj;
public static var pGoalObj;
}

var LimbObj : Transform;
var StopObj : Transform;
var GoalObj : Transform;

function Start () {
posArray = Array();
posArray.clear();
rotArray = Array();
rotArray.clear();
for (var child : Transform in transform) {
dist = getDistance(transform.position.x, transform.position.y, transform.position.z, child.position.x, child.position.y, child.position.z);
posArray.Add(dist);
rot = child.localEulerAngles;
child.LookAt(transform.position);
rotArray.Add(child.localEulerAngles);
child.localEulerAngles = rot;
}

if (transform.parent != null) {
rot1 = transform.parent.eulerAngles;
transform.parent.LookAt(transform.position);
rot2 = transform.parent.eulerAngles;
transform.parent.eulerAngles = rot1;
rotDiff = rot2 - rot1;
posDiff = getDistance(transform.parent.position.x,transform.parent.position.y,transform.parent.position.z,transform.position.x,transform.position.y,transform.position.z);
} else {
rotDiff = 0;
posDiff = 0;
}

if (transform.parent == null) {
pRoot = transform;
pStopObj = StopObj;
} else {
if (transform.parent.GetComponent(“ik”) == null) {
pRoot = transform;
pStopObj = StopObj;
pGoalObj = GoalObj;
pLimbObj = LimbObj;
}
}

for (var child : Transform in transform) {
if (child.gameObject.GetComponent(“ik”) == null) {
child.gameObject.AddComponent(“ik”);
child.gameObject.GetComponent(“ik”).pRoot = pRoot;
child.gameObject.GetComponent(“ik”).pStopObj = pStopObj;
child.gameObject.GetComponent(“ik”).pGoalObj = pGoalObj;
child.gameObject.GetComponent(“ik”).pLimbObj = pLimbObj;
}
}

}

function getDistance(x1, y1, z1, x2, y2, z2) {
return (Mathf.Sqrt((Mathf.Abs(x1-x2)*Mathf.Abs(x1-x2))+(Mathf.Abs(y1-y2)*Mathf.Abs(y1-y2))+(Mathf.Abs(z1-z2)*Mathf.Abs(z1-z2))));
}

function Update () {

i = 0;

var t : Transform;
for (var child : Transform in transform) {
if (child.gameObject.GetComponent(“ik”) != null) {
child.position.x = transform.position.x;
child.position.y = transform.position.y;
child.position.z = transform.position.z;
ang = child.localEulerAngles;
child.localEulerAngles = rotArray*;*
_ child.Translate(Vector3(0, 0, -posArray*));_
_
if (child.name == pLimbObj.name) {_
_
t = child;_
_
while (t.parent != null t.name != pRoot.name t.name != pStopObj.name) {_
_
if (t.name != pRoot.name t.name != pStopObj.name) {_
_
if (t.GetComponent(“ik”).rotDiff != null) {_
_
t.LookAt(pGoalObj.position);_
_
t.Rotate(-t.GetComponent(“ik”).rotDiff);_
_
}_
_
t = t.parent;_
_
}_
_
}_
_
} else {_
_
child.localEulerAngles = ang;_
_
}_
_
}_
_
i++;_
_
}*_

}

I forgot to mention I named my script “ik”. It is very important to name it “ik” because the scripts reproduce themselves onto child objects. I hope nobody steals my newest invention because I know nothing about patents or publishing, and would like to use what I’ve done so far as a reference.

Probably you would not want to post it publicly if you’re that worried about it being stolen. Probably a more good idea would be to create an example project showcasing its strengths (“here we have a dude climbing a wall, but I’m just moving his hands, yay”), and include that project in a portfolio you submit to whoever you’re talking to.

That said, we programmers are overall a pretty decent lot, so if you just ask us to give credit where it’s due, 99% of the time you’ll be credited as the script author. :smile:

Definitely include comments naming yourself as the author

// Super IK Solver Extreme Deluxe v2.7
// Script by Blah, King of Space
// Free to use, but please give credit :slight_smile:
or whatever.

I must point out though -
The large number of string comparisons (.name==) in an Update is a huge hit on game speed.

Also your getDistance function exists as

(transform1.position - transform2.position).magnitude

:slight_smile:

also code tags

Class Awesome {
  var seeNowIHave = "some whitespace";
}

function SoYouCanTellWhere( things : Are ) {
 var more : Better;
}

I noticed when I used pos1-pos2 in my “get distance” function, it wasn’t always accurate and would return a whole numbered answer followed by 1 decimal (only the tenth’s place) for each coordinate, but when I used 6 arguments and did pos1.x-pos2.x, pos1.y-pos2.y and pos1.z-pos2.z, that’s when my function finally worked and returned more than just 1 decimal for each coordinate.

I was under the impression that Vector3 stores the information correctly, but the Vector3’s log code only prints the first decimal place. (While float’s log code prints all of them.)

Could be wrong, though. D:

That’s correct.

–Eric

Hi EnsurdFrndship. Your solution to the inverse kinematic it’s really what I was looking for to deal with a problem that it’s really driving me crazy!

Basically, when my character crossfades from walk to idle, his forearms won’t come back to the idle position. (I described the whole problem in this post http://forum.unity3d.com/viewtopic.php?t=65309).

So I’d like to give your script a try. Would you help me figure out how to apply your script to solve my problem?

Thank you :slight_smile:

Have you measured this? I highly doubt it is true. Modern compilers, including Mono, use interning to reduce string comparisons to a reference lookup. I’d expect GameObject names to be interned, making these comparisons no slower than, for example, int comparisons.

I am still working to add more to the code and fix it so that I can do multiple limbs and also noticed that my code does reverse for legs of characters, where instead of the legs pointing toward the goal position, they point away from the goal position, so I need to create another variable called offset so that each connecting limb can have it’s own separate offset rotation when I use the LookAt statement in my code. In order to get the legs to point toward the goal position and not away from, I would set it to vector 0,180,0 to give it a y rotational offset of 180 degrees. I also want to make it so that I can change the private variables in my class during run time so I can move the goal position to whichever vector I’d like.

It’s quite true. Comparing gameObject.name vs. gameObject.layer is about 10X slower, depending on the length of the names.

While on the subject of strings, “GetComponent(“ik”)” should be “GetComponent(ik)” for better performance. Speaking of performance, component references should be cached. For example, instead of:

child.gameObject.AddComponent("ik"); 
child.gameObject.GetComponent("ik").pRoot = pRoot; 
child.gameObject.GetComponent("ik").pStopObj = pStopObj; 
child.gameObject.GetComponent("ik").pGoalObj = pGoalObj; 
child.gameObject.GetComponent("ik").pLimbObj = pLimbObj;

it would be

var ikScript = child.gameObject.AddComponent(ik); 
ikScript.pRoot = pRoot; 
ikScript.pStopObj = pStopObj; 
ikScript.pGoalObj = pGoalObj; 
ikScript.pLimbObj = pLimbObj;

Not that it would make much if any difference in this case since it’s only done occasionally I gather, but at least the code’s a lot shorter… While we’re at it, “ik” should be “IK”…not for performance reasons of course, but class names should be upper case. :wink:

–Eric

Indeed. Quite odd, GameObject names seem like the perfect candidate for interning.