TLDR: By making the component consist of multiple meshes to begin with.
I agree with Asakeron/Byte56/Laurent in that another level of indirection is needed between the mesh/material pairs, and the entity itself. Instead of looking at the GraphicsComponent as vertices and materials, think of it as a blob of pixels on the final raster - how it/they get there is an implementation detail and nothing more.
I thought about this a lot for my project and I think the optimal solution is to make the GraphicsComponent a much higher level component, encompassing much of the functionality of the traditional 'Model' object - because this functionality isn't optional! To render those polygons a lot more than just the buffer data and the shader is needed, such as:
- Position which you have mentioned
- Skinning/Animation data
- The Current Pass (e.g. if using two pass alpha)
- Shadow casting information (if you are doing it)
- Information on how and when to update the material
- Culling functionality
And thats just for 3D assets, without considering particle systems, billboards, etc. But all of it is pertinent only to the graphics/rendering code - it doesn't affect the physics, sound or scripting, so it makes sense it should sit in the Graphics/Rendering component.
I ended up with:
Model : Entity, IHasGraphicsComponent, IHasSkeleton, IHasAnimationStore //This is the 'game object' - it is passed to the GraphicsController
ModelComponent : GraphicsComponent //This is the actual graphics component, used by the GraphicsController in the context of the game object.
ModelComponentPart : GraphicsComponent //This is also a graphics component
Mesh //These are implementation details
Material
ModelComponentPart : GraphicsComponent
Mesh
Material
Skeleton
Animations
In this:
Model is any game asset that has a graphics component.
The ModelComponent is analogous to the traditional Model and in fact, is, for 3D assets. The GraphicsComponent controller (if you use the Model-View-Controller pattern) is responsible for figuring out what type of graphics asset it is and drawing it correctly (note that ModelComponent is a subclass of GraphicsComponent).
There were also a couple of compromises in mine for simplicity and backwards compatabilitys sake, such as each GraphicsComponent is also an Entity, and Entity stores Position data directly so its only calculated in one place, but the idea is the same: GraphicsComponent handles what is needed to draw the item - all of what is needed - not just what comes from the modeller.
SkeletalMeshActor
only has oneSkeletalMeshComponent
. It’s a common problem that can be addressed in many different ways. \$\endgroup\$