0
\$\begingroup\$

I'm encountering a design challenge while developing my 2D C++ OpenGL engine. I'm using a batching technique for rendering my drawable objects, and I want to ensure they are drawn in the same order that I call the 'draw' function. For example

Renderer::draw(m_player);
Renderer::draw(m_playerHealthBox):
Renderer::draw(m_enemy);
Renderer::draw(m_enemyHealthBox);

I aim to have the enemy health box appear in front, with the player being positioned furthest in the background.

The issue is that I can't easily sort my objects within the Renderer because I'm using different vertex structures for sprites, rectangles, texts, and circles. Consequently, when I flush my objects, the last flushed object type (e.g., rectangles) always ends up on top. I'm struggling to find a way to achieve the correct drawing order while still utilizing batching, without resorting to a single vertex vector and a monolithic shader to handle all cases, which doesn't seem like a great idea to do.

I've also attempted to use depth testing and the z-buffer (firstly changing my vertex positions to Vector3f type), but it doesn't seem to work as expected. I tried manually setting the z-values for each object, such as assigning 'z = 1' for sprite1, 'z = 2' for sprite2, and 'z = 3' for rectangle1 etc, but the correct order is still not reflected on the screen (even when experimenting with different depth testing functions). Do you have any suggestions or tips to address this issue? Many thanks.

My simplified setup:

struct Vertex
{
    Vector4f color = { 1.0f, 1.0f, 1.0f, 1.0f };
    Vector2f position;
    Vector2f textureCoords;

    float textureIndex;
};

struct LineVertex
{
    Vector4f color = { 1.0f, 1.0f, 1.0f, 1.0f };
    Vector2f position;
};

class Renderer
{
public:
    void draw(Ref<Sprite> sprite)
    {
        for (int i = 0; i < 4; i++)
            sprites.vertices[sprites.verticesCount + i] = sprite.getVertices()[i];

        sprites.verticesCount += 4;
    }

    void draw(Vector2f start, Vector2f end, Color color)
    {
        lines.vertices[lines.verticesCount + 0] = { start, color };
        lines.vertices[lines.verticesCount + 1] = { end, color };
        lines.verticesCount += 2;
    }

    void start()
    {
        sprites.verticesCount = 0;
        lines.verticesCount = 0;
    }

    void flush()
    {
        flushLines(); 
        flushSprites();
    }

private:
    void flushLines()
    {
        //bind line shader, vertexArray, set vertexArray data etc. one draw call
    }

    void flushSprites();
    {
        //bind line shader, vertexArray, set vertexArray data etc. one draw call
    }

    struct Lines
    {
        Ref<Shader> shader;
        Ref<VertexArray> vertexArray;
        Ref<VertexBuffer> vertexBuffer;
        std::array<LineVertex, MAX_LINES_VERTICES> vertices;

        uint32 verticesCount = 0u;
    } lines;

    struct Sprites
    {
        Ref<Shader> shader;
        Ref<VertexArray> vertexArray;
        Ref<VertexBuffer> vertexBuffer;
        std::array<Vertex, MAX_SPRITES_VERTICES> vertices;
        std::array<Ref<Texture>, MAX_TEXTURE_SLOTS> textures;

        uint32 verticesCount = 0u;
        uint32 texturesCount = 0u;
    } sprites;
}

``` 
\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

Disable depth testing for the health boxes. No matter when they are drawn they are always on top.

\$\endgroup\$
2
  • \$\begingroup\$ I don't have any depth testing beacuse I cannot get it working correctly, as I said in my comment... \$\endgroup\$
    – DDD
    Commented Sep 23, 2023 at 9:34
  • \$\begingroup\$ Beside health boxes aren't best example, what about circles etc \$\endgroup\$
    – DDD
    Commented Sep 23, 2023 at 9:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .