如何在Blender导出脚本中导出每顶点UV坐标

Sal*_*rtz 10 python blender blender-2.61

我正在写一个来自Blender 2.64的python导出脚本.我的想法是我试图以OpenGL VBO友好的方式导出网格数据.所以我在结构布局数组中导出顶点属性.例如,对于具有顶点,法线和1对纹理坐标的网格,vertexAttributeVBO中的每个都将是8个连续的浮点数:

vvvnnntt 
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.问题是,当Blender进行UV映射时,它实际上可以将不同的uv分配给同一个顶点.

也就是说,假设你有一个立方体:你有8个顶点,你有6个面(在这种情况下为四边形).我原以为指数0,1,2,3的面/多边形意味着:

vertex 0, normal 0, uvCoord0 
vertex 1, normal 1, uvCoord1 
vertex 2, normal 2, uvCoord2 
vertex 3, normal 3, uvCoord3 
Run Code Online (Sandbox Code Playgroud)

因此,任何提及索引0,例如,在任何面上,总是意味着顶点0,正常0,uvCoord0元组.好吧,在Blender中,如果我理解正确,一个面可以用uvCoord 0引用顶点0,而另一个面可能用不同的uVCoord引用相同的顶点0.因此,一个face的loop_indices实际上必须用于在objets general data.verticesdata.uv_layers[].data容器中查找向量和uvCoord .

这允许每面应用uv贴图.所以你可以有一个立方体,其中每个面都应用了不同的uv纹理,即使两个相邻的面共享一个顶点,顶点也有不同的uv坐标,具体取决于面.

尽管如此,我的网格对于同一个顶点不应该有不同的uv,因为我正在展开相邻的面.这意味着在我的UV地图中,展开的网格是一组相邻的面(例如,如果它是由6个面构成的立方体,则为十字形),在两个相邻面之间,它们的公共顶点应该对应于相同的点在紫外线地图中.

所以鉴于上述情况,我认为这种方法应该有效:

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]])
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,上面代码中的含义是我将不止一次访问顶点,因为我正在迭代共享顶点的网格面(本例中为三角形).每次我访问一个顶点时,如果它还没有分配它的UV坐标,那么我通过使用三角形的loop_indices查找它们来分配它们.毕竟,我的假设是,在一天结束时,每个顶点都有独特的uv coords.

上面的代码给出了以下布局,例如(我正在显示网格的前6个顶点属性):

-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
...
Run Code Online (Sandbox Code Playgroud)

但是当我使用这个信息加上一个网格的面孔时,我的布局是这样的:

4 5 1
5 6 2
6 7 3
7 4 0
...
Run Code Online (Sandbox Code Playgroud)

在我的程序(一种引擎)中渲染我的模型,uv映射显然搞砸了.也就是说,模型在顶点和法线方面渲染得很好,但是uv纹理显然没有正确映射.

有什么想法吗?我的意思是,要么我正在导出并弄乱我的应用程序中的OpenGL渲染代码,要么我在顶点和uv坐标之间导出错误的映射.(或两者,当然..但我现在假设我搞乱了导出脚本).

最后一点,如果我改变上面的python代码来附加分配给顶点的每个新的uv而不是仅在没有分配uv的情况下附加,对于顶点1,我得到:

[-1.0, -1.0, -1.0, -0.7070833444595337, -0.7070833444595337, 0.0, 0.07638061791658401, 0.9485195726156235, 0.5816344618797302, 0.9485194832086563, 0.07638061791658401, 0.9485195726156235]
Run Code Online (Sandbox Code Playgroud)

请注意,此示例中只有一个uv层.很明显,Blender确实为顶点1分配了2个uv坐标.

Sal*_*rtz 3

我认为可能有一种方法可以插值或以其他方式协调/混合 UV,以便在所有内容都相邻的情况下最终每个顶点只有一个 UV。但与此同时,鉴于没有人提出替代方案,我最终复制了具有不同 UV 的顶点,并放弃了导出 GL_ELEMENT_ARRAY 的尝试。如果使用单个 VBO 渲染(使用 glDrawArrays),则以下代码有效:

def exportMesh(filepath):

    # Only one mesh per scene
    objList = [object for object in bpy.context.scene.objects if object.type == 'MESH']

    if len(objList) == 0:
        return
    elif len(objList) > 1:
        return
    #raise exepction? dialog box?


    # Process the single mesh object:
    mesh = objList[0]

    # File name is same as the mesh's name in Blender
    meshFilePath = filepath[0 : filepath.rindex('/') + 1] + mesh.name + ".mesh"
    file = open(meshFilePath, 'w')

    WorldTransform = Matrix().Identity(4)
    WorldTransform *= Matrix.Rotation(radians(90), 4, "X")
    file.write('World Transform:\n')
    for rcol in WorldTransform_T.row:
        file.write('{:9f} {:9f} {:9f} {:9f}\n'.format(row[0], row[1], row[2], row[3]))
    file.write('\n')

    # Mesh (local) transform matrix
    file.write('Mesh Transform:\n')
    localTransform_T = mesh.matrix_local.copy()
    localTransform_T.transpose()
    for row in localTransform_T.row:
        file.write('{:9f} {:9f} {:9f} {:9f}\n'.format(row[0], row[1], row[2], row[3]))
    file.write('\n')

    vertexAttributeList = []
    for triangle in mesh.data.polygons:
        vertices = list(triangle.vertices)
        i = 0
        for vertex in vertices:
            vertexAttribute = list(mesh.data.vertices[vertex].co)

            if triangle.use_smooth:
                vertexAttribute.extend(list(mesh.data.vertices[vertex].normal))
            else:
                vertexAttribute.extend(list(triangle.normal))

            for uv_layer in mesh.data.uv_layers:
                uvCoord = uv_layer.data[triangle.loop_indices[i]].uv
                vertexAttribute.extend([uvCoord[0], 1 - uvCoord[1]])

            totalVertexWeight = 0
            jointWeights = [group.weight for group in mesh.data.vertices[vertex].groups]
            jointIndices = [group.group for group in mesh.data.vertices[vertex].groups]
            for weight in jointWeights:
                totalVertexWeight += weight

            vgNum = len(mesh.vertex_groups)
            jointWeightsAttribute = []
            jointIndicesAttribute = []
            for vgIndex in range(4):
                if vgIndex < len(jointIndices):
                    jointWeightsAttribute.append(jointWeights[vgIndex] / totalVertexWeight)
                    jointIndicesAttribute.append(jointIndices[vgIndex])
                else:
                    jointWeightsAttribute.append(0)
                    jointIndicesAttribute.append(0)

            vertexAttribute.extend(jointWeightsAttribute)
            vertexAttribute.extend(jointIndicesAttribute)

            vertexAttributeList.append(vertexAttribute)
            i += 1

    # VBO
    vNum = len(vertexAttributeList)
    tNum = len(mesh.data.uv_layers)
    file.write('VBO Length: {:d}\n'.format(vNum))
    for vertexAttribute in vertexAttributeList:
        file.write('{:9f} {:9f} {:9f} {:9f} {:9f} {:9f} {:9f} {:9f} {:9f} {:9f} {:9f} {:9f} {:d} {:d} {:d} {:d}\n'.format(vertexAttribute[0],
                                                                                                                          vertexAttribute[1],
                                                                                                                          vertexAttribute[2],
                                                                                                                          vertexAttribute[3],
                                                                                                                          vertexAttribute[4],
                                                                                                                          vertexAttribute[5],
                                                                                                                          vertexAttribute[6],
                                                                                                                          vertexAttribute[7],
                                                                                                                          vertexAttribute[8],
                                                                                                                          vertexAttribute[9],
                                                                                                                          vertexAttribute[10],
                                                                                                                          vertexAttribute[11],
                                                                                                                          vertexAttribute[12],
                                                                                                                          vertexAttribute[13],
                                                                                                                          vertexAttribute[14],
                                                                                                                          vertexAttribute[15]))
    file.write('\n')


    # Done writing mesh file
    file.close()
Run Code Online (Sandbox Code Playgroud)