首页 > 解决方案 > HLSL:如何像光栅化器一样将顶点转换为屏幕空间,但具有亚像素精度?

问题描述

我想使用顶点和像素着色器绘制一个点列表。每个点的渲染颜色应该代表其子像素精确的屏幕空间坐标(输出到 R32G32_FLOAT 纹理)。我在我的 VS 中执行以下操作:

struct VSOutput
{
    float4 position : SV_Position;
    float2 screenSpacePosition : COLOR;
};

VSOutput VS(uint index : SV_VertexID)
{
    float3 pointPos = inPointPositions[index];
    VSOutput output;
    output.position = mul(transform, float4(pointPos, 1));
    output.screenSpacePosition = (float2(+1, -1) * output.position.xy / output.position.w * 0.5f + 0.5f) * float2(width, height);
    return output;
}

在我的 PS 中,我通常只使用 screenSpacePosition 字段作为我的最终目标颜色,但由于我遇到了一些问题,我对其进行了更改以验证计算的 screenSpacePosition 是否与用于光栅化的实际像素位置一致(以调试问题)。如果计算出的 screenSpacePosition 与光栅化位置匹配,它将输出白色,否则输出红色。

float4 PS(VSOutput input) : SV_Target
{
    return all(floor(output.screenSpacePosition) == floor(input.position.xy)) ? float4(1, 1, 1, 1) : float4(1, 0, 0, 1);
}

现在几乎所有像素都是白色的,正如预期的那样,但顶部偶尔会出现红噪声。我强烈认为这是因为光栅化器使用内部 16.8 定点格式映射到实际像素,因此该定点格式和我的浮点转换之间的映射不能 100% 达成一致。有没有办法解决这个问题?

标签: c++hlsldirect3d11rasterizing

解决方案


使用ceil()而不是floor().

考虑点光栅化规则, 点光栅化规则

假设 VS 输出的屏幕空间 pos 恰好在整数像素坐标处,则以(n, m)为中心的像素(n - 0.5, m - .5)将被光栅化并接收(n - 0.5, m - 0.5)PS 中的 SV_POSITION,而手动计算的传递给 PS 的 pos 仍然是(n, m),这将在之后返回不同的值申请floor()


推荐阅读