как экспортировать вершинным UV-координаты в экспорте блендер скрипт

Я пишу скрипт экспорта python из Blender 2.64. Идея в том, что я пытаюсь экспортировать данные сетки в OpenGL VBO-дружественным способом. Поэтому я экспортирую атрибуты вершин в array of structs layout. Например, для сетки с вершинами, нормалями и 1 парой координат текстуры, каждая vertexAttribute в VBO будет 8 последовательных поплавков:

vvvnnntt 

пока все хорошо. Проблема в том, что когда Blender делает УФ-отображение, он может фактически назначить разные uvs одной и той же вершине.

то есть, скажем, у вас есть куб: у вас есть 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 

и, следовательно, любое упоминание индекса 0, например, в любом лице, всегда будет подразумевать вершина 0, Нормаль 0, кортеж uvCoord0. Ну, оказывается, в Blender, если я правильно понимаю, одна грань может ссылаться на вершину 0 с uvCoord 0, а другая может ссылаться на ту же вершину 0 с другим uVCoord. Таким образом, loop_indices лица должны фактически использоваться для поиска как вектора, так и uvCoord в objects general data.vertices и data.uv_layers[].data контейнеров.

это позволяет применять УФ-карты на лицо. Таким образом, вы можете иметь куб, где каждая грань имеет разную УФ-текстуру, и даже если две соседние грани разделяют вершину, вершина имеет разную УФ-координату в зависимости от грани.

тем не менее, моя сетка не должна иметь разные uvs для одной и той же вершины с тех пор, как я разворачиваюсь в соседние лица. Это означает, что в моей УФ-карте развернутая сетка представляет собой набор смежных граней (например, перекрестную форму, если бы это был куб, состоящий из 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]])

как вы можете видеть, подразумевается в приведенном выше коде, что я буду посещать вершины более одного раза, потому что я итерация по граням сетки (треугольники в этом случае), которые разделяют вершины. И каждый раз, когда я посещаю вершину, если ей еще не назначены УФ-координаты, я назначаю их, просматривая их с помощью loop_indices треугольника. В конце концов, я предполагал, что у меня есть, в конце концов, уникальные УФ-координаты на вершину.

приведенный выше код дает следующий макет, например (я показываю первые 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
...

но когда я использую эту информацию плюс лица сетки, которые я раскладываю так:

4 5 1
5 6 2
6 7 3
7 4 0
...

чтобы отобразить мою модель в моей программе (своего рода движок), УФ-отображение явно испорчено. То есть модель отлично отображает вершины и нормали, но УФ-текстура явно не отображается правильно.

какие мысли? Я имею в виду, либо я экспортирую правильный и испортил код рендеринга OpenGL в своем приложении, либо я экспортирую неправильное отображение между вершинами и УФ-координатами. (или обе, конечно.. но я предполагая, что сейчас я испортил сценарий экспорта).

и последнее, если я изменю приведенный выше код 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]

и имейте в виду, что в этом примере есть только один УФ-слой. Так четко блендер назначили 2 UV-координаты для вершины 1.

1 ответов


Я думаю, что может быть способ интерполировать или иным образом согласовать / смешать UVs, чтобы в конечном итоге получить один UV на вершину, если все смежно. Но в то же время, и учитывая, что никто не предложил альтернативу, я закончил дублирование вершин с их различными UVs и отбросил попытку экспорта для 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()