我们在WPF中使用D3DImage
来显示在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上的"Introduction to D3DImage",“简要介绍D3D互操作要求”部分。)
我通过将每个像素乘以C#中的alpha值并使用自定义像素着色器来验证这实际上是个问题。结果都很好。但是,我想直接从DirectX获得此结果。
如何直接从DirectX获取预乘数据?我可以在调用CreateRenderTarget
时以某种方式指定它吗?我不是DirectX专家,所以请原谅解决方案是否明显......
答案 0 :(得分: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,请查看here以获得开始的好地方。