0
\$\begingroup\$

When working with OpenGL, you often recieve integer id:s to keep track of OpenGL objects.

For example, representing a simple mesh, you may have a number of references to objects like so:

GLuint arrayBuffer;
GLuint elementArrayBuffer;
GLuint texture;    

Having many meshes, the id:s add up quickly. Therefore my problem is, where it is most logical and efficient to store them?

Alternative 1

My first thaught was to hand out the id:s to corresponding game entities. Something along the lines:

class Entity {
public:   
    GLuint arrayBuffer;
    GLuint elementArrayBuffer;
    GLuint texture;
    // Other methods...
}

Then having a render class:

// Create the buffers and textures and pass id:s to entity.
renderer.init(entity); 
// Render with corresponding buffer/texture id:s stored in entity
renderer.render(projection, view, entity); 

Where it then is easy enough, in the implementation of the render method, just picking id:s and render with them.

Some disadvantages is that this is a leaky abstraction, where OpenGL concepts are "leaked" to game entities. Which does not feel quite right. An advantage might be that the method supposedly is efficient. You do not have to find id:s, you know them for each rendering pass.

Alternative 2

Another alternative would be to store the id:s internally in the renderer. For example, an internal data struct:

struct RenderData {
    GLuint arrayBuffer;
    GLuint elementArrayBuffer;  
    GLuint texture;   
}

Then having an unordered map with references to each entity and corresponding RenderData:

std::unordered_map<unsigned int, RenderData> render_data;

Then in the rendering method, the correct render data is fetched from the map only by a unique id that is stored in each entity.

Advantages of this approach, is that it is less "leaky", where only the entity id is passed to the renderer, to know what data to use. Disadvantages may be slightly less efficiency, because of lookups in the unordered map?

I would greatly appreciate inputs on this, what approach to prefer, or if there are any other approaches out there?

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

I would suggest the second approach. About optimisations:

  1. Should follow the rule "Don't do that unless you have to" or your system will suffer from premature optimisation.
  2. Should not harm the system architecture. The API and maintainability is always first priority, since in the long run it pays itself by letting us sleep well...
  3. Should be preceded by profiling.

As an improvement, if in your system all entities have an associated Renderer renderer object or component, then you could do only renderer.render(projection, view) and can eliminate the map completelly from the process.

On the other hand, if the map is needed in your system it will not do any harm to performance since lookup on maps have constant expected time.

In summary:

  • Always go for the path with better API, encapsulation and less mutability;
  • Do optimisations in the lags of the system (which you will find by profiling).
\$\endgroup\$

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.