Sign in to follow this  
SFCBias

Cannot Understand or get VBOs working

Recommended Posts

SFCBias    162
Im sure people are getting quite tired of seeing posts about VBOs by now. And since this is my first post, it may not be priority. However,

I've searched these and several other forums have done about a weeks worth or research on this but i still cannot get my VBO's to work. SO I decided to post my code and find out where im going wrong.

I've had the impression that it may be the Vertex stucture or simply how im passing the data, and so i've tried different methods and tweaked parameters here and there but still not luck.

Class VertexBufferObject (Based off of CVertexBufferObject class found in this post http://www.gamedev.net/community/forums/topic.asp?topic_id=424778 with additions)

/*
* SFC_VertexBufferObject.cpp
*
* Created on: Nov 8, 2010
* Author: bryce
*/


#include "SFC_VertexBufferObject.h"
#include "SFC_LogManager.h"

namespace SFC
{

VertexBufferObject::VertexBufferObject() :
mVBOData(NULL), mVBODataSize(0), mAvailableSize(0), mVBOID(0)

{
glGenBuffersARB(1, &mVBOID);
}

VertexBufferObject::~VertexBufferObject()
{
glDeleteBuffersARB(1, &mVBOID);
}

void VertexBufferObject::Bind()
{
glBindBufferARB(GL_ARRAY_BUFFER, mVBOID);
}

void VertexBufferObject::disableVBOs()
{
glBindBufferARB(GL_ARRAY_BUFFER, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, 0);
}

void VertexBufferObject::setData(int size, void *data)
{
Bind();

glBufferDatARB(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
mVBOData = data;
mVBODataSize = size;

if (data == NULL)
mAvailableSize = size;

#ifdef _DEBUG
char str[256];
sprintf(str, "Allocating VBO Memory. Size: %d", size);
LogManager::getSingletonPtr()->logMessage(str);
#endif

}

void VertexBufferObject::setData(int size, void *data, GLenum usage,
GLenum target)
{
Bind();

glBufferDataARB(target, size, data, usage);

mVBOData = data;
mVBODataSize = size;

if (data == 0)
mAvailableSize = size;

#ifdef _DEBUG
char str[256];
sprintf(str, "Allocating VBO Memory. Size: %d", size);
LogManager::getSingletonPtr()->logMessage(str);
#endif

}

void VertexBufferObject::setSubData(int size, int offset, const void *data)
{
Bind();

glBufferSubDataARB(GL_ARRAY_BUFFER, offset, size, data);
mAvailableSize -= size;


#ifdef _DEBUG
char str[256];
sprintf(str,
"Filling VBO Memory. Size: %d\nAvailable Buffer memory: %d",
size, mAvailableSize);
LogManager::getSingletonPtr()->logMessage(str);
#endif

}

void VertexBufferObject::setSubData(int size, int offset, const void *data,
GLenum target)
{
Bind();
glBufferSubDataARB(target, offset, size, data);
mAvailableSize -= size;

#ifdef _DEBUG
char str[256];
sprintf(str,
"Filling VBO Memory. Size: %d\nAvailable Buffer memory: %d",
size, mAvailableSize);
LogManager::getSingletonPtr()->logMessage(str);
#endif

}
void *VertexBufferObject::getVBOData() const
{
return mVBOData;
}

unsigned int VertexBufferObject::getVBODataSize() const
{
return mVBODataSize;
}

unsigned int VertexBufferObject::getVBOID() const
{
return mVBOID;
}
}




Mesh.cpp
[source ]
/*
* SFC_Mesh.cpp
*
* Created on: Oct 27, 2010
* Author: bryce
*/


#include "SFC_Mesh.h"
#include "SFC_StdAfx.h"
#include "SFC_Point2D.h"
#include "SFC_Point3D.h"
#include "SFC_VertexBufferManager.h"
#include "SFC_VertexBufferObject.h"

namespace SFC
{
/*

// VBO Extension Function Pointers
PFNGLGENBUFFERSARBPROC glGenBuffersARB; // VBO Name Generation Procedure
PFNGLBINDBUFFERARBPROC glBindBufferARB; // VBO Bind Procedure
PFNGLBUFFERDATAARBPROC glBufferDataARB; // VBO Data Loading Procedure
PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB; // VBO Deletion Procedure

*/


Mesh::Mesh()
{
// Set Pointers To NULL
mVertices = NULL;
mVertexCount = 0;
}

Mesh::~Mesh()
{
// Delete Data
if (mVertices)
delete[] mVertices;
mVertices = NULL;

if (mSubMeshes)
{
for (int i = 0; i < mSubMeshCount; i++)
{
free(mSubMeshes[i].mIndexArray);
}
free(mSubMeshes);
}
}

void Mesh::loadMesh(const std::string& meshName)
{
int vertexCount;
int subMeshCount;
char outPathName[2048] = "";
FILE* file;

strcpy(outPathName, meshName.c_str());

file = fopen(outPathName, "rb");

if (file == NULL)
{
std::string str;
str.assign("Cannot locate file named: ").append(meshName);
SFC_EXCEPT(E_FileNotFound,str);
}

// read all of the vertices's, normal and UV
fscanf(file, "%s %d/n", outPathName, &vertexCount);
mVertexCount = mNormalCount = vertexCount;
mVertices = new Vertex[mVertexCount]; // Allocate Vertex Data
//GLfloat* mTestVert = (GLfloat*)malloc(3 * mVertexCount * sizeof(float));
for (int i = 0; i < vertexCount; i++)
{
fscanf(file, "%f %f %f ", &mVertices[i].positions[0],
&mVertices[i].positions[1], &mVertices[i].positions[2]);
fscanf(file, "%f %f %f ", &mVertices[i].normal[0],
&mVertices[i].normal[1], &mVertices[i].normal[2]);
fscanf(file, "%f %f\n", &mVertices[i].tex[0], &mVertices[i].tex[1]);
}

// read all of the mesh segments,
fscanf(file, "%s %d/n", outPathName, &subMeshCount);
mSubMeshCount = subMeshCount;
mSubMeshes = new SubMesh[mSubMeshCount];
for (int i = 0; i < subMeshCount; i++)
{
int indexCount;
char texName[256];
fscanf(file, "%s %s/n", outPathName, texName);
fscanf(file, "%s %d/n", outPathName, &indexCount);

// load the texture for this submesh
//mSubMeshes[i].mTextureHandle = LoadTexture(texName);
mSubMeshes[i].mIndexCount = indexCount;
mSubMeshes[i].mIndexArray = new unsigned short[indexCount];
for (int j = 0; j < indexCount; j++)
{
int index;
fscanf(file, "%d ", &index);
mSubMeshes[i].mIndexArray[j] = (unsigned short) index;
}
fscanf(file, "\n");
}

// close file after reading
fclose(file);

}

void printArray(float* array, int arraySize)
{
for (int i = 0; i < arraySize; i++)
std::cout << array[i * 3] << " " << array[i * 3 + 1] << " "
<< array[i * 3 + 2] << std::endl;
}

void Mesh::BuildVBOs()
{

//printArray(&mVertices[0].positions[0].fX,mVertexCount);
VertexBufferManager *vbm = VertexBufferManager::getSingletonPtr();
mVBO0 = vbm->createVBO();
mVBO0->setData(sizeof(Vertex) * mVertexCount, NULL);
mVBO0->setSubData(sizeof(Vertex) * mVertexCount, 0, mVertices);
mVBO1 = vbm->createVBO();
mVBO1->setData(sizeof(unsigned short) * mSubMeshes[0].mIndexCount,
mSubMeshes[0].mIndexArray, GL_STATIC_DRAW,
GL_ELEMENT_ARRAY_BUFFER);
//mVBO->setSubData(mNormalCount, 0, &mNormal[0].fX);

}
}





This is where it's rendered
Entity.cpp
[source ]
bool Entity::update(float timeSinceLastFrame)
{

mMesh->mVBO0->Bind();
mMesh->mVBO1->Bind();
// Set the state of what we are drawing (I don't think order matters here, but I like to do it in the same
// order I set the pointers
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
//glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);

// Resetup our pointers. This doesn't reinitialise any data, only how we walk through it
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
// glColorPointer(4, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));

// Actually do our drawing, parameters are Primative (Triangles, Quads, Triangle Fans etc), Elements to
// draw, Type of each element, Start Offset
glDrawElements(GL_TRIANGLES, mMesh->mSubMeshes->mIndexCount, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));

// Disable our client state back to normal drawing
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
// it is good idea to release VBOs with ID 0 after use.
// Once bound with 0, all pointers in gl*Pointer() behave as real
// pointer, so, normal vertex array operations are re-activated
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);

return true;
}





