quinta-feira, fevereiro 03, 2011

Vertex Buffer Objects

Bom dia pessoal a grande novidade agora são os Vertex Buffer Objects, para quem não conhece os VBO é uma maneiro de enviar os arrays dos vetores, indices coordenadas de textura, normais para a memória da placa de video desta maneira não é necessário chamar o glVertex* para cada vetor diminuindo drasticamento o overred do programa desta maneira você envia os arrays para a placa de video uma única vez, e depois chama o  glDrawElements ele desenha seu mesh.

a um vasto conteudo na internet sobre VBO, abaixo segue alguns links de referência:

http://www.songho.ca/opengl/gl_vbo.html
http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=45

na engine consegui colocar o terreno no VBO, tive que fazer um re-build na estrutura basicamente por causa do tipo de dados, mas como tudo aqui é experimental ainda vão haver muitas modificações, os indices funcionão corretamente, só as coordenadas de textura que me deram uma bela surra.

 Abaixo segue as respectivas classes e um exemplo de utilização:
**** VertexBufferObject.h
/**
* @brief Gera Buffer Object
**/

class VertexBufferObject
{
    public:
        unsigned int vertexBuffId; //id do buffer vertices
        unsigned int indexBuffId; //id do buffer indices
        unsigned int normalBuffId; //id do buffer de normal
        unsigned int texBuffId; //id do buffer de coordenada de textura
        unsigned int numIndices;
        float *vertices; // data dos vertices
        unsigned int *indexs; // data dos indicex
        float *normals; // data das normais
        float *texCoord; //data das coordenadas de Texturas

        VertexBufferObject();

        /**
        * @brief seta os vetices do VBO
        * @param vec3d *data ponteiro para os vertices
        * @param uint32 size tamanho do buffer
        */
        void setVertices(float *data,unsigned int size);

        /**
        * @brief seta os indices do VBO
        * @param uint32 *data ponteiro para os indices
        * @param uint32 size tamanho do buffer
        */
        void setIndexs(unsigned int *data,unsigned int size);

        /**
        * @brief seta as normais do VBO
        * @param vec3d *data ponteiro para os normais
        * @param uint32 size tamanho do buffer
        */
        void setNormals(float *data,unsigned int size);

        /**
        * @brief seta as coordenadas de textura VBO
        * @param TexCoord2 *data ponteiro para os vertices
        * @param uint32 size tamanho do buffer
        */
        void setTexCoords(float *data,unsigned int size);

        /**
        * @brief desenha o VBO
        */
        void draw();
        virtual ~VertexBufferObject();
};

***EOF***
***VertexBufferObject.cpp****

VertexBufferObject::VertexBufferObject()
{
    vertexBuffId = 0;
    indexBuffId = 0;
    normalBuffId = 0;
    texBuffId = 0;
    numIndices = 0;
    vertices = NULL;
    indexs = NULL;
    normals = NULL;
    texCoord = NULL;

}

void VertexBufferObject::setVertices(float *data,unsigned int size)
{


    glGenBuffersARB( 1, &vertexBuffId);
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, vertexBuffId );

    vertices = data;

    glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, data, GL_STATIC_DRAW_ARB );

}
void VertexBufferObject::setIndexs(unsigned int *data,unsigned int size)
{
    glGenBuffersARB( 1, &indexBuffId );
    glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER, indexBuffId );

    indexs = data;

    numIndices = (size/sizeof(unsigned int));
    glBufferDataARB( GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW_ARB );
}

void VertexBufferObject::setNormals(float *data,unsigned int size)
{
    glGenBuffersARB( 1, &normalBuffId );
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, normalBuffId );

    normals = data;

    glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, data, GL_STATIC_DRAW_ARB );
}

void VertexBufferObject::setTexCoords(float *data,unsigned int size)
{
    glGenBuffersARB( 1, &texBuffId );
    glBindBufferARB( GL_ARRAY_BUFFER_ARB, texBuffId );

    texCoord = data;
    glBufferDataARB( GL_ARRAY_BUFFER_ARB, size, data, GL_STATIC_DRAW_ARB );
}

void VertexBufferObject::draw()
{

    if (vertexBuffId != 0 )
    {
        glBindBufferARB(GL_ARRAY_BUFFER_ARB, vertexBuffId);
        glEnableClientState(GL_VERTEX_ARRAY);

        glVertexPointer(3,GL_FLOAT,0,0);
    }

    if (indexBuffId != 0 )
    {
        glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, indexBuffId);
        glEnableClientState(GL_INDEX_ARRAY);
        glIndexPointer(GL_UNSIGNED_INT,0,0);
    }

    if (normalBuffId != 0)
    {
        glEnableClientState(GL_NORMAL_ARRAY);
        glNormalPointer(GL_FLOAT,0,normals);
    }

    if (texBuffId != 0)
    {
        glBindBufferARB(GL_ARRAY_BUFFER_ARB, texBuffId);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glTexCoordPointer(2,GL_FLOAT,0,0);
    }

    //glDrawArrays(GL_TRIANGLES,0,3);
    glDrawElements(GL_TRIANGLES,numIndices,GL_UNSIGNED_INT,0);


    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_INDEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}

VertexBufferObject::~VertexBufferObject()
{

}
***EOF***

Um exemplo da maneira que se possa utilizar segue abaixo isso vai desenhar um quadrado na tela.

// vertex coords array
GLfloat vertices[] =
{1,-1,1, 1,1,1, -1,1,1,
-1,-1,1
 };


unsigned int indices[] = {0,1,2,2,3,0};

float texCord[] = {0,1, 1,1, 1,0, 0,0, 0,1};

VertexBufferObject *vbo = NULL;
TexturePCX *tex = NULL;
...
...
...

int main(int argc,char **argv)
{
 ...
 ...
 ...

 vbo = new VertexBufferObject();
 vbo->setVertices(vertices,sizeof(vertices));
 vbo->setIndexs(indices,sizeof(indices));
tex = new TexturePCX("storage//textures//ground.bmp"); //Não era pra carregar um bmp?
}

void draw()
{
 ...
 glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();
    glTranslatef(0.0f,0.0f,-5.0f);
    tex->begin();
    vbo->draw();
    tex->end();
    glPopMatrix();
}

o resultado é o quadrado na tela você pode perceber que as texturas não estão aparecendo corretamente, você pode perceber tb o terreno sendo desenhado em um vbo, com o terreno coloquei um mapa de 512*512 sem sentir queda no FPS:

no gDEBugger você pode ver na placa de video como estão os dados:
Vertices:
Indices:
se você quiser ver os códigos completos da um pulo lá no svn:
https://newbie-engine.svn.sourceforge.net/svnroot/newbie-engine

Sem comentários: