0

我在 OpenGL 应用程序中加载 .obj 文件时遇到问题。这是一个由不同部分制成的汽车模型(使用不同的材料,例如玻璃、车轮等)

我有一个 WavefrontModel 类,它包含一个 WavefrontSection 数组,它们有自己的顶点、法线、材质和 tex 坐标。

class WavefrontSection
{
  public:
        WavefrontSection(string mat_name = ""){ material = NULL; }
        void ConstructVAO();
        void Render();

    std::vector<float> vert;
    std::vector<float> tex_coord;
    std::vector<float> norm;

        /* these are the indexes used to build the VAO */
        std::vector<int>   vert_index;
    std::vector<int>   norm_index;
    std::vector<int>   tex_index;

        /* This is the material, containing ambient, diffuse and specular materials,
           and texture */
    Material *material;

        /* This is the VAO */
        VAO vao;
};

材质、法线和顶点加载良好 这是一个屏幕:

http://postimg.org/image/ubkm0nrjj/

当我尝试应用我加载的纹理(每部分一个)时,问题就出现了。这是加载程序代码:

int WavefrontModel::load(string file,string _mtlFile)
{
    gl3WriteOnStream("Loading model "+file,log_stream);

    ifstream model(file.c_str());

    if(!model)
    {
       cerr<<"Cannot open file "<<file<<endl;
       gl3WriteOnStream("Cannot open file "+file,error_stream);
       return -1;
    }

    char buf[256];
    char *curr_tok = NULL;

    /* These vectors stores all the vertices,normals and texture coord.
       Later each section will just copy in their arrays their vertices, normals
       and coords. To get the right order, i store the .obj face index information
       in WavefrontSections::*_index vector */

    std::vector<float> vert;
    std::vector<float> norm;
    std::vector<float> tex;

    mtlHeader.Open(_mtlFile);  /* I open the material file, to parse all the materials */

    int curr_section = 0;

    while(!model.eof())
    {
        model.getline(buf,256);

        curr_tok = strtok(buf,WHITESPACE);

        if(!curr_tok || curr_tok[0] == '#')
        {
            continue;
        }
        else if(strcmp(curr_tok,"v") == 0)
        {
            vert.push_back(atof(strtok(NULL,WHITESPACE)));
            vert.push_back(atof(strtok(NULL,WHITESPACE)));
            vert.push_back(atof(strtok(NULL,WHITESPACE)));
        }
    else if(strcmp(curr_tok,"vn") == 0)
    {
        norm.push_back(atof(strtok(NULL,WHITESPACE)));
        norm.push_back(atof(strtok(NULL,WHITESPACE)));
        norm.push_back(atof(strtok(NULL,WHITESPACE)));
    }
    else if(strcmp(curr_tok,"vt") == 0)
    {
        tex.push_back(atof(strtok(NULL,WHITESPACE)));
        tex.push_back(atof(strtok(NULL,WHITESPACE)));
    }
    else if(strcmp(curr_tok,"usemtl") == 0)
    {
        char *mtl = strtok(NULL,WHITESPACE);
        bool already_pres = false;

            /*I check if a sections already uses that material,
              if so, i add the new indexes to that section,
              otherwise I just create a new section */

        for(int i = 0;i < sections.size();i++)
        {
           if(strcmp(mtl,sections[i]->material->name.c_str()) == 0)
           {
               curr_section = i;
               already_pres = true;
               break;
           }
        }


        if(!already_pres)
        {
           curr_section = sections.size();
           sections.push_back(new WavefrontSection(mtl));
           sections[curr_section]->material = mtlHeader.parseMaterial(mtl);
        }
    }
    else if(strcmp(curr_tok,"f") == 0)
    {
      char *tmp_tok = NULL;
      char *temp = NULL;

          /* Here I parse model's faces. I added a '-1' to the indexes, because in the .obj
             file they start from 1, but in my vectors they start from 0 */

      while((tmp_tok = strtok(NULL,WHITESPACE)))
      {
            sections[curr_section]->vert_index.push_back(atoi(tmp_tok)-1);

            if((temp = strstr(tmp_tok,"//"))) ///no texture
            {
               temp++;
               sections[curr_section]->norm_index.push_back(atoi(++temp)-1);
            }
            else if((temp = strstr(tmp_tok,"/"))) ///with texture
            {
           sections[curr_section]->tex_index.push_back(atoi(++temp)-1);

           if((temp = strstr(temp,"/")))
           {
              sections[curr_section]->norm_index.push_back(atoi(++temp)-1);
           }
            }
       }
    }

    }


    cout<<"This model has got "<<sections.size()<<" sections"<<endl;

    /* Now I add vertices, normals and texture coords to each section, 
       using the indexes that I previously stored in each section */

    for(int i = 0;i < sections.size();i++)
    {
      for(int j = 0;j < sections[i]->vert_index.size();j++)
      {
        sections[i]->vert.push_back(vert[sections[i]->vert_index[j]*3]);   //x component
        sections[i]->vert.push_back(vert[sections[i]->vert_index[j]*3+1]); //y component
        sections[i]->vert.push_back(vert[sections[i]->vert_index[j]*3+2]); //z component
      }

      for(int j = 0;j < sections[i]->tex_index.size();j++) 
      {
        sections[i]->tex_coord.push_back(tex[sections[i]->tex_index[j]*2]);   //u component
        sections[i]->tex_coord.push_back(tex[sections[i]->tex_index[j]*2+1]); //v component
      }

      for(int j = 0;j < sections[i]->norm_index.size();j++)
      {
        sections[i]->norm.push_back(norm[sections[i]->norm_index[j]*3]);     //x component
        sections[i]->norm.push_back(norm[sections[i]->norm_index[j]*3+1]);   //y component
        sections[i]->norm.push_back(norm[sections[i]->norm_index[j]*3+2]);   //z component
      }

       sections[i]->ConstructVAO();   //I construct the VAO for each section

        printf("Section %i has %i verts, %i normals, %i tex coords\n",i,sections[i]->vert.size()/3,sections[i]->norm.size()/3,sections[i]->tex_coord.size()/2);
    }


}

