Jump to content

Drawing Process?


terinfire

Recommended Posts

Alright, maybe I'm an idiot, but I'm *really* struggling with how to draw things. I can take care of the actual drawing, but I think my positioning and angles, etc, are not correct.

Is there a process for "drawing" and building up each animation? I understand that we have to tween between animations, i.e. if we're between two key-frames, we need to interpolate what occurs between each -- not a problem.

But how do each of the transformations work? At the moment, I have something that looks like HP Lovecraft wrote -- a bunch of bizarre, mangled body parts that are floating around unusually...

I'm animating based off of Timeline Objects only -- but I'm assuming at this point that this assumption is wrong. Do I have to find the bones, then find which objects are referenced to them, and then transform the bones, then transform the objects? Is there a clear way on how to look at this, even if pseudo code, i.e.

Scan Mainline. Get a Key. Get the two key frames you can potentially be between. Find out the Timeline for each. Get the Timeline Object and then calculate the Linear/Cubic/Quadratic tweened variables between the two and render.

(this is what I'm currently doing)

Am I missing something? Thank you!!!

Link to comment
Share on other sites

Hello terinfire.

The most up to date docs are here: http://www.brashmonkey.com/ScmlDocs/ScmlReference.html

But as stated in the other thread, we're going to completely overhaul the documentation and make it easier to understand and more thorough. Basically each has information about the bones and zorder. They are listed in an order that doesn't require you to do more than one pass in the hierarchy.




























The way we recommend doing this is just making an array for the bone_refs in the same order, and fill that with the unmapped values, so the x and y coordinates after it's been unmapped from it's parent (if it has a parent - unmapFromParent is an example of the function in the docs linked above), as you fill this array, each time you see parent='3' for instance, then you have the values there ready to go. As stated before, it's provided in an order where you never have to worry about saying bonerefs[3], and not having added that value yet. The z-ordered refs (object_refs like sprites) use the same indexes for their parents.

Please let me know if that answers your question.

Link to comment
Share on other sites

That doesn't help me much -- you've made the mud slightly more translucent, but not much.

So, let's say I'm doing what you're talking about.

I would walk through the MainlineKey's -- bones included. If an object_ref has a parent, that refers to its bone? So, if I see a parent=0, that means to refer to the value in its parent, where the bone_ref id=0? And bones can be connected to bones, but an object_ref is only connected to a bone, yes?

So for the example of bone_ref id=1, the parent bone is id=0. And object_ref id=0's parent is bone_ref id=1?

Then do all of the values scale down the hierarchy? i.e. if bone_ref id=0 has x = 2, y = 4, and bone_ref id=1 has x = 3, y = 5, the total "scaled" value for bone_ref id=1 is x = 2 + 3 (5) and y = 4 + 5 (9)? And then, would I scale the object_ref referring to parent bone_ref = 1 by the values there? (i.e. x = +5, y = +9) ?

Assume I have this correct -- I don't see any information on the bone's point of rotation, etc?

When I read, pivot_x/y correspond to the: 0,0 (bottom left) to 1, 1 (top right) of the image -- so if you get .5, .5, that would mean the center of the image -- so if the image is 60 x 50, the center (effectively) for rotating is 30, 25?

And how do scale_x/y work? Do they apply to the X/Y coordinates only, or also the width/height?

Whew! Sorry, I know this is a lot to ask, but I'm trying very hard to understand how everything works together and how the data correlates. Right now, I have a very ugly mess, and I'd desperately like to make it work!

Link to comment
Share on other sites

Sorry to double post -- but I think I checked out the document you provided.

So, the formulas for unmapping (so the parent's scalar values are applied correctly to the child) are in the document. Then is my process otherwise correct? And how about pivot points for bones?

So, end of day -- if I built SpatialInfo every frame, the only piece it would need now would be the FolderID/FileID to know WHICH image to paint and where?

Link to comment
Share on other sites

I would walk through the MainlineKey's -- bones included. If an object_ref has a parent, that refers to its bone? So, if I see a parent=0, that means to refer to the value in its parent, where the bone_ref id=0? And bones can be connected to bones, but an object_ref is only connected to a bone, yes?

...

Then do all of the values scale down the hierarchy? i.e. if bone_ref id=0 has x = 2, y = 4, and bone_ref id=1 has x = 3, y = 5, the total "scaled" value for bone_ref id=1 is x = 2 + 3 (5) and y = 4 + 5 (9)? And then, would I scale the object_ref referring to parent bone_ref = 1 by the values there? (i.e. x = +5, y = +9) ?

Bones are the only parents anything can have. The 'parent' refers the bone_ref id, correct. If you copy the position values for the bone_refs in order, then 'parent' will also refer to the array index:

bone_refs[parent] would be where it'd get the parent value from.









now pretend I have a resizeable array or vector called:

bone_refs[];

I would start with the first bone_ref id, which will never have a parent. You would take the information from timeline 16 key 7, and tween with the next key if you're between them, and store this info in bone_refs[0]

the when you got to bone_ref id=1 you'll see it's parent is 0, so you would go to bone_refs[0], and use that information you stored there to unmap it and because this is bone_ref id=1, you store it at bone_refs[1]. Anything that has a parent of 1 will get all the info they need from bone_refs[1], and don't need to check whether bone_refs[1] had it's own series of parents or not.

One important thing to note is that any bone_ref's or object_refs without parents. You should basically make your in game object the parent. So if your spriter animation was for a character in the game, you would take the character's xy position, angle, etc, and then unmap those parent=0 refs, from your actual game object.

Assume I have this correct -- I don't see any information on the bone's point of rotation, etc?

Bone's don't have any point of rotation, just x,y,angle,scale, and that's all the information you need for animating. If you actually want to draw the bones themselves for a debug mode, or something, their pivot would be 0,0, and their length would be their scale * the bone length information at the beginning of the scml in the structures

When I read, pivot_x/y correspond to the: 0,0 (bottom left) to 1, 1 (top right) of the image -- so if you get .5, .5, that would mean the center of the image -- so if the image is 60 x 50, the center (effectively) for rotating is 30, 25?

correct

And how do scale_x/y work? Do they apply to the X/Y coordinates only, or also the width/height?

Both, just multiply parent's (if they have one) scale *xy coordinates. And multiply parent scale * object_scale, and this is what you multiply by the images width to get the final width.

Whew! Sorry, I know this is a lot to ask, but I'm trying very hard to understand how everything works together and how the data correlates. Right now, I have a very ugly mess, and I'd desperately like to make it work!

No problem at all. Also, if you post a screencap or send me a private email (lucid@brashmonkey.com) if you don't want to post it publicly - the character how they look in spriter, and then how they look in your engine. I've seen a lot of people's implementations, and made some of those mistakes early on myself, so I may be able to help more specifically if I see the incorrectly drawn frames. So if the above doesn't help you, please send me an example.

Sorry to double post -- but I think I checked out the document you provided.

So, the formulas for unmapping (so the parent's scalar values are applied correctly to the child) are in the document. Then is my process otherwise correct? And how about pivot points for bones?

So, end of day -- if I built SpatialInfo every frame, the only piece it would need now would be the FolderID/FileID to know WHICH image to paint and where?

correct

The document of spriter is so bad.

We are currently working on a much better document.

But anyway, Spriter is a great application , I love it .

Thank you!

Link to comment
Share on other sites

So, I've tried to go through the routine of applying the transformations, and it looks like I'm getting "closer."

I've attached the image -- I'm using the standard "walking" animation. He appears to be drawn partially upside down and the animation seems to be all kinds of funky... But, it does look closer, at least.

Still trying to make sense of some of the specification -- it's really challenging.

Is it safe to assume that for each Timeline Key, there will be only ONE object beneath it? Either a bone or an object?

Thanks!

post-16990-14159834214782_thumb.png

Link to comment
Share on other sites

So, I've tried to go through the routine of applying the transformations, and it looks like I'm getting "closer."

Is it safe to assume that for each Timeline Key, there will be only ONE object beneath it? Either a bone or an object?

It is safe to assume that. That was something we had done to leave room for future expansion.

From looking at your image, there's a few things you can try, and I'm pretty sure it's some combination of the things below. It may be just one or two, or all three, so try each of the following:

As you're loading the file, do this to these values before you start trying to play back the animation

    [*:axizdid8]
y=y*-1.0;


[*:axizdid8]

angle=360.0-angle;


[*:axizdid8]

pivotPointY=1.0-pivotPointY;

Spriter saves so Y increases as you go up, and many engines are the opposite. It also uses angles that increase clockwise, and pivot coordinates with 0,0 at the bottom left. Some engines and api's use these same coordinate systems and some don't. So if your engine is the opposite it will need one or more of these changes. This information will be included in the upcoming documentation.

Link to comment
Share on other sites

So, funny enough, those things seemed to help! Funny, I tried it before and had no luck, but it works now -- so thank you!

I just need to fix my actual animation renderer -- seems like I'm going a little too fast through things right now and that it isn't properly tweening it towards the end -- but otherwise, it's pretty good!

Link to comment
Share on other sites

OK, sorry -- one more question. I got a little over-excited that at least things were showing up in the correct position.

The animations are very choppy. I have a feeling it has something to do with some of the Mainline Key's having points that are not existent in the Timeline. For example, in the main sample that comes with Spriter, the head moves at time=2473, but the legs/arms do not have any key during that time... So I'm not sure how it works.

What my process for drawing at the moment is:

1) Find the current animation

2) Find the primary mainline key that it is on

3) Find the secondary mainline key that is next (And we have to interpolate between, should be primary + 1 index)

