PDA

View Full Version : 2D Skeletal Animation System Questions (and Source)



jdarling
03-05-2006, 07:02 PM
Hey all, I've had a few minutes since Chance came along and started back to work on some of my projects. One of these is a 2D Skeletal Animation Package (lets you create 2D sprites and then animate them easily). To achieve this I'm using the standard Joint and Bone mech.

Now though I have some problems, I can't seem to find out how to perform proper translations and rotations based upon the other "Nodes" in the system.

You can view the source Here (Rather then post the entire thing in the forum) (http://www.eonclash.com/temp/Bones.pas) and here is a sample of the desired output:
http://www.eonclash.com/temp/Bones_Sample.PNG

Basically the node at the top in green is the root joint (Joints don't have to have bones, but bones must have end point joints). From their I have a "Bone" moving on a downward vector (X:0, Y:1) etc, etc...

When rendering I take the root joint, walk its bones and their joints recursively and place the items on the screen. The idea is you would call Translate(X, Y) or Rotate(Degree) and this would set the FRelativeValid flag to false, upon reading the RelativeTranslation or RelativeRotation it calls CalculateRelative (only if RelativeValid = false) and then returns the calculated values (as well as sets privates for later use to lower recursion and overhead). I should then be able to plot the RelativeTranslation point to the screen directly (minus any world transformations).

What code should be in CalculateRelative?

If I'm completely on the wrong track please SPEAK UP! I have no clue what I'm doing and their are few if any good articles on the subject. This can't be rocket science as I know that others have done it in 3D, I just want to do it in 2D.

Thanks ahead of time.

grudzio
03-05-2006, 09:36 PM
I think that the easiest way is to use OpenGL's glPushMatrix and glPopMatrix. The pseudocode for drawing would be


procedure TBone.DrawBone;
var
i : integer;
begin
glPushMatrix;
RelativeTranslation;
RelativeRotation;
for i := 0 to ChildrenCount - 1 do
Children[i].DrawBone;
glPopMatrix;
end;

procedure TSkeleton.Draw;
begin
root.DrawBone;
end;


If you dont want to use glPushMatrix and glPopMatrix (or you dont use OpenGL) then in each bone (or joint?) you should store relative position/rotation (bone's local coordinate system) and absolute position/rotation (world coordinate system) Then to calculate new absolute values:


AbsoluteMatrix := RelativeMatrix*Parent.AbsoluteMatrix;

I hope it helps.

User137
04-05-2006, 06:09 PM
Interesting.. I am currently starting a bone animator for OpenGL. Problem with that render recursion is that each polygon may have vertices that belong to different bones. So in theory i should do recursive matrix multiplication (whole bone branch) per vertex? Maybe some faster way?

Sly
05-05-2006, 07:55 AM
Most characters use the hips as the root node.

User137, are you referring to weighted vertices? Recurse through each node, storing the resulting matrix in that node. When it comes to rendering the weighted vertices (making sure that the sum of all weights for each vertex equals one), multiply the matrix for the node by the vertex weight assigned to that node. Add these matrices together to get the transformation for that vertex.

User137
05-05-2006, 08:45 AM
I don't know about weighted vertices, each vertex has an index that refers to bone.

Yes, having relative and transformed matrix for each bone makes it only 1 multiplication per vertex, smooth enough.

Can't remember now if glMultMatrixf is allowed to call between glBegin and glEnd but i guess i could calculate it too...

jdarling
05-05-2006, 01:04 PM
Interesting.. I am currently starting a bone animator for OpenGL. Problem with that render recursion is that each polygon may have vertices that belong to different bones. So in theory i should do recursive matrix multiplication (whole bone branch) per vertex? Maybe some faster way?

Well I got the system working last night, what I finally ended up doing was this (I'll post the app once I complete it):Removed All Bones
Used only Joints (joints have multiple references out and a single parent)
Joints manage their child joints
Joints contain methods to: Rotate, Translate, and Scale (recursively or non-recursivly)
This pretty much worked to get things running. Now I'm going to go back and setup properties for Rotation, Scale and Translation as I'm not a big fan of procedures for these operations. That and right now their is no frame of reference :). I'll keep everyone posted.

XProger
05-05-2006, 04:24 PM
My old steps :)
http://xproger.mirgames.ru/tmp/TFK_ME.rar

IMHO using of matrixes is not desirable

jdarling
05-05-2006, 07:54 PM
My old steps :)
http://xproger.mirgames.ru/tmp/TFK_ME.rar

IMHO using of matrixes is not desirable

Well the exe looks decent, minus the fact that nothing is readable in it (I'm guessing not in english). I did manage to get a model loaded and take a look at it.

Any chance you have the source lying around as well? I have everything working fine in my system now (well at least you can rotate and translate each node). Now I have to figure out how to get movement from pointA to pointB using locked nodes and max ranges. Funny how I passed Algebra, Calc, Trig all with flying colors and now I can't remember a damned bit of it :)

User137
10-05-2006, 06:12 PM
Here's small demo i made, no source included because the whole class is unfinished and uses my game engine.. just hope they run as smooth on others as it does for me:
http://www.filethatfile.com/uploads/33539BoneDemo.zip
Mouse + wheel rotate and zoom the view. The demo is only making a random bone tree and multiplying each bone matrices per frame.

http://i2.tinypic.com/xnxfs0.jpg

wagenheimer
09-03-2012, 02:46 PM
This is very old! But how is the progress of this?

I would need to create 2D bones animation and I would like some advices of where to start!

Carver413
09-03-2012, 03:53 PM
maybe this will help
http://content.gpwiki.org/index.php/OpenGL:Tutorials:Basic_Bones_System

mobilus
09-03-2012, 11:22 PM
This is my solution.

A few words of introduction: We operate only on angles (one bone = one angle) and one start point (X0, Y0) from figure B (picture 1) - this is the only data that we need to read and write to the file (for one frame of animation).
Additionally, you can have a bone length L, but this is unnecessary when you have a human bones (ideal human proportion) or you can get L from sprite length.

Algorithm:
- starting from the point (X0, Y0), Figure B (picture 1).
- we have angle (a), length of bone (L1), start point (X0,Y0), so we can calculate the point (X1, Y1). (X1, Y1) is a central position of our next sprite (be sure your sprite can be rotated from a center (picture 2, figure A))
- if we have (X1, Y1), (b) and (L2), we can calculate (X2, Y2) and next (X3, Y3)
- we do this same for left and right leg (figure C), and left and right hand (figure D)

Optimization:
This method requires a large number of calculations, but it does not need a lot of resources to read and write. To better work with animation, we can use KeyFrames - write data only for KeyFrames, and the rest is calculated automatically (picture 2, Figure B). It's not difficult to calculate AutoFrames if we operate on angles.


Result (AutoFrames = 5):
http://www.youtube.com/watch?v=igSRP0J5q_I

wagenheimer
12-03-2012, 08:05 PM
Thanks Mobilus!

Your info will be very useful! =)

I think I have understood! I will try to make something here!

Thanks

wagenheimer
12-03-2012, 09:06 PM
How do you calculate the new X1,Y1 position?

I have the original X0, Y0 values and X1, Y1 Values. And the length of Bone, L.



X1 := X0 + L * Cos(DegToRad(Angle-90));
Y1 := Y0 + L * Sin(DegToRad(Angle-90));


This almost works for me. It only works if the Initial Angle between (X0,Y0) and (X1,Y1) is 0 otherwise I got a small difference after the rotation. And my Math does not help! :P

Do you have any advice?

mobilus
13-03-2012, 01:34 PM
My first advice is to not work with Degrees (Animation.zip):


var
S, C: Single;

SinCos(Angle, S, C);
X1:= X0 + L * S;
Y1:= Y0 - L * C;


Your angle must be in the range from 0 to 2*Pi (Figure A, Picture 1):
If Angle > 2*Pi then Angle:= Angle - 2*Pi;
If Angle < 0 then Angle:= Angle + 2*Pi;
(but this should not happen if your animation is prepare properly)

Figure B and C presents the problem that you can have by using Auto Frames.
In my case, one minute of animation takes 40 KB with Auto Frames and 200 KB without Auto Frames - this is still not much, so it is not necessary to implement Auto Frames.