opengl vbo纹理

问题描述:

我仍然是vbo的初学者,我想渲染一个collada模型。在从cae文件中获取关于顶点,法线和纹理以及顶点,法线和纹理索引所需的所有信息后,我将它们作为模型对象放置在内存中。剩下的事情是如何使用vbo与纹理渲染这个对象。我设法通过取顶点和索引来成功地渲染对象,然后在vbo渲染的情况下应用提示元素。但是,当我尝试渲染纹理时,使用显示列表渲染它们失败,因为我正在穿过每个三角形,并根据顶点索引和纹理索引正确应用顶点和texcoord。那么我如何应用vbo中的对象中找到的纹理索引,以便正确渲染纹理?opengl vbo纹理

这是该项目的代码:

#include "bmp.h" 

    struct mdl_vert 
    { 
     float x,y,z; 
    }; 
    struct mdl_normal 
    { 
     float x,y,z; 
    }; 
    struct mdl_texCoord 
    { 
     float u,v; 
    }; 
    struct mdl_capacity 
    { 
     int vertsSize,indicesSize,normalsSize,texCoordsSize; 
    }; 
    struct mdl_indices 
    { 
     int *vertIndices; 
     int *normalIndices; 
     int *texIndices; 
    }; 

    class Group 
    { 
    public: 
     mdl_capacity capacity; 
     mdl_vert *verts; 
     mdl_normal *normals; 
     mdl_texCoord *texCoords; 
     mdl_indices indices; 
     char grp_name[64]; 

     Group() 
     { 
      capacity.texCoordsSize=0; 
      capacity.normalsSize=0; 
      capacity.indicesSize=0; 
      capacity.vertsSize=0; 
      verts=NULL; 
      normals=NULL; 
      texCoords=NULL; 
      indices.vertIndices=NULL; 
      indices.normalIndices=NULL; 
      indices.texIndices=NULL; 
      for(int i=0;i<64;i++) 
       grp_name[i]='\0'; 
     } 
    }; 

    class Model 
    { 
    public: 
     char tex_name[512]; 
     std::string Name; 
     Group **groups; 
     int groupsSize; 
    } 
    #define VBO_BUFFER_SIZE 4 
    struct GroupObject 
    { 
     GLuint *buffer; 
    }; 
    class ModelObject 
    { 
    private: 
     GLuint displayList; 
     GroupObject *groupBuffer; 
     bool isLoaded; 
     GLuint tex; 
     float ang,iniRotX,iniRotY,iniRotZ; 
     Model *mdl; 
     bool Hide; 
     AUX_RGBImageRec* m_pTextureImage;     // Heightmap Data 
    public: 
     ModelObject(Model* mdl) 
     { 
      this->mdl=mdl; 
      Redraw(); 
     } 
     void Redraw() 
     { 
      Hide=false; 
      ang=-0; 
      iniRotX=1; 
      iniRotY=0; 
      iniRotZ=0; 
      if(displayList!=-1) 
       displayList=-1; 
      groupBuffer=NULL; 
     } 

     void BuildTexture(int i) 
     { 
      if(mdl->groups[i]->capacity.texCoordsSize>0) 
      { 
       try 
       { 
        m_pTextureImage = auxDIBImageLoad(mdl->tex_name);    // Utilize GLaux's Bitmap Load Routine 
        glGenTextures(1, &tex);     // Get An Open ID 
        glBindTexture(GL_TEXTURE_2D, tex);    // Bind The Texture 
        glTexImage2D(GL_TEXTURE_2D, 0, 3, m_pTextureImage->sizeX, m_pTextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, m_pTextureImage->data); 
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 
        glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 

        // Free The Texture Data 
        if(m_pTextureImage) 
        { 
         if(m_pTextureImage->data) 
          free(m_pTextureImage->data); 
         free(m_pTextureImage); 
        } 
       } 
       catch(std::exception &ex) 
       { 
       } 
      } 
     } 

     void BuildVBO() 
     { 
      int index=0; 
      groupBuffer=new GroupObject[mdl->groupsSize]; 

      for(int i=0;i<mdl->groupsSize;i++) 
      { 
       BuildTexture(i); 
       groupBuffer[i].buffer=new GLuint[VBO_BUFFER_SIZE]; 
       // Generate And Bind The Vertex Buffer 
       glGenBuffersARB(1, &groupBuffer[i].buffer[0]);       // Get A Valid Name 
       glBindBufferARB(GL_ARRAY_BUFFER_ARB, groupBuffer[i].buffer[0]);   // Bind The Buffer 
       glBufferDataARB(GL_ARRAY_BUFFER_ARB,mdl->groups[i]->capacity.vertsSize*sizeof(mdl_vert), mdl->groups[i]->verts, GL_STATIC_DRAW_ARB); 
       // Generate And Bind The Normal Buffer 
       glGenBuffersARB(1, &groupBuffer[i].buffer[1]);       // Get A Valid Name 
       glBindBufferARB(GL_ARRAY_BUFFER_ARB, groupBuffer[i].buffer[1]);   // Bind The Buffer 
       glBufferDataARB(GL_ARRAY_BUFFER_ARB,mdl->groups[i]->capacity.normalsSize*sizeof(mdl_normal), mdl->groups[i]->normals, GL_STATIC_DRAW_ARB); 
       // Generate And Bind The Texture Buffer 
       glGenBuffersARB(1, &groupBuffer[i].buffer[2]);       // Get A Valid Name 
       glBindBufferARB(GL_ARRAY_BUFFER_ARB, groupBuffer[i].buffer[2]);   // Bind The Buffer 
       glBufferDataARB(GL_ARRAY_BUFFER_ARB,mdl->groups[i]->capacity.texCoordsSize*sizeof(mdl_texCoord), mdl->groups[i]->texCoords, GL_STATIC_DRAW_ARB); 
       // Generate And Bind The Index Buffer 
       glGenBuffersARB(1, &groupBuffer[i].buffer[3]); 
       glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, groupBuffer[i].buffer[3]); 
       glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, mdl->groups[i]->capacity.indicesSize*sizeof(unsigned int), mdl->groups[i]->indices.vertIndices, GL_STATIC_DRAW_ARB); 
      } 
     } 

     void render() 
     { 
      if(!Hide) 
      { 
       if(Drawer.vboSupported()) 
       { 
        if(groupBuffer==NULL) 
         BuildVBO(); 
        glRotatef(ang,iniRotX,iniRotY,iniRotZ); 
        for(int i=0;i<mdl->groupsSize;i++) 
        { 
         // Enable Pointers 
         glEnableClientState(GL_VERTEX_ARRAY);     // Disable Vertex Arrays 
         glEnableClientState(GL_NORMAL_ARRAY);    // Enable Normal Arrays 
         glEnableClientState(GL_TEXTURE_COORD_ARRAY);    // Enable Texture Coord Arrays 

         glBindBufferARB( GL_ARRAY_BUFFER_ARB, groupBuffer[i].buffer[0]); 
         glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0)); 

         glBindBufferARB( GL_ARRAY_BUFFER_ARB, groupBuffer[i].buffer[1]); 
         glNormalPointer(GL_FLOAT,0, BUFFER_OFFSET(0)); 

         glClientActiveTexture(GL_TEXTURE0); 
         glBindBufferARB( GL_ARRAY_BUFFER_ARB, groupBuffer[i].buffer[2]); 
         glTexCoordPointer(2,GL_FLOAT,0,BUFFER_OFFSET(0)); 

         glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, groupBuffer[i].buffer[3]); 
         glIndexPointer(GL_UNSIGNED_INT,0,BUFFER_OFFSET(0)); 
         glDrawElements(GL_TRIANGLES, mdl->groups[i]->capacity.indicesSize,GL_UNSIGNED_INT, 0); // Draw All Of The Triangles At Once 

         // Disable Pointers 
         glDisableClientState(GL_VERTEX_ARRAY);     // Disable Vertex Arrays 
         glDisableClientState(GL_NORMAL_ARRAY);    // Enable Normal Arrays 
         glDisableClientState(GL_TEXTURE_COORD_ARRAY);    // Enable Texture Coord Arrays 
        } 
        glRotatef(-ang,iniRotX,iniRotY,iniRotZ); 
       } 
       else 
       { 
        if(this->displayList==-1) 
        { 
         displayList = glGenLists(1); 
         glNewList(displayList,GL_COMPILE_AND_EXECUTE); 
         glRotatef(ang,iniRotX,iniRotY,iniRotZ); 
         for(int j=0;j<mdl->groupsSize;j++) 
         { 
          glEnable(GL_TEXTURE_2D); 
          glBindTexture(GL_TEXTURE_2D, tex); 
          // Enable Pointers 
          BuildTexture(j); 
          //glColor3f(((float)(rand()%256)/256.0f),((float)(rand()%256)/256.0f),((float)(rand()%256)/256.0f)); 
          for(int i=0;i<mdl->groups[j]->capacity.indicesSize;i+=3) 
          { 
           int iv1=mdl->groups[j]->indices.vertIndices[i]; 
           int in1=mdl->groups[j]->indices.normalIndices[i]; 
           int it1=mdl->groups[j]->indices.texIndices[i]; 
           int iv2=mdl->groups[j]->indices.vertIndices[i+1]; 
           int in2=mdl->groups[j]->indices.normalIndices[i+1]; 
           int it2=mdl->groups[j]->indices.texIndices[i+1]; 
           int iv3=mdl->groups[j]->indices.vertIndices[i+2]; 
           int in3=mdl->groups[j]->indices.normalIndices[i+2]; 
           int it3=mdl->groups[j]->indices.texIndices[i+2]; 
           glBegin(GL_TRIANGLES); 
            glTexCoord2f(mdl->groups[j]->texCoords[it1].u,mdl->groups[j]->texCoords[it1].v); 
            glNormal3f(mdl->groups[j]->normals[in1].x,mdl->groups[j]->normals[in1].y,mdl->groups[j]->normals[in1].z); 
            glVertex3f(mdl->groups[j]->verts[iv1].x,mdl->groups[j]->verts[iv1].y,mdl->groups[j]->verts[iv1].z); 
            glTexCoord2f(mdl->groups[j]->texCoords[it2].u,mdl->groups[j]->texCoords[it2].v); 
            glNormal3f(mdl->groups[j]->normals[in2].x,mdl->groups[j]->normals[in2].y,mdl->groups[j]->normals[in2].z); 
            glVertex3f(mdl->groups[j]->verts[iv2].x,mdl->groups[j]->verts[iv2].y,mdl->groups[j]->verts[iv2].z); 
            glTexCoord2f(mdl->groups[j]->texCoords[it3].u,mdl->groups[j]->texCoords[it3].v); 
            glNormal3f(mdl->groups[j]->normals[in3].x,mdl->groups[j]->normals[in3].y,mdl->groups[j]->normals[in3].z); 
            glVertex3f(mdl->groups[j]->verts[iv3].x,mdl->groups[j]->verts[iv3].y,mdl->groups[j]->verts[iv3].z); 
           glEnd(); 
          } 
          glDisable(GL_TEXTURE_2D); 
         } 
         glRotatef(-ang,iniRotX,iniRotY,iniRotZ); 
         glEndList(); 
         glCallList(displayList); 
        } 
        else 
         glCallList(displayList); 
       } 
      } 
     } 
