【问题标题】:What is a good algorithm to load OBJ files for use with openGL?什么是加载 OBJ 文件以与 openGL 一起使用的好算法?
【发布时间】:2013-12-08 19:46:31
【问题描述】:

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

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

VBO 没有无限空间,因此只能在 GL_MAX_ELEMENTS_VERTICES 之前填满,据我了解,在此之后您最终会受到严重的性能损失。

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

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

【问题讨论】:

  • 超过GL_MAX_ELEMENTS_VERTICES 限制不会给您带来严重的性能损失。它只会“减慢”glDrawRangeElements 功能到glDrawElements 的速度。
  • @MārtiņšMožeiko 鉴于我使用 java,这可能会更容易并且不会对性能产生严重影响..嗯。我应该对此进行一些测试。谢谢!
  • 您是否实际测试过您计算机上的 GL_MAX_ELEMENTS_VERTICES 是什么。我猜它比你需要加载的尺寸模型要高得多。另外,我很久以前做过一些测试,发现由于所有额外的索引,你最终实际上并没有为许多模型节省那么多空间。我不会担心的
  • @zacaj:是的,我做到了。在我的机器上都是 33k。我想使用的模型之一大大超过了这个数字(文件本身大约 80Mb)。然而,这确实意味着减少内存负载很容易导致节省几 Mb 的 VRAM。我发现这足以尝试找到一种方法来实现它,但没有结果。

标签: opengl


【解决方案1】:

您可以保留来自.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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    • 2015-08-30
    • 1970-01-01
    相关资源
    最近更新 更多