So I've been trying to teach myself to use VBOs, in order to boost the performance of my OpenGL project and learn more advanced stuff than fixed-function rendering. But I haven't found much in the way of a decent tutorial; the best ones I've found so far are Songho's tutorials and the stuff at OpenGL.org, but I seem to be missing some kind of background knowledge to fully understand what's going on, though I can't tell exactly what it is I'm not getting, save the usage of a few parameters.
In any case, I've forged on ahead and come up with some cannibalized code that, at least, doesn't crash, but it leads to bizarre results. What I want to render is this (rendered using fixed-function; it's supposed to be brown and the background grey, but all my OpenGL screenshots seem to adopt magenta as their favorite color; maybe it's because I use SFML for the window?).
What I get, though, is this:
I'm at a loss. Here's the relevant code I use, first for setting up the buffer objects (I allocate lots of memory as per this guy's recommendation to allocate 4-8MB):
GLuint WorldBuffer;
GLuint IndexBuffer;
...
glGenBuffers(1, &WorldBuffer);
glBindBuffer(GL_ARRAY_BUFFER, WorldBuffer);
int SizeInBytes = 1024 * 2048;
glBufferData(GL_ARRAY_BUFFER, SizeInBytes, NULL, GL_STATIC_DRAW);
glGenBuffers(1, &IndexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);
SizeInBytes = 1024 * 2048;
glBufferData(GL_ELEMENT_ARRAY_BUFFER, SizeInBytes, NULL, GL_STATIC_DRAW);
Then for uploading the data into the buffer. Note that CreateVertexArray() fills the vector at the passed location with vertex data, with each vertex contributing 3 floats for position and 3 floats for normal (one of the most confusing things about the various tutorials was what format I should store and transfer my actual vertex data in; this seemed like a decent approximation):
std::vector<float>* VertArray = new std::vector<float>;
pWorld->CreateVertexArray(VertArray);
unsigned short Indice = 0;
for (int i = 0; i < VertArray->size(); ++i)
{
std::cout << (*VertArray)[i] << std::endl;
glBufferSubData(GL_ARRAY_BUFFER, i * sizeof(float), sizeof(float), &((*VertArray)[i]));
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, i * sizeof(unsigned short), sizeof(unsigned short), &(Indice));
++Indice;
}
delete VertArray;
Indice -= 1;
After that, in the game loop, I use this code:
glBindBuffer(GL_ARRAY_BUFFER, WorldBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBuffer);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, 0);
glNormalPointer(GL_FLOAT, 0, 0);
glDrawElements(GL_TRIANGLES, Indice, GL_UNSIGNED_SHORT, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
I'll be totally honest - I'm not sure I understand what the third parameter of glVertexPointer() and glNormalPointer() ought to be (stride is the offset in bytes, but Songho uses an offset of 0 bytes between values - what?), or what the last parameter of either of those is. The initial value is said to be 0; but it's supposed to be a pointer. Passing a null pointer in order to get the first coordinate/normal value of the array seems bizarre. This guy uses BUFFER_OFFSET(0) and BUFFER_OFFSET(12), but when I try that, I'm told that BUFFER_OFFSET() is undefined.
Plus, the last parameter of glDrawElements() is supposed to be an address, but again, Songho uses an address of 0. If I use &IndexBuffer instead of 0, I get a blank screen without anything rendering at all, except the background.
Can someone enlighten me, or at least point me in the direction of something that will help me figure this out? Thanks!
The initial value is said to be 0; but it's supposed to be a pointer.
The context (not meaning the OpenGL one) matters. If one of the gl*Pointer functions is called with no Buffer Object being bound to GL_ARRAY_BUFFER, then it is a pointer into client process address space. If a Buffer Object is bound to GL_ARRAY_BUFFER it's an offset into the currently bound buffer object (you may thing the BO forming a virtual address space, to which the parameter to gl*Pointer is then an pointer into that server side address space).
Now let's have a look at your code
std::vector<float>* VertArray = new std::vector<float>;
You shouldn't really mix STL containers and new, learn about the RAII pattern.
pWorld->CreateVertexArray(VertArray);
This is problematic, since you'll delete VertexArray later on, leaving you with a dangling pointer. Not good.
unsigned short Indice = 0;
for (int i = 0; i < VertArray->size(); ++i)
{
std::cout << (*VertArray)[i] << std::endl;
glBufferSubData(GL_ARRAY_BUFFER, i * sizeof(float), sizeof(float), &((*VertArray)[i]));
You should submit large batches of data with glBufferSubData, not individual data points.
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, i * sizeof(unsigned short), sizeof(unsigned short), &(Indice));
You're passing just incrementing indices into the GL_ELEMENT_ARRAY_BUFFER, thus enumerating the vertices. Why? You can have this, without the extra work using glDrawArrays insteaf of glDrawElements.
++Indice;
}
delete VertArray;
You're deleting VertArray, thus keeping a dangling pointer.
Indice -= 1;
Why didn't you just use the loop counter i?
So how to fix this? Like this:
std::vector<float> VertexArray;
pWorld->LoadVertexArray(VertexArray); // World::LoadVertexArray(std::vector<float> &);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float)*VertexArray->size(), &VertexArray[0] );
And using glDrawArrays; of course if you're not enumerating vertices, but have a list of faces→vertex indices, using a glDrawElements is mandatory.
Don't call glBufferSubData for each vertex. It misses the point of VBO. You are supposed to create big buffer of your vertex data, and then pass it to OpenGL in a single go.
Read http://www.opengl.org/sdk/docs/man/xhtml/glVertexPointer.xml
When using VBOs those pointers are relative to VBO data. That's why it's usually 0 or small offset value.
stride = 0 means the data is tightly packed and OpenGL can calculate the stride from other parameters.
I usually use VBO like this:
struct Vertex
{
vec3f position;
vec3f normal;
};
Vertex[size] data;
...
glBufferData(GL_ARRAY_BUFFER, size*sizeof(Vertex), data, GL_STATIC_DRAW);
...
glVertexPointer(3,GL_FLOAT,sizeof(Vertex),offsetof(Vertex,position));
glNormalPointer(3,GL_FLOAT,sizeof(Vertex),offsetof(Vertex,normal));
Just pass a single chunk of vertex data. And then use gl*Pointer to describe how the data is packed using offsetof macro.
For knowing about the offset of the last parameter just look at this post....
What's the "offset" parameter in GLES20.glVertexAttribPointer/glDrawElements, and where does ptr/indices come from?
Related
Ok,after a longer break I am a bit on a loss here.
I am trying to use a persistent mapped buffer, split to 2 buffers to improve performance. If using it as one buffer, everything works fine, once using it as 2, it fails miserably. I am not sure what I am missing, but maybe someone can enlighten me. I read quite some tutorials and descriptions, but so far no luck understanding it any better or finding the answer to these questions.
To my setup, I have the following data:
Buffer[0] = Point.X;
Buffer[1] = Point.Y;
Buffer[2] = Point.Z;
Buffer[3] = U;
Buffer[4] = V;
Buffer[5] = Color.X;
Buffer[6] = Color.Y;
Buffer[7] = Color.Z;
Buffer[8] = Color.W;
in my approach without persistent buffers, I do this:
...
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * TotalSize, Buffer, GL_STREAM_DRAW);
...
glVertexAttribPointer(VERTEX_COORD_ATTRIB, 3, GL_FLOAT, GL_FALSE, StrideSize, 0);
glVertexAttribPointer(TEXTURE_COORD_ATTRIB, 2, GL_FLOAT, GL_FALSE, StrideSize, (void*)VertFloatSize);
glVertexAttribPointer(COLOR_ATTRIB, 4, GL_FLOAT, GL_FALSE, StrideSize, (void*)(VertFloatSize+TexFloatSize));
...
glDrawArrays(Mode, 0, (BufferData.VertSize / FloatsPerVertex));
...
Now to the persistent part (I am leaving out fences and sync stuff here, since this doesn't seem to be a problem.):
GLbitfield PersistentBufferFlags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;
GLsizeiptr BufferSize=(2 * BUFFER_SIZE);
glBindBuffer(GL_ARRAY_BUFFER, PMB);
glBufferStorage(GL_ARRAY_BUFFER, BufferSize, 0, PersistentBufferFlags);
Buffer = (float*)glMapBufferRange(GL_ARRAY_BUFFER, 0, BufferSize, PersistentBufferFlags);
Now this already my first question- is this the right approach? Map it with one and use the offset of the size of the first buffer run to continue then from there with the data of the 2nd or should it be rather 2 mappings of the same storage like this? :
glBindBuffer(GL_ARRAY_BUFFER, PMB);
glBufferStorage(GL_ARRAY_BUFFER, BufferSize, 0, PersistentBufferFlags);
Buffer[0] = (float*)glMapBufferRange(GL_ARRAY_BUFFER, 0, BUFFER_SIZE, PersistentBufferFlags)
Buffer[1] = (float*)glMapBufferRange(GL_ARRAY_BUFFER, BUFFER_SIZE, BUFFER_SIZE, PersistentBufferFlags)
I found no hint whats to be preferred or what's right or even wrong. How is it correctly split?
Then trying to draw with
glDrawArrays(Mode, 0, (BufferData.VertSize / FloatsPerVertex)); //Draw "first" buffer, everything works if only this one.
...next round...
glDrawArrays(Mode, offset_of_datasize_first_buffer, (BufferData.VertSize / FloatsPerVertex)); //Second part of the buffer, fails.
Not entirely sure here about the 2nd parameter, I find the explanation of it confusing:
Specifies the starting index in the enabled arrays.
Am I right that this should be too the offset size of the first buffer then in the second run?
Other than that I use the same setup as above, just without the glBufferData.
So anyway, no matter which version above I use, it works if I use it only as 1 buffer, but if using it as 2, it very much looks like it ignores the data in the second part of the buffer.
So this is my next question- is it even allowed to use a persistent buffer like this? Does it respect the interleaved setup done with glVertexAttribPointer or is it plain for verts only and solely?
Let me know if you need any more information or if something is not clear. Many thanks.
The second parameter of glDrawArrays() isn't an offset, but an index to the first vertex, like when using indexed rendering with glDrawElements(). Use offset_in_bytes/stride_in_bytes to get the correct value, or actually compute BUFFER_SIZE has a function of stride and use that value for glDrawArrays().
Second parameter is almost definitely giving you trouble. Is offset_of_datasize_first_buffer an index or byte offset? Try offset_of_datasize_first_buffer / FloatsPerVertex.
Also, you can rebind your attribute pointers and add BUFFER_SIZE to the last parameter to set 0 index at the start of the second buffer.
Try to make sure that offset_of_datasize_first_buffer is an index type and not byte offset first before trying to switch your attribute pointers. That should be faster.
I wrote obj loader and got following:
It is yellow eagle but as you see it has some additional triangles that go from its leg to wing. The code that I used:
{....
glBindBuffer(GL_ARRAY_BUFFER,vbo);
glBufferData(GL_ARRAY_BUFFER,sizeof(data),data,GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER,numOfIndices*sizeof(GLuint),indices,GL_STATIC_DRAW);
}
void Mesh::draw( )
{
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER,vbo);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,ibo);
glDrawElements(GL_TRIANGLES,numOfIndices,GL_UNSIGNED_INT,(void*)0 );
glDisableVertexAttribArray(0);
}
Where data is array of vertices and indices is array of indices.
When I take and save data and indices in obj format and open resulting file in 3D editor eagle looks fine and doesn't have these additional triangles (that implies that both data and indices are fine).
I spent hours trying to to fix code and make eagle look normal but now I run out of ideas. So please if you have any ideas how to make eagle normal share them with me.
For those who think the problem is in loader here is screen of obj model that is made out of data from loader (from data[] and indices[])
Finally found solution.
Indexing in obj. format starts at 1 (not 0 ) and when you load vertices to GL_ARRAY_BUFFER vertex #1 becomes vertex#0 and whole indexing breaks.
Therefore it is necessary to decrease all values of indices by 1 and then index that pointed to vertex #1 will point to vertex #0 and indexing will become correct.
In a single frame, is it "allowed" to update the same GL_ARRAY_BUFFER continuously and keep calling glDrawArrays after each update?
I know this is probably not the best and not the most recommended way to do it, but my question is: Can I do this and expect to get the GL_ARRAY_BUFFER updated before every call to glDrawArrays ?
Code example would look like this:
// setup a single buffer and bind it
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
while (!renderStack.empty())
{
SomeObjectClass * my_object = renderStack.back();
renderStack.pop_back();
// calculate the current buffer size for data to be drawn in this iteration
SomeDataArrays * subArrays = my_object->arrayData();
unsigned int totalBufferSize = subArrays->bufferSize();
unsigned int vertCount = my_object->vertexCount();
// initialise the buffer to the desired size and content
glBufferData(GL_ARRAY_BUFFER, totalBufferSize, NULL, GL_STREAM_DRAW);
// actually transfer some data to the GPU through glBufferSubData
for (int j = 0; j < subArrays->size(); ++j)
{
unsigned int subBufferOffset = subArrays->get(j)->bufferOffset();
unsigned int subBufferSize = subArrays->get(j)->bufferSize();
void * subBufferData = subArrays->get(j)->bufferData();
glBufferSubData(GL_ARRAY_BUFFER, subBufferOffset, subBufferSize, subBufferData);
unsigned int subAttributeLocation = subArrays->get(j)->attributeLocation();
// set some vertex attribute pointers
glVertexAttribPointer(subAttributeLocation, ...);
glEnableVertexAttribArray(subAttributeLocation, ...);
}
glDrawArrays(GL_POINTS, 0, (GLsizei)vertCount);
}
You may ask - why would I want to do that and not just preload everything onto the GPU at once ... well, obvious answer, because I can't do that when there is too much data that can't fit into a single buffer.
My problem is, that I can only see the result of one of the glDrawArrays calls (I believe the first one) or in other words, it appears as if the GL_ARRAY_BUFFER is not updated before each glDrawArrays call, which brings me back to my question, if this is even possible.
I am using an OpenGL 3.2 CoreProfile (under OS X) and link with GLEW for OpenGL setup as well as Qt 5 for setting up the window creation.
Yes, this is legal OpenGL code. It is in no way something that anyone should ever actually do. But it is legal. Indeed, it makes even less sense in your case, because you're calling glVertexAttribPointer for every object.
If you can't fit all your vertex data into memory, or need to generate it on the GPU, then you should stream the data with proper buffer streaming techniques.
I have two 'std::vector's, one for indices and one for vertices, which I fill with std::vector.push_back(). Then I do
glGenBuffers(1, &verticesbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, verticesbuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, /*EDITED-->*/vertices.size() * sizeof(vertices[0])/*<--EDITED*/, &vertices[0], GL_STATIC_DRAW);
to create the buffers for each, and then attempt to draw the polygon with
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glBindBuffer(GL_ARRAY_BUFFER, verticesbuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesbuffer);
glDrawElements(
GL_TRIANGLES,
indices.size(),
GL_UNSIGNED_INT,
&indices[0]
);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
When I run the program, nothing shows up. I can get it to work using the glBegin() / glEnd() approach but the indexed vbo just doesn't work (glGetError() also doesn't give any errors). I don't even know if this is remotely close to correct as I have searched through countless tutorials and other stackoverflow questions and tried many different things to fix it. I should also mention that I called
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glOrtho(0.0f, windowX, windowY, 0.0f, 0.0f, 1000.0f);
at the beginning of the program, which I also have no idea if this is correct (as you can see, I am pretty new at this stuff).
The problem is that you expected sizeof(vertices) to give you the total number of bytes stored in the vector. However, it only gives the size of the vector object itself, not the dynamic data it contains.
Instead, you should use vertices.size() * sizeof(vertices[0]).
You misunderstand how sizeof operator works. It is an operator which is executed at compile-time and returns the size (in bytes) of the specified type or variable.
float f;
std::cout << sizeof(f); // prints 4
std::cout << sizeof(float); // prints 4
But what happens when we use sizeof on a pointer to an array? Let's examine the following case:
float array1[50]; // static size array, allocated on the stack
float *array2 = new float[50]; // dynamic size array, allocated on the heap
std::cout << sizeof(array1); // prints 200, which is ok (50*4 == 200)
std::cout << sizeof(array2); // prints out the size of a float pointer, not the array
In the first case we use sizeof on a static array, which is allocated on the stack. Since the size of array1 is constant, the compiler knows about it and returns it's actual size in bytes on sizeof(array1).
In the second case we use sizeof on a dynamic array which is allocated on the heap. The size of array2 ideally cannot be known at compile time (otherwise you should use a static array, if fits into the stack), so the compiler knows nothing about the size of the array array2, so it returns the size of the pointer to our array.
What happens when you use sizeof on std::vector?
std::vector<float> vec(50);
std::cout << sizeof(vec); // prints out the size of the vector (but it's not 4*50)
But if sizeof(vec) returns the size of the vector, why doesn't return 4*50? std::vector manages an underlying dynamically allocated array (second case in the previous example), so the compiler don't know anything about the size of that underlying array. That's why it returns the size of the overall encapsulated (hidden) variables of the vector object, including the size of the pointer to the actual array data. If you want the number of elements in your underlying array, you need to use vec.size(). To get the size of the underlying float array in bytes, just use vec.size() * sizeof(float).
Fixing your code with the knowledge from above:
std::vector<float> vertices;
// ...add vertices with push_back()...
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vertices.size() * sizeof(float), &vertices[0], GL_STATIC_DRAW);
or
std::vector<float> vertices;
// ..add vertices with push_back()...
glBufferData(GL_ELEMENT_ARRAY_BUFFER, vertices.size() * sizeof(vertices[0]), &vertices[0], GL_STATIC_DRAW);
In the future you can also use a graphics debugger to help with these issues. Depending on your card you can use AMDs gpu perf studio or nVidia nsight on windows or graphics debugger on Linux. This saves a lot of time and headaches.
If you get your blank screen again. Run your app with the debugger attached and follow the pipeline.
You should see the data fed into the vertex shader and since it was shorter than what you expected it would flag an issue and you could start there.
I have fairly large C++ objects which load mesh data into memory and then draws based on an OnDisplay callback.
The problem is that the refresh rate is really slow which I suspect is because my code is poorly written.
Anyway; here is what my class looks like (function prototypes shown to give you an idea of how my class is set up).
What I want to know is if it is possible to just call the "glDrawElements" function somehow on what is in memory if most of my VBOs haven't changed and skip my Begin and end draw functions as shown below.
OR, even better,
If there is a magic OpenGL function I can call that, with one pass, OpenGL can render all of my unchanged Buffer IDs and I can simply focus on drawing the ones that have changed and the camera?
Mostly I will just have the camera moving through the scene.
I set these functions up based on tutorials and documentation so I know they work; I just want to speed up the drawing, especially when the meshes I am loading in are 100MB + in size.
First, here is my class prototype:
class MyMeshData
{
public:
MyMeshData();
~MyMeshData();
// Save up data into GPU buffers.
bool Initialize(const MeshDataFromFileClass * StaticMeshData);
// Update vertex positions for deformed meshes.
void UpdateVertexPosition(const MeshDataFromFileClass * StaticMeshData, const MyVector4Class * pVertices) const;
// Bind buffers, set vertex arrays, turn on lighting and texture.
void BeginDraw(ShadingMode pShadingMode) const;
// Draw all the faces with specific material with given shading mode.
void Draw(int pMaterialIndex, ShadingMode pShadingMode) const;
// Unbind buffers, reset vertex arrays, turn off lighting and texture.
void EndDraw() const;
// Get the count of material groups
int GetSubMeshCount() const { return mSubMeshes.GetCount(); }
private:
enum
{
VERTEX_VBO,
NORMAL_VBO,
UV_VBO,
INDEX_VBO,
VBO_COUNT,
};
// For every material, record the offsets in every VBO and triangle counts
struct SubMesh
{
SubMesh() : IndexOffset(0), TriangleCount(0) {}
int IndexOffset;
int TriangleCount;
};
GLuint mVBONames[VBO_COUNT];
MyMeshArray<SubMesh*> mSubMeshes;
bool mHasNormal;
bool mHasUV;
bool mAllByControlPoint; // Save data in VBO by control point or by polygon vertex.
};
And here is my Initialize Function:
bool Initialize(const MeshDataFromFileClass * StaticMeshData) {
[...]
/*
Earlier code that retrieves data from file removed.
Only the point where the data is transferred to the GPU is shown.
*/
// Create VBOs
glGenBuffers(VBO_COUNT, mVBONames);
// Save vertex attributes into GPU
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[VERTEX_VBO]);
glBufferData(GL_ARRAY_BUFFER, lPolygonVertexCount * VERTEX_STRIDE * sizeof(float), lVertices, GL_STATIC_DRAW);
delete [] lVertices;
if (mHasNormal)
{
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[NORMAL_VBO]);
glBufferData(GL_ARRAY_BUFFER, lPolygonVertexCount * NORMAL_STRIDE * sizeof(float), lNormals, GL_STATIC_DRAW);
delete [] lNormals;
}
if (mHasUV)
{
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[UV_VBO]);
glBufferData(GL_ARRAY_BUFFER, lPolygonVertexCount * UV_STRIDE * sizeof(float), lUVs, GL_STATIC_DRAW);
delete [] lUVs;
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mVBONames[INDEX_VBO]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, lPolygonCount * TRIANGLE_VERTEX_COUNT * sizeof(unsigned int), lIndices, GL_STATIC_DRAW);
delete [] lIndices;
}
Here is my BeginDraw Function:
void MyMeshData::BeginDraw(ShadingMode pShadingMode) const
{
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[VERTEX_VBO]);
/*
glVertexPointer(VERTEX_STRIDE, GL_FLOAT, 0, 0);
glEnableClientState(GL_VERTEX_ARRAY);
*/
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, VERTEX_STRIDE, GL_FLOAT, GL_FALSE, 0, 0);
// Set normal array.
if (mHasNormal && pShadingMode == SHADING_MODE_SHADED)
{
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[NORMAL_VBO]);
glNormalPointer(GL_FLOAT, 0, 0);
glEnableClientState(GL_NORMAL_ARRAY);
}
// Set UV array.
if (mHasUV && pShadingMode == SHADING_MODE_SHADED)
{
glBindBuffer(GL_ARRAY_BUFFER, mVBONames[UV_VBO]);
glTexCoordPointer(UV_STRIDE, GL_FLOAT, 0, 0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mVBONames[INDEX_VBO]);
if (pShadingMode != SHADING_MODE_SHADED)
{
glColor4fv(DEFAULT_WIREFRAME_COLOR);
}
}
My Draw function ...
void MyMeshData::Draw(int pMaterialIndex, ShadingMode pShadingMode) const
{
// Where to start.
GLsizei lOffset = mSubMeshes[pMaterialIndex]->IndexOffset * sizeof(unsigned int);
if ( pShadingMode == SHADING_MODE_SHADED)
{
const GLsizei lElementCount = mSubMeshes[pMaterialIndex]->TriangleCount * 3;
glDrawElements(GL_TRIANGLES, lElementCount, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid *>(lOffset));
}
else
{
for (int lIndex = 0; lIndex < mSubMeshes[pMaterialIndex]->TriangleCount; ++lIndex)
{
glDrawElements(GL_LINE_LOOP, TRIANGLE_VERTEX_COUNT, GL_UNSIGNED_INT, reinterpret_cast<const GLvoid *>(lOffset));
lOffset += sizeof(unsigned int) * TRIANGLE_VERTEX_COUNT;
}
}
}
And finally my End Draw Function....
void VBOMesh::EndDraw() const
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
What I want to know is if it is possible to just call the
"glDrawElements" function somehow on what is in memory if most of my
VBOs haven't changed and skip my Begin and end draw functions as shown
below.
There is a feature in opengl that exactly does that, called Vertex Array Buffer (VAO). This feature allows you to save what you have in your begin draw into an object ( much like a VBO ) bind it, unbind it, saving you time so you don't have to bind all buffers by hand each time. I don't really remember since when it is supported, it is a core feature since opengl3 I'm sure about that, as far as I know even OpenGL ES 2.0 supports this via extension.
If there is a magic OpenGL function I can call that, with one pass,
OpenGL can render all of my unchanged Buffer IDs and I can simply
focus on drawing the ones that have changed and the camera?
If I understand this correctly, you want something like a cached rendering so instead of manually calling glDrawElements each time you want a function where you can throw in all your buffer id's and tell it to 'render these'. As far as I know the closest thing to this is instanced rendering, but that comes with it's limitations.
Altho I think there might be something else here since VBOs already make your rendering fast, and GPUs don't like small models, large models are really good for the GPU since it gets a chance to use its nifty features, super duper caching and what not to make it fast, where with small models there is not chance since before caches start to fill up the model is already rendered. So if this runs slow in your case it might be something else since what you are doing is almost ideal for a GPU to reach its top performance, I would suggest running something like gDebugger to profile which is the function or code piece that takes the most time and if that seems okay, then try a GPU debugger/profiler to see what takes the most time ( like NVPerfKit for nVidia ).