加载OBJ文件以用于openGL的好算法是什么?

时间:2012-07-02 19:04:57

标签: opengl

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

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

VBO没有无限的空间,因此它们只能在GL_MAX_ELEMENTS_VERTICES之前填写,之后根据我的理解,最终会导致严重的性能损失。

我一直在寻找能够填充这些VBO缓冲区的算法,同时尽可能地保持OBJ中重用的几何数据,同时遵守GL_MAX_ELEMENTS_VERTICES / GL_MAX_ELEMENTS_INDICES设置的限制。

这样做有什么好的方法或算法吗?

1 个答案:

答案 0 :(得分: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;
    }
}