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

Я пишу сценарий экспорта Python из Blender 2.64. Идея в том, что я пытаюсь экспортировать данные меша удобным для OpenGL VBO способом. Итак, я экспортирую атрибуты вершин в массив макетов структур. Например, для меша с вершинами, нормалями и 1 парой координат текстуры каждый vertexAttribute в VBO будет 8 последовательными плавающими точками:

vvvnnntt 

Все идет нормально. Проблема в том, что когда 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 

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

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

Тем не менее, моя сетка не должна иметь разных 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]])

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

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

для рендеринга моей модели в моей программе (своего рода движок) УФ-отображение явно испорчено. То есть, модель хорошо отображается с точки зрения вершин и нормалей, но 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]

И учтите, что в этом примере только один УФ-слой. Итак, очевидно, что Blender присвоил вершине 1 2 uv-координаты.


person SaldaVonSchwartz    schedule 11.11.2012    source источник
comment
Кстати, тем временем я выбрал подход без GL_ELEMENT_ARRAY, так что в итоге я получаю дублированные вершины, но с разными uvs, и, хотя теперь у меня есть огромный VBO, где вершины появляются столько раз, сколько треугольники ссылаются на них, uvs mapp просто хорошо, когда я рендерю.   -  person SaldaVonSchwartz    schedule 11.11.2012


Ответы (1)


Я думаю, что может быть способ интерполировать или иным образом согласовать / смешать 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()
person SaldaVonSchwartz    schedule 20.11.2012