2
\$\begingroup\$

Where should I put the shader and the light / shadow calculation? Should that be a component too?

And should the rendering system know how to handle them or should there be a separate light system?

I'm specifically talking about about a 2D system, but it should be the same in for 3D I think.

\$\endgroup\$
4
\$\begingroup\$

A component-based entity system works best when an entity represents something in the logical game world and a component some single aspect of that entity, generally things that you'd want to compose.

An entity may have a component that describes visual properties or behavior of an object. A component that represents a sprite or model, for example. It is perhaps appropriate to have a component that represents the fact that some entity emits light in a certain fashion. But those should just act as proxies, game-logic packages of information that are ultimately fed into the renderer in a more optimal form.

Do not make the mistake of going overboard with your "entity system" and putting everything in there. Not everything should be a component; it is a horrible way to architect anything at scale, and trying to homogenize everything in that fashion can result in extremely confusingly-coupled and poorly-performing code.

To that end, the renderer should not know about or process component types. It should understand the representation of sprites or models, shaders or lights in the viewable space and the rendering of those sprites/models/lights in an efficient manner. It should not have any dependencies on the entity/component system at all (I mean this literally: you should be able to compile the rendering code without including the component code).

Rather, have the components (which are naturally a game logic domain) store pointers or references to the renderer (which is naturally a lower-level part of the technology stack) if needed to avoid duplication of data or inefficiency state transfer every frame. But do not directly couple the entity system and the renderer.

\$\endgroup\$
  • \$\begingroup\$ Which object would you exclude then? I thought of describing Cameras and Lights as entities too, becasue I thought it would be highly likely that I'd have more than one of them. By using components I could compose different camera types, such as static cameras, orbiting/chase cameras (with a TargetComponent?) and so on. Similarly with lights. So you think the Renderer would have to be a different class, outside of the ES architecture? The ES would do its job, update all systems and then the renderer would access some sort of list of Drawables? \$\endgroup\$ – TheWanderer Jan 28 '14 at 10:59
  • \$\begingroup\$ Basically, yes. \$\endgroup\$ – Josh Jan 28 '14 at 16:14
0
\$\begingroup\$

I am implementing the same functionalities. Here's how I have architectured my engine:

Entities are not just renderable objects. In my ECS cameras and lights are also entities.

  • I have a ContentLoadingSystem<TComponent> where TComponent can be a ModelComponent, a ShaderComponent (i.e., the actual bytecode), etc.
  • this is where it gets tricky, the ContentLoadingSystem once a shader is loaded, it sends a ContentLoadedMessage<TComponent> to systems that have subscribed for that particular type of message.
  • My CameraSystem, PointLightSystem etc all are subscribed to these messages, so when it is their turn to examine the message queue, they get a reference to the shader and are thus able to set various shader properties
  • For example the PointLightSystem might want to set the light's colour. The ShaderComponent that is loaded also contains metadata that helps these systems to know which value to actually fetch from the engine.

I think that shadows should be handled by an independent system. Not all entities might want to cast a shadow. So the ShadowSystem would be responsible of rendering a ShadowMap for example and then set it to those shaders that request it. With the approach I used, if the ShadowSystem subscribes to ContentLoadedMessage<ShaderComponent>, it will be notified when each shader is loaded. Thus when initialising a shader, if its metadata contains a reference to a ShadowMap texture it will set it to the appropriate texture register.

\$\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.