开发者

opengl vbo texture

I am still a beginner in vbo and I want to render a collada model. After taking all the needed info from the cae file about the vertices, normals and textures and indices for the vertices, normals and textures respectively, then i placed them in memory as a Model object. the thing that remained is how to render this object using vbo with the textures. I managed to render the object successfully by taking the vertices and indices then applying drawlelement for that in case of vbo render. But when I try to render textures it fails while rendering them using the display list works correctly thats because I am passing through every triangle and applying the vertex and texcoord correctly according to the vertex index and texture index. So how can i apply the texture indices found in the object in vbo in order for the texture to be rendered correctly?

This is the code for the project:

#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 Buf开发者_如何转开发fer
                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);
                }
            }
        }


There are no texture indices in OpenGL. This separation of positions and textures is quite common in modelling software, as it is simpler to manage. But in OpenGL, you need to have the exactly same count of texture coordinates as there are positions, so they could both be indexed using the same index.

This will require you to rebuild all the buffers, so that every combination of vertex index, normal index and texcoord index that occurs in your model can be mapped to a single index for OpenGL rendering. I'll try and write some pseudocode:

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
}

Now you can put new_indices, new_positions, new_normals and new_texcoords to VBOs and render them. I hope this helps ...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