Using Vertex Buffer Objects

Tutorial 7: Using Vertex Buffer Objects

 

This tutorial is very small compared with previous one. It only will explain what are the Vertex Buffer Objects (VBO) and how to use them. We will part from the tutorial 6. Remove the particle class files and all references to particlesystem in the render.cpp file, and you will be ready to begin with this tutorial.

 

What are VBO? Well, until now, we’ve sent the data from main memory to OpenGL using vertex arrays. This means that at every frame, all data is transported (copied) from main memory to client memory, but think about textures. They are uploaded only one time, and when they are needed, they are binded and referenced from client memory. VBO does exactly the same thing, but with vertices, instead of texels information. The needed steps to create and use a VBO are very close to the steps needed to create and use a texture. Lets see how.

 

Mesh class is modified to accommodate the VBO handlers by this way:

class Mesh

{

public:

  Mesh(const char *filename, bool useVBO = false);

  ~Mesh();

  void Draw();

  bool GetState () {return m_state;};

 

private:

 FixedMesh m_mesh;

 bool m_state;

 

 //new VBO variables

 bool m_useVBO; //to know if this mesh will use VBO or not

 

 //VBO handlers

 GLuint m_indexBuffer;

 GLuint m_vertexBuffer;

 GLuint m_normalBuffer;

 GLuint m_texCoordBuffer;

};


Next, there will be write the mesh.cpp class, which contains all relative information about VBO

Render.cpp

 

#include "mesh.h"

Mesh::Mesh(const char *filename,bool useVBO)

{

  m_state = true;

  m_useVBO = useVBO;

  m_mesh.Geometry = NULL;

  m_mesh.Indices = NULL;

  m_mesh.Normals = NULL;

  m_mesh.TexCoord = NULL;

  

  GSDHeader header;

  FILE *meshFile = fopen(filename,"rb");

  if(!meshFile)

  {

    m_state = false;

    return;

  }

 

  fread(&header,sizeof(GSDHeader),1,meshFile);

 

  if(header.numberOfSubObjects < 1)

  {

    m_state = false;

    fclose(meshFile);

    return;

  }

 

  GenericObjectData o;

 

  fread(o.Name,sizeof(char)*128,1,meshFile);

  fread(o.ParentName,sizeof(char)*128,1,meshFile);   

  fread(&o.iC,sizeof(unsigned long),1,meshFile);

  fread(&o.vC,sizeof(unsigned long),1,meshFile);

 

  o.Indices = new unsigned int[o.iC];

  m_mesh.Indices = new GLushort[o.iC];

  fread(o.Indices,sizeof(unsigned int) * o.iC,1,meshFile);

 

  o.Geometry = new float[o.vC * 3];

  m_mesh.Geometry = new GLfixed[o.vC * 3];

  fread(o.Geometry,o.vC * 3 * sizeof(float),1,meshFile);

 

  o.TexCoord = new float[o.vC * 2];

  m_mesh.TexCoord = new GLfixed[o.vC * 2];

  fread(o.TexCoord,o.vC * 2 * sizeof(float),1,meshFile);

 

  o.Normals= new float[o.vC * 3];

  m_mesh.Normals = new GLfixed[o.vC * 3];

  fread(o.Normals,o.vC * 3* sizeof(float),1,meshFile); 


 

  for(unsigned int i=0;i<o.vC * 3;i++)

  {

    m_mesh.Geometry[i]= FixedFromFloat(o.Geometry[i]);

    m_mesh.Normals[i] = FixedFromFloat(o.Normals[i]);

  }

 

  for(i=0;i<o.vC * 2;i++)

    m_mesh.TexCoord[i] = FixedFromFloat(o.TexCoord[i]);

 

  for(i=0;i<o.iC;i++)

    m_mesh.Indices[i] = (GLushort)o.Indices[i];

 

  m_mesh.indexCounter = (GLushort)o.iC;

  m_mesh.vertexCounter= (GLushort)o.vC;

 

  delete [] o.Indices;

  delete [] o.Geometry;

  delete [] o.Normals;

  delete [] o.TexCoord;

  fclose(meshFile);  

/*----------------------- NEW CODE -------------------------*/

  //if we will use the VBO features, then lets create them

  if(m_useVBO)

  {

    // First, we need create a buffer handle

    glGenBuffers(1, &m_indexBuffer);

    //Then we have to bind it, like a texture

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer); 

    /*Now we have to specify the data. Because this is a index buffer,

    we use GL_ELEMENT_ARRAY_BUFFER , in other case, we will use

    GL_ARRAY_BUFFER. The buffer size (in bytes) is the next parameter,

    Then the buffer itself is specified, and at last, GL_STATIC_DRAW

    is a hint that only points to the future usage of this buffer*/

    glBufferData(GL_ELEMENT_ARRAY_BUFFER,

     m_mesh.indexCounter * sizeof(GLushort),

     m_mesh.Indices, GL_STATIC_DRAW);   

  

    //remember unbind the VBO if you wint use it in the future

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

 

    glGenBuffers(1, &m_vertexBuffer);

    glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);

    glBufferData(GL_ARRAY_BUFFER,

     m_mesh.vertexCounter * 3 * sizeof(GLfixed),

     m_mesh.Geometry, GL_STATIC_DRAW);

     

    glGenBuffers(1, &m_normalBuffer);

    glBindBuffer(GL_ARRAY_BUFFER, m_normalBuffer);

    glBufferData(GL_ARRAY_BUFFER,

                 m_mesh.vertexCounter * 3 * sizeof(GLfixed),

                 m_mesh.Normals, GL_STATIC_DRAW);

 

    glGenBuffers(1, &m_texCoordBuffer);

    glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer);

    glBufferData(GL_ARRAY_BUFFER,

                 m_mesh.vertexCounter * 2 * sizeof(GLfixed),

                 m_mesh.TexCoord, GL_STATIC_DRAW);   

    //remember unbind the VBO if you wint use it in the future

    glBindBuffer(GL_ARRAY_BUFFER, 0);


    /*because VBO data is stored in client memory, we do not need it

      in main memory for more time*/

    if(m_mesh.Geometry) delete [] m_mesh.Geometry;

    if(m_mesh.Indices) delete [] m_mesh.Indices;

    if(m_mesh.Normals) delete [] m_mesh.Normals;

    if(m_mesh.TexCoord) delete [] m_mesh.TexCoord;

  }   

}

//--------------------------------------------------------------------

Mesh::~Mesh()

{

  if(m_useVBO)

  {

    glDeleteBuffers(1, &m_indexBuffer);

    glDeleteBuffers(1, &m_vertexBuffer);

    glDeleteBuffers(1, &m_normalBuffer);

    glDeleteBuffers(1, &m_texCoordBuffer);

  }

  else

  {

    if(m_mesh.Geometry) delete [] m_mesh.Geometry;

    if(m_mesh.Indices) delete [] m_mesh.Indices;

    if(m_mesh.Normals) delete [] m_mesh.Normals;

    if(m_mesh.TexCoord) delete [] m_mesh.TexCoord;

  }

}

//--------------------------------------------------------------------

void Mesh::Draw()

{

  glEnableClientState(GL_VERTEX_ARRAY);

  glEnableClientState(GL_NORMAL_ARRAY);

  glEnableClientState(GL_TEXTURE_COORD_ARRAY);

  if(m_useVBO)

  {

    /*Binding the VBO and assigning NULL to the pointer, means that

      next drawing call will use the previus data stored at the VBO*/

    glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);

    glVertexPointer(3, GL_FIXED, 0, NULL);

       

    glBindBuffer(GL_ARRAY_BUFFER, m_normalBuffer);

    glNormalPointer(GL_FIXED, 0, NULL);

   

    glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer);

    glTexCoordPointer(2,GL_FIXED, 0, NULL);

  

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);  

    glDrawElements(GL_TRIANGLES,m_mesh.indexCounter,GL_UNSIGNED_SHORT,

 NULL);

    //VBO unbinds

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    glBindBuffer(GL_ARRAY_BUFFER, 0);

  }

  else

  {

    glVertexPointer(3, GL_FIXED, 0, m_mesh.Geometry);           

    glNormalPointer(GL_FIXED, 0, m_mesh.Normals);       

    glTexCoordPointer(2,GL_FIXED, 0, m_mesh.TexCoord);      

    glDrawElements(GL_TRIANGLES,m_mesh.indexCounter,GL_UNSIGNED_SHORT,

  m_mesh.Indices); 

  }

  glDisableClientState(GL_VERTEX_ARRAY);  

  glDisableClientState(GL_NORMAL_ARRAY);

  glDisableClientState(GL_TEXTURE_COORD_ARRAY);  

}

 

Well, that’s all. Very easy, isn’t? In hardware accelerated systems, VBO can give a great performance boost, but in current PDA’s, without 3D acceleration, the gain won’t be too big, but VBO are a too important topic to do not take care about it.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值