Page 1 of 3

Get child bone "real" position after parent bone r

Posted: Sun Jan 14, 2007 12:39 am
by heyvern
Is it possible via LUA to retrieve the "new" bone position of a bone whose parent has been rotated?

Currently constraints can't use this type of translation. But if it could be pulled out via a script and applied to a "holder" bone of some kind, this info could be applied via the constraint.

Example usage:

Bone B is child of bone A.

Bone A is rotated and bone B has a new position in the document space.

Script retrieves the "actual" position of bone B and applies it to a bone called "B.tmp" or something like that to identify it by the name of the other bone.

Since B.tmp is "really" translated, another bone with a constraint pointing to it will be able to use that position information.

I have a situation where if I could only get the "real" position of ONE BONE translated in this manner it would be fantastic. I can transfer that value to about 50 other bones using constraints with different values.

Of course if it would work with one bone it work with a bunch.

-vern

Posted: Sun Jan 14, 2007 8:32 am
by Rasheed
Your wish is my command ;)

TransRotate.zip

The zip archive contains a layer script and a sample Moho file. Embed the layer script in the bone layer and manipulate the rigged rectangle and circle, using the Manipulate Bones or Rotate Bone tools. The bones "child1.tmp" and "child2.tmp" will translate as slave bones (with the same offset to their master bones, "child1" and "child2"), while the master bones rotate. Give the slave bones the same name as the master bones, with ".tmp" as a suffix (attached to the end of the name).

Note however, that if you translate the master bones, the slave bones move in a perhaps unexpected way, because the script doesn't take bone translation into account (you did not request for that, so I left it out). If you also need bone translation of the master bone to be incorporated, just ask me and I will see what I can do to solve it.

If you want to key the slave bones, to save the position permanently in the Timeline, simply use the Translate Bone tool, and click on each slave bone. If you do this in the example file, the labels "circle" and "rectangle" move to their Bone Translation keys, but without putting the keys in the Timeline, they will remain at their current locations. It is a bit hard to explain. Simply try it and see how it works.

BTW It took about five hours to create this layer script, so I hope it is useful to you.

Posted: Sun Jan 14, 2007 8:53 am
by Rasheed
Let's say, this script is only half finished. It still needs some work. The problem is probably in the RealPosition function.

Code: Select all

function RealPosition(skel, boneID)
    -- find the real position of a bone in a bone layer
    local childBone = skel:Bone(boneID)
    local parentID = childBone.fParent
    if ( parentID == -1 ) then
        return childBone.fPos
    end
    local parentBone = skel:Bone(parentID)
    local child = LM.Vector2:new_local()
    local parent = RealPosition(skel, parentID)
    local radius = childBone.fPos:Mag() * parentBone.fScale / 2
    local angle = parentBone.fAngle
    child.x = parent.x + radius * math.cos(angle)
    child.y = parent.y + radius * math.sin(angle)
    return child
end
Please do not use the script until I have solved this. I will not do this today, because my mind is numb from all the maths.

Posted: Sun Jan 14, 2007 2:11 pm
by heyvern
Thanks Rasheed!

You have no idea the potential of this thing.
And I understand the pain of the math.

I was playing around with it myself last night but got totally lost trying to figure out the new position of the child bone based on the angle of rotation of the parent and something about artesian... planter... grid... coordination... something... I looked it up and it had a lot of parenthesis. ;)

I found "math.pow" in a LUA reference... and then passed out under my desk.

But at least I proved to myself it could work. I got a bone to move to a new spot and another bone to move using a constraint to it... it wasn't even close to the right spot but it did move. ;)

-vern

Posted: Sun Jan 14, 2007 2:43 pm
by heyvern
this might be helpful?

In my "math" studies last night I cam across this which is a JS snippet:

Code: Select all

var xdiff = x2 - x1;
var ydiff = y2 - y1;
Math.pow((xdiff * xdiff + ydiff * ydiff), 0.5)
It is for calculating the distance between two points using Cartesian Coordinates.