+0

发布一个完整的,最小的程序来演示问题。 – genpfault 2011-04-04 13:42:28

有在OpenGL没有质感指数。这种位置和纹理的分离在建模软件中非常常见,因为它更易于管理。但在OpenGL中,您需要具有与位置完全相同的纹理坐标计数,因此它们都可以使用相同的索引进行索引。

这将需要您重建所有缓冲区,使发生在你的模型的顶点索引,普通索引和texcoord指数的每一个组合可以映射到OpenGL渲染一个指数。我会试着写一些伪代码:

struct Trinity { 
    int iv, in, it; 

    bool operator <(const Trinity &t) const // implement less-than operator as required by std::map 
    { 
     return iv < t.iv || (iv == t.iv && (in < t.in || (in == t.in && it < t.it))); 
    } 
}; 

#include <map> 
#include <vector> 

for(int j=0;j<mdl->groupsSize;j++) { // for each object ... 
    int next_index = 0; // next index to be assigned 

    std::map<int, Trinity> index_map; // map of collada indices to OpenGL indices 

    std::vector<int> new_indices; // new indices that can be used for drawing with OpenGL 
    std::vector<float> new_positions, new_texcoords, new_normals; // other arrays 

    for(int i=0;i<mdl->groups[j]->capacity.indicesSize;i++) { // for each vertex ... 
     Trinity t; 
     t.iv = mdl->groups[j]->indices.vertIndices[i]; 
     t.in = mdl->groups[j]->indices.normalIndices[i]; 
     t.it = mdl->groups[j]->indices.texIndices[i]; 
     // go through all the vertices' indices 

     int index; 
     if(index_map.find(t) != index_map.end()) 
      index = index_map[t]; // we already saw this combination of indices, reuse it 
     else { 
      index = next_index; // this is new; assign a new index 
      ++ next_index; 
      index_map[t] = index; // store the index in the map 

      new_positions.push_back(mdl->groups[j]->verts[t.iv].x); 
      new_positions.push_back(mdl->groups[j]->verts[t.iv].y); 
      new_positions.push_back(mdl->groups[j]->verts[t.iv].z); 

      new_texcoords.push_back(mdl->groups[j]->texCoords[t.it].u); 
      new_texcoords.push_back(mdl->groups[j]->texCoords[t.it].v); 

      new_normals.push_back(mdl->groups[j]->normals[t.in].x); 
      new_normals.push_back(mdl->groups[j]->normals[t.in].y); 
      new_normals.push_back(mdl->groups[j]->normals[t.in].z); 
      // add this particular combination of coordinates at the end of the buffers 
     } 
     // translate the combination of iv, in, it to a single index 

     new_indices.push_back(index); 
     // store it in the array 
    } 

    // object data ready to pass to VBOs 
} 

现在你可以把new_indices,new_positions,new_normals和new_texcoords到维也纳组织和渲染他们。我希望这可以帮助...