And finally my Vertex Structure
[source ]	typedef struct //Struct represents ONE VERTEX in a polygon or triangle
{
GLfloat positions[3];
GLfloat tex[2];
GLfloat normal[3];
GLfloat color[4];
GLubyte padding[16];
} Vertex;




[Edited by - SFCBias on November 11, 2010 1:18:58 PM]

Share this post


Link to post
Share on other sites
dpadam450    2357
Maybe i'll look at it later and help you out. But for now, make a single function called outputDebugMessage(string message), and put a single #ifdef _DEBUG in to either output the string or not. That way you dont have ifdef's everywhere.

Share this post


Link to post
Share on other sites
karwosts    840
The first thing I notice is that you're binding both data and indices to GL_ARRAY_BUFFER, when you should be binding your index to GL_ELEMENT_ARRAY_BUFFER (see the Bind()) function. This will definitely break your code, though I don't know if that's the only thing wrong.


Also please edit your post and place 'source' tags around your code, it creates nice formatting.


int x = 0+1;


Share this post


Link to post
Share on other sites
SFCBias    162
Quote:
Original post by karwosts
The first thing I notice is that you're binding both data and indices to GL_ARRAY_BUFFER, when you should be binding your index to GL_ELEMENT_ARRAY_BUFFER (see the Bind()) function. This will definitely break your code, though I don't know if that's the only thing wrong.


