具有两个渲染目标的Alpha混合(DirectX或OpenGL)

时间:2016-01-22 17:10:16

标签: opengl colors directx

我正在尝试执行以下操作:

  • 创建一个名为T

  • 的透明纹理
  • 渲染一个名为Q的纹理四边形到

  • 将T渲染到屏幕

请注意,T的alpha分量将为零,Q的alpha分量可能小于1。

我需要两个alpha混合方程,这样如果我渲染Q到T的多个实例(使用第一个混合方程)然后渲染T(使用第二个混合方程),它将直接渲染Q的多个实例屏幕。

我使用这个混合方程式

color = src * srcAlpha + dst * (1 - srcAlpha)
alpha = 1 * srcAlpha + 0 * destAlpha

对于我直接将Qs渲染到屏幕的情况,但是当我首先渲染到T时,无法定义两个实现相同事物的混合方程式。

请注意,T的像素最初是完全透明的(alpha = 0),因为我不希望它覆盖屏幕(如果它没有被绘制)。 Q可能在每个像素中都有任何透明度级别。

3 个答案:

答案 0 :(得分:0)

使用线性插值在数学上是不可能的。

假设您有两个透明对象AB。您有纹理T和屏幕SBlend是混合方程式。

您在渲染T时所做的是:

T = Blend(B, Blend(A, T))
S = Blend(T, S)

//Therefore
S = Blend(Blend(B, Blend(A, T)), S)

了解这里有3个独立的混合操作?使用两个混合操作无法做到这一点。如果您渲染AB,那么这就是您的全部。

线性插值既不是commutative也不是associative。混合操作的顺序很重要。通过写入临时中间体并将其与最终缓冲区混合而实现的效果无法在没有中间的情况下实现

有混合操作是关联和可交换的。例如,添加剂。但这几乎肯定不会达到你想要的视觉效果,因为它会将颜色加在一起。如果你正在做HDR照明,这可能是你可以使用的东西。但是在很多情况下这是不合适的。

添加剂混合将涉及以下形式的混合方程:

glBlendFunc(GL_SRC_ALPHA, GL_ONE);

使用源alpha确定要添加的传入颜色的百分比。

答案 1 :(得分:0)

我认为这在将Q渲染到T:

时有效
color = src * srcAlpha + dst * (1 - srcAlpha)
alpha = (1 - destAlpha) * srcAlpha + 1 * destAlpha

编辑:想一想,我的答案不会导致屏幕的Alpha通道与您在直接渲染到屏幕时描述的Alpha通道相匹配。直接渲染到屏幕时,您的Alpha混合模式非常不寻常。我不确定你是否真的希望屏幕的alpha表示你渲染的最后一个纹理的alpha,或者你是否真的不关心屏幕的alpha通道是什么样的。在大多数渲染情况下,人们并不关心后台缓冲区的alpha通道的状态,希望这就是这种情况,我的回答对你有用。

答案 2 :(得分:0)

我已经想到这一点,并且鉴于它不是我在互联网上其他地方看到的东西,我希望这会帮助其他人......

对于第一个混合方程,对于四边形Q渲染到T:

Q - > Ť

color = src * srcAlpha + dst * (1 - srcAlpha)
alpha = 1 * srcAlpha + (1 - srcAlpha) * destAlpha

对于第二个混合方程,T进入屏幕:

T - >小号

color = src * 1 + dst * (1 - srcAlpha)
alpha = doesn't matter as screen alpha isn't used

<强>解释

对于Q - &gt; T,颜色分量的等式是按照正常的α混合等式:

color = src * srcAlpha + dst * (1 - srcAlpha)

但是我们需要确保为第二部分设置alpha通道。因为我们在使用这个混合方程渲染到T时有效地预先乘以Q的alpha,我们只需要在第二阶段中使用alpha来确定在渲染T时调暗屏幕颜色的颜色,因此alpha in第一个等式是:

alpha = 1 * srcAlpha + (1 - srcAlpha) * destAlpha

但是我们只使用它来淡化第二个等式中T颜色后面的目标颜色(我们使用1作为src颜色,因为它预先乘以等式1):

color = src * 1 + dst * (1 - srcAlpha)

在DirectX 11中,无论使用等式1直接渲染到屏幕还是两个等式用于渲染到T然后用于屏幕,这都会得到相同的结果。

DirectX 11代码(适用于喜欢真实代码的用户):

第一个等式:

D3D11_BLEND_DESC blend{};

blend.AlphaToCoverageEnable = FALSE;

auto& target = blend.RenderTarget[0];

target.BlendEnable = TRUE;
target.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

target.SrcBlend = D3D11_BLEND_SRC_ALPHA;
target.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
target.BlendOp = D3D11_BLEND_OP_ADD;

target.SrcBlendAlpha = D3D11_BLEND_ONE;
target.DestBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
target.BlendOpAlpha = D3D11_BLEND_OP_ADD;

第二个等式:

D3D11_BLEND_DESC blend{};

blend.AlphaToCoverageEnable = FALSE;

auto& target = blend.RenderTarget[0];

target.BlendEnable = TRUE;
target.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

target.SrcBlend = D3D11_BLEND_ONE;
target.DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
target.BlendOp = D3D11_BLEND_OP_ADD;

target.SrcBlendAlpha = D3D11_BLEND_ZERO;
target.DestBlendAlpha = D3D11_BLEND_ONE;
target.BlendOpAlpha = D3D11_BLEND_OP_ADD;

T最初被清除为{0,0,0,0}。