I had planned to give this one a shot today. It can easily be converted to LUA. My trouble was figuring how to add in rotation to this equation... sort of... get a "bearing" pointing to the new child position.

EDIT:

This is totally useless. ;) What is the point in finding the distance if you've already got the coordinates? <sigh>

-vern

Posted: Sun Jan 14, 2007 5:59 pm
by Rasheed
I have to do this methodically.

Suppose we have three bones, that are root, child and grandchild
root <- child <- grandchild

Here are the properties:

Code: Select all

            root    child   grandchild
position    0, -1   0, -1   0, -1
angle       90º     90º     90º
scale       1       1       1

origin          grandchild
O(0,0)         * (1,0)
+              +
+              + 90º (0,-1)
+        90º   +
*(0,-1)++++++++*(1,-1)
root    (0,-1) child
Because the root bone has a 90 degrees angle, the child bone's coordinates are calculated as follows:

Code: Select all

child.x = root.x - child.fPos.y = 1
child.y = root.y + child.fPos.x = -1
Because the child bone has a 180 degrees angle, the grandchild bone's coordinates are calculated as follows:

Code: Select all

grandchild.x = child.x - grandchild.fPos.x = 1
grandchild.y = child.y - grandchild.fPos.y = 0
More general (fScale is one for the root and child bone):

Code: Select all

child.x = root.x + child.fPos.x * cos(root.fAngle) - child.fPos.y * sin(parent.fAngle)

child.y = root.y + child.fPos.x * sin(root.fAngle) + child.fPos.y * cos(root.fAngle)

grandchild.x = child.x + grandchild.fPos.x * cos(root.fAngle + child.fAngle) - grandchild.fPos.y * sin(root.fAngle + child.fAngle)

grandchild.y = child.y + grandchild.fPos.x * sin(root.fAngle + child.fAngle)
The bone scale is worked into these formulas by multiplying the fPos.x values by the fScale value of the parent bone, like so:

Code: Select all

root.fScale * child.fPos.x * cos(root.fAngle)
root.fScale * child.fPos.x * sin(root.fAngle)
child.fScale * grandchild.fPos.x * cos(root.fAngle + child.fAngle)
child.fScale * grandchild.fPos.x * sin(root.fAngle + child.fAngle)
This should be worked into an algorithm and turned into lua code.

Posted: Sun Jan 14, 2007 6:58 pm
by Rai López
EY! Only to be sure... have you taked an eye to THIS thread where relevant information about individual bones position was posted by the very kind Fazek? I'm not totally sure, but If you are looking for something like that I think it could (maybe) save a lot of time & mathness to you... Even I think that could be more related posts in the immensity of the forum but I neither be sure about this now... Well, I hope that helps, anyway I enjoy a lot seeing this section of the forum (my favourite, in fact :)) so active lately so, if finally not, I take advance of the post to say you THANKS! and run away... Byeee!

Posted: Sun Jan 14, 2007 7:55 pm
by heyvern
Oh boy! Lots of stuff to play with!

I am determined to get this working. It would kick arse.

I am fine at cutting and pasting code and figuring out stuff if I have the basic information to start with. I could never do this whole thing on my own.

My ultimate goal is to be able to "limit" translation constraints the same as the rotation limits. If the translation is based on Genete's really cool "spring" rotation gizmo I can use angle limits to limit translation (I've tested this and it WORKS!).

This would solve a problem I have with my face rig. There are points that I don't want to translate beyond a certain point on the opposite turn. The new rig I am putting together has two sides. By using the rotation limits I can make these bones "stop" at a certain point creating a better head turn.

For instance the side of the head near the eyes, ears and the jaw line. On the far side of each turn, if the bones move symmetrically it is near to impossible to get a totally realistic head turn with just bones. Being able to limit translation means that one side can "go further" on one side and not as far on the other. Each of those spots have to "become" a different part of the head or face. It's all an illusion. For instance the cheek below the eye should "stick out" when the head turns, but "flatten" as it becomes the back of the head.