4*) Loop through the bones and store the transforms in advance (per your advice -- this is good)

5) Loop through the object references in the primary mainline key

5.1) Find the primary timeline key that we are currently on

5.2) Find the secondary timeline key that is next (and we have to interpolate between, should be primary + 1 index)

5.3*) If there is a parent to this (a bone), apply the transformations

So, for most of this, as I said, it renders correctly. But I think when it bumps into these points where the mainline (which has 15 items of bone/object's). The timeline with id=0 only has 12 items... I think there is some kind of issue with how to interpret the results for this when looping through the mainline. It's hard to read the SCML and figure out how it's interpolating for these points by hand. The problem *has* to lie here.

Link to comment
Share on other sites

1) Find the current animation

2) Find the primary mainline key that it is on

3) Find the secondary mainline key that is next (And we have to interpolate between, should be primary + 1 index)

Ok, right here, a slight difference. The mainline key will point you to the timeline key you should be at, and you tween the timelinekey with the next key in that timeline

so even if you have mainlinekey at 100, and another at 120,

if it points you to a timeline key at 90, and the next key in that timeline is at 1000, you interpolate using those times 90 and 1000, with whatever your actual current time is.

Link to comment
Share on other sites

Awesome! I'm almost there! I have it rendering perfectly for if it just shows the individual points and doesn't interpolate (unless Progress through either is either a 0 or a 1). I found out that I had an issue wherein I didn't interpolate correctly, so I only had Progress between Primary & Secondary Timeline Key's was a whole number.

