Jump to content
  • Advertisement
Order340

DX12 SkyBox Depth Troubles

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

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

  • Advertisement
  • Advertisement
  • Popular Tags

  • Similar Content

    • By owenjr
      Hi, I'm a Multimedia Engineering student. I am about to finish my dergree and I'm already thinking about what topic to cover in my final college project.
      I'm interested in the procedural animation with c++ and OpenGL of creatures, something like a spider for example. Can someone tell me what are the issues I should investigate to carry it out? I understand that it has some dependence on artificial intelligence but I do not know to what extent. Can someone help me to find information about it? Thank you very much.
       
      Examples: 
      - Procedural multi-legged walking animation
      - Procedural Locomotion of Multi-Legged Characters in Dynamic Environments
    • By Hellados
      Hello guys, my name is Giorgi and i'm newbie game developer i'm learning Pixel art and after pixel art  i want learn C# and don't know how and where start i'm bad with programming language and know only HTML/CSS
    • By Andrew Parkes
      I am a talented 2D/3D artist with 3 years animation working experience and a Degree in Illustration and Animation. I have won a world-wide art competition hosted by SFX magazine and am looking to develop a survival game. I have some knowledge of C sharp and have notes for a survival based game with flexible storyline and PVP. Looking for developers to team up with. I can create models, animations and artwork and I have beginner knowledge of C sharp with Unity. The idea is Inventory menu based gameplay and is inspired by games like DAYZ.
      Here is some early sci-fi concept art to give you an idea of the work level. Hope to work with like minded people and create something special. email me andrewparkesanim@gmail.com.
      Developers who share the same passion please contact me, or if you have a similar project and want me to join your team email me. 
      Many thanks, Andrew.

    • By mike44
      Hi
      saw in dependency walker that my app still needs msvcp140d.dll even after disabling debug.
      What did I forget in the VS2017 release settings? After setting to multithreaded dll I get linker errors.
      Thanks
       
    • By NikiTo
      Recently I read that the APIs are faking some behaviors, giving to the user false impressions.
      I assume Shader Model 6 issues the wave instructions to the hardware for real, not faking them.

      Is Shader Model 6, mature enough? Can I expect the same level of optimization form Model 6 as from Model 5? Should I expect more bugs from 6 than 5?
      Would the extensions of the manufacturer provide better overall code than the Model 6, because, let say, they know their own hardware better?

      What would you prefer to use for your project- Shader Model 6 or GCN Shader Extensions for DirectX?

      Which of them is easier to set up and use in Visual Studio(practically)?
    • By 3dmodelerguy
      So I have been playing around with yaml-cpp as I want to use YAML for most of my game data files however I am running into some pretty big performance issues and not sure if it is something I am doing or the library itself.
      I created this code in order to test a moderately sized file:
      Player newPlayer = Player(); newPlayer.name = "new player"; newPlayer.maximumHealth = 1000; newPlayer.currentHealth = 1; Inventory newInventory; newInventory.maximumWeight = 10.9f; for (int z = 0; z < 10000; z++) { InventoryItem* newItem = new InventoryItem(); newItem->name = "Stone"; newItem->baseValue = 1; newItem->weight = 0.1f; newInventory.items.push_back(newItem); } YAML::Node newSavedGame; newSavedGame["player"] = newPlayer; newSavedGame["inventory"] = newInventory; This is where I ran into my first issue, memory consumption.
      Before I added this code, the memory usage of my game was about 22MB. After I added everything expect the YAML::Node stuff, it went up to 23MB, so far nothing unexpected. Then when I added the YAML::Node and added data to it, the memory went up to 108MB. I am not sure why when I add the class instance it only adds like 1MB of memory but then copying that data to a YAML:Node instance, it take another 85MB of memory.
      So putting that issue aside, I want want to test the performance of writing out the files. the initial attempt looked like this:
      void YamlUtility::saveAsFile(YAML::Node node, std::string filePath) { std::ofstream myfile; myfile.open(filePath); myfile << node << std::endl; myfile.close(); } To write out the file (that ends up to be about 570KB), it took about 8 seconds to do that. That seems really slow to me.
      After read the documentation a little more I decide to try a different route using the YAML::Emitter, the implemntation looked like this:
      static void buildYamlManually(std::ofstream& file, YAML::Node node) { YAML::Emitter out; out << YAML::BeginMap << YAML::Key << "player" << YAML::Value << YAML::BeginMap << YAML::Key << "name" << YAML::Value << node["player"]["name"].as<std::string>() << YAML::Key << "maximumHealth" << YAML::Value << node["player"]["maximumHealth"].as<int>() << YAML::Key << "currentHealth" << YAML::Value << node["player"]["currentHealth"].as<int>() << YAML::EndMap; out << YAML::BeginSeq; std::vector<InventoryItem*> items = node["inventory"]["items"].as<std::vector<InventoryItem*>>(); for (InventoryItem* const value : items) { out << YAML::BeginMap << YAML::Key << "name" << YAML::Value << value->name << YAML::Key << "baseValue" << YAML::Value << value->baseValue << YAML::Key << "weight" << YAML::Value << value->weight << YAML::EndMap; } out << YAML::EndSeq; out << YAML::EndMap; file << out.c_str() << std::endl; } While this did seem to improve the speed, it was still take about 7 seconds instead of 8 seconds.
      Since it has been a while since I used C++ and was not sure if this was normal, I decided to for testing just write a simple method to manually generate the YAMLin this use case, that looked something like this:
      static void buildYamlManually(std::ofstream& file, SavedGame savedGame) { file << "player: \n" << " name: " << savedGame.player.name << "\n maximumHealth: " << savedGame.player.maximumHealth << "\n currentHealth: " << savedGame.player.currentHealth << "\ninventory:" << "\n maximumWeight: " << savedGame.inventory.maximumWeight << "\n items:"; for (InventoryItem* const value : savedGame.inventory.items) { file << "\n - name: " << value->name << "\n baseValue: " << value->baseValue << "\n weight: " << value->weight; } } This wrote the same file and it took about 0.15 seconds which seemed a lot more to what I was expecting.
      While I would expect some overhead in using yaml-cpp to manage and write out YAML files, it consuming 70X+ the amount of memory and it being 40X+ slower in writing files seems really bad.
      I am not sure if I am doing something wrong with how I am using yaml-cpp that would be causing this issue or maybe it was never design to handle large files but was just wondering if anyone has any insight on what might be happening here (or an alternative to dealing with YAMLin C++)?
    • By N Drew
      I am working on a 2D SideScroller game in my own made game engine using SFML and C++.I am searching for 2D artists,especially pixel artist for making and animating characters,backgrounds and other props that can be made in any Drawing Program.The artist will become part of the team of Hammer Studios and he got a part of the Revenue Sharing.If you are interested send me a mail at:ghiurcutaandrei@gmail.com .If you are not an artist but you want to be a part of our Team,Soon we will be recruiting an C++ AI programmers that worked in SFML/OpenGL.
      We work together using Discord.

    • By 3dmodelerguy
      So I am trying to using Yaml as my game data files (mainly because it support comments, is a bit easier to read than JSON, and I am going to be working in these files a lot) with C++ and yaml-cpp (https://github.com/jbeder/yaml-cpp) seems like the most popular library for dealing with it however I am running into an issue when using pointers.
      Here is my code:
      struct InventoryItem { std::string name; int baseValue; float weight; }; struct Inventory { float maximumWeight; std::vector<InventoryItem*> items; }; namespace YAML { template <> struct convert<InventoryItem*> { static Node encode(const InventoryItem* inventoryItem) { Node node; node["name"] = inventoryItem->name; node["baseValue"] = inventoryItem->baseValue; node["weight"] = inventoryItem->weight; return node; } static bool decode(const Node& node, InventoryItem* inventoryItem) { // @todo validation inventoryItem->name = node["name"].as<std::string>(); inventoryItem->baseValue = node["baseValue"].as<int>(); inventoryItem->weight = node["weight"].as<float>(); return true; } }; template <> struct convert<Inventory> { static Node encode(const Inventory& inventory) { Node node; node["maximumWeight"] = inventory.maximumWeight; node["items"] = inventory.items; return node; } static bool decode(const Node& node, Inventory& inventory) { // @todo validation inventory.maximumWeight = node["maximumWeight"].as<float>(); inventory.items = node["items"].as<std::vector<InventoryItem*>>(); return true; } }; } if I just did `std::vector<InventoryItem> items` and had the encode / decode use `InventoryItem& inventoryItem` everything works fine however when I use the code above that has it as a pointer, I get the following error from code that is part of the yaml-cpp library:
      impl.h(123): error C4700: uninitialized local variable 't' used The code with the error is:
      template <typename T> struct as_if<T, void> { explicit as_if(const Node& node_) : node(node_) {} const Node& node; T operator()() const { if (!node.m_pNode) throw TypedBadConversion<T>(node.Mark()); T t; if (convert<T>::decode(node, t)) // NOTE: THIS IS THE LINE THE COMPILER ERROR IS REFERENCING return t; throw TypedBadConversion<T>(node.Mark()); } }; With my relative lack of experience in C++ and not being able to find any documentation for yaml-cpp using pointers, I am not exactly sure what is wrong with my code.
      Anyone have any ideas what I need to change with my code? 
    • By Gnollrunner
      I already asked this question on stack overflow, and they got pissed at me, down-voted me and so forth, LOL .... so I'm pretty sure the answer is NO, but I'll try again here anyway just in case..... Is there any way to get the size of a polymorphic object at run-time? I know you can create a virtual function that returns size and overload it for each child class, but I'm trying to avoid that since (a) it takes a virtual function call and I want it to be fast and (b) it's a pain to have to include the size function for every subclass. I figure since each object has a v-table their should be some way since the information is there, but perhaps there is no portable way to do it.
    • By MarcusAseth
      This is the code I have:
       //Create Window     DWORD windowStyle = WS_VISIBLE;     DWORD windowExStyle = WS_EX_OVERLAPPEDWINDOW;     SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE);     RECT client{ 0, 0, 100, 40 };     UINT dpi = GetDpiForSystem();     AdjustWindowRectExForDpi(&client, windowStyle, false, windowExStyle, dpi);     UINT adjustedWidth = client.right - client.left;     UINT adjustedHeight = client.bottom - client.top;     m_hwnd = CreateWindowEx(windowExStyle,                             className.c_str(),                             windowName.c_str(),                             windowStyle,                             CW_USEDEFAULT,                             CW_USEDEFAULT,                             adjustedWidth,                             adjustedHeight,                             nullptr,                             nullptr,                             m_hInstance,                             m_emu     ); The generated window has a client area of 1 pixel in height, even though I'm asking for 40. so I'm always getting 39 pixel less than what I need...can someone help me with this? x_x
  • Advertisement
  • Popular Now

  • Forum Statistics

    • Total Topics
      631372
    • Total Posts
      2999627
×

Important Information

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

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!