Having access to this type of rotation/translation for constraints is going to be very helpful.

Some of you might think I'm nuts to go this far with bones... but I love it. It's like people building the Eiffel tower out of legos... only more practical. ;)

-vern

Posted: Mon Jan 15, 2007 12:36 am
by Rasheed
Ramón López wrote:Only to be sure... have you taked an eye to THIS thread where relevant information about individual bones position was posted by the very kind Fazek?
No, I wasn't aware of that. I've browsed through the code and saw that I still have a lot of studying to do. The Lua interface of Moho is just so extensive, and the learning curve so steep. My limited brain has troubles keeping up.

I also remember why both C++ and Java were never the programming languages for me. You just cannot keep the complete language in the active memory of your brain. Because Moho (and Anime Studio) is written in C++, the complexity of the notation of the objects reflects that. Writing Moho must have cost Mike a lot of sleepless nights. I can only imagine how much pain and suffering must have gone into that project...

Posted: Mon Jan 15, 2007 2:47 am
by Rasheed
I studied the script by Fazek, and boy, what a piece of fine code that is! It's unfortunate that Fazek is currently so occupied with other things to do, because he would be of great help for writing new Lua code.

I can use the capture of the vector (vec1) that describes the position of bone base in plain coordinates. I don't need to draw the bones, so I can leave that part out as well. I just have to create a function that processes the vectors that point to the base of each bone. I can then select the valid bones with a ".tmp" suffix (which I already have in my script) as slaves and put the vec1 values of the master bones into the fPos values of the slave bones for frames higher than zero, and use bone.fAnimPos:SetValue(0, vec1) for frame zero.

That could be a huge time-saver (if it works).

Thanks a lot, Ramón!

Posted: Mon Jan 15, 2007 6:35 am
by Rasheed
This is a neat little layer script, which has been written with the help of some forum members: Heyvern, Ramón Lopèz, Fazek, and myself, Rasheed.

Image

The script should be used as follows:
  • embed in a bone layer (check Embedded script file in general tab of the bone layer menu)
  • slave bones are bones that are named after another bone in the bone layer, with ".tmp" at the end (without the quotes)
  • slave bones should be standalone root bones without any child bones
The slave bones will appear at the same location as their master bones, but all in bone translation. The slave bone translation is recorded, so once you've run the animation, you can remove the script (uncheck Embedded script file in the layer menu) and the bone translations of the slave bones will remain, and you can make slight corrections to the movement of the slave bones, if you need to.

Download the zip archive here: TransRotate.zip

Thanks to all who have contributed to this script. I hope it is going to be useful.

Posted: Mon Jan 15, 2007 9:11 am
by Rasheed
I have tweaked the script a bit, so that the slave bone's keys aren't recorded in the Timeline. You now have to do this manually by clicking on the slave bone with the Translate Bone tool. This request came from Genete.

Posted: Mon Jan 15, 2007 9:30 am
by Rasheed
I decided to tweak it even more. In the first line of the code, you can set the variable record to either true or false. If it is true, the keys in the Trranslate bone channel are recorded for the slave bones. If false (the default), these keys are not recorded.

Does anyone has another request for modification?

Posted: Mon Jan 15, 2007 12:14 pm
by heyvern
This is just plain amazing.

Once again you did it Rasheed!

Thank you thank you thank you!!

-vern

Posted: Mon Jan 15, 2007 12:35 pm
by bupaje
Hi Rasheed. Your really going off on the scripting - great. :) Do you mind posting a formal description with your script? I haven't tried all of the different scripts popping up and it might be useful to be able to have a simple blurb "This script does x, y,z. Use it if you need to a, b,c." for those who are coming on this for the first time. We may have to collect and pin a few more threads for the various authors as was done for macton.