C++ OpenGL加载OBJ模型,纹理失真

C++ OpenGL加载OBJ模型,纹理失真,c++,opengl,C++,Opengl,我决定将Wavefront.OBJ格式导入到我正在处理的测试场景中。我得到的模型(顶点)在正确的位置,它显示良好。当我应用纹理时,很多东西看起来都扭曲了。我检查了我的Maya场景(在那里看起来不错),对象的uv坐标比顶点位置多得多(我猜这就是为什么在OpenGL中场景看起来很奇怪) 我该如何加载这样的场景。是否需要复制顶点以及如何将其存储在顶点缓冲区对象中?必须复制顶点是正确的。 除此之外,还必须按绘制顺序对它们进行排序,这意味着您必须使用与纹理坐标和法线相同的偏移对顶点进行排序。 基本上,您需

我决定将Wavefront.OBJ格式导入到我正在处理的测试场景中。我得到的模型(顶点)在正确的位置,它显示良好。当我应用纹理时,很多东西看起来都扭曲了。我检查了我的Maya场景(在那里看起来不错),对象的uv坐标比顶点位置多得多(我猜这就是为什么在OpenGL中场景看起来很奇怪)


我该如何加载这样的场景。是否需要复制顶点以及如何将其存储在顶点缓冲区对象中?

必须复制顶点是正确的。 除此之外,还必须按绘制顺序对它们进行排序,这意味着您必须使用与纹理坐标和法线相同的偏移对顶点进行排序。 基本上,您需要这种结构:

float *verts = {v1_x,v1_y,v1_z,v1_w,v2_x,v2_y,v2_z,v2_w,...};
float *normals = {n1_x,n1_y,n1_z,n2_x,n2_y,n2_z,...};
float *texcoords = {t1_u,t1_v,t1_w,t2_u,t2_v,t2_w,...};
然而,这意味着每个三角形至少有108字节

 3(vert,norm,tex)
*3(xyz/uvw)
*3(points in tri)
*4(bytes in a float)) 
-----------------------
= 108
通过仅复制实际重复的顶点(具有相同的纹理坐标、顶点和法线,意思是:平滑法线和无UV边界),并使用索引缓冲区对象设置绘制顺序,可以显著减少该数量

我最近在一个小项目中遇到了同样的问题,我只是沿着硬边和UV壳边界分割模型,因此只创建必要的重复顶点。然后我使用Nate Robins的glm.h和glm.cpp,并按照顶点的相同顺序复制/排序法线和纹理坐标

然后设置VBO和IBO:

//this is for Data that does not change dynamically
//GL_DYNAMIC_DRAW and others are available
GLuint mDrawMode = GL_STATIC_DRAW;

//////////////////////////////////////////////////////////
//Setup the VBO
//////////////////////////////////////////////////////////
  GLuint mId;
  glGenBuffers(1, &mId);
  glBindBuffer(GL_ARRAY_BUFFER, mId);
  glBufferData(GL_ARRAY_BUFFER,
               mMaxNumberOfVertices * (mVertexBlockSize + mNormalBlockSize + mColorBlockSize + mTexCoordBlockSize),
               0,
               mDrawMode);
  glBufferSubData(GL_ARRAY_BUFFER, mVertexOffset, numberOfVertsToStore * mVertexBlockSize, vertices);
  glBufferSubData(GL_ARRAY_BUFFER, mNormalOffset, numberOfVertsToStore * mNormalBlockSize, normals);
  glBufferSubData(GL_ARRAY_BUFFER, mColorOffset, numberOfVertsToStore * mColorBlockSize, colors);
  glBufferSubData(GL_ARRAY_BUFFER, mTexCoordOffset, numberOfVertsToStore * mTexCoordBlockSize, texCoords);

//////////////////////////////////////////////////////////
//Setup the IBO
//////////////////////////////////////////////////////////
  GLuint IBOId;
  glGenBuffers(1, &IBOId);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOId);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, mMaxNumberOfIndices * sizeof(GLuint), 0, mDrawMode);
  glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numberOfIndicesToStore * sizeof(GLuint), indices);

//////////////////////////////////////////////////////////
//This is how to draw the object  
//////////////////////////////////////////////////////////
  glBindBuffer(GL_ARRAY_BUFFER, mId);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOId);

  //Enables and Disables are only necessary each draw
  //when they change between objects
  glEnableClientState(GL_VERTEX_ARRAY);
  glVertexPointer(mVertexComponents, GL_FLOAT, 0, (void*)mVertexOffset);
  if(mNormalBlockSize){
    glEnableClientState(GL_NORMAL_ARRAY);
    glNormalPointer(GL_FLOAT, 0, (void*)mNormalOffset);
  }
  if(mColorBlockSize){
    glEnableClientState(GL_COLOR_ARRAY);
    glColorPointer(mColorComponents, GL_FLOAT, 0, (void*)mColorOffset);
  }
  if(mTexCoordBlockSize){
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(mTexCoordComponents, GL_FLOAT, 0, (void*)mTexCoordOffset);
  }

  glDrawRangeElements(primMode,
                      idFirstVertex,
                      idLastVertex,
                      idLastVertex - idFirstVertex + 1,
                      mAttachedIndexBuffer->getDataType(),
                      0);

  if(mTexCoordBlockSize)
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  if(mColorBlockSize)
    glDisableClientState(GL_COLOR_ARRAY);
  if(mNormalBlockSize)
    glDisableClientState(GL_NORMAL_ARRAY);
  glDisableClientState(GL_VERTEX_ARRAY);

