I've been playing with an entity/component/system design recently, and I've come across a couple of stumbling blocks.

Instancing

Let's say I have a few hundred "things" (asteroids, chickens, whatever) that are being drawn with instancing. In a classic component hierarchy, I'd have a game object that keeps the individual instance index and vertex buffers, as well as the second dynamic vertex buffer for the instance data (collection of matrices, etc.). That object would be responsible for checking collisions with other objects and between the instances themselves.

In an ES system, I'd like to track each instance as an individual entity, but I don't want to give up simplicity and performance of instancing. The first thing that occurred to me was to create an "instance group" component, with a field that defines a group ID to enable handling of multiple types of instanced geometry.

An "Instance System" would collect those components and maintain the instance vertex buffer. My entity manager already notifies systems when an entity is created or destroyed which makes this part pretty easy to implement.

My confusion comes from how to cleanly integrate that with the rendering system. If each instance appears as a separate entity with a "renderable" component/attribute, the render system will process them individually.

I could:

Include a special case for entities that have both a "renderable" and an "instanced" component, but that seems messy and feels like starting down the path of having a huge render system with tons of special cases.

Have the render system maintain a collection of instance vertex buffers, query the entity list for "instanced" entities, filter based on a group ID, etc., and render as appropriate, so the render system becomes responsible for maintaining instance collections, but that seems like the wrong place to put that sort of logic.

I could also include a single entity in addition to the instances with, say, an "InstanceOutput" component/attribute and a Renderable component, and remove the Renderable component from the individual instance entities, giving a single render point for all of the instances. This component would probably also server as a place to keep the geometry and persistent instance/vertex buffer.

Is there a better way?

Rendering

I have several types of renderable entities. Some have procedural geometry and textures, some are just sprites, some are text displays. What's the best way to differentiate these from the point of view of the rendering system without having to write a massive switch statement? In a game object hierarchy, each of these types would have their own Draw() method, but moving the logic into a Render System doesn't seem to provide a lot of flexibility in terms of different effect parameters, etc.

2 Answers
2

You are over generalizing and trying too hard to use what your idea of an entity system is.

Instancing is easily just as simple as having your renderer automatically batch together all renderable objects with the same mesh and materials.

It's not the job of the data or the components to render themselves. It's the job of the rendering system, which should be expected to be intelligent.

There's no reason to have tons of different rendering systems for each type of renderer, either. The difference between a sprite, a mesh, and static terrain all comes down to materials (different vertex shader for bill boarding sprites va lighting meshes) and draw order, all of which can be completely handled by the same system and even the exact same render pipeline.

I like that idea. Rather than even having anything other than the rendering system aware or instancing, have the renderer examine each entity as its created, and determine if it can/should be batched with similar items. That potentially introduces some complexity re:having both an instancing and non-instancing version of the relevant shaders, though, and makes the renderer responsible for maintaining the buffers. Hmm.
–
David LivelyAug 3 '12 at 17:54

1

The renderer should be responsible for such things. Again, the component based design is a great tool, but you can't build a (sane) engine entirely on one design pattern. Especially with games and graphics, expect one-off specialized systems. And when you get to gameplay, expect haxx. :)
–
Sean MiddleditchAug 3 '12 at 21:01

Thanks for the tips. Specialized edge-case handling code seems inevitable, but I try to make it the exception rather than the rule. Then again, this ain't web development. Thank goodness.
–
David LivelyAug 6 '12 at 16:40

@seanmiddleditch I'm beginning to discover the edge cases, hacks and one-off specialised parts are actually the game itself. It's totally different to business apps where sterile, rigid frameworks can be designed :)
–
PikuAug 7 '12 at 10:21

I think you may be losing some of the performance of instancing if you're making each instance an entity. I think your idea of using a instance group is good. I would then create a system that looks for entities with a instance group component and renders the instances. Like other systems, this system doesn't care about other components the entity has, including renderable. If the entity also had a renderable component that would be picked up by the appropriate system and rendered, but the rendering wouldn't be of the instances. For example, if you had a chicken generator, the instance group system would render all the chickens and the renderable system would render the chicken generator. You can have a separate system that updates the instances within instance group components.

As for other rendering stuff. It would be a simple thing to create a spriteRender component, textRender component or any other kind of component for each different type of rendering. Then have a system for each component with a different rendering style. For example, my game has a billboard rendering system, a static model rendering system and an animated model rendering system. An entity could have all of them, or any combination. For example a goblin could have an animated model component for its body and a billboard component for a status icon above its head.

The issue with not having each "chicken" be an entity is that then they can't easily be manipulated by the other systems, such as the input processor, motion/animation, collision detection, etc.
–
David LivelyAug 3 '12 at 17:08

The instance group component can receive and apply whatever updates you need to the instances. The instance group update system would be responsible for processing the instance groups.
–
Byte56♦Aug 3 '12 at 17:18

I'm confused how that would work with, say, colliding a chicken with a non-instanced entity. If the instances aren't entities, and all of their behavior is handled by chicken-specific systems, they can't interact with entities that aren't instanced, or aren't part of the same group without modifying the logic of those other systems, removing a lot of the benefit of ECS. What am I missing?
–
David LivelyAug 3 '12 at 17:50

The system that handles the instance group is the interaction point for all the instances it maintains. For eaxmple, Entity A has an instance component, Entity B does not. When we check collision between A and B, we check all of A's instances too. The "physics body" of A includes all the instances. So when a chicken collides with a non-instanced entity, it's a collision with the chicken generator. The instance group system handles the collision.
–
Byte56♦Aug 3 '12 at 18:05

Is it weird that this makes me want to write "chicken pong?"
–
David LivelyJul 8 '13 at 14:01