Now, when I interpolate, (converting it to floating point before it does the division) I seem to be having issues. The arms spin around on the default model like he's going crazy... or doing propeller arms against some bad guy. Kind of a funny effect, but wrong.

For the interpolation for angles, the parameters per the SCML (angleA, angleB, int spin, float t) would correspond to (PrimaryTimelineKey.Angle, SecondaryTimelineKey.Angle, PrimaryTimelineKey.Spin, Progress)

wherein Progress is...

Single Progress = ( (Single) ( Milliseconds - PrimaryTimelineKey.Time ) ) / ( SecondaryTimelineKey.Time - PrimaryTimelineKey.Time );

(Milliseconds is the amount of time that has passed for the animation, and lies between 0 and animation.Length).

Do we have to do any weird interpolation on spin? Is there anything special we have to follow for the spin itself? I'm just trying to figure out why my character is going nuts and choppy on a few of the animations...

Just for the sake of it, here's the code I have (TimelineObjectReference is essentially a return with all of the data for each "frame" after being transformed):


public List GetTimelineObjects()
{
List results = new List();
if ( Reference != null && EntityID != INVALID && AnimationID != INVALID )
{
Animation CurrentAnimation = GetCurrentAnimation();

MainlineKey CurrentMainlineKey = GetCurrentMainlineKey( CurrentAnimation );

List BoneReferences = new List();

for ( int i = 0; i < CurrentMainlineKey.BoneReferences.Count; i++ )
{
int TimelineIndex = CurrentMainlineKey.BoneReferences[i].Timeline;
int TimelineKeyIndex = CurrentMainlineKey.BoneReferences[i].Key;
int NextTimelineKeyIndex = TimelineKeyIndex;

if ( NextTimelineKeyIndex < CurrentAnimation.Timelines[TimelineIndex].Keys.Count - 1 )
{
NextTimelineKeyIndex++;
}

TimelineKey PrimaryTimelineKey = CurrentAnimation.Timelines[TimelineIndex].Keys[TimelineKeyIndex];
TimelineKey SecondaryTimelineKey = CurrentAnimation.Timelines[TimelineIndex].Keys[NextTimelineKeyIndex];

TimelineObjectReference Bone;

if ( PrimaryTimelineKey == SecondaryTimelineKey )
{
Bone = GetTimelineObjectReference( PrimaryTimelineKey.Bone );
}
else
{
Single Progress = ( (Single) ( Milliseconds - PrimaryTimelineKey.Time ) ) / ( SecondaryTimelineKey.Time - PrimaryTimelineKey.Time );

Bone = GetInterpolatedTimelineObjectReference( PrimaryTimelineKey.Bone, SecondaryTimelineKey.Bone, Progress );
}

if ( CurrentMainlineKey.BoneReferences[i].Parent != BoneReference.DEFAULT_PARENT )
{
Bone = ApplyTransformations( BoneReferences[CurrentMainlineKey.BoneReferences[i].Parent], Bone );
}

BoneReferences.Add( Bone );
}

for ( int i = 0; i < CurrentMainlineKey.ObjectReferences.Count; i++ )
{
int TimelineIndex = CurrentMainlineKey.ObjectReferences[i].Timeline;
int TimelineKeyIndex = CurrentMainlineKey.ObjectReferences[i].Key;
int NextTimelineKeyIndex = TimelineKeyIndex;

if ( NextTimelineKeyIndex < CurrentAnimation.Timelines[TimelineIndex].Keys.Count - 1 )
{
NextTimelineKeyIndex++;
}

TimelineKey PrimaryTimelineKey = CurrentAnimation.Timelines[TimelineIndex].Keys[TimelineKeyIndex];
TimelineKey SecondaryTimelineKey = CurrentAnimation.Timelines[TimelineIndex].Keys[NextTimelineKeyIndex];

TimelineObject PrimaryTimelineObject = PrimaryTimelineKey.Object;

if ( PrimaryTimelineKey == SecondaryTimelineKey )
{
TimelineObjectReference Object = GetTimelineObjectReference( PrimaryTimelineObject );

if ( CurrentMainlineKey.ObjectReferences[i].Parent != MainlineObjectReference.DEFAULT_PARENT )
{
Object = ApplyTransformations( BoneReferences[CurrentMainlineKey.ObjectReferences[i].Parent], Object );
}

Object.FileID = PrimaryTimelineObject.File;
Object.FolderID = PrimaryTimelineObject.Folder;

results.Add( Object );
}
else
{
try
{
Single Progress = ( ( Milliseconds - PrimaryTimelineKey.Time ) ) / ( SecondaryTimelineKey.Time - PrimaryTimelineKey.Time );

TimelineObject SecondaryTimelineObject = SecondaryTimelineKey.Object;

TimelineObjectReference Object = GetInterpolatedTimelineObjectReference( PrimaryTimelineObject, SecondaryTimelineObject, Progress );

if ( CurrentMainlineKey.ObjectReferences[i].Parent != MainlineObjectReference.DEFAULT_PARENT )
{
Object = ApplyTransformations( BoneReferences[CurrentMainlineKey.ObjectReferences[i].Parent], Object );
}

Object.FileID = PrimaryTimelineObject.File;
Object.FolderID = PrimaryTimelineObject.Folder;

results.Add( Object );
}
catch ( Exception )
{ }
}
}
}

return results;
}


