Jump to content
  • Advertisement
Order340

DX12 SkyBox Depth Troubles

This topic is 500 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

I am having an issue with always passing the depth test and writing my skybox over existing geometry.  I draw the skybox last, and it is all you see on screen.  Turn it off, and my scene renders fine.  Here is the setup, hope someone can tell me where I am wrong (pulling hair out) trying to setup DirectX 12 depth testing correctly:

Header:

using the Microsoft mini engine core as my renderer

	SamplerDescriptor				m_skySampler;
	RootSignature					m_skyRootSig;
	GraphicsPSO					m_skyPSO;

Initialization:

	// root signature sky map
	m_skyRootSig.Reset(2, 2); 
	m_skyRootSig.InitStaticSampler(0, SamplerAnisoWrapDesc, D3D12_SHADER_VISIBILITY_PIXEL); 

	SamplerDesc samplerSkyDesc;
	samplerSkyDesc.Filter = D3D12_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
	samplerSkyDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;
	samplerSkyDesc.SetTextureAddressMode(D3D12_TEXTURE_ADDRESS_MODE_CLAMP);
	m_skySampler.Create(samplerSkyDesc);

	m_skyRootSig.InitStaticSampler(1, samplerSkyDesc, D3D12_SHADER_VISIBILITY_PIXEL);
	// parameters
	m_skyRootSig[0].InitAsConstantBuffer(0, D3D12_SHADER_VISIBILITY_VERTEX); // vertex shader float4x4 modelToProjection;
	m_skyRootSig[1].InitAsDescriptorRange(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 0, 6, D3D12_SHADER_VISIBILITY_PIXEL);
	m_skyRootSig.Finalize(L"SkyMap", D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

	/* Sky box PSO */
	m_skyPSO.SetRootSignature(m_skyRootSig);
	
	D3D12_RASTERIZER_DESC rastDesc;
	rastDesc.FillMode = D3D12_FILL_MODE_SOLID;
	rastDesc.CullMode = D3D12_CULL_MODE_NONE; 
	rastDesc.DepthClipEnable = TRUE;
	m_skyPSO.SetRasterizerState(rastDesc);
	
	m_skyPSO.SetBlendState(BlendDisable);

	D3D12_DEPTH_STENCILOP_DESC stencilOp;
	stencilOp.StencilDepthFailOp = D3D12_STENCIL_OP_KEEP;
	stencilOp.StencilPassOp = D3D12_STENCIL_OP_KEEP;
	stencilOp.StencilFailOp = D3D12_STENCIL_OP_KEEP;
	stencilOp.StencilFunc = D3D12_COMPARISON_FUNC_NEVER;

	D3D12_DEPTH_STENCIL_DESC skyBox = DepthStateDisabled;
	skyBox.DepthEnable = TRUE; // depth testing enabled on pixel shader
	skyBox.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO; // read only
	skyBox.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL; 
	skyBox.StencilEnable = FALSE;
	skyBox.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK;
	skyBox.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK;
	skyBox.FrontFace = stencilOp;
	skyBox.BackFace = stencilOp;

	m_skyPSO.SetDepthStencilState(skyBox);	

	D3D12_INPUT_ELEMENT_DESC vertElemSky[] =
	{
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D12_APPEND_ALIGNED_ELEMENT, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 }
	};
	
	m_skyPSO.SetInputLayout(_countof(vertElemSky), vertElemSky);
		
	m_skyPSO.SetSampleMask(0xFFFFFFFF);
	m_skyPSO.SetPrimitiveTopologyType(D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE);
	m_skyPSO.SetRenderTargetFormats(1, &ColorFormat, DepthFormat);
	m_skyPSO.SetVertexShader(g_pSkyVS, sizeof(g_pSkyVS));
	m_skyPSO.SetPixelShader(g_pSkyPS, sizeof(g_pSkyPS));
	m_skyPSO.Finalize();

Shader parameter validation:

