handling DepthStencil / Blend / Rasterizer State dilemma...

Started by
2 comments, last by Jason Z 8 years, 8 months ago

How do you think it would be best to handle DepthStencilState / BlendState / RasterizerState ?

Associating each object in scene to its own states, like this:


class Object
{
   // shaders and stuff

   RasterizerState   rs;
   BlendState        bs;
   DepthStencilState pss;
};


void Render()
{
   for( Object obj : ObjectList )
   {
       SetRasterizerState( obj.rs );
       SetBlendState( obj. bs );
       SetDepthStencilState( obh.pss );

       Draw();
   }
}

.

Or having a flag in each object indicating how is it going to be drawn, and setup states inside the rendering function:


class Object
{
   // shaders and stuff
   int  flags;  // uses transparency / casts shadows / etc
};

void Render()
{
   // Draw Normal Objects
   RasterizerState rs; // setup acordingly
   SetRasterizerState( rs );

   BlendState bs; // setup acordingly
   SetBlendState( bs );

   DepthStencilState pss; // setup acordingly
   SetDepthStencilState( pss );

   for( Object obj : NormalObjectList )
   {
       Draw();
   }


   // Draw Objects with transparency
   RasterizerState   rs; // setup acordingly
   SetRasterizerState( rs );

   BlendState       bs; // setup acordingly
   SetBlendState( bs );

   DepthStencilState pss; // setup acordingly
   SetDepthStencilState( pss );

   for( Object obj : TransparentObjectList )
   {
       Draw();
   }

   // ETC....
}

.

So far I was using the first one, and it was working ok, but then I started to implement Mirrors wich require first to render the mirror to the Stencil buffer, then render the scene on the stenciled area, and then render the mirror's glass with some sort of transpareny over the reflected scene... which would be hard to do having each object associated with it's own DepthStencil / Blend / Rasterizer states...

However, sometimes you would like to render a specific object in wireframe mode, and sounds more natural to just modify that object's RasterizerState...

So.... how do you experienced people handle your states in your code?

"lots of shoulddas, coulddas, woulddas in the air, thinking about things they shouldda couldda wouldda donne, however all those shoulddas coulddas woulddas ran away when they saw the little did to come"
Advertisement

I use an object that represents the rendering state the drawing to be done. This is contained within a material object, and each individual object in the scene can reference a material (via a smart pointer). This lets you have a shared material when it makes sense, or you can just as easily duplicate a material for a special object that wants to mutate its material state.

In the methods you show above, you are limiting yourself to a fixed number of states - if you make them their own objects then you can have an unlimited number of states to use.

Thanks Jason Z,

Ok, so, you have a Material object with the DepthStencil / Blend / Rasterizer States... and each Object en your scene references any particular Material they'll use... some thing like this:

.


class Material
{
   RasterizerState   rs;
   BlendState        bs;
   DepthStencilState pss;
};

class Object
{
   // other stuff
   shared_ptr<Material> mat;
};

Am I right?.... now, in the actual rendering code how do you handle Mirrors in your case?...

I mean... you'd have to draw to the stencil buffer the area where the mirror is (which needs one particular set of states), then the renderer needs to draw the reflected scene objects in that area (which imply another set of states), and finally again draw the actual mirror with some transpareny over the reflected area (which again implies other set of states).

Thanks!

"lots of shoulddas, coulddas, woulddas in the air, thinking about things they shouldda couldda wouldda donne, however all those shoulddas coulddas woulddas ran away when they saw the little did to come"

That is more or less correct. I have a structure that holds the references to the states (RenderEffect), and a material can reference a number of different RenderEffects for different situations. The higher level rendering pass is actually controlled in a separate object called a SceneRenderTask. This object is the one that sets up the pipeline outputs (i.e. render and depth targets) and provides whatever special logic is needed for that particular rendering pass. In your example of a mirror, the stencil rendering would be done in one pass and the reflected scene would be a second SceneRenderTask.

If you are interested in seeing how it works more closely, the whole engine is available as open source: Hieroglyph 3

This topic is closed to new replies.

Advertisement