Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

My E/C implementation is the basic one where Entities are just ID's, Components are data and Systems act on the Data. Right now I'm having trouble with object materials and rendering in general. For simple objetcs I have a ModelComponent, tied to a RenderSystem, ModelComponent has the vertex buffer ids that the render system uses. A simple MaterialComponent would probably have color or specular strenght, etc, but I wanted it to be flexible enough to allow for more than one render pass and general "effects" that are not as easy as a simple variable in the MaterialComponent.

Trying to solve these problems I came up with two solutions:

1 - Super-generic Material Component

Something like this:

struct Material : public Component
{
    ShaderData* shader;
    std::vector<std::pair<std::string, boost::any>> uniforms;
    [...]
};

and in the render system I would loop and pass the uniforms to the shader. I suppose this would be slow, but fast enough for my purposes.

2 - Another layer of abstraction, MaterialData

Having a class to wrap specific materials, that could be inherited by whatever specialized material, the base class would have something like void set_shader_constants(ShaderData* d) but the implementation is up to each class, and the MaterialComponent would have a pointer to a MaterialData object.

I'm not sure which approach I would prefer, but neither of these touch the subject of multiple passes, or other complex rendering techniques.

Any idea on how to accomplish this?

share|improve this question
add comment

1 Answer 1

up vote 17 down vote accepted

Materials are a graphics concept, and belong in your renderer. A renderer is too low-level a piece of architecture to be built on top of an entity system. Entity systems should be for higher-level game objects. Not everything needs to be a component, and in fact, it's generally a bad idea to try to force everything into a single paradigm like that. It creates a least-common-denominator solution.

Consequently I would advise that you take a different approach:

  • A material is just another type in your renderer.
  • Your renderer has a type that represents "a thing to be drawn to the screen." Frequently these are called "render instances" or "renderables" or even "models." This type has a reference to the material it will use when drawing and provides a public API to allow a consumer of the renderer to set that material to whatever is desired.

This is essentially asking you to take your ModelComponent and rename it Model, removing the dependency on the entity/component layer and thus moving it to a lower layer of abstraction, alongside the rest of your renderer.

Then, you do this:

  • In the same layer of abstraction as your other components, you have some kind of "aspect component" which represents the visual presentation of an entity. This component just contains a reference to some renderable (as described above), which in turn contains the reference to a material. The component may provide an API to expose the renderable (thus allowing clients to manipulate it) or it may wrap the renderable's API to control exposure. That's up to you.

This addresses the component interdependence issue you're running into by having models and materials both be components; an entity should either have an aspect or not, and that aspect should be able to encode everything about the presentation of the entity, including the material.

This also affords you the flexibility to take other approaches with the material object that would be harder to do with that object as a component because of the lack of parity with the rest of the render system abstraction.

Your issue of allowing for more complex effects and multiple passes is one that could be solved primarily in the material, by exposing functions to query and set named shader constants exposed by the material's shader file. This is especially true if you use effect files (in D3D) which support multiple passes and the like. Even if you aren't using effect files, you can expose the idea of multiple passes from the material, each with distinct shaders, and allow the material API to provide manipulators for that. It would be easier and cleaner to integrate into the rendering API most likely, since material is now at the same level of abstraction.

share|improve this answer
1  
Thanks for your answer, this problem was plaguing me for quite some time, but creating a renderer without the constraints of E/C is much easier. –  Luke B. Jan 10 '13 at 18:08
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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