我的HLSL深度着色器出了什么问题?

时间:2015-07-24 20:46:24

标签: xna hlsl depth

我试图在XNA 4.0中渲染深度纹理。我几次读了几本不同的教程,真的无法理解我做错了什么。

深度着色器:

float4x4 WVPMatrix;

struct VertexShaderOutput
{
    float4 Position : position0;
    float Depth : texcoord0;
};

VertexShaderOutput VertexShader1(float4 pPosition : position0)
{
    VertexShaderOutput output;
    output.Position = mul(pPosition, WVPMatrix);
    output.Depth.x = 1 - (output.Position.z / output.Position.w);
    return output;
}    

float4 PixelShader1(VertexShaderOutput pOutput) : color0
{
    return float4(pOutput.Depth.x, 0, 0, 1);
}    

technique Technique1
{
    pass Pass1
    {
        AlphaBlendEnable = false;
        ZEnable = true;
        ZWriteEnable = true;

        VertexShader = compile vs_2_0 VertexShader1();
        PixelShader = compile ps_2_0 PixelShader1();
    }
}

图:

this.depthRenderTarget = new RenderTarget2D(
    this.graphicsDevice,
    this.graphicsDevice.PresentationParameters.BackBufferWidth,
    this.graphicsDevice.PresentationParameters.BackBufferHeight);

...

public void Draw(GameTime pGameTime, Camera pCamera, Effect pDepthEffect, Effect pOpaqueEffect, Effect pNotOpaqueEffect)
{
    this.graphicsDevice.SetRenderTarget(this.depthRenderTarget);
    this.graphicsDevice.Clear(Color.CornflowerBlue);
    this.DrawChunksDepth(pGameTime, pCamera, pDepthEffect);

    this.graphicsDevice.SetRenderTarget(null);
    this.spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.PointClamp, null, null);
    this.spriteBatch.Draw(this.depthRenderTarget, Vector2.Zero, Color.White);
    this.spriteBatch.End();
}

private void DrawChunksDepth(GameTime pGameTime, Camera pCamera, Effect pDepthEffect)
{
    // ...

    this.graphicsDevice.RasterizerState = RasterizerState.CullClockwise;
    this.graphicsDevice.DepthStencilState = DepthStencilState.Default;

    // draw mesh with pDepthEffect
}

结果: enter image description here

正如我看到output.Position.z总是等于output.Position.w,但为什么?

1 个答案:

答案 0 :(得分:0)

有几种深度定义可能有用。以下是其中一些。

最简单的是相机空间中的z坐标(即在应用世界和视图变换之后)。它通常与世界坐标系具有相同的单位,并且是线性的。但是,它始终与视图方向平行测量。这意味着左/右和上/下移动不会改变距离,因为您保持在同一平面(平行于znear / zfar剪裁平面)。稍微变化是z/far,它只是将值缩放到[0,1]间隔。

如果需要实际距离(在欧几里德度量标准中),则必须在着色器中计算它们。如果您只需要粗略值,则顶点着色器就足够了。如果值应该准确,请在像素着色器中执行此操作。基本上,您需要在应用世界和视图变换后计算位置矢量的长度。单位等于世界空间单位。

深度缓冲深度是非线性的,并针对深度缓冲进行了优化。这是投影变换(以及跟随w-clip)返回的深度。近剪裁平面被映射到深度为0,远剪裁平面被映射到深度为1.如果沿视图方向更改非常近的像素的位置,则深度值的变化远远大于远像素。同样感动。这是因为在近像素处的显示误差(由于浮点不精确)比在远像素处更明显。该深度也与视图方向平行测量。