//Code for the interpolation, for the sake of it, but is a copy of the ScmlReference stuff on your website


public static Single Linear( Single pA, Single pB, Single pPercentComplete )
{
return ( ( pB - pA ) * pPercentComplete ) + pA;
}

public static Single AngleLinear( Single pStartAngle, Single pEndAngle, Single pPercentComplete, Int32 pSpin )
{
if ( pSpin == 0 )
{
return pStartAngle;
}
if ( pSpin > 0 )
{
if ( ( pEndAngle - pStartAngle ) < 0 )
{
pEndAngle += 360;
}
}
else if ( pSpin < 0 )
{
if ( ( pEndAngle - pStartAngle ) > 0 )
{
pEndAngle -= 360;
}
}

return Linear( pStartAngle, pEndAngle, pPercentComplete );
}

And remember -- the Progress (when 0 or 1) seems to render the animation fine -- just choppy (since there is no transition between the frames).

It would be nice to release this assembly/code to everyone as soon as I get it "correct" so others can use it. I'll probably include a C#/XNA/MonoGame example of the code, so others can use it, along with notes on how to render/process the result, such that we can avoid a lengthy (and information -- thank you!) discussion again.

Thank you, lucid! Hopefully we can nail this down.

Link to comment
Share on other sites

Didn't help. When we interpolate, which spin parameter do we want? The one from the index, or from index + 1 on the timeline keys? I'm literally reading in Spriter -- this is the data from Spriter -- not any of my own data. So the angle will be the exact same representation as it is in the file.

