I am refactoring some parts of the game engine I am working on. This engine is made in C# with XNA.
The part I have trouble with is shader/material and the render queue. In the new version I will give ability to indicate differents render states per pass within a technique (blend state, rasterizer state, ...). In my engine, all renderables have a material and each material is associated to one technique (thus to one or more passes).
Later, when the game will be running, I will add renderable objects to the render queue and then sort it based on the pass used by each material. What I want to achieve is to reduce states changes between draw calls by first grouping same passes together and then passes with nearly identical states to be as closed as possible to minimize changes. But this solution seems to be problematic when it comes to use technique with more than one pass with completely different states. Passes within a same technique can be completely separated in the render queue and not rendered one after the other. If I say that it's because I have always see multi-passes technique render in a loop and all passes rendered immediately like that :
foreach(EffectPass pass in technique.Passes)
{
/* Update parameters */
pass.apply();
graphicsDevice.Draw(...);
}
But I don't know if I can deferred pass rendering from a same technique instead of using them one after the other as in the previous example.
Here is an example of what will probably happen with the solution I try to build:
- Shader1
- TechniqueA
- Pass1 (State A)
- Pass2 (State C)
- TechniqueA
- Shader2
- TechniqueB
- Pass1 (State A)
- TechniqueB
- Shader3
- TechniqueC
- Pass1 (State A)
- TechniqueC
Now I have three models to draw, Model1, Model2 and Model3, each one use a different technique from the previous list. If I add those three models in the render queue I will end up with the following render queue :
-> Set state A -> Draw Model1(Pass1) -> Draw Model2(Pass1) -> Draw Model3(Pass1) -> Set state C -> Draw Model1(Pass2)
We can see that the Model1 will be drawn two times (two passes for the Technique A) but the draw call are separated by others draw call.
I don't know how to resolve this. What will be a good solution to this problem? How can I design my render queue to reduce state changes as much as possible between draw calls.
EDIT:
After searching a little more, I have found this helpful article : http://realtimecollisiondetection.net/blog/?p=86. It seems to be an elegant way to sort object by depth and materials. And in the material id, I can had a pass id to sort same pass together that will allow to reduce state changes.
Currently my renderer draw objects directly in the backbuffer without lights nor shadows, everything is flat. So I will just loop over my render queue and call draw methods. But in a future I will probably implement deferred rendering.
I don't know a lot about it but I know that I have to render my objects in different render target to gather differents informations (Z-buffer, Normal buffer, G-Buffer, ...). I assume that for z-buffer and normal buffer I will use the same shader on every objects no matter which material they use. But for the G-buffer I will use the materials of each object so that means different shaders with different number of pass. If I use the solution in the previous link, if I have an object with a material that needs to do two or more passes, my render queue will have at least two times the object (one for each pass). But for Z-buffer or normal buffer isn't it useless to have the same object multiple times?
What I see is that I will need to have at least two different render queue : one for G-buffer in which an object can be multiple times depending on the number of pass the material require and another render queue for Z-buffer or other buffer in which each objects are only one time. Am I right?