View Full Version : Sample Project for Animating Coalesce Models Available
BobimusPrime
2003.07.31, 02:20 PM
I just finished putting together a Cocoa ProjectBuilder project that opens and animates a Coalesce model. The source code is free to be used by anyone. It's not exactly a tutorial but there should be enough commenting understand it.
Let me know if you have any questions.
AnimateModel.sit (http://www.bobbosoft.com/AnimateModel.sit) 959 kB
Robert
codemattic
2003.08.01, 11:02 PM
Here is a suggestion on possibly a better way to organize your code/file format. The way you have it now:
Loop through triangles
set texture/color
draw triangle
when:
Loop through textures
set texture/color
Loop through triangles with that texture
draw triangle
seems much more OGL friendly. Look at how meshwork defines its file format. It has the 'MATERIAL' keyword and then defines that material's properties. Then it lists the triangles that use that material. Grouping it this way is beneficial. Lets say you have a model with 2000 tris and 2 materials - would you rather set the material twice or 2000 times! And usually for low-poly models there is only one texture.
Thank you for posting the code. One of the things posted constantly on idev's boards is "how do I animate my skeletal models?". The code is well commented enough that developers can learn how this works.
I wish it was oo - but many people on idev seem to prefer non-oop - so its a matter of taste.
The code uses globals which would have to be taken out if someone wanted to use it in a game (unless their game only had one model!)
Also - can you add a duration variable to each frame (and get rid of the speed variable for each animation)? The duration would be a float and represent seconds. Many animations are hard to create with rigid frames. Check out 'dim3 Animator' app <http://homepage.mac.com/shavendave/FileSharing7.html> which includes source.
Thanks again for letting us d/l this source code. There is much we can learn from it.
cheers
BobimusPrime
2003.08.01, 11:34 PM
codemattic:
I think you are right about the setting the textures only once. If you look at the code I use the texture only changes when the texture of the current triangle is different from the previous triangle. With one texture it should never change but with many textures there is the possibility of it changing textures way more often than it should need to.
The global model variable could be turned into a linked list or even just a larger array. All of the files besides Model.h retrieve a pointer to the current model variable so to get access to one of many models you would just need to return the proper pointer. I personally don't understand how you would get around having global variables. I would think the variable has to come from somewhere. But then again I don't understand object-oriented programming very well :).
I'm guessing you played around with the original Coalesce before it was cocoaized. I had the animation timing set to durations for each frame before, but I just found it to be too much effort to change the delay on each frame individually when an overall change of speed is all that was really needed. You don't think setting the delay on each frame is too much effort?
Thanks for your comments.
Robert
codemattic
2003.08.03, 02:45 AM
first of all - these are only suggestions - this is just the style I would program in (if I wasnt using oo - which I *would* use here instead - more on that later). Maybe it will give you some programming design ideas - or not! These are just some ideas Im throwing out there - and trying to think ahead about how you can use your code in a game. And this is being typed at 2am off the top of my head - so there could be many typos/syntax errors.
Anyway - you can avoid globals like this:
in File.h/.cpp instead of having:
void LoadCoalesceModel(char *data);
define it as:
void LoadCoalesceModel(Model *aModel, char *data);
when LoadCoalesceModel calls:
SetupVertices(tvertex);
I would instead call SetupVertices(aModel, tvertex);
which would be defined in Model.h/.cpp as:
void SetupVertices(Model *aModel, long tvertex);
and of course instead of having:
void DrawGLScene(void);
in Render.h/.cpp id have something like:
void SetupGLScene();
void DrawModel(Model *aModel);
And so forth. You get the idea. This lets the calling program tell LoadCoalesceModel what model you want to load into - and LoadCoalesceModel passes that pointer to any function it calls and so on. The caller is in control. And we get rid of globals.
So to use it I would:
Model *runningGuyModel, *robotOverlordModel;
runningGuyModel = malloc (sizeof(Model));
LoadCoalesceModel(runningGuyModel, "/Assets/runningGuy.coal");
robotOverlordModel = malloc (sizeof(Model));
LoadCoalesceModel(robotOverlordModel, "/Assets/robotOverlord.coal");
...and so on. If I was really slick I might make a function:
(Model *) NewCoalesceModel(char *data);
which does the memory allocation itself and returns the new model to the caller. So now the code could read:
Model *runningGuyModel, *robotOverlordModel;
runningGuyModel = NewCoalesceModel("/Assets/runningGuy.coal");
robotOverlordModel = NewCoalesceModel("/Assets/robotOverlord.coal");
and when Im done of course:
free (runningGuyModel);
free (robotOverlordModel);
the next step might be to create a new struct/object - Id call it 'entity'. These entity objects would be the ones to tell a model to draw - the game engine wouldnt call DrawModel(Model *aModel) directly. So I would have a multi-step process, something like:
Model *bugModel;
BugModelEntity *bugEntity;
GameEngine *centipedeGame;
centipedeGame = NewCentipedeGameEngine();
bugModel = NewCoalesceModel("/Assets/bug.coal");
bugEntity = NewBugEntity(bugModel, 100.0, 100.0, 0.0); //new entity at point 100,100,0 which uses bug model
AddEntityToEngine(centipedeGame, bugEntity);
In fact I dont need to have the BugModelEntity *bugEntity pointer at all. I can just condense it and call:
AddEntityToEngine(centipedeGame, NewBugEntity(bugModel, 100.0, 100.0, 0.0));
why would I add the hassle of the Entity structure/object? Lets say Im making Centipede which has 100 bugs on the screen. I *dont* want to load the bug model 100 times!! I want 1 copy of the bug model - with 100 entities that have a pointer to it. So I have 100 BugModelEntity objects each of which has a pointer to the model it uses (initialized when I call NewBugEntity(bugModel, ...)). The BugModelEntity keeps track of its location, rotation, scale, which animation its using, which frame its up to, etc...
So now if I want 100 bugs randomly placed all over the screen I can:
for (i=0;i<100;i++) {
AddEntityToEngine(centipedeGame, NewBugEntity(bugModel, (float)MyRandom(0, 640), (float)MyRandom(0, 480), 0.0));
}
Now all isnt well though. The problem here is the entity structure. We will have many different kinds of these structures. BugModelEntity, SpaceshipModelEntity, LaserModelEntity, ScoreboardEntity, etc... Many entity functions will use the same code (MoveTo(), SetRotation(), SetScale()...) for all the different kinds of entities. But some functions like Step(time) will be different for each kind of entity. And there will be some functions specific only to certain entities - SetLaserStrength(), SetScore(). This is where OO and inheritance comes in. You can do it w/o oo, but its more elegant in oo. Ill post some more notes/ideas (hopefully clearer) later. Hopefully this post will give you some ideas.
cheers
BobimusPrime
2003.08.09, 02:56 PM
Hmm, found a pretty important bug. If you have noticed that the program crashes when the model you try to load has no bones it's because in model.cpp there needs to be
void SetVertex1(long num,float x,float y,float z)
{
model.vertex[num].v=SetVector3(x,y,z);
model.vertex[num].bone=-1;
}
rather than
void SetVertex1(long num,float x,float y,float z)
{
model.vertex[num].v=SetVector3(x,y,z);
}
When the vertices are not attached to bones the original code didn't set the bone attachment to -1 when loading like it should have. Hope that didn't cause too much frustration! I'll be uploading an updated version momentarily.
Robert
Wheatie
2003.08.10, 03:38 AM
Has anyone had any success making a separate C++ "loader" class for loading and animating the .coal files? I tried making my own, but ran into a little trouble.
When I comment out the code for animating, the model displays correctly, but when I try to run the animation I get funky results. Some vertices are animate correctly, but some appear way out of place. My file runs correctly in the test application you posted in this forum.
I'm thinking that the problem may lie in the fact that I'm using my own Vector and Quaternion classes instead of the structs that you provided in your application.
Any ideas as to what is going wrong or where in the code I should look (my best guess is MapSkeleton() or CalculateFrame(), but I could be wrong).
I'll try to get a screenshot soon.
David Blyth
dblyth@usc.edu
vBulletin® v3.6.8, Copyright ©2000-2008, Jelsoft Enterprises Ltd.