I tried reversing the order of the items getting interpolated as well, but that didn't help.

The issue seems to occur *somewhere* in the interpolation. Can you maybe look over the algorithm itself one more time and check to see if the process is correct?

1) Find Current Mainline Key (loop through mainline keys, find the LAST one that has time <= current time)

2) (For Bones) Find the Timeline's associated with this Mainline Key.

2.a) Find the TimelineKey associated from this, as well as the next logical TimelineKey (if one exists).

2.b) Get the stacked Bone transformations and store them.

3) (For Objects) Find the Timeline's associated with this Mainline Key.

3.a) Find the TimelineKey associated from this, as well as the next logical TimelineKey (if one exists).

3.b) Get the object and apply parent transformations.

The interpolation has to be wrong somewhere. I'm just not sure where. Any help would be appreciated. Maybe the interpolation is correct, but for some reason the order or bones are wrong? I'm not sure.

EDIT: Spin appears to be coming back as 1, when it should be 0 -- will double check/investigate further.

Link to comment
Share on other sites

If a parent bone has a spin, but the child does not -- how does that affect it? Or what if the parent is a "1" and the child is a "1" or a "-1"? Do we multiply them?

So, from what I can tell, the issue I've bumped into is that the child has a default value of "1" (SpatialInfo)?

The more I look at it, the more I think I'm just getting confused because of the frustration involved with the outdated ScmlReference page. It looks like Spin is no longer on the Bone/ObjectTimelineKey, but located above it.

EDIT: And that was it! GOT IT!

Thanks for the help, lucid!

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...