无法使用OpenGL渲染FBX导入的纹理模型

时间:2019-05-22 19:38:20

标签: opengl mesh texture-mapping fbx

我正在尝试使用来自OpenGL的FBX文件中的数据渲染纹理模型,但是纹理坐标是错误的。

由FBX文件提供的模型数据的摘要包括映射到模型顶点的纹理参考的UV坐标。

  • 顶点数量:19895
  • PolygonVertexIndices数量:113958

  • 紫外线数量:21992

  • 紫外线指数:113958

很明显,该模型具有113958个感兴趣的顶点。据我了解,“ PolygonVertexIndices”指向“顶点”,“ UVIndices”指向“ UV”值。

我正在使用带有GL_TRIANGLES的glDrawElements渲染模型,使用“ PolygonVertexIndices”作为GL_ELEMENT_ARRAY_BUFFER和“顶点”作为GL_ARRAY_BUFFER。该模型本身可以正确渲染,但纹理化效果很差。

由于我为GL_ELEMENT_ARRAY_BUFFER使用了“ PolygonVertexIndices”,据我了解,对于UV坐标的属性数组将发生相同的索引编制。我认为OpenGL无法使用导出的UV索引,因此我为113958大小的UV值创建了一个新缓冲区,其中包含与“ PolygonVertexIndices”相对应的相关UV值。

即对于[0:113958]中的顶点i,我愿意

new_UVs[PolygonVertexIndices[i]] = UVs[UVIndices[i]]

,然后将new_UV绑定为UV坐标属性数组。

但是,纹理化显然是错误的。我的思路不对吗?

当使用OpenGL的索引渲染glDrawElements时,我感觉误会了如何使用UV缓冲区。扩展我的UV缓冲区以将顶点数量匹配到113958也感觉不对,因为glDrawElements的优点是可以保存重复的顶点值,并且UV缓冲区可能包含重复的顶点。

执行索引并将“ Vertices”和“ UVs”扩展到大小为113958并在性能方面仅使用glDrawArrays会更好吗?

任何想法/想法/建议都值得赞赏。

2 个答案:

答案 0 :(得分:0)

您是正确的,OpenGL仅支持一个索引缓冲区。

您的UV分配代码不正确。您不能仅复制UV,因为顶点和UV数组的大小不同。您需要做的是为具有多个UV的顶点创建重复的顶点,然后为每个副本分配一个UV。

将UV和顶点坐标视为包含两者的单个结构,并以此为基础。 示例:

class Account:
    def __init__(self, cust_id, checking_total_amount):
        self.cust_id = cust_id
        self.total_amount = total_amount

    def add_funds(self, funds):
        self.total_amount += funds
        return self.total_amount

    def remove_funds(self, funds):
        if funds > self.total_amount:
            raise ValueError('insufficient funds!')
        self.total_amount -= funds
        return self.total_amount


class BankAccount:

    def __init__(self, cust_id, checking_total, savings_total):
        self.cust_id = cust_id
        self.checking = Account(cust_id, checking_total)
        self.savings = Account(cust_id, savings_total)

    def move_to_checking(self, amount_to_move):
        # remove_funds will throw an error if there are insufficient funds
        self.savings.remove_funds(amount_to_move)
        self.checking.add_funds(amount_to_move)

jacksons_account = BankAccount('Jackson', 200, 500)
jacksons_account.move_to_checking(100)
print(jacksons_account.savings.total_amount)

这还使您可以轻松地对数据进行交织,并将整个结果数组上载到一个VBO中并进行渲染。

struct Vertex
{
   float3 position;
   float2 UV;
};

std::vector<Vertex> vertices;
// Fill "vertices" here.

这不是性能问题,而是字面上的唯一方法。

答案 1 :(得分:0)

上一篇文章仅适用于4.3之前的OpenGL。如果您使用的是4.3以上版本,则完全有可能对顶点使用多个索引(尽管可能并不是渲染几何体的最有效方法-这取决于您的用例)。

首先,您需要在顶点着色器中将顶点和texcoord索引指定为变化的顶点参数,例如

in int vs_vertexIndex;
in int vs_uvIndex;

确保使用glVertexArrayAttribIFormat指定这些参数(注意:“ I”很重要!还要注意,glVertexAttribIFormat也可以使用)。

下一步是将顶点和UV数组绑定为SSBO。

layout(std430, binding = 1) buffer vertexBuffer
{
    float verts[];
};
layout(std430, binding = 2) buffer uvBuffer
{
    float uvs[];
};

现在,在main()中,您可以像这样提取正确的vert + uv:

vec2 uv = vec2(uvs[2 * vs_uvIndex], 
               uvs[2 * vs_uvIndex + 1]);
vec4 vert = vec4(verts[3 * vs_vertexIndex], 
                 verts[3 * vs_vertexIndex + 1], 
                 verts[3 * vs_vertexIndex + 2], 1.0);

这时跳过glDrawElements,而只使用glDrawArrays(顶点数是网格中索引的数量)。

我并不是说这是最快的方法(建立自己的索引元素可能是性能最高的)。但是,在某些情况下这很有用-通常当您拥有FBX / USD / Alembic等格式的数据,并且需要更新(例如)每帧的顶点和法线时。