Sign in to follow this  

Sprites, primitives and depth testing

This topic is 1989 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,
I am trying to draw both sprites and 2d primitives on the screen at the same time and am having problems with the depth. The primitives are created using D3D10_PRIMITIVE_TOPOLOGY_LINESTRIP.

There are two situations that I can have. Note that the rectangles have a depth of 0.5, the left hand ball of 0.2 and the two balls on the right 0.6:

1) Depth Enabled: the sprites render correctly based on the assigned depth. However the alpha channels of the sprite show up.

[attachment=9834:DepthEnabled.png]



2) Depth Disabled: the primitives and sprites do not render correctly on depth. If the sprites are the last group to be drawn the they will be on top and visa versa

[attachment=9833:DepthDisabled.png]

During initialisation have created two depth stencils:

[source lang="cpp"]//Create a disabled depth state
SAFE_RELEASE(m_pDepthDisabledState);
D3D10_DEPTH_STENCIL_DESC depthStencilDesc;
ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));

depthStencilDesc.DepthEnable = false;
depthStencilDesc.DepthWriteMask = D3D10_DEPTH_WRITE_MASK_ALL;
depthStencilDesc.DepthFunc = D3D10_COMPARISON_LESS;
depthStencilDesc.StencilEnable = false;
depthStencilDesc.StencilReadMask = 0xFF;
depthStencilDesc.StencilWriteMask = 0xFF;
depthStencilDesc.FrontFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilDepthFailOp = D3D10_STENCIL_OP_INCR;
depthStencilDesc.FrontFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilFunc = D3D10_COMPARISON_ALWAYS;
depthStencilDesc.BackFace.StencilFailOp = D3D10_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilDepthFailOp = D3D10_STENCIL_OP_DECR;
depthStencilDesc.BackFace.StencilPassOp = D3D10_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilFunc = D3D10_COMPARISON_ALWAYS;

hr = DXUTGetD3D10Device()->CreateDepthStencilState(&depthStencilDesc, &m_pDepthDisabledState);


//Create an enabled depth state
SAFE_RELEASE(m_pDepthEnabledState);
depthStencilDesc.DepthEnable = true; //the only difference
hr = DXUTGetD3D10Device()->CreateDepthStencilState(&depthStencilDesc, &m_pDepthEnabledState);


//set to disabled by default.
DXUTGetD3D10Device()->OMSetDepthStencilState(m_pDepthDisabledState, 0);
//DXUTGetD3D10Device()->OMSetDepthStencilState(m_pDepthEnabledState, 0);
[/source]
I have tried switching between depth enabled/disabled during the rendering of either the primitives or the sprites but it seems and cannot mix and match the two. Has anyone any ideas what approach I should take to solve this?

Thanks,

Ben.

Share this post


Link to post
Share on other sites
If you turn depth testing off rendering is done in the order you submit the draw calls in, so say you have two objects that overlap and one is at 0.1 and the other is at 0.2 depth. With depth testing on and rendering the 0.1 object first that would be the object you see, when it is off however the one with 0.2 is rendered last and will overlap the other one.

Are you sure you aren't changing the alpha blend equations as well? If you render something thats changing the Alpha blend state before or after this draw call when you next come to this drawcall the alpha state will not have reset itself.

Share this post


Link to post
Share on other sites
Thanks for your response.

[quote name='NightCreature83' timestamp='1341419387' post='4955660']
If you turn depth testing off rendering is done in the order you submit the draw calls in, so say you have two objects that overlap and one is at 0.1 and the other is at 0.2 depth. With depth testing on and rendering the 0.1 object first that would be the object you see, when it is off however the one with 0.2 is rendered last and will overlap the other one.
[/quote]

My calls to draw may not come in an order based on depth so I really want to keep depth testing on. However this approach results in image 1) shown in my original post.

[quote name='NightCreature83' timestamp='1341419387' post='4955660']
Are you sure you aren't changing the alpha blend equations as well? If you render something thats changing the Alpha blend state before or after this draw call when you next come to this drawcall the alpha state will not have reset itself.
[/quote]

I don't know much about the alpha blending. I have posted my code below that handles the alpha channel. Again looking at image 1); are you suggesting that this problem may have nothing to do with depth testing and that I should be looking at my alpha code? Apart from the initialisation code below and the rendering code that follows I don't touch the alpha set up. Perhaps my Alpha setup is wrong?

More initialisation code wrt alpha:

