HLSL修改像素着色器中的深度

时间:2018-06-02 18:29:22

标签: c# directx-11 depth sharpdx pixel-shader

我需要渲染一张从外面得到的图像(有深度)。我可以构造两个纹理并将它们传递到着色器中而没有问题(我可以验证在像素着色器中采样的值是否正确)。

这是我的HLSL的样子:

PrimitiveTopology.TriangleStrip

我从那些(Vector4)构造顶点缓冲区,其中第一个参数Vector2是位置,第二个参数new[] { new Vertex(new Vector4(-1, -1, 0.5f, 1), new Vector2(0, 1)), new Vertex(new Vector4(-1, 1, 0.5f, 1), new Vector2(0, 0)), new Vertex(new Vector4(1, -1, 0.5f, 1), new Vector2(1, 1)), new Vertex(new Vector4(1, 1, 0.5f, 1), new Vector2(1, 0)), } 是纹理坐标:

DirectX11

一切都运转得很好:我看到了我的图像,我可以从深度纹理中采样深度并从中构造一些视觉效果(这就是我如何验证它 深度值我采样是正确的)。但是,我无法弄清楚如何修改像素的深度,以便在进行深度测试时能够正确使用它。因为目前这一切都取决于我设置为我的顶点位置的z值。

这就是我设置SharpDX的方式(我使用C#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); ):

// 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);

设置缓冲区和深度/模板缓冲区:

var description = DepthStencilStateDescription.Default();
description.DepthComparison = Comparison.LessEqual;
description.IsDepthEnabled = true;
description.DepthWriteMask = DepthWriteMask.All;
DepthState = new DepthStencilState(Device, description);

准备深度模板状态:

DeviceContext.OutputMerger.SetDepthStencilState(DepthState);

使用它:

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);
}

这就是我如何构建我发送到着色器的颜色/深度纹理:

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);
}

此外,由于我需要经常更新它们:

 import android.support.v7.app.NotificationCompat;

我也搜索了很多关于此的内容,发现了类似的帖子:https://www.gamedev.net/forums/topic/573961-how-to-set-depth-value-in-pixel-shader/然而无法解决这个问题。

提前致谢!

1 个答案:

答案 0 :(得分:1)

要写入深度缓冲区,您需要定位SV_Depth系统值语义。所以你的像素着色器输出结构看起来更像是:

struct PS_OUT
{
    float4 color : SV_Target;
    float depth : SV_Depth;
};

并且着色器不会像您的示例中那样指定SV_Target(SV_输出在结构中定义)。所以它看起来像:

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硬件上)时,您可能会受到一些性能损失,因为这会强制绕过其早期深度的硬件优化。使用该深度缓冲区的所有未来绘制调用都将禁用早期Z优化,因此通常最好尽可能晚地执行深度写入操作。