DirectX 渲染到纹理 alpha 混合
DirectX render to texture alpha blending
问题如下:我将精灵渲染到纹理,然后我将纹理渲染到屏幕。简单吧?但是,当我这样做时,每次渲染精灵时,它都会覆盖它覆盖的每个像素,而不管其像素的 alpha 值。示例:
在这里您可以看到两个带有文字 "ABC" 的精灵。第一个渲染在右上角,第二个渲染在它的顶部,带有 Y 偏移量。如您所见,第二个甚至覆盖了第一个精灵中不应被背景颜色覆盖的像素。当我这样做时,但不是将其渲染到纹理,然后将该纹理渲染到屏幕,而是直接将精灵渲染到屏幕,结果符合预期,第二个精灵仅覆盖应该被覆盖的像素。
因此,我不太确定那里发生了什么,因为所有渲染目标都启用了 alpha 混合,并且屏幕和纹理渲染的深度测试已关闭。我在 Windows Phone 8 - XAML 上使用 DirectX11 与 DirectX 互操作。
编辑:稍微重述一个问题:假设我将纹理清除为红色,所以当我将它渲染到屏幕时,我有红色屏幕。现在我将完全透明(颜色 0,0,0,0)的纹理渲染为所述红色纹理。我希望不会有任何变化,在渲染到屏幕后,我会看到红屏。情况并非如此,因为当我渲染透明精灵时,它实际上将 (0,0,0,0) 颜色写入纹理,我得到一个透明 window 的红色纹理。所以在将它渲染到屏幕后,我可以看到彩色屏幕被清除了。怎么回事?
您最后的评论说明了问题所在。我假设 源纹理和中间渲染目标都有一个 alpha 通道,对吗?如果是这样,您需要为颜色 和 alpha 通道使用正确的混合方程。通常,直接混合到后台缓冲区的标准方程会忽略正确的 alpha 通道混合,因为后台缓冲区 alpha 通常被忽略。我怀疑在您的情况下,颜色通道已正确混合,但最后渲染的精灵将其 alpha 值直接写入中间纹理。因此,这些像素是完全透明的,尽管它们应该保持不透明,因为之前的绘制使它们不透明。当您随后将此纹理渲染到后台缓冲区时,相同颜色的 alpha 混合会导致这些像素对最终图像没有任何贡献。
这是对具有透明度的纹理进行标准 alpha 混合渲染的正确设置:
// dest.rgb = dest.rgb * (1 - src.a) + src.rgb * src.a
SrcBlend = SRC_ALPHA
DestBlend = INV_SRC_ALPHA
BlendOp = ADD
// dest.a = 1 - (1 - dest.a) * (1 - src.a), with some rearranging
SrcBlendAlpha = INV_DEST_ALPHA
DestBlendAlpha = ONE
BlendOpAlpha = ADD
此外,不要忘记在渲染之前将中间目标清除为透明(不是不透明的黑色,这很常见),假设您希望纹理的某些部分是渲染后透明。
问题如下:我将精灵渲染到纹理,然后我将纹理渲染到屏幕。简单吧?但是,当我这样做时,每次渲染精灵时,它都会覆盖它覆盖的每个像素,而不管其像素的 alpha 值。示例:
在这里您可以看到两个带有文字 "ABC" 的精灵。第一个渲染在右上角,第二个渲染在它的顶部,带有 Y 偏移量。如您所见,第二个甚至覆盖了第一个精灵中不应被背景颜色覆盖的像素。当我这样做时,但不是将其渲染到纹理,然后将该纹理渲染到屏幕,而是直接将精灵渲染到屏幕,结果符合预期,第二个精灵仅覆盖应该被覆盖的像素。
因此,我不太确定那里发生了什么,因为所有渲染目标都启用了 alpha 混合,并且屏幕和纹理渲染的深度测试已关闭。我在 Windows Phone 8 - XAML 上使用 DirectX11 与 DirectX 互操作。
编辑:稍微重述一个问题:假设我将纹理清除为红色,所以当我将它渲染到屏幕时,我有红色屏幕。现在我将完全透明(颜色 0,0,0,0)的纹理渲染为所述红色纹理。我希望不会有任何变化,在渲染到屏幕后,我会看到红屏。情况并非如此,因为当我渲染透明精灵时,它实际上将 (0,0,0,0) 颜色写入纹理,我得到一个透明 window 的红色纹理。所以在将它渲染到屏幕后,我可以看到彩色屏幕被清除了。怎么回事?
您最后的评论说明了问题所在。我假设 源纹理和中间渲染目标都有一个 alpha 通道,对吗?如果是这样,您需要为颜色 和 alpha 通道使用正确的混合方程。通常,直接混合到后台缓冲区的标准方程会忽略正确的 alpha 通道混合,因为后台缓冲区 alpha 通常被忽略。我怀疑在您的情况下,颜色通道已正确混合,但最后渲染的精灵将其 alpha 值直接写入中间纹理。因此,这些像素是完全透明的,尽管它们应该保持不透明,因为之前的绘制使它们不透明。当您随后将此纹理渲染到后台缓冲区时,相同颜色的 alpha 混合会导致这些像素对最终图像没有任何贡献。
这是对具有透明度的纹理进行标准 alpha 混合渲染的正确设置:
// dest.rgb = dest.rgb * (1 - src.a) + src.rgb * src.a
SrcBlend = SRC_ALPHA
DestBlend = INV_SRC_ALPHA
BlendOp = ADD
// dest.a = 1 - (1 - dest.a) * (1 - src.a), with some rearranging
SrcBlendAlpha = INV_DEST_ALPHA
DestBlendAlpha = ONE
BlendOpAlpha = ADD
此外,不要忘记在渲染之前将中间目标清除为透明(不是不透明的黑色,这很常见),假设您希望纹理的某些部分是渲染后透明。