1

对于一个小游戏,我正在尝试编写一个 OBJ 文件加载器来加载用于 openGL 的模型。

OBJ 文件格式的一个很好的特点是它可以通过在定义面时通过索引引用它们来重用相同的顶点。OpenGL 又具有以类似方式组织的顶点缓冲区对象(VBO);有一个几何数据缓冲区和一个索引缓冲区。

VBO 没有无限的空间,所以它们只能被填满,直到GL_MAX_ELEMENTS_VERTICES,据我了解,你最终会受到严重的性能损失。

我一直在寻找一种算法,它可以填充这些 VBO 缓冲区,同时尽可能多地保持来自 OBJ 的重用几何数据,同时尊重 GL_MAX_ELEMENTS_VERTICES / GL_MAX_ELEMENTS_INDICES.

有没有什么好的方法或算法可以做到这一点?

4

1 回答 1

0

您可以保留来自.obj顶点共享的数据。这是从顶点缓冲区加载数据.obj并为顶点缓冲区生成顶点/面的代码:

int FaceIndex = 0;
int VertexIndex = 1;
int TextureVertexIndex = 1;

char Prefix[3];

float X, Y, Z;
int A1, A2, A3, B1, B2, B3, C1, C2, C3, D1, D2;

while ( !IStream->Eof() )
{
    std::string Line = IStream->ReadLine();

    int NumRead = sscanf( Line.c_str(), "%2s %f %f %f", Prefix, &X, &Y, &Z );

    if ( NumRead < 1 ) continue;

    switch ( Prefix[0] )
    {
    case '#':
        continue;

生成单个顶点。这些可以在多个面之间共享:

    case 'v':
        {
            switch ( Prefix[1] )
            {
            case 0:
                if ( NumRead != 4 ) continue;
                EmitVertex( VertexIndex++, vec3( X, Y, Z ), -1, -1 );
                break;
            case 't':
                if ( NumRead != 3 ) continue;
                EmitTextureVertex( TextureVertexIndex++, vec3( X, 1.0f-Y, 0.0f ) );
                break;
            case 'n':
                if ( NumRead != 4 ) continue;
                EmitNormal( VertexIndex, vec3( X, Y, Z ) );
                break;
            }
        }
        break;

使用索引生成具有纹理坐标的面:

    case 'f':
        {
            if ( sscanf( Line.c_str(), "%2s %d/%d %d/%d %d/%d %d/%d", Prefix, &A1, &A2, &B1, &B2, &C1, &C2, &D1, &D2 ) == 9 )
            {
                A3 = B3 = C3 = 0;
                EmitTextureFace( FaceIndex, A2, B2, D2 );
                EmitFace( FaceIndex++, A1, B1, D1, -1, -1 );
                EmitTextureFace( FaceIndex, B2, C2, D2 );
                EmitFace( FaceIndex++, B1, C1, D1, -1, -1 );
            }
            else if ( sscanf( Line.c_str(), "%2s %d/%d/%d %d/%d/%d %d/%d/%d", Prefix, &A1, &A2, &A3, &B1, &B2, &B3, &C1, &C2, &C3 ) == 10 )
            {
                EmitTextureFace( FaceIndex, A2, B2, C2 );
                EmitFace( FaceIndex++, A1, B1, C1, -1, -1 );
            }
            else if ( sscanf( Line.c_str(), "%2s %d//%d %d//%d %d//%d", Prefix, &A1, &A3, &B1, &B3, &C1, &C3 ) == 7 )
            {
                A2 = B2 = C2 = 0;
                EmitFace( FaceIndex++, A1, B1, C1, -1, -1 );
            }
            else if ( sscanf( Line.c_str(), "%2s %d/%d %d/%d %d/%d", Prefix, &A1, &A2, &B1, &B2, &C1, &C2 ) == 7 )
            {
                A3 = B3 = C3 = 0;
                EmitTextureFace( FaceIndex, A2, B2, C2 );
                EmitFace( FaceIndex++, A1, B1, C1, -1, -1 );
            }

        }
        break;
    }
}
于 2013-12-08T11:46:31.223 回答