这是渲染整个模型的代码:

void WavefrontModel::render(GLenum render_mode,bool normals,bool textured)
{
    glPolygonMode(GL_FRONT_AND_BACK,render_mode);

    glModelMatrix.LoadIdentity();
    glModelMatrix.translate(pos);
    glModelMatrix.rotate(angle,rot.x,rot.y,rot.z);
    glModelMatrix.scale(scaleVec);

    shader->sendUniformMatrix4fv(shader->getUniformLocation("projMat"),1,GL_FALSE,GLXSDLRenderPipeline::glProjectionMatrix);
    shader->sendUniformMatrix4fv(shader->getUniformLocation("viewMat"),1,GL_FALSE,GLXSDLRenderPipeline::glViewMatrix);
    shader->sendUniformMatrix4fv(shader->getUniformLocation("modMat"),1,GL_FALSE,glModelMatrix);
    shader->sendUniform1i(shader->getUniformLocation("texture"),0);


    for(int i = 0;i < sections.size();i++)
    {
      if(sections[i]->material)
      {
        sections[i]->material->sendMaterialUniforms(shader);
        sections[i]->material->texture.bind_unit(0);
      }
        shader->bind();
        sections[i]->Render();
        shader->unbind();

      if(sections[i]->material)
        sections[i]->material->texture.unbind();


    }
}

它在每个 WavefrontSection 实例上调用 render()。WavefrontSection::render() 方法实现如下

void WavefrontSection::Render()
{
    vao.DrawArrays(GL_TRIANGLES,0,vert.size());
}

(调用 ConstructVAO,我创建了旧法线和纹理坐标的缓冲区)

这就是我得到的:(搅拌机渲染应该是这样,其他是它在我的引擎中的渲染方式)

搅拌机渲染和引擎渲染

有什么建议吗?

4

1 回答 1

0

我解决了。问题就在这里

else if(strcmp(curr_tok,"vt") == 0)
{
       tex.push_back(atof(strtok(NULL,WHITESPACE)));
       tex.push_back(atof(strtok(NULL,WHITESPACE)));
}

我把它换成了

else if(strcmp(curr_tok,"vt") == 0)
{
        tex.push_back(atof(strtok(NULL,WHITESPACE)));
        tex.push_back(1-atof(strtok(NULL,WHITESPACE)));
}
于 2013-08-22T12:17:26.707 回答