[source lang="cpp"] D3D10_BLEND_DESC StateDesc;
ZeroMemory(&StateDesc, sizeof(D3D10_BLEND_DESC));
StateDesc.AlphaToCoverageEnable = TRUE; //changed from FALSE 040712
StateDesc.BlendEnable[0] = TRUE;
StateDesc.SrcBlend = D3D10_BLEND_SRC_ALPHA;
StateDesc.DestBlend = D3D10_BLEND_INV_SRC_ALPHA;
StateDesc.BlendOp = D3D10_BLEND_OP_ADD;
StateDesc.SrcBlendAlpha = D3D10_BLEND_ZERO;
StateDesc.DestBlendAlpha = D3D10_BLEND_ZERO;
StateDesc.BlendOpAlpha = D3D10_BLEND_OP_ADD;
StateDesc.RenderTargetWriteMask[0] = D3D10_COLOR_WRITE_ENABLE_ALL;

hr=pD3DDevice->CreateBlendState(&StateDesc, &m_pBlendState10);[/source]
And the code that renders the sprites:

[source lang="cpp"]hr = m_pSpriteObject->SetProjectionTransform(&(g_pGameManager->m_pMatProjection));

// start drawing the sprites
hr=m_pSpriteObject->Begin(D3DX10_SPRITE_SORT_DEPTH_BACK_TO_FRONT); //D3DX10_SPRITE_SORT_DEPTH_FRONT_TO_BACK,D3DX10_SPRITE_SORT_DEPTH_BACK_TO_FRONT

//Save the current blend state
ID3D10BlendState* pOrigBlendState;
DXUTGetD3D10Device()->OMGetBlendState(&pOrigBlendState, OriginalBlendFactor, &OriginalSampleMask);

// Draw all the sprites in the pool
hr=m_pSpriteObject->DrawSpritesBuffered(&(m_spritePool[0]), m_spritePoolIdx);

// Set the blend state for alpha drawing
if(m_pBlendState10)
{
FLOAT NewBlendFactor[4] = {1,1,1,1};
DXUTGetD3D10Device()->OMSetBlendState(m_pBlendState10, NewBlendFactor, 0xffffffff);
}

// Finish up and send the sprites to the hardware
hr=m_pSpriteObject->Flush();

hr=m_pSpriteObject->End();

DXUTGetD3D10Device()->OMSetBlendState(m_pBlendState10, OriginalBlendFactor, OriginalSampleMask);
[/source]
Note: I am checking all my Direct X calls. I have just removed them for clarity.

Share this post


Link to post
Share on other sites
With depth testing enabled, the drawing order for alpha objects matter. The problem you're seeing is caused by the first object filling the depth buffer with a quad so when the second object which is behind draws it's tested against the depth buffer which contains a quad so that area is clipped out rather than alpha blended with the object in front of it.

This is a common problem with alpha blending. What you want to do is sort your objects from back to front before you render them. Even if you are submitting these objects out of order, if you queue them up in a buffer you can sort that buffer before you actually submit them to be rendered.

Share this post


Link to post
Share on other sites
[quote name='Dancin_Fool' timestamp='1341424542' post='4955677']
With depth testing enabled, the drawing order for alpha objects matter. The problem you're seeing is caused by the first object filling the depth buffer with a quad so when the second object which is behind draws it's tested against the depth buffer which contains a quad so that area is clipped out rather than alpha blended with the object in front of it.

This is a common problem with alpha blending. What you want to do is sort your objects from back to front before you render them. Even if you are submitting these objects out of order, if you queue them up in a buffer you can sort that buffer before you actually submit them to be rendered.
[/quote]

OK. So for sprites the following line sorts the buffer:

m_pSpriteObject->Begin(D3DX10_SPRITE_SORT_DEPTH_BACK_TO_FRONT);

I will however have to ensure that no two sprites have the same depth; in image 1) both sprites were 0.6. Thats fine I can write a trivial bit of code that takes the user defined depth and adds 0.0001 to it so that it is highly unlikely two sprites will have the same depth.

I was going to say that I still had a problem with the primitives (which are drawn at a depth of 0.5). However I found that if I draw the primitives before the sprites (which may be shallower or deeper than sprites) then there is no clipping and all the depth is correct. I can't quite understand why this works as the ordering is not as discussed but it does.

Successful depth enabled sprites and primitives below:
[attachment=9847:DepthEnabledWorks.png]

Thanks both for you help.

Ben.

Share this post


Link to post
Share on other sites
The reason for why the primitives need to be drawn before the alpha objects is the same as for why you have to sort the alpha objects. If you draw the primitives after the alpha objects and you had depth writes on for the alpha objects, then you're still going to have the problem of the alpha object writing a quad to the depth buffer and the primitives testing against that quad when it's rendered and essentially clipping out the primitive.

Glad to see you have it working though!

Share this post


Link to post
Share on other sites

This topic is 1989 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this