Rendering with glDrawRangeElements() not working properly - c++

This is a followup to my previous question. All of my questions were answered in my last thread but this is a new error that I am having. When rendering in intermediate mode, everything looks great.
In fact:
http://i.imgur.com/OFV6i.png
Now, I am rendering with the glDrawRangeElements() and look what happens:
http://i.imgur.com/mEmH5.png
Has anyone seen something like this before? It looks as if some of the indices are simply in the middle, which makes no sense at all.
This is the function I am using to render my level.
void WLD::renderIntermediate(GLuint* textures, long curRegion, CFrustum cfrustum)
{
// Iterate through all of the regions in the PVS
for(int i = 0; i < regions[curRegion].visibility.size(); i++)
{
// Grab a visible region
int vis = regions[curRegion].visibility[i];
// Make sure it points to a mesh
if(regions[vis].meshptr == NULL)
continue;
// Make sure it is in our PVS
if(!cfrustum.BoxInFrustum(regions[vis].meshptr->minX, regions[vis].meshptr->minY, regions[vis].meshptr->minZ, regions[vis].meshptr->maxX, regions[vis].meshptr->maxY, regions[vis].meshptr->maxZ))
continue;
// Optional: Only render the region we are in (for testing)
//if(vis != curRegion)
// continue;
// Now find the ID of the zone mesh in the array
int id = regions[vis].meshptr->id;
// Figure out how many calls we will have to do to render it (different textures)
int calls = zmeshes[id].numPolyTex;
int count = 0;
// Render each call in batches
for(int j = 0; j < calls; j++)
{
// Bind the correct texture
glBindTexture(GL_TEXTURE_2D, textures[zmeshes[id].polyTexs[j].texIndex]);
// Set up rendering states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
errorLog.writeSuccess("Drawing debug: ID: %i - Min: %i - Max: %i - Polys in this call %i - Count: %i - Location: %i", id, zmeshes[id].minmax[j].min, zmeshes[id].minmax[j].max, zmeshes[id].polyTexs[j].polyCount, zmeshes[id].polyTexs[j].polyCount * 3, count);
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &zmeshes[id].vertices[0].x);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &zmeshes[id].vertices[0].u);
// Draw
glDrawRangeElements(GL_TRIANGLES, zmeshes[id].minmax[j].min, zmeshes[id].minmax[j].max, zmeshes[id].polyTexs[j].polyCount * 3, GL_UNSIGNED_SHORT, zmeshes[id].indices + count);
// End of rendering - disable states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// Add the number of indices rendered
count += zmeshes[id].polyTexs[j].polyCount * 3;
}
}
}
I've done a ton of debug information indicating that my min/max values are set up correctly. At this point, I think it might be an error with the indices so I am going to go ahead an look over/rewrite that function.

Managed to get it to work. Very thankful that someone on another forum labeled his question accurately where a third vertex was being drawn at the origin.
http://www.gamedev.net/topic/583558-gldrawelements-is-drawing-all-of-my-vertices-with-one-vertex-at-the-origin-solved/page_gopid_4867052#entry4867052
Seems I needed to change my indices datatype from int to short. Works like a charm and I am getting a %1500 increase in FPS.

Related

OpenGL glMultiDrawElementsIndirect with Interleaved Buffers

Originally using glDrawElementsInstancedBaseVertex to draw the scene meshes. All the meshes vertex attributes are being interleaved in a single buffer object. In total there are only 30 unique meshes. So I've been calling draw 30 times with instance counts, etc. but now I want to batch the draw calls into one using glMultiDrawElementsIndirect. Since I have no experience with this command function, I've been reading articles here and there to understand the implementation with little success. (For testing purposes all meshes are instanced only once).
The command structure from the OpenGL reference page.
struct DrawElementsIndirectCommand
{
GLuint vertexCount;
GLuint instanceCount;
GLuint firstVertex;
GLuint baseVertex;
GLuint baseInstance;
};
DrawElementsIndirectCommand commands[30];
// Populate commands.
for (size_t index { 0 }; index < 30; ++index)
{
const Mesh* mesh{ m_meshes[index] };
commands[index].vertexCount = mesh->elementCount;
commands[index].instanceCount = 1; // Just testing with 1 instance, ATM.
commands[index].firstVertex = mesh->elementOffset();
commands[index].baseVertex = mesh->verticeIndex();
commands[index].baseInstance = 0; // Shouldn't impact testing?
}
// Create and populate the GL_DRAW_INDIRECT_BUFFER buffer... bla bla
Then later down the line, after setup I do some drawing.
// Some prep before drawing like bind VAO, update buffers, etc.
// Draw?
if (RenderMode == MULTIDRAW)
{
// Bind, Draw, Unbind
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, m_indirectBuffer);
glMultiDrawElementsIndirect (GL_TRIANGLES, GL_UNSIGNED_INT, nullptr, 30, 0);
glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0);
}
else
{
for (size_t index { 0 }; index < 30; ++index)
{
const Mesh* mesh { m_meshes[index] };
glDrawElementsInstancedBaseVertex(
GL_TRIANGLES,
mesh->elementCount,
GL_UNSIGNED_INT,
reinterpret_cast<GLvoid*>(mesh->elementOffset()),
1,
mesh->verticeIndex());
}
}
Now the glDrawElements... still works fine like before when switched. But trying glMultiDraw... gives indistinguishable meshes but when I set the firstVertex to 0 for all commands, the meshes look almost correct (at least distinguishable) but still largely wrong in places?? I feel I'm missing something important about indirect multi-drawing?
//Indirect data
commands[index].firstVertex = mesh->elementOffset();
//Direct draw call
reinterpret_cast<GLvoid*>(mesh->elementOffset()),
That's not how it works for indirect rendering. The firstVertex is not a byte offset; it's the first vertex index. So you have to divide the byte offset by the size of the index to compute firstVertex:
commands[index].firstVertex = mesh->elementOffset() / sizeof(GLuint);
The result of that should be a whole number. If it wasn't, then you were doing unaligned reads, which probably hurt your performance. So fix that ;)

