OpenGL加载OBJ模型,纹理失真

问题描述:

我决定将Wavefront .OBJ格式导入到我正在处理的测试场景中。我得到的模型(顶点)是在正确的地方,它显示正常。当我使用纹理时,很​​多东西看起来都会变形。我检查了我的Maya场景(它看起来不错),并且该对象具有比顶点位置更多的UV坐标(这使得场景在OpenGL中看起来很奇怪,这是我的猜测)。OpenGL加载OBJ模型,纹理失真

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

+0

配置哪种语言的操作系统?也许你的.OBJ解析器使用该语言的小数点分隔符。在英语中,句点(。)用作小数点分隔符,但在瑞典语和法语等其他语言中,逗号(,)是标准。因此,如果.obj文件使用句号作为小数点分隔符进行编码,但是使用逗号进行解析,则最终会出现错误的坐标。 – Rulle

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

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,...}; 

然而,这将意味着你至少有108bytes每三角。

3(vert,norm,tex) 
*3(xyz/uvw) 
*3(points in tri) 
*4(bytes in a float)) 
----------------------- 
= 108 

可以显著仅复制,实际上是重复的顶点减少数量(有相同的纹理坐标,顶点和法意:平滑法线,无紫外线边界),并使用索引缓冲区对象设置抽奖订购。

我最近在一个小项目中遇到了同样的问题,我只沿着硬边和UV-Shell边界分割模型,因此只创建必要的重复顶点。然后我使用了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);