0
\$\begingroup\$

I am currently creating a 2D game/game engine using an ECS architecture. Currently I have a renderer_2d system which is a function that takes all Sprite and Text components and draws them using a draw function in a Renderer interface. The draw function takes in a handle to a texture, pipeline and an array of vertices to be drawn. The Renderer is an interface to the Graphics API, currently Vulkan or OpenGL and handles texture creation and draw calls.

I would like to allow my renderer_2d system to be extensible and I am wondering what the best way to do this would be. I would like to add other types of objects to be rendered, such as tilemaps, etc. and in the future support multiple passes (e.g. world and UI). I was thinking of a few various methods.

  1. Allowing systems to queue draw calls and placing them in the graphics queue at end of frame
  2. Registering callback functions/lambdas called when the system is executed which each make draw calls

I am a unsure on what would be the ideal way(s) to implement this. The engine is targeting 2D games and so I do not plan to support complex 3D meshes, etc.

\$\endgroup\$
1
\$\begingroup\$

A little bit of both.

To be able to queue render calls is useful. In particular in 3D. The render system can group them (e.g. by materials) and execute the groups in a preferred order (e.g. non transparent things first). You could also do deferred shading, and batching, batching, batching.

On the other hand an strategy pattern is a good idea. Each entity that can be drawn would have a draw strategy associated, and then render system can call the code for that strategy to handle rendering.

Now, let us consider:

  • Which is better to implement on top of the other?

    You can have an strategy that queues render calls. It does not give you all the benefits, but will allow you entities that change how they are rendered dynamically.

    And you can have strategies that queue render calls. I think this gives you the best of both worlds. In fact, the strategy that queues the calls could be useful for grouping and batching.

    Thus it is better to have strategies that queue render calls.

  • Which can be made as an extension of the other?

    Let us say you implemented systems that queue render calls. You can have components that mark the entities so they are handled by different systems. And each of these system queue render calls.

    On the other hand, let us say you implemented render strategies. That is, you have a render strategy component that the render system gets, and depending on its value it calls an strategy to render. To implement a strategy that allows queuing calls you would need to store the queued somewhere so that strategy can get them. It is not clear where.

    Thus, if you are going to implement one, to later have the option to built the other on top, implement queued render calls.

It appears that allowing systems to queue render calls is better. You can go with that.

\$\endgroup\$
1
  • \$\begingroup\$ Great! Thanks for the pointers, ill create a queue corresponding to each pipeline resource which will get submitted at end of frame. \$\endgroup\$ Dec 3 '21 at 9:34

You must log in to answer this question.

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