Also please edit your post and place 'source' tags around your code, it creates nice formatting.

*** Source Snippet Removed ***


Sorry im used the the VB [code] tags

Share this post


Link to post
Share on other sites
Juanxo    189
hi:

I look at your code and i think i have spotted your bug.

In your Bind function, you always bind GL_ARRAY_BUFFER, but you need to bind your face indices with GL_ARRAY_ELEMENT_BUFFER imo

PS: next time, give an explanation of what errors are you getting, in order to help us to spot the error

Share this post


Link to post
Share on other sites
SFCBias    162
Thank you but that was not the problem. I just recently made that change but before I already was binding to GL_ELEMENT_ARRAY_BUFFER. Also I'm getting no errors, only getting a blank screen that is not rendering any triangles. But i have made the change you said.

Share this post


Link to post
Share on other sites
karwosts    840
Well it certainly was 'a' problem.

Are you checking for opengl errors (glGetError)? I know you said you're getting no errors, but I don't know if you are checking opengl errors or not.

Are you certain your mesh data is correct? Can you try starting with just a single triangle?

Also if you made the fix that was suggested, can you keep your original post up to date with your most current code? Nobody can tell if you fixed it the right way, and it will save everyone else from noticing the same thing.

Share this post


Link to post
Share on other sites
SFCBias    162
I very well was getting a GL_INVALID_OPERATION error after calling


mVBO1->setData(sizeof(unsigned short) * mSubMeshes[0].mIndexCount,
mSubMeshes[0].mIndexArray, GL_STATIC_DRAW,
GL_ELEMENT_ARRAY_BUFFER);

Share this post


Link to post
Share on other sites
karwosts    840
Is it failing on glBindBuffer or glBufferData? Double check all your variables in the debugger (vbo buffer id, number of indices, things like that).

Share this post


Link to post
Share on other sites
karwosts    840
Post your new bind() method.

These are the invalid operations described by glBufferData

Quote:

GL_INVALID_OPERATION is generated if the reserved buffer object name 0 is bound to target.

GL_INVALID_OPERATION is generated if glBufferData is executed between the execution of glBegin and the corresponding execution of glEnd.

Share this post


Link to post
Share on other sites
PrestoChung    334
I'm working with a similar problem and I would feel kind of silly to make another thread. I tried to keep all the code straight here in this post and edit it down to the relevant parts to make it understandable. The vertex data seems to be reading fine, but no texture.

I call glGetError() when I end the program and it returns 0.

I have a vertex struct with 5 floats: 3 position and 2 uv.

Texture is loaded:
void LoadTexture(){
SDL_Surface* mysurface = SDL_LoadBMP("tex01.bmp");
if (mysurface == NULL){
std::cout << "RoomData LoadTexture() ERROR: Unable to load bitmap" << std::endl;
return;
}
PrintSDLSurface(mysurface);

glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

glGenTextures(1, &Tex_Id);
glBindTexture(GL_TEXTURE_2D, Tex_Id);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

SDL_LockSurface(mysurface);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, mysurface->w, mysurface->h,
0, GL_RGB, GL_UNSIGNED_BYTE, mysurface->pixels);

SDL_UnlockSurface(mysurface);

SDL_FreeSurface(mysurface);
}
Rendering:
Render()const{ 
glMatrixMode( GL_MODELVIEW );
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glColor3f(1.f, 1.f, 1.f);

glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glActiveTexture( GL_TEXTURE0_ARB );
glBindTexture( GL_TEXTURE_2D, Tex_Id );

for(int i = 0; i < last; ++i){
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, Indices[i]);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, Vertices[i]);
glVertexPointer(3, GL_FLOAT, 20, 0);
glTexCoordPointer (2, GL_FLOAT, 20, (GLvoid*) (NULL + sizeof (float) * 3));
glDrawElements(GL_TRIANGLES, size, GL_UNSIGNED_BYTE, 0);
}

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);

SDL_GL_SwapBuffers();
}
I have a feeling it might be something I'm not initializing correctly, so here's my OpenGL init that gets called once at the beginning of the program:
void System::Program::InitGL()
{
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glDepthFunc(GL_LESS);
glShadeModel(GL_FLAT);
glClearColor(0.f, 0.f, 0.f, 0.f);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective(45, Aspect_, 1, 1000);
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glewInit();
}

So I don't get any errors, just plain white triangles, no texture.

Share this post


Link to post
Share on other sites
karwosts    840
Well I don't really see how your problem is similar (you should probably make your own thread, it doesn't hurt anyone), but anyway...

Do you set the min/mag filters for your textures?

Read this

Share this post


Link to post
Share on other sites
PrestoChung    334
Quote:
Original post by karwosts
Well I don't really see how your problem is similar (you should probably make your own thread, it doesn't hurt anyone), but anyway...

Do you set the min/mag filters for your textures?

Read this


That was it :D thanks! Colors are inverse but I will figure that out.

Share this post


Link to post
Share on other sites
SFCBias    162
I realize my error. And you actually were right. When you asked me to post my new bind method, I noticed that even when I changed it , I didn't update the target BEFORE the bind. So I was still binding to the default GL_ARRAY_BUFFER.
So thank you. My object is now rendering correctly.

void VertexBufferObject::Bind()
{
glBindBufferARB(mTargetType, mVBOID);
}


void VertexBufferObject::setData(int size, void *data, GLenum usage,
GLenum target)
{
mTargetType = target;
Bind();

glBufferDataARB(target, size, data, usage);



mVBOData = data;
mVBODataSize = size;

if (data == 0)
mAvailableSize = size;


}



Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this