Rendering a lot of animated meshes.

Started by
5 comments, last by DmGoober 18 years, 11 months ago
Hi, I'm just wondering if anyone can give me some advice about rendering a lot of animated meshes on screen at once. At the moment I'm using a .x file skinned mesh approach, but I'm wondering if there is a more efficient way of doing this. If I render one animated mesh, my fps will be ~800, but when I render two, it drops to ~650. That's a ~20% hit. If I render 50 of them, the frame rate drops right down to 50fps. Now that might not sound to bad, but what happens when I start rendering the actually world, performing physics, collision detection, AI, etc... It will grind to a halt. I'm wondering how other games (like strategy games for example) can render hundreds of animated meshes on screen at once. Admittedly, they are usually pretty low-poly, but nevertheless, there is still hundreds of them. Then they have a whole game wrapped around it and it is actually playable without bogging down. I'm thinking that skinned meshes might not be the holy grail in this case. Is there some other technique I should be looking at... Keyframing without bones? Morphing or vertex tweening? Multiple fixed meshes that you just flick through to create animation (i.e. no bone processing)? Something else I don’t know about? If anyone can point me to some discussions/articles/tutorials/etc... on the topic, that would be much appreciated. Thanks.
Advertisement
1) Geometry Instancing. This is a new feature (in D3D9, at least) that enables you to use multiple Streams to seperate the vertexdata so some stuff only have to be submitted ONCE to the GPU.. While the whole thing can be drawn hundreds and thousands of times. So 1 DrawPrimitive() == XXX objects. (See SDK for examples)

2) Occlusion Culling. You basically don't draw the stuff you don't see. Here's how to do it in hardware.

3) Level Of Detail. When using Progressive Meshes, one can determine the number of polygons drawn by checking the distance fom the camera. Object further away are low-polyer than objects close. (See SDK for examples)
Number 2 & 3 are cool for later. But for now, I'm trying to figure out how to efficiently render hundreds of animated meshes on the screen at once. In other words, they are all on the screen and visible.

Geometry Instancing sounds interesting. I have heard of it, but have only had a quick look at it as I assumed it was only used for static geometry. Can it be used for animated (i.e. skinned) meshes where the geometry changes every frame due to the animation? Can I still instance a hundred meshes even though their geometry may all be different as they are in different poses of their animations? Do you follow what I'm saying?
To be honest, I'm not sure how Geometry Instancing works either [grin]
But maybe the following is possible..

A) You could use the same vertices but different bones to animate the meshes in the Vertex Shader. The bone information would be per mesh.

B) Submit all frames once, and use a Vertex Shader to pick out the frame you need. I'm not sure how it would work..

I think you'll have to implement occlusion culling and progressive meshes for animated models.
Another thing you can do, if you don't want to use the geometry instancing system, is to pass all vertex data in some buffers, sorted on material etc.

Then dynamically construct an index buffer that will render all parts of the characters that share the same material. So basically, if you have many instances of the same character, you would first render all heads in one draw primitive, then all upper bodies, etc.

That significantly reduces the number of batches, which is a big bottleneck when rendering many complex characters (with different clothing layers etc).

However, still this has issues with GPU skinning, as you have to update the bone matrices and pass them ot the shader for each character. So maybe the instancing system would be the only way to get it fast.

About the progressive mesh LOD. You shouldn't base the number of triangles on the distance to camera, but on for example the area of the bounding sphere projected on the image plane. If you don't do this, then you will have issues when you "zoom in" using camera FOV. Also better precalculate the LOD's instead of using progressive meshes. You might use progressive meshes to precalc the static LOD's though :)

I have no direct experience with the instancing API of DX9. But maybe you can make a separate stream of bone matrices? Same like you would render objects with different colors, but then you'd render them with different bones? Maybe that idea is flawed though, as still all bones matrices have to fit in the shader constants.

Deformable objects always are a bitch to deal with :)



Hello.

This sound like "normal values" to me.
i´ve got not very much experience with that things, but i think, that the other things like physics, AI an so on do more work on the cpu than on the gpu and by this you will not get greater problems, when you implement these things.

low-poly is one solution. Another way , to reduce the meshes kept in the localmem is using one animated item twice or more times.
i dont think, that if you have a battlefield (or something like that) with 50 or more items, that every item must have its own, unique animation.



*Los Brutalos*(Sorry for my brutal english ;)
Are you dealing with Vertex Buffers and Index Buffers directly or are you using the Direct3D "Mesh" class? As much as I like the Mesh class for simple rendering and prototyping, I don't know what's going on under the covers, so I try to stay away from it for "production" code.

Do your skinned meshes all share the same mesh? If yes, then simply setting the VB/IB only once per mesh per frame should make a huge difference (I believe, don't quote me on this, that if you create, say, one hundred Mesh objects and tell them all to render, you'll end up setting the VB/IB one hundred times! This a huge waste of time, especially if the VB and IB for each mesh is exactly the same.)

In general, I stay away from the Mesh class as it tends to be overally complex and inefficient. You may want to invest time into understanding and parsing the .X format yourself so you can have full control.

"General solutions are generally inefficient." The Mesh class is a general solution.
Alexander "DmGoober" Jhinalexjh@online.microsoft.com[Warning! This email account is not attended. All comments are the opinions of an individual employee and are not representative of Microsoft Corporation.]

This topic is closed to new replies.

Advertisement