Blender, Direct3D, Meshes and You

July 10th, 2009

I’ve spent last couple of days writing a custom mesh exporter for Blender. It all seemed pretty trivial in the beginning (“it’s just conversion of data structures”). It’s easy to iterate over all the faces in the mesh, and then over vertices and then reading their position and normal. Everything seems fine, but there’s a difference in how Blender stores the data, and what format will a Direct3D VertexBuffer accept. Specifically I had two major annoyances.

First problem – flat faces vs smooth faces. If you look at Blender’s Python API Documentation, you will see, that a MFace is just marked as smooth and there’s all to it. If a face is smooth, the normals get interpolated for positions between the vertices. This works the same in Direct3D world. What about flat faces? Well, in Blender a MFace is not marked as smooth and has another attribute – no (short for “normal”). Therefore, if you want to have a flat-shaded face in Direct3D, you have to duplicate the vertices and use their original positions and replace their normals with face normals. This introduces another problem – your exported vertex buffer will have additional vertices in it, which won’t map easily (1-to-1) to the indices Blender has.

Second problem – UV mapping. In Blender you can create a UVLayer. It’s just a set of UV coordinates mapped to vertices in faces. What does Direct3D expect? UV coordinates mapped to vertices… not faces. Blender stores UV coordinates as an attribute of MFace, as list of UV vectors. Notice how a single vertex can belong to multiple faces, and therefore can be assigned a different set of UV coordinates for every face. This means we can’t reuse this vertex in VertexBuffer (or I don’t know a way to do so). Direct3D VertexBuffer will have to hold a copy of this vertex with its original position and normal for every pair of UV coordinates it’s assigned. This again introduces problem of vertex indices not mapping easily (1-to-1) between Blender world and Direct3D world.

The indices problem can be solved by reindexing the newly created vertices and matching them with the faces. Of course that would work, as long as it would be done in a deterministic way (vertices not changing their indices between exports and mesh modifications). And everyone knows indices are needed for the DrawIndexedPrimitive call.

After spending a couple of hours thinking about an elegant solution, I gave up. I’ve decided to go with less elegant, simpler DrawPrimitive calls. So I just iterate over all the faces in the mesh and create vertices as I go – three new vertices per every face. I realize there will be more data to process for the GPU, but I’m just beginning to write my engine and need to make progress. I have more interesting problems to solve at this very moment. After all, I write abstractions for the low-level stuff and can always optimize the mesh later. Using NvTriStrip comes to mind as one of possible ways to achieve that. Or something smart, as I’ll get to know more about Blender and Direct3D.

Leave a Reply