HLSL modify depth in pixel shader
我需要渲染从外部获得的图像(具有深度)。我可以构造两个纹理,并将它们毫无问题地传递到着色器中(我可以验证在像素着色器中采样的值是正确的)。
我的HLSL如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // image texture Texture2D m_TextureColor : register(t0); // depth texture with values [0..1] Texture2D<float> m_TextureDepth : register(t1); // sampler to forbid linear filtering since we're dealing with pixels SamplerState m_TextureSampler { Filter = MIN_MAG_MIP_POINT; }; struct VS_IN { float4 position : POSITION; float2 texcoord : TEXCOORD; }; struct VS_OUT { float4 position : SV_POSITION; float2 texcoord : TEXCOORD0; }; struct PS_OUT { float4 color : COLOR0; float depth : DEPTH0; }; VS_OUT VS(VS_IN input) { VS_OUT output = (VS_OUT)0; output.position = input.position; output.texcoord = input.texcoord; return output; } PS_OUT PS(VS_OUT input) : SV_Target { PS_OUT output = (PS_OUT)0; output.color = m_TextureColor.SampleLevel(m_TextureSampler, input.texcoord, 0); // I want to modify depth of the pixel, // but it looks like it has no effect on depth no matter what I set here output.depth = m_TextureDepth.SampleLevel(m_TextureSampler, input.texcoord, 0); return output; } |
我从那些(用
1 2 3 4 5 6 7 |
一切正常:我正在查看图像,可以从深度纹理中采样深度并从中构造出一些视觉效果(这就是我可以验证的方式
我采样的深度值是正确的)。但是我无法弄清楚如何修改像素的深度,以便在进行深度测试时可以正确地吃掉它。因为目前,这完全取决于我将哪种z值设置为顶点位置。
这就是我设置
1 2 3 4 5 6 7 8 9 10 11 12 | var swapChainDescription = new SwapChainDescription { BufferCount = 1, ModeDescription = new ModeDescription(bufferSize.Width, bufferSize.Height, new Rational(60, 1), Format.R8G8B8A8_UNorm), IsWindowed = true, OutputHandle = HostHandle, SampleDescription = new SampleDescription(1, 0), SwapEffect = SwapEffect.Discard, Usage = Usage.RenderTargetOutput, }; var swapChainFlags = DeviceCreationFlags.None | DeviceCreationFlags.BgraSupport; SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, swapChainFlags, swapChainDescription, out var device, out var swapchain); |
设置后缓冲区和深度/模板缓冲区:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | // color buffer using (var textureColor = SwapChain.GetBackBuffer<Texture2D>(0)) { TextureColorResourceView = new RenderTargetView(Device, textureColor); } // depth buffer using (var textureDepth = new Texture2D(Device, new Texture2DDescription { Format = Format.D32_Float, ArraySize = 1, MipLevels = 1, Width = BufferSize.Width, Height = BufferSize.Height, SampleDescription = new SampleDescription(1, 0), Usage = ResourceUsage.Default, BindFlags = BindFlags.DepthStencil, CpuAccessFlags = CpuAccessFlags.None, OptionFlags = ResourceOptionFlags.None })) { TextureDepthResourceView = new DepthStencilView(Device, textureDepth); } DeviceContext.OutputMerger.SetTargets(TextureDepthResourceView, TextureColorResourceView); |
准备深度模具状态:
1 2 3 4 5 | var description = DepthStencilStateDescription.Default(); description.DepthComparison = Comparison.LessEqual; description.IsDepthEnabled = true; description.DepthWriteMask = DepthWriteMask.All; DepthState = new DepthStencilState(Device, description); |
并使用它:
1 | DeviceContext.OutputMerger.SetDepthStencilState(DepthState); |
这是构造发送到着色器的颜色/深度纹理的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public static (ShaderResourceView resource, Texture2D texture) CreateTextureDynamic(this Device device, System.Drawing.Size size, Format format) { var textureDesc = new Texture2DDescription { MipLevels = 1, Format = format, Width = size.Width, Height = size.Height, ArraySize = 1, BindFlags = BindFlags.ShaderResource, Usage = ResourceUsage.Dynamic, SampleDescription = new SampleDescription(1, 0), CpuAccessFlags = CpuAccessFlags.Write, }; var texture = new Texture2D(device, textureDesc); return (new ShaderResourceView(device, texture), texture); } |
另外,由于我需要经常更新它们:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public static void UpdateResource(this Texture2D texture, int[] buffer, System.Drawing.Size size) { var dataBox = texture.Device.ImmediateContext.MapSubresource(texture, 0, MapMode.WriteDiscard, MapFlags.None, out var dataStream); Parallel.For(0, size.Height, rowIndex => Marshal.Copy(buffer, size.Width * rowIndex, dataBox.DataPointer + dataBox.RowPitch * rowIndex, size.Width)); dataStream.Dispose(); texture.Device.ImmediateContext.UnmapSubresource(texture, 0); } public static void UpdateResource(this Texture2D texture, float[] buffer, System.Drawing.Size size) { var dataBox = texture.Device.ImmediateContext.MapSubresource(texture, 0, MapMode.WriteDiscard, MapFlags.None, out var dataStream); Parallel.For(0, size.Height, rowIndex => Marshal.Copy(buffer, size.Width * rowIndex, dataBox.DataPointer + dataBox.RowPitch * rowIndex, size.Width)); dataStream.Dispose(); texture.Device.ImmediateContext.UnmapSubresource(texture, 0); } |
我对此也进行了很多搜索,发现了类似的帖子:https://www.gamedev.net/forums/topic/573961-how-to-set-depth-value-in-pixel-shader/但无法设法解决了这一点。
提前致谢!
要写入深度缓冲区,您需要定位SV_Depth系统值语义。 因此,您的像素着色器输出结构将更像以下内容:
1 2 3 4 5 | struct PS_OUT { float4 color : SV_Target; float depth : SV_Depth; }; |
并且着色器不会像您的示例中那样指定SV_Target(SV_输出在结构中定义)。 因此,它看起来像:
1 2 3 4 5 6 7 8 9 10 11 12 | PS_OUT PS(VS_OUT input) { PS_OUT output = (PS_OUT)0; output.color = m_TextureColor.SampleLevel(m_TextureSampler, input.texcoord, 0); // Now that output.depth is defined with SV_Depth, and you have depth-write enabled, // this should write to the depth buffer. output.depth = m_TextureDepth.SampleLevel(m_TextureSampler, input.texcoord, 0); return output; } |
请注意,在显式写入深度(特别是在AMD硬件上)时,可能会导致性能下降,因为这会绕过其早期的深度硬件优化。 将来所有使用该深度缓冲区的绘图调用都将禁用Early-Z优化,因此,通常最好尽可能晚地执行深度写入操作。