I'm writing a a python export script from Blender 2.64. The idea is that I'm trying to export the mesh data in an OpenGL VBO-friendly way. So I'm exporting vertex attributes in array of structs layout. For instance, for a mesh with vertices, normals and 1 pair of texture coordinates, each vertexAttribute
in the VBO would be 8 consecutive floats:
vvvnnntt
So far so good. The problem is, when Blender does UV mapping, it can actually assign different uvs to a same vertex.
That is, say you have a cube: you have 8 vertices and you have, say 6 faces (quads in this case). I would have expected that a face/polygon with indices 0,1,2,3 implied:
vertex 0, normal 0, uvCoord0
vertex 1, normal 1, uvCoord1
vertex 2, normal 2, uvCoord2
vertex 3, normal 3, uvCoord3
And consequently, any mention of index 0 for instance, in any face, will always imply the
vertex 0, normal 0, uvCoord0 tuple. Well, turns out in Blender, if I understand correctly one face could reference vertex 0 with uvCoord 0 while another might reference the same vertex 0 with a different uVCoord. So a face's loop_indices must actually be used to lookup both a vector and a uvCoord in an objets general data.vertices
and data.uv_layers[].data
containers.
This allows for applying uv maps per-face. So you could have a cube where each face has a different uv texture applied and even if two adjacent faces share a vertex, the vertex has a different uv coord depending on the face.
Still, my mesh shouldn't really have different uvs for a same vertex since I'm unwrapping into adjacent faces. Which means in my UV map, the unwrapped mesh is a set of adjacent faces (think for instance, a cross shape if it were a cube made up of 6 faces) and between two adjacent faces, their common vertices should mapp to the same point in the uv map.
So given the above, I thought this approach should work:
vertexAttributeList = []
for vertex in mesh.data.vertices:
vertexAttribute = list(vertex.co)
vertexAttribute.extend(list(vertex.normal))
vertexAttributeList.append(vertexAttribute)
for triangle in mesh.data.polygons:
for uv_layer in mesh.data.uv_layers:
for i in triangle.loop_indices:
lookupIndex = mesh.data.loops[i].vertex_index
if len(vertexAttributeList[lookupIndex]) == 6:
uvCoord = uv_layer.data[i].uv
vertexAttributeList[lookupIndex].extend([uvCoord[0], 1 - uvCoord[1]])
As you can see, the implication in the above code is that I'll visit vertices more than once cause I'm iterating over a mesh's faces (triangles in this case) which share vertices. And every time I visit a vertex, if it hasn't had its UV coords assigned yet, then I assign them by looking them up using the triangle's loop_indices. After all, my assumption was I do have, at the end of the day, unique uv coords per vertex.
The above code gives he following layout, for example (I'm showing a mesh's first 6 vertex attributes):
-1.000000 -1.000000 -1.000000 -0.707083 -0.707083 0.000000 0.076381 0.948520
-1.000000 1.000000 -1.000000 -0.707083 0.707083 0.000000 0.454183 0.948519
1.000000 1.000000 -1.000000 0.707083 0.707083 0.000000 0.325162 0.948519
1.000000 -1.000000 -1.000000 0.707083 -0.707083 0.000000 0.205674 0.948519
-1.000000 -1.000000 1.000000 -0.577349 -0.577349 0.577349 0.581634 0.795012
-1.000000 1.000000 1.000000 -0.577349 0.577349 0.577349 0.454183 0.795012
...
But when I use this info plus a mesh's faces, which I layout like so:
4 5 1
5 6 2
6 7 3
7 4 0
...
to render my model in my program (an engine of sorts), the uv mapping is clearly messed up. That is, the model renders fine in terms of vertices and normals but the uv texture is clearly not correctly mapped.
Any thoughts? I mean, either I'm exporting right and messing up the OpenGL render code in my app or I'm exporting the wrong mapping between vertices and uv coordinates. (or both, sure.. but I'm assuming for now I'm messing up the export script).
One last thing, if I change the above python code to append each new uv which is assigned to a vertex instead of appending only if no uv was assigned yet, for vertex 1 I get:
[-1.0, -1.0, -1.0, -0.7070833444595337, -0.7070833444595337, 0.0, 0.07638061791658401, 0.9485195726156235, 0.5816344618797302, 0.9485194832086563, 0.07638061791658401, 0.9485195726156235]
And mind you there's only one uv layer in this example. So clearly Blender did assign 2 uv coordinates to vertex 1.