Skeleton animation question

Started by
6 comments, last by deadstar 15 years, 1 month ago
Hi there. I'm writing my own engine, and so far, it's going good. I have a little question, though. With skeletal animation, after you compute all the new angles and positions of your bones, how are you supposed to apply it to the mesh? Im asking this, because all i've found so far, means that i have to recompute EVERY vertex of the mesh, EVERY frame. That's ridiculous. Take, for example, Dawn of War. It has about 100 marines on the screen at the same time. Am I supposed to have 100 copies of the mesh in memory, one for each marine, just because they're playing different animations? One other thing I thought, was to simply apply the skeleton to the meshes. That way, I would not have to keep an internal copy of the model, and reprocess every vertex. Instead, just traverse the tree and mesh list for each model, and apply rotations to each mesh. The problem with that is that it creates joint holes. How to do this? Thanks.
Advertisement
A vertex shader is perfect for this - you pass in all the bone matrices, and the bone IDs and weights for each vertex, then render the original mesh - the shader applies the relevant matrix to each vertex.

"The right, man, in the wrong, place, can make all the dif-fer-rence in the world..." - GMan, Half-Life 2

A blog of my SEGA Megadrive development adventures: http://www.bigevilcorporation.co.uk

Are you using a vertex shader or are you computing vertices on the CPU?

For VS, here is some info
http://www.opengl.org/wiki/Skeletal_Animation
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
Quote:Im asking this, because all i've found so far, means that i have to recompute EVERY vertex of the mesh, EVERY frame. That's ridiculous.

What would be the point of computing matricies if you weren't going to transform the verticies by them some way, either by CPU or GPU? Yes, you have to transform every vertex of the mesh, every frame, for every animated model. That doesn't necessarily mean for N actors you need N copies, though that is most efficient if you are using software skinning. To use the marine example...

Each marine has a pointer to the singular copy of the base mesh data. Each marine also has an empty "output" buffer that is exactly the same size/format of the singular copy. You transform each vertex and place the resulting transformation in the per-object buffer. You render using that filled vertex buffer. It seems like a waste of memory to keep N copies of the vertex buffer around, and indeed it is, but duplication allows *parallelism*. Since each has its own transformation output buffer, the algorithm can be parallelized with almost a straight linear speedup. Each core can perform software skinning. Since it is likely that the number of actors will be greater than CPU cores, you'll not likely have many idle cores. Check out "thread pools" for how to have code that adapts to the number of cores in the machine at runtime.

As for the CPU speed...there is white paper from Intel that shows a software skinning algorithm reaching 70% the speed of a GPU (of that era) using a single-core x86 processor. No doubt that on newer processors with > 1 core and more efficient SSE implementations, this will be even faster by a significant factor. I've personally written code to do this and it is blazingly fast. My test bed computer was a Pentium II @ 233 MHz with 3dfx Voodoo3 3500 (no hardware T&L). Even without SSE, it still ran 60FPS. On a faster computer, I can't notice any impact on overall speed, especially considering that my CPU was otherwise idle waiting for the graphics card to finish rendering.
Vector x Matrix is an issue that SSE was designed for, and in the extremely likely case that you are targeting x86 processors, the impact is likely to be negligible on modern multicore CPUs unless you have some seriously complicated algorithms running as well. Test well, and your mileage may vary.

The memory efficient way is that for each mesh, you have a dynamic vertex buffer (write-only) that is the output, and the vertex data is stored in system memory (i.e. simple C/C++ array). From there you lock/map the vertex buffer, transform the verticies, writing result to the buffer, unlock/unmap, and render. When you lock/map again, since it is write-only, the driver will likely allocate new memory rather the same chunk (which the graphics subsystem might still be using) resulting in no stall. However, since you have only one output buffer, this results in the algorithm being serial, something that is really not a great idea on today's multicore CPUs, especially if you working on an embarrassingly parallel problem. For an exaggerated case, consider a mesh made of 4K verticies that are each 64 bytes (!) -- this will eat a maximum of 64*4K = 256KB of memory. Those 100 soldiers barely use 25MB, which is a significant, but not fatal when even low end computers are being shipped with 2048MB or RAM or more (25MB = 1.2%). At that point, I would consider asking why so many verticies and so large verticies. Try a normal map or something.

Alternatively, if there was only some kind of on-the-fly vector transforming device that you could program to do this for you as you rendered you could skip keeping copies...
Ah. A GPU.
Damn, that was some quick response! (Already a fan of these forums)
Well, here's my second post ;)

Thanks for your answers. It seems like what I thought that was stupid, afterall, is reality. You DO have to keep a copy for each instance of the model... DAMN.

I was thinking more like, breaking the model into parts, one per bone. Draw each of the parts on their own, with the associated matrix, calculated from the bones. Basically, you would just have to load a matrix, and send a GL vertex buffer object, or display list, or whatever. No more multiplying the matrix for every vertex.... Then, the problem would be the joints, between these parts.

But ok, i surrender to your advices. Apparently, that's the way it works, now.

The problem is... I never touched a shader. Never even thought about it. Never got to that point on my engine. So, this is going to be a hard one for me.
And, just to get me to definitely try out shaders.... Does it handle vertex weighting, and the rest of the stuff?

Oh, and by the way. Is there any difference between a joint-skeleton and a bone-skeleton? Besides the name, and what data it is, of course. Any difference that should make me pick one over the other?

[Edited by - Rhiakath on March 12, 2009 6:31:20 AM]
Quote:Original post by Rhiakath
And, just to get me to definitely try out shaders.... Does it handle vertex weighting, and the rest of the stuff?


It handles what you want it to handle, you write them yourself. There's plenty of GLSL examples of skinning (and some HLSL and Cg ones for reference), Google should provide.

Quote:Original post by Rhiakath
Is there any difference between a joint-skeleton and a bone-skeleton?


No, and technically there's no such thing as a 'bone' - it's just a visual guide to help people understand (whether be the artist designing the model, or the programmer like yourself figuring out how to animate it). All bones/joints consist of is a position/rotation (or a matrix).

"The right, man, in the wrong, place, can make all the dif-fer-rence in the world..." - GMan, Half-Life 2

A blog of my SEGA Megadrive development adventures: http://www.bigevilcorporation.co.uk

Ok, great. One final question.
What's this about GLSL, HLSL, etc etc?

From what I saw initially, shaders resembled assembly language.
I know later appeared some high level language C++ style for shaders.

Does it work for vertex and pixel shaders?
what's the difference between hlsl and glsl?

Thanks.

EDIT:
Ok, got my own answers. HLSL -> Microsoft, GLSL -> OpenGL

So, it's GLSL for me. :D

Thanks guys!

(and girls, although I doubt they exist as game programmers.... If one did exist, I'd marry her ;) )
Quote:Original post by Rhiakath
So, it's GLSL for me. :D


There's also NVIDIA's Cg shader language, which you can use with openGL. It's almost identical to HLSL, which helps since there's a big collection of HLSL tutorials for the XNA fans out there.

GLSL has the benefits of being OpenGL tailored, and most of the recent OpenGL books cover it.

Also take a look at NVIDIA's FX Composer or ATI's RenderMonkey, some good free IDEs for writing and testing shaders.

Quote:Original post by Rhiakath
(and girls, although I doubt they exist as game programmers.... If one did exist, I'd marry her ;) )


There's a few around my University :)
In fact... I think there's a female lecturer teaching DirectX stuff.

"The right, man, in the wrong, place, can make all the dif-fer-rence in the world..." - GMan, Half-Life 2

A blog of my SEGA Megadrive development adventures: http://www.bigevilcorporation.co.uk

This topic is closed to new replies.

Advertisement