Tuesday, January 24, 2012

71 – WTF LOD case study, part one

I need to make sure that slow but steady progress is made towards finishing the models required by the game and that the process of getting the assets in game is perfected. I am not going to bore you again with barrels, so today we'll use chests as an example. 

And be warned: wackiness will ensue. I have absolutely no explanation yet for some of the weird stuff that is going on. And I apologize for the length of the post.

Here is the chest mesh created by BrewStew:

Pretty high quality stuff! Probably too high. Blender reports that it has 184 vertices and 169 faces. But Blender faces are polygons while in the 3D engine we deal with triangles, so this mesh is actually 184 vertices and 1014 indices. How do we get from 169 faces to 1014 indices? Well if we apply a Decimate operator to the mesh and parametrize it so that it does nothing, leaving the mesh intact, it will report 338 faces, and... that leads us nowhere. Or wait! If blender has changed the emaning of faces from polygon to triangle, we get 338 * 3 = 1014 . On the other hand 169 * 6 = 1014. There, that's it! It makes sense. If all polygons have 4 vertices we need two triangles with 3 vertices each to represent that polygon. Each triangle has 3 indices to select the correct vertex, so we have number_of_faces * 6. We'll call this mesh A.

Taking this mesh and applying smoothing to it leads us to this:

Maybe not the best result. What if we only selectively smooth:

Look like this need more thought. I'll just go with flat shading for now and see what happens. Our goal is to try and reduce mesh complexity. First step is to remove that elevation shift in hope that we can compensate with a texture:

A lot of detail is lost, but the idea is to use this only for objects that are further away. We can go one step further and remove some back-facing handle detail:

The difference is minor for the handle. Blender says we have 128 vertices and 107 faces. In the engine we have 128 vertices and 618 indices, so the formula holds. This is mesh B.

The final step is to create a really low detail mesh:

This is just an approximation, but it is meant to be viewed from great distances where the loss of detail is hard to notice:

That speck still looks kind of like a chest. I'm thinking of removing the handles and baking them into the texture for this LOD level. Metrics: Blender 32/19, engine 32/114. This is mesh C.

In the past I used the Decimate operator to simplify meshes for low LOD. The problem with it is that you can only use so much before it starts to become really ugly and no longer resemble the object. This was the mesh produced by decimate and as you can see it had too much detail and I could't lower it more:

So far so good. I am barely starting to reach the part where I actually start to talk about subject of this post.

I tried to create an uniform stress test: a leveled plain where every single cell is occupied by a chest. Because of the memory requirements for this I am only testing on one quarter of a map. So all memory measurements should be multiplied by 4 to get accurate numbers for default sized maps. And we should have 22500 barrels at once in a scene.

And this is where the weirdness starts: exporting mesh A with either smooth shading or flat shading (as *.obj) and without exporting normals has the same look in game. I diff the two exports and see that one has the smooth flag set to off and the other has it set to 1. Going into my importer/exporter and deactivating Gouraud Shading makes everything ugly and setting the normalize normals flags has no effect. Recalculating normals with the CPU has no effect.

Now when exporting normals too things start to become really weird. Doing so with flat shading causes the vertex count to jump up to 652 while index count remains 1014. Exporting as *.3ds makes the vertex count be equal to the index count, as in 1014 and the up directions behave differently from *.obj. Exporting as *.dae has again 652 vertices, yet another up direction mapping that is different and a different scale factor. Awesome.

So I guess I'll continue the experiment with the smoothed look. First step is to fill the quarter map with high LOD meshes. I've updated the little counter to only count items and ignore terrain and I am running on a weak computer so I can really see the difference:

I won't list all the values, suffice to say that mesh A eats up 184 MiBs and has a FPS of 17 from top down view. From first person things are much worse:

While memory consumption and item count and complexity is exactly the same, from this view point frustum culling can't eliminate as much of the scene and we only get 3 FPS.

Let's repeat the experiment with mesh B:

We now only have 124 MiB memory use for item meshes and one extra frame/sec. I won't add another picture with top down view, but we get a FPS of 23. And one final experiment with mesh C:

Memory consumption is at 29 and we have 16 FPS, while from top down we have 46. Using this low detail mesh I had to make sure that I export the mesh smoothed and with normals because otherwise it was too flat (especially from top down view). Strangely, this had absolutely no effect on vertex count, like it did for mesh A.

Oh god, this post is soooooo long. I'm sorry. I am nowhere near done, so I have to break it up into two parts.

So join me next time when we see what can be done with LOD switching. With the help of this technique we can get high visual fidelity while maintaining a reasonable memory consumption. I'll show the benefits of my old LOD technique and see if I can get better results with a new idea I had for it.

No comments:

Post a Comment