My 3d scene consists of three main polygons:
The first and the second polygons overlap each other (have the same World matrix and use the same geometry), the third one is perpendicular to the first two and is positioned a few meters away from them. All three polygons are rendered with a forward shader that uses clip() function to do alpha cutoffs. As I read in a Radeon's article, this causes EarlyZ test to be turned off and my simple subjective tests proved it: I had around 480 FPS when the second polygon's texture was empty (resulting in clip being called in every pixel) and dropping to 415 when it had a colorful for-section square in it (see the picture).
I did try to make sure that Z-test happens: I tried drawing the second polygon first while "rising" it above the ground (polygon #2) and thus bringing it closer to camera - it changed nothing. I also tried removing clip() function from the shader and recieved an FPS boost just as expected. But obviously this produced incorrect results as the ground underneath the second polygon was never drawn as it always failed the Z-Test. So I decided to try using DepthBias to be able to draw two polygons one over another and have no depth-fighting. This is what MSDN writes about it:
Sets or retrieves the depth bias for polygons, which is the amount of bias to apply to the depth of a primitive to alleviate depth testing problems for primitives of similar depth. The default value is 0.
Property Value The amount of bias to apply to the depth of a primitive. The value ranges from 0 to 16 (inclusive).
When I finally managed to make it work, I surprisingly got a performance boost. Now the thing is I even managed to gain FPS applying it to the third polygon! This is how I render them to gain the best performance:
GraphicsDevice.RasterizerState = CCWLayer1;
DrawSecond(gameTime);
GraphicsDevice.RasterizerState = CCWLayer2;
DrawThird(gameTime);
GraphicsDevice.RasterizerState = CCWLayer3;
DrawFirst(gameTime);
public RasterizerState CCWLayer1 = new RasterizerState()
{
CullMode = CullMode.CullCounterClockwiseFace,
DepthBias = 0.005f,
};
public RasterizerState CCWLayer2 = new RasterizerState()
{
CullMode = CullMode.CullCounterClockwiseFace,
DepthBias = 1,
};
public RasterizerState CCWLayer3 = new RasterizerState()
{
CullMode = CullMode.CullCounterClockwiseFace,
DepthBias = 0.015f,
};
I now 525 FPS and it only drops down to 515 when I draw the huge colored square on the second polygon, which clearly shows that only one set of pixels is being drawn at a time in that particular place (which is similar to EarlyZ test!).
So here is the question: can anyone explain to me what is going on? If I could understand this system better I could make more use of it and gain even more FPS.
Update: now I only draw the two polygons (no other geometry), both using clip(), the one with the colored quad (second) is always closer to the camera. With this code:
DrawSecond(gameTime);
DrawFirst(gameTime);
I get 1.5 ms per frame. With this:
GraphicsDevice.RasterizerState = CCWLayer1;
DrawSecond(gameTime);
GraphicsDevice.RasterizerState = CCWLayer2;
DrawFirst(gameTime);
public RasterizerState CCWLayer1 = new RasterizerState()
{
CullMode = CullMode.CullCounterClockwiseFace,
DepthBias = 0.03f,
};
public RasterizerState CCWLayer2 = new RasterizerState()
{
CullMode = CullMode.CullCounterClockwiseFace,
DepthBias = 0.045f,
};
I get 1.2 ms.
NO BIAS:
BIAS APPLIED: