8
\$\begingroup\$

I have some code that loops through a set of objects and renders instances of those objects. The list of objects that needs to be rendered is stored as a std::map>, where an object of class MeshResource contains the vertices and indices with the actual data, and an object of classMeshRenderer defines the point in space the mesh is to be rendered at.

My rendering code is as follows:

glDisable(GL_BLEND);
    glEnable(GL_CULL_FACE);
    glDepthMask(GL_TRUE);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_DEPTH_TEST);

    for (std::map<MeshResource*, std::vector<MeshRenderer*> >::iterator it = renderables.begin(); it != renderables.end(); it++)
    {
        it->first->setupBeforeRendering();
        cout << "<";
        for (unsigned long i =0; i < it->second.size(); i++)
        {
            //Pass in an identity matrix to the vertex shader- used here only for debugging purposes; the real code correctly inputs any matrix.
            uniformizeModelMatrix(Matrix4::IDENTITY);
            /**
             * StartHere fix rendering problem.
             * Ruled out:
             *  Vertex buffers correctly.
             *  Index buffers correctly.
             *  Matrices correct?
             */
            it->first->render();
        }
        it->first->cleanupAfterRendering();
    }

    geometryPassShader->disable();
    glDepthMask(GL_FALSE);
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);

The function in MeshResource that handles setting up the uniforms is as follows:

void MeshResource::setupBeforeRendering()
{
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glEnableVertexAttribArray(2);
    glEnableVertexAttribArray(3);
    glEnableVertexAttribArray(4);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID);
    glBindBuffer(GL_ARRAY_BUFFER, vboID);

    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); // Vertex position
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 12); // Vertex normal
    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 24); // UV layer 0
    glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 32); // Vertex color
    glVertexAttribPointer(4, 1, GL_UNSIGNED_SHORT, GL_FALSE, sizeof(Vertex), (const GLvoid*) 44); //Material index
}

The code that renders the object is this:

void MeshResource::render()
{
    glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}

And the code that cleans up is this:

void MeshResource::cleanupAfterRendering()
{
    glDisableVertexAttribArray(0);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(2);
    glDisableVertexAttribArray(3);
    glDisableVertexAttribArray(4);
}

The end result of this is that I get a black screen, although the end of my rendering pipeline after the rendering code (essentially just drawing axes and lines on the screen) works properly, so I'm fairly sure it's not an issue with the passing of uniforms. If, however, I change the code slightly so that the rendering code calls the setup immediately before rendering, like so:

void MeshResource::render()
{
    setupBeforeRendering();
    glDrawElements(GL_TRIANGLES, geometry->numIndices, GL_UNSIGNED_SHORT, 0);
}

The program works as desired. I don't want to have to do this, though, as my aim is to set up vertex, material, etc. data once per object type and then render each instance updating only the transformation information.

The uniformizeModelMatrix works as follows:

void RenderManager::uniformizeModelMatrix(Matrix4 matrix)
{
    glBindBuffer(GL_UNIFORM_BUFFER, globalMatrixUBOID);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(Matrix4), matrix.ptr());
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
\$\endgroup\$
  • \$\begingroup\$ I have a nearly identical setup for rendering my models. Except my render call binds the buffer and sets the attribute pointers each time. Are you running into performance issues with this? It runs very fast for me. \$\endgroup\$ – MichaelHouse Oct 11 '12 at 21:51
  • \$\begingroup\$ I haven't run into performance problems unless I have hundreds of identical objects on-screen, but still, I cannot figure out what's going wrong here, and it'd be great to learn why the code isn't working as expected. \$\endgroup\$ – HJ Media Studios Oct 12 '12 at 0:21
  • 1
    \$\begingroup\$ We just need to get the attention of @NicolBolas he's the resident openGL expert. \$\endgroup\$ – MichaelHouse Oct 12 '12 at 16:49
  • \$\begingroup\$ Might be a good idea to use offsetof when specifying vertex attributes \$\endgroup\$ – JBeurer Jun 22 '16 at 20:53
2
\$\begingroup\$

First of all, OpenGL is full of weird things so a driver bug, however unlikely it may be, is still an option - consider testing the app on different setups (nVidia vs. AMD, older drivers) and other tiny modifications of code. For example, you could start with removing the "glBindBuffer(GL_UNIFORM_BUFFER, 0);" line - it appears to be doing nothing useful anyway.

Since everything here appears to be correct, the problem is most probably not here. There are two options: gDEBugger and stepping through the code in the C++ debugger. It appears that something is being reset just before drawing. In gDEBugger, there's a "call history" feature which could help you see which calls were made before the draw call and in what order.

By the way, I strongly suggest you to wrap every error-returning call with a macro that checks for all possible errors and throws them. It has to be a macro to support extended debugging (printing file, line and the faulty line of code itself) that can be disabled in release builds. If some secret rule is broken, such setup should warn you of that immediately.

\$\endgroup\$
  • 5
    \$\begingroup\$ I would avoid linking to the Gremedy site. That version of gDEBugger is ancient and unsupported and very buggy. developer.amd.com/tools/heterogeneous-computing/amd-gdebugger is the up-to-date AMD supported version, with Windows and Linux support (no OS X, unfortunately). There are also some other fantastic GL debugging/perf tools on AMD's site, not to mention the tools that NVIDIA and Intel offer. \$\endgroup\$ – Sean Middleditch Nov 11 '12 at 20:46
0
\$\begingroup\$

I am pretty sure the attribute should bind to the current buffer so there is no reason to be redoing this business with the attributes every frame unless you rebuild the buffer every time....

So you should probably do it one way or the other - either leave it be or rebuild the whole thing every frame.

\$\endgroup\$
0
\$\begingroup\$

TL;DR: Driver bugs.

In my tests as of today (Oct 2016) uniform buffers are not supported properly by most drivers out there.

Some don't respect glUniformBlockBinding some don't update the uniform data (glBufferSubData and glBufferData) properly, where the shaders' / GPU cached internal copies of said buffers are not kept coherent.


The way I understand it (and the way Nvidia also understands it)

  • Bind/Map your Uniform Buffer Object to a global table shared by all shaders inside the OpenGL driver/GPU using glBindBufferBase or glBindBufferRange.
  • Map the shader's uniform buffer accesses to an entry into that global table using glUniformBlockBinding(shader_id, shader_ubo_index, global_ubo_index); this setting is per shader program, not shared globally.

Note: global_ubo_index is NOT the name of the uniform buffer object but an index into that global table.

This "complexity" (which is a great feature to share UBOs between different shaders, such as lighting values) seem to be what most OpenGL drivers get wrong. To be fair the wording in the OpenGL documentation isn't the most unambiguous it could be either.

I had to resort back to using plain old uniforms for other drivers.

Both screenshots using uniform buffer objects, two different drivers:

Uniform Buffer Bugs

\$\endgroup\$
  • \$\begingroup\$ What drivers did you test with? What platform? \$\endgroup\$ – akaltar Nov 6 '16 at 6:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.