使用 OpenGL 渲染 .obj 文件

Rendering .obj files with OpenGL

本文关键字:文件 obj 渲染 OpenGL 使用      更新时间:2023-10-16

我在 opengl 中渲染模型时遇到了问题。我已经使用 glDrawElements 制作了自己的 obj 解析器和渲染函数,但我看不到问题所在。这是我的解析器函数:

void load_obj(char *nom)
{
FILE *file = fopen(nom, "r");
int iv = 0, in = 0, it = 0, ifa = 0;
if(file != NULL)
{
    while(1)
    {
        char lineHeader[128];
        int res = fscanf(file, "%s", lineHeader);
        if(res == EOF)
            break;
        if(strcmp(lineHeader, "v") == 0)
        {
            float vertex[3] = {0,0,0};
            fscanf(file, "%f %f %fn", 
                &vertex[0], &vertex[1], &vertex[2]);
            vertices[iv] = vertex[0];
            vertices[iv+1] = vertex[1];
            vertices[iv+2] = vertex[2];
            iv += 3;
        }
        else if(strcmp(lineHeader, "vt") == 0)
        {
            float tex_vert[2] = {0,0};
            fscanf(file, "%f %fn", 
                &tex_vert[0], &tex_vert[1]);
            texturas[it] = tex_vert[0];
            texturas[it+1] = tex_vert[1];
            it += 2;
        }
        else if(strcmp(lineHeader, "vn") == 0)
        {
            float normal[3] = {0,0,0};
            fscanf(file, "%f %f %fn", 
                &normal[0], &normal[1], &normal[2]);
            normales[in] = normal[0];
            normales[in+1] = normal[1];
            normales[in+2] = normal[2];
            in += 3;
        }
        else if(strcmp(lineHeader, "f") == 0)
        {
            unsigned int vertexIndex[9] = {0,0,0,0,0,0,0,0,0};
            fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%dn", 
                &vertexIndex[0], &vertexIndex[1], &vertexIndex[2],
                &vertexIndex[3], &vertexIndex[4], &vertexIndex[5],
                &vertexIndex[6], &vertexIndex[7], &vertexIndex[8]);
            vertTriangulos[ifa] = vertexIndex[0];
            vertTriangulos[ifa+1] = vertexIndex[1];
            vertTriangulos[ifa+2] = vertexIndex[2];
            vertTriangulos[ifa+3] = vertexIndex[3];
            vertTriangulos[ifa+4] = vertexIndex[4];
            vertTriangulos[ifa+5] = vertexIndex[5];
            vertTriangulos[ifa+6] = vertexIndex[6];
            vertTriangulos[ifa+7] = vertexIndex[7];
            vertTriangulos[ifa+8] = vertexIndex[8];
            ifa += 9;
            nTriangulos++;
        }
    }
 }

这是我的绘制函数:

void draw()
{
        glClear(GL_COLOR_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glEnableClientState(GL_NORMAL_ARRAY);
        glVertexPointer(3, GL_FLOAT, 0, vertices);
        glTexCoordPointer(2, GL_FLOAT, 0, texturas);
        glNormalPointer(GL_FLOAT, 0, normales);
        glDrawElements(GL_TRIANGLES, nTriangulos*9, GL_UNSIGNED_INT, vertTriangulos);
        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        glDisableClientState(GL_NORMAL_ARRAY);
   }

作为变量:

    long nTriangulos;
float *vertices, *normales, *texturas;
unsigned int *vertTriangulos;

我使用的obj文件是一个简单的立方体,但我渲染的网格是一场彻底的灾难。

编辑:我已经更改了我的代码,现在解析器如下所示:

    if(strcmp(lineHeader, "f") == 0)
    {
    unsigned int vertexIndex[9] = {0,0,0,0,0,0,0,0,0};
    fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%dn", 
        &vertexIndex[0], &vertexIndex[1], &vertexIndex[2],
        &vertexIndex[3], &vertexIndex[4], &vertexIndex[5],
        &vertexIndex[6], &vertexIndex[7], &vertexIndex[8]);
        for(int i = 0; i < 9; i += 3)
        {
            bool cierto = true;
            int pos = 0;
            if(indexbuff.size() > 0)
            {
                for(int i = 0; i < registro.size(); i++)
                {
                    if(vertexIndex[0] == registro[i].in1 
                        && vertexIndex[1] == registro[i].in2 
                        && vertexIndex[2] == registro[i].in3)
                    {
                        cierto = false;
                        pos = i;
                    }
                }
            }
            if(cierto)
            {
                verticebuff.push_back(vertices[vertexIndex[i]]);
                verticebuff.push_back(vertices[vertexIndex[i]+1]);
                verticebuff.push_back(vertices[vertexIndex[i]+2]);
                textbuff.push_back(texturas[vertexIndex[i+1]]);
                textbuff.push_back(texturas[vertexIndex[i+1]+1]);
                normalbuff.push_back(normales[vertexIndex[i+2]]);
                normalbuff.push_back(normales[vertexIndex[i+2]+1]);
                normalbuff.push_back(normales[vertexIndex[i+2]+2]);
                indexbuff.push_back(verticebuff.size()/3);
                index3 indice;
                indice.in1 = vertexIndex[i];
                indice.in2 = vertexIndex[i+1];
                indice.in3 = vertexIndex[i+2];
                registro.push_back(indice);
            }
            else
            {
                indexbuff.push_back(i);
            }
        }
       }

但它似乎无法正常工作。

经典的 obj 到 opengl 缓冲区错误,元素缓冲区索引指向所有属性。换句话说,如果 opengl 看到一个0索引,它会从所有启用的缓冲区中取出第一个元素,然后移动到下一个索引。没有办法直接使用 obj 结构,而不会在阅读时重复数据

你的脸代码应该是

if(/*vertexIndex[0..2] triplet has not been seen yet*/){
verticebuff.pushback(vertices[vertexIndex[0]]);
verticebuff.pushback(vertices[vertexIndex[0]+1]);
verticebuff.pushback(vertices[vertexIndex[0]+2]);

textbuff.pushback(texturas[vertexIndex[1]]);
textbuff.pushback(texturas[vertexIndex[1]+1]);
normalbuff.pushback(normales[vertexIndex[2]]);
normalbuff.pushback(normales[vertexIndex[2]+1]);
indexbuff.pushback(verticebuff.size()/3);
} else {
    indexbuff.pushback(/*index of the seen triplet*/);
}
//repeat 3 times

然后,您可以使用绘图元素绘制它们。