Dealing with 2D pixel shaders and SpriteBatches in XNA 4.0 component-object game engine?
- by DaveStance
I've got a bit of experience with shaders in general, having implemented a couple, very simple, 3D fragment and vertex shaders in OpenGL/WebGL in the past. Currently, I'm working on a 2D game engine in XNA 4.0 and I'm struggling with the process of integrating per-object and full-scene shaders in my current architecture.
I'm using a component-entity design, wherein my "Entities" are merely collections of components that are acted upon by discreet system managers (SpatialProvider, SceneProvider, etc). In the context of this question, my draw call looks something like this:
SceneProvider::Draw(GameTime) calls...
ComponentManager::Draw(GameTime, SpriteBatch) which calls (on each drawable component)
DrawnComponent::Draw(GameTime, SpriteBatch)
The SpriteBatch is set up, with the default SpriteBatch shader, in the SceneProvider class just before it tells the ComponentManager to start rendering the scene. From my understanding, if a component needs to use a special shader to draw itself, it must do the following when it's Draw(GameTime, SpriteBatch) method is invoked:
public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.End();
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, EffectShader, ViewMatrix);
// Draw things here that are shaded by the "EffectShader."
spriteBatch.End();
spriteBatch.Begin(/* same settings that were set by SceneProvider to ensure the rest of the scene is rendered normally */);
}
My question is, having been told that numerous calls to SpriteBatch.Begin() and SpriteBatch.End() within a single frame was terrible for performance, is there a better way to do this? Is there a way to instruct the currently running SpriteBatch to simply change the Effect shader it is using for this particular draw call and then switch it back before the function ends?