• Advertisement
Sign in to follow this  

glMultiDrawArrays does not render properly

This topic is 700 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Good evening.

 

I'm developing a game engine and I'm trying to write a function that renders all the colliders on the scene. My problem is that glMultiDrawArrays works if I only have one collider, but does not when I have two or more. I've spent the last 3 days reading countless threads, examples, tutorials and docs and I still can't figure out what I'm doing wrong. This is the code that I have:

 

[spoiler]

void MRenderer::RenderColliders() const
{
    const auto& Colliders = MPhysicsManager::Instance().GetColliders();

    GLuint VertexBufferID;
    
    // Current offset of our collider vertices.
    int Offset = 0;

    // Each collider's offset in the vertex buffer.
    std::vector<GLint> ColliderOffsets;

    // Each collider's total vertices.
    std::vector<GLsizei> ColliderVertexCount;

    GL_CALL(glGenBuffers(1, &VertexBufferID));
    GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID));
    GL_CALL(glBufferData(GL_ARRAY_BUFFER, 400 * sizeof(GLfloat), 0, GL_STATIC_DRAW));

    GL_CALL(glEnableVertexAttribArray(0));
    GL_CALL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0));

    for (const auto& Collider : Colliders)
    {
        //Collider.second->Shape->Rotate(0.01f);
        std::vector<Vector2> ShapeVertices = Collider.second->GetVertices();
        std::vector<GLfloat> VertexBuffer;

        for (int i = 0; i < ShapeVertices.size(); i++)
        {
            VertexBuffer.push_back(ShapeVertices[i].GetX());
            VertexBuffer.push_back(ShapeVertices[i].GetY());
        }

        ColliderOffsets.push_back(Offset);
        ColliderVertexCount.push_back(ShapeVertices.size());

        GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, Offset, VertexBuffer.size() * sizeof(GLfloat), VertexBuffer.data()));

        Offset += (VertexBuffer.size() * sizeof(GLfloat));
    }

    GL_CALL(glMultiDrawArrays(GL_LINE_LOOP, ColliderOffsets.data(), ColliderVertexCount.data(), ColliderOffsets.size()));
    GL_CALL(glDisableVertexAttribArray(0));
}
 

[/spoiler]

 

I know I'm not being too efficient creating a VBO on every frame and allocating that much space, but my first concern was to write something that works.

I have hardcoded 3 OBB colliders with 0 rotation on my scene and I'm getting only the first one. If I change the rendering mode to GL_POINTS, I'm getting the 4 vertices plus an extra one located at the origin (which means, from what I've read, that I've done something wrong with sizes or indices).

[spoiler][attachment=31979:glmultidraw2.jpg][/spoiler]

 

This is a screencap of my offset/count vectors before the draw call.

[spoiler][attachment=31978:glmultidraw1.jpg][/spoiler]

 

And this is a gDEBugger screencap of my first VBO (all other VBOs are the same).

[spoiler][attachment=31980:glmultidraw3.jpg][/spoiler]

 

The thing is that if I use the following code, all 3 colliders are rendered as they should:

[spoiler]

GL_CALL(glGenBuffers(1, &VertexBufferID));
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID));
GL_CALL(glBufferData(GL_ARRAY_BUFFER, VertexBuffer.size() * sizeof(GLfloat), VertexBuffer.data(), GL_STATIC_DRAW));
 
GL_CALL(glEnableVertexAttribArray(0));
GL_CALL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0));
GL_CALL(glDrawArrays(GL_LINE_LOOP, 0, ShapeVertices.size()));

[/spoiler]

 

Maybe using separate draw calls and buffers wouldn't make much difference in this case, but I'd like to learn how to properly use multidraw, because I'll probably need it down the line.

 

Thank you.

 

PS. I'm not using any shaders.

Edited by Kercyn

Share this post


Link to post
Share on other sites
Advertisement

I haven't used multidraw things myself, but isn't your offset wrong? Shouldn't it be the index for the first vertex, and not the byte offset?

// Offset += (VertexBuffer.size() * sizeof(GLfloat));
Offset += ShapeVertices.size()

Share this post


Link to post
Share on other sites

Initially I had used Offset as an index, just like you suggested. However, glBufferSubData needs a byte offset. Not to mention that I'm getting an empty screen if I use Offset as an index and not as a byte offset.

Share this post


Link to post
Share on other sites

This is what I'm trying right now. I was experimenting with hardcoded values (no vectors, no sub-buffers no nothing) and it occurred to me that I might as well do that.

 

EDIT:

I'm still doing something wrong. I added an Index variable and use that in my draw calls, but I'm getting an empty screen.

Updated code:

[spoiler]

void MRenderer::RenderColliders() const
{
    const auto& Colliders = MPhysicsManager::Instance().GetColliders();

    GLuint VertexBufferID;
    
    // Current byte offset of our collider vertices.
    int Offset = 0;

    // Current collider index.
    int Index = 0;

    // Each collider's index in the vertex buffer.
    std::vector<GLint> ColliderIndices;

    // Each collider's total vertices.
    std::vector<GLsizei> ColliderVertexCount;

    GL_CALL(glGenBuffers(1, &VertexBufferID));
    GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID));
    GL_CALL(glBufferData(GL_ARRAY_BUFFER, 400 * sizeof(GLfloat), 0, GL_STATIC_DRAW));

    for (const auto& Collider : Colliders)
    {
        //Collider.second->Shape->Rotate(0.01f);
        std::vector<Vector2> ShapeVertices = Collider.second->GetVertices();
        std::vector<GLfloat> VertexBuffer;

        for (int i = 0; i < ShapeVertices.size(); i++)
        {
            VertexBuffer.push_back(ShapeVertices[i].GetX());
            VertexBuffer.push_back(ShapeVertices[i].GetY());
        }
        
        ColliderIndices.push_back(Index);
        ColliderVertexCount.push_back(ShapeVertices.size());

        GL_CALL(glBufferSubData(GL_ARRAY_BUFFER, Offset, VertexBuffer.size() * sizeof(GLfloat), VertexBuffer.data()));
        
        Index += ShapeVertices.size();
        Offset += (VertexBuffer.size() * sizeof(GLfloat));
    }

    GL_CALL(glMultiDrawArrays(GL_LINE_LOOP, ColliderIndices.data(), ColliderVertexCount.data(), ColliderIndices.size()));
    GL_CALL(glDisableVertexAttribArray(0));
}

[/spoiler]

 

EDIT 2:

This is the code I was testing earlier and actually works.

[spoiler]

const GLfloat vertices[] = { -0.4, -0.2, -0.4, 0.2, 0.4, 0.2, 0.4, -0.2,
    0.5, 0.1, 0.5, 0.5, 0.7, 0.5, 0.7, 0.1,
    -0.6, -0.5, -0.6, -0.1, 0.0, -0.1, 0.0, -0.5
    };
const GLsizei index[] = { 0, 4, 8 };
const GLsizei size[] = { 4, 4, 4 };

GL_CALL(glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW));

GL_CALL(glEnableVertexAttribArray(0));
GL_CALL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (void*)0));

GL_CALL(glMultiDrawArrays(GL_LINE_LOOP, index, size, 3));

[/spoiler]

 

EDIT 3:

With all this copy-pasting, I forgot to include the calls to glEnableVertexAttribArray and glVertexAttribPointer. With those included, it works as it should now! Thanks a lot!

Edited by Kercyn

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement