0

我们在 WPF 中使用 aD3DImage在 WPF 中创建的背景上显示使用 Direct3D 呈现的部分透明的 3D 内容。所以,我们有这样的事情:

<UserControl Background="Blue">
    <Image>
        <Image.Source>
            <D3DImage .../>
        </Image.Source>
    </Image>
</UserControl>

现在,我们遇到了抗锯齿边缘无法正确显示的问题。我们在某些边缘得到某种白色“发光”效果,类似于第一张图片中显示的文本周围的效果:

(取自http://dvd-hq.info/alpha_matting.php

原因是我们从 DirectX 获得的数据显然没有与 alpha 通道进行预乘。但是 WPF 和D3DImage期望这是他们的输入(参见CodeProject 上的“D3DImage 简介”,“A Brief Look at D3D Interop Requirements”一节)。

我通过在 C# 中将每个像素乘以其 alpha 值并使用自定义像素着色器来验证这实际上是问题所在。结果都很好。但是,我想直接从 DirectX 获得这个结果。

如何直接从 DirectX 获取预乘数据?我可以在调用中以某种方式指定它CreateRenderTarget吗?我不是 DirectX 专家,所以如果解决方案可能很明显,请原谅......

4

1 回答 1

1

为了正确预乘 DirectX 内容,您需要自定义 ID3D11BlendState。D3D11_BLEND_DESC结构应设置如下:

AlphaToCoverageEnable = FALSE;
IndependentBlendEnable = FALSE;
RenderTarget[0].BlendEnable = TRUE;

// dest.rgb = src.rgb * src.a + dest.rgb * (1 - src.a)
RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;

// dest.a = 1 - (1 - src.a) * (1 - dest.a) [the math works out]
RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;

RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

使用ID3D11Device::CreateBlendState创建混合状态,然后使用ID3D11DeviceContext::OMSetBlendState设置它。然后,只需像往常一样设置 Direct3D 管道的其余部分,渲染目标的输出应该具有带有正确 Alpha 通道输出的预乘 Alpha,用于 Direct2D、WPF 或任何其他需要预乘内容的 API .

请注意,如果您使用的是 Direct3D 9,则概念相同,但 API 不同。如果您使用的是 9,请在此处寻找一个不错的起点。

于 2013-09-24T04:22:16.673 回答