You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从D3D9移植到DX11后,线列表绘制的水平线为何在特定缩放级显示为2px宽?

D3D9转DX11后线条宽度异常的解决方案

D3D9与DX11的核心差异

  • D3D9默认采用像素中心对齐的光栅化规则:投影后的顶点坐标会自动偏移0.5个像素(从像素网格的角落移到中心),避免线条落在像素边界上导致跨像素绘制。
  • DX11默认采用像素角落对齐:没有自动偏移,当线条的屏幕坐标恰好处于两个像素的边界时,会被光栅化到两个相邻像素,表现为2px宽度的线条,水平/垂直线条这类问题尤其明显。

正确解决方案

方案1:顶点着色器中添加像素偏移

在顶点着色器完成WorldViewProjection变换后,添加0.5像素的偏移,将坐标从像素角落对齐转为中心对齐。需要传入视口的宽高作为常量:

cbuffer ViewportParams : register(b0)
{
    float viewportWidth;
    float viewportHeight;
}

struct VSInput
{
    float3 position : POSITION;
};

struct PSInput
{
    float4 position : SV_POSITION;
};

PSInput VS(VSInput input)
{
    PSInput output;
    // 常规的MVP变换
    float4 clipPos = mul(worldViewProj, float4(input.position, 1.0));
    // 在透视除法前添加偏移,适配齐次坐标
    clipPos.xy += clipPos.w * float2(0.5 / viewportWidth, 0.5 / viewportHeight);
    output.position = clipPos;
    return output;
}

这种方式兼容性最好,支持所有DX11版本。

方案2:修改光栅化状态启用像素中心对齐

如果使用DX11.1及以上版本,可以直接通过光栅化状态切换到像素中心对齐,完全复刻D3D9的行为,无需修改着色器:

D3D11_RASTERIZER_DESC rasterDesc = {};
rasterDesc.FillMode = D3D11_FILL_SOLID;
rasterDesc.CullMode = D3D11_CULL_BACK;
rasterDesc.Alignment = D3D11_PIXEL_CENTER_ALIGNMENT; // 启用像素中心对齐
rasterDesc.DepthClipEnable = TRUE;
rasterDesc.ScissorEnable = FALSE;
rasterDesc.MultisampleEnable = FALSE;
rasterDesc.AntialiasedLineEnable = FALSE;

ID3D11RasterizerState* pRasterState = nullptr;
HRESULT hr = pDevice->CreateRasterizerState(&rasterDesc, &pRasterState);
if (SUCCEEDED(hr))
{
    pContext->RSSetState(pRasterState);
    // 使用完记得释放资源
    pRasterState->Release();
}

方案3:在投影矩阵中整合偏移

可以将0.5像素偏移直接嵌入到投影矩阵中,这样顶点着色器无需修改。以正交投影为例,构造矩阵时额外添加平移分量:

// 常规正交投影矩阵构造
float orthoMatrix[16] = {
    2.0f / (right - left), 0.0f, 0.0f, 0.0f,
    0.0f, 2.0f / (top - bottom), 0.0f, 0.0f,
    0.0f, 0.0f, 1.0f / (zFar - zNear), 0.0f,
    -(right + left) / (right - left), -(top + bottom) / (top - bottom), -zNear / (zFar - zNear), 1.0f
};
// 添加0.5像素偏移
float offsetX = 0.5f / viewportWidth;
float offsetY = 0.5f / viewportHeight;
orthoMatrix[12] += offsetX * 2.0f / (right - left);
orthoMatrix[13] += offsetY * 2.0f / (top - bottom);

这种方式适合不想修改着色器或光栅化状态的场景,但需要熟悉投影矩阵的构造逻辑。

为什么CPU端投影反投影的方式不推荐

  • 增加CPU计算负担:将原本GPU的投影计算移到CPU,在复杂场景或动态视角下会降低性能。
  • 精度风险:多次矩阵变换和舍入操作容易引入浮点精度误差。
  • 维护成本:当渲染逻辑变化(如修改投影矩阵、视口大小)时,需要同步修改CPU端的计算逻辑,容易出错。

内容的提问来源于stack exchange,提问作者testalino

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 14:32:11