Can I call `glDrawArrays` multiple times while updating the same `GL_ARRAY_BUFFER`?

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.

glDrawElementsInstanced - model matrix not transfered correctly

I'm currently trying to teach myself some OpenGL using some Tutorials and LWJGL. Obviously I'm just at rendering cubes.
What I've done up until now, and what works is, that for each cube I'll do
glUniformMatrix4(RenderProgram.ModelMatrixID, false,
renderobject.getTransformationBuffer());
glDrawElements(GL_TRIANGLES, renderobject.Model.countIndices(),
GL_UNSIGNED_INT, renderobject.Model.indexOffset);
Since that only gives me about 50-55 FPS with about 70k cubes, I decided trying instanced rendering, like so:
glDrawElementsInstanced(GL_TRIANGLES, Model.countIndices(),
GL_UNSIGNED_INT, 0, instanceCount);
Of course I've created another buffer for that beforehand, filling it with renderobject.getTransformationBuffer() of each cube and I'm binding this buffer before I try to draw instanced.
I also added it to my vertex shader like so layout(location = 12) in mat4 mModel and I've initialized the attrib pointers like so:
for (int i = 0; i < 4; i++) {
glEnableVertexAttribArray(12 + i);
glVertexAttribPointer(12 + i, 4, GL_FLOAT, false, Float.BYTES * 16,
Float.BYTES * 4 * i);
glVertexAttribDivisor(InstanceBufferID, 1);
}
I get no errors and while I don't see anything on screen, it's rendering and I see an FPS increase of about 350% so I think that I don't get the right model matrix in the shader.
Unfortunately I can't debug variable contents within the shader :) So I'm a little bit stumped as to what I might be missing or how I could unravel this... Also, obviously, Google didn't help me much either and SO just comes up with glDrawElements not working for people.
Edit: The accepted answer was the one error that could be determined from the code provided. However, I had another error in the code, which needed fixing before finally something was visible on the screen, which I'd like to share as well: I unbound the VAO before populating the VBO with the matrix data. As soon as I pushed that unbinding after loading the data into the VBO it worked!
Edit2: Interestingly the performance increase is even more imense now that something IS rendered. With my blank screen I got around 170 FPS for around 70k cubes. Now that it renders correctly I'm getting around 350-400 FPS for around 270k cubes! I didn't expect that.
The first argument to glVertexAttribDivisor should be the index of the vertex attribute that you want to use as an instanced array and not InstanceBufferID.
This should thus become:
for (int i = 0; i < 4; i++) {
glEnableVertexAttribArray(12 + i);
glVertexAttribPointer(12 + i, 4, GL_FLOAT, false, Float.BYTES * 16,
Float.BYTES * 4 * i);
glVertexAttribDivisor(12 + i, 1);
}

OpenGL - Drawing Large Amounts of Information stored in VBO's

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 ).

Using vertex buffers in jogl, crash when too many triangles

I have written a simple application in Java using Jogl which draws a 3d geometry. The camera can be rotated by dragging the mouse. The application works fine, but drawing the geometry with glBegin(GL_TRIANGLE) ... calls ist too slow.
So I started to use vertex buffers. This also works fine until the number of triangles gets larger than 1000000. If that happens, the display driver suddenly crashes and my montior gets dark. Is there a limit of how many triangles fit in the buffer? I hoped to get 1000000 triangles rendered at a reasonable frame rate.
I have no idea on how to debug this problem. The nasty thing is that I have to reboot Windows after each launch, since I have no other way to get my display working again. Could anyone give me some advice?
The vertices, triangles and normals are stored in arrays float[][] m_vertices, int[][] m_triangles, float[][] m_triangleNormals.
I initialized the buffer with:
// generate a VBO pointer / handle
if (m_vboHandle <= 0) {
int[] vboHandle = new int[1];
m_gl.glGenBuffers(1, vboHandle, 0);
m_vboHandle = vboHandle[0];
}
// interleave vertex / normal data
FloatBuffer data = Buffers.newDirectFloatBuffer(m_triangles.length * 3*3*2);
for (int t=0; t<m_triangles.length; t++)
for (int j=0; j<3; j++) {
int v = m_triangles[t][j];
data.put(m_vertices[v]);
data.put(m_triangleNormals[t]);
}
data.rewind();
// transfer data to VBO
int numBytes = data.capacity() * 4;
m_gl.glBindBuffer(GL.GL_ARRAY_BUFFER, m_vboHandle);
m_gl.glBufferData(GL.GL_ARRAY_BUFFER, numBytes, data, GL.GL_STATIC_DRAW);
m_gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
Then, the scene gets rendered with:
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, m_vboHandle);
gl.glEnableClientState(GL2.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL2.GL_NORMAL_ARRAY);
gl.glVertexPointer(3, GL.GL_FLOAT, 6*4, 0);
gl.glNormalPointer(GL.GL_FLOAT, 6*4, 3*4);
gl.glDrawArrays(GL.GL_TRIANGLES, 0, 3*m_triangles.length);
gl.glDisableClientState(GL2.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL2.GL_NORMAL_ARRAY);
gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0);
Try checking the return value of calling glBufferData. It will return GL_OUT_OF_MEMORY if it cannot satisfy numBytes.