你是对的,你必须复制顶点。 除此之外,还必须按绘制顺序对它们进行排序,这意味着您必须使用与纹理坐标和法线相同的偏移对顶点进行排序。 基本上,您需要这种结构:

float *verts = {v1_x,v1_y,v1_z,v1_w,v2_x,v2_y,v2_z,v2_w,...};
float *normals = {n1_x,n1_y,n1_z,n2_x,n2_y,n2_z,...};
float *texcoords = {t1_u,t1_v,t1_w,t2_u,t2_v,t2_w,...};
然而,这意味着每个三角形至少有108字节

 3(vert,norm,tex)
*3(xyz/uvw)
*3(points in tri)
*4(bytes in a float)) 
-----------------------
= 108
通过仅复制实际重复的顶点(具有相同的纹理坐标、顶点和法线,意思是:平滑法线和无UV边界),并使用索引缓冲区对象设置绘制顺序,可以显著减少该数量

我最近在一个小项目中遇到了同样的问题,我只是沿着硬边和UV壳边界分割模型,因此只创建必要的重复顶点。然后我使用Nate Robins的glm.h和glm.cpp,并按照顶点的相同顺序复制/排序法线和纹理坐标

然后设置VBO和IBO:

//this is for Data that does not change dynamically
//GL_DYNAMIC_DRAW and others are available
GLuint mDrawMode = GL_STATIC_DRAW;

//////////////////////////////////////////////////////////
//Setup the VBO
//////////////////////////////////////////////////////////
  GLuint mId;
  glGenBuffers(1, &mId);
  glBindBuffer(GL_ARRAY_BUFFER, mId);
  glBufferData(GL_ARRAY_BUFFER,
               mMaxNumberOfVertices * (mVertexBlockSize + mNormalBlockSize + mColorBlockSize + mTexCoordBlockSize),
               0,
               mDrawMode);
  glBufferSubData(GL_ARRAY_BUFFER, mVertexOffset, numberOfVertsToStore * mVertexBlockSize, vertices);
  glBufferSubData(GL_ARRAY_BUFFER, mNormalOffset, numberOfVertsToStore * mNormalBlockSize, normals);
  glBufferSubData(GL_ARRAY_BUFFER, mColorOffset, numberOfVertsToStore * mColorBlockSize, colors);
  glBufferSubData(GL_ARRAY_BUFFER, mTexCoordOffset, numberOfVertsToStore * mTexCoordBlockSize, texCoords);

//////////////////////////////////////////////////////////
//Setup the IBO
//////////////////////////////////////////////////////////
  GLuint IBOId;
  glGenBuffers(1, &IBOId);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOId);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, mMaxNumberOfIndices * sizeof(GLuint), 0, mDrawMode);
  glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, numberOfIndicesToStore * sizeof(GLuint), indices);

//////////////////////////////////////////////////////////
//This is how to draw the object  
//////////////////////////////////////////////////////////
  glBindBuffer(GL_ARRAY_BUFFER, mId);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBOId);

  //Enables and Disables are only necessary each draw
  //when they change between objects
  glEnableClientState(GL_VERTEX_ARRAY);
  glVertexPointer(mVertexComponents, GL_FLOAT, 0, (void*)mVertexOffset);
  if(mNormalBlockSize){
    glEnableClientState(GL_NORMAL_ARRAY);
    glNormalPointer(GL_FLOAT, 0, (void*)mNormalOffset);
  }
  if(mColorBlockSize){
    glEnableClientState(GL_COLOR_ARRAY);
    glColorPointer(mColorComponents, GL_FLOAT, 0, (void*)mColorOffset);
  }
  if(mTexCoordBlockSize){
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(mTexCoordComponents, GL_FLOAT, 0, (void*)mTexCoordOffset);
  }

  glDrawRangeElements(primMode,
                      idFirstVertex,
                      idLastVertex,
                      idLastVertex - idFirstVertex + 1,
                      mAttachedIndexBuffer->getDataType(),
                      0);

  if(mTexCoordBlockSize)
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
  if(mColorBlockSize)
    glDisableClientState(GL_COLOR_ARRAY);
  if(mNormalBlockSize)
    glDisableClientState(GL_NORMAL_ARRAY);
  glDisableClientState(GL_VERTEX_ARRAY);

您的操作系统配置为哪种语言?可能您的.OBJ解析器正在使用该语言的十进制分隔符。在英语中,句号(.)用作小数分隔符,但在其他语言(如瑞典语和法语)中,逗号(,)是标准。因此,如果.obj文件使用句点作为十进制分隔符进行编码,但使用逗号对其进行解析,则最终会得到错误的坐标。您的操作系统配置为哪种语言?可能您的.OBJ解析器正在使用该语言的十进制分隔符。在英语中,句号(.)用作小数分隔符,但在其他语言(如瑞典语和法语)中,逗号(,)是标准。因此,如果.obj文件使用句点作为十进制分隔符进行编码,但使用逗号对其进行解析,那么最终将得到错误的坐标。