#define Sky_RootSig \
	"RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT), " \
	"CBV(b0, visibility = SHADER_VISIBILITY_VERTEX), " \
	"DescriptorTable(SRV(t0, numDescriptors = 6), visibility = SHADER_VISIBILITY_PIXEL)," \
	"StaticSampler(s0, maxAnisotropy = 8, visibility = SHADER_VISIBILITY_PIXEL)," \
	"StaticSampler(s1, visibility = SHADER_VISIBILITY_PIXEL," \
		"addressU = TEXTURE_ADDRESS_WRAP," \
		"addressV = TEXTURE_ADDRESS_WRAP," \
		"addressW = TEXTURE_ADDRESS_WRAP," \
		"comparisonFunc = COMPARISON_LESS_EQUAL," \
		"filter = FILTER_MIN_MAG_LINEAR_MIP_POINT)"

Vertex Shader:

#include "SkyRS.hlsli"

cbuffer VSConstants : register(b0)
{
	float4x4 modelToProjection;
};

struct VSInput
{
	float3 position : POSITION;
};

struct VSOutput
{
	float4 position  : SV_POSITION; // screen space position of the pixel
	float3 texLookUp : POSITION;
};

[RootSignature(Sky_RootSig)]
VSOutput main(VSInput vsInput)
{
	VSOutput vsOutput;

	vsOutput.texLookUp = vsInput.position; // use position as index to cube map
	
	float3 projected = mul(vsInput.position, (float3x3)modelToProjection); // ignore translation 
	vsOutput.position = float4(projected, 1.0f).xyww; // Set z = w which forces the farthest possible z value
	//vsOutput.position = float4(vsInput.position, 1.0f).xyww;

	return vsOutput;
}

Pixel shader:


#include "SkyRS.hlsli"

struct VSOutput
{
	float4 position  : SV_POSITION; // screenspace position of the pixel
	float3 texLookUp : POSITION;
};

TextureCube cubeMap : register(t0);

SamplerState sampler0 : register(s0);
SamplerState sampler1 : register(s1);

[RootSignature(Sky_RootSig)]
float3 main(VSOutput pin) : SV_Target0
{ 
	//return float3(1.f,0.f,0.f);
	return cubeMap.Sample(sampler1, pin.texLookUp);
}

 

Share this post


Link to post
Share on other sites
Advertisement

I don't know the correct way to do it in DirectX, but in OpenGL I draw the skybox last with the depth range set to [1.0,1.0] instead of [0.0,1.0], with depth test less-than-or-equal. This way, all output fragments of the skybox are at the furthest depth value (the clear depth), and won't overdraw any foreground objects.

Share this post


Link to post
Share on other sites

The sky box is behind everything, so you can just do so at the end of the vertexshader :

 

return float4(vsOutput.xy,1,1);

 

This way the geometry is pushed to the far plane or infinity, independently from his scale. A change to the viewport bounds is not the best option as it is an heavier state to change + in theory, you should not set a NIL range for depth.

Edited by galop1n

Share this post


Link to post
Share on other sites

@galop1n Thank you, but my shader is doing the same thing with vsOutput.position = float4(projected, 1.0f).xyww; so that does not appear to be the issue.

@Aressera Thank you, thank you!  Solved!  This is a great practice I will now adopt.  By setting the depth range to one value, it can be only one value.  However, my problem still exists, so that means only one thing: the comparison function is not working. 

Solution:  Mini-engine open source code from Microsoft optimizes the z-pass by reversing it (0 far plane and 1.0 near plane).  So the comparison tests have to be greater-than-or-equal rather than less-than-or-equal.  I changed that and it works perfectly now.

Thank you both for your help.  First time posting here because I was out of ideas and you led me to water :)

 

Share this post


Link to post
Share on other sites
Quote

samplerSkyDesc.ComparisonFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;

Sampler comparisons are used for shadow-mapping, where you want your texture filter to compare the texel values against a reference that you provide and return a boolean result (0.0f or 1.0f).

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!