2016-01-22 79 views
0

我努力做到以下几点:Alpha混合利用两个渲染目标(的DirectX或OpenGL)

  • 创建一个透明的质感称为T

  • 渲染一个名为Q纹理四到T

  • 渲染吨至屏幕

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

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

我用这种混合等式

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

的情况下,当我直接呈现补足至屏幕,但不能定义实现同样的事情时,我第一次呈现给T这两种混合方程。

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

+0

对不起,我已经纠正了我的问题零应该是一个。 – keith

回答

0

我已经想通了这一点,并赋予它不是我在其他地方看到在互联网上,我希望这会帮助别人......

对于第一个混合式,为四边形Q渲染与T :

Q - >Ť

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

对于第二共混物方程,T将在屏幕:

笔 - >取值

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

说明

对于化合物Q - > T,对于彩色分量的方程式是按正常阿尔法混合方程:

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

但是我们需要确保alpha通道是为第二部分设立的。因为我们使用这个混合等式有效地将Q的alpha值预渲染到T上,所以我们只需要第二阶段的alpha就可以确定在渲染T的时候屏幕颜色的暗淡程度,因此Alpha所述第一等式为:

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}。

+0

我不认为这是正确的。看看你的Q->Tα方程(alpha = 1 * srcAlpha +(1-srcAlpha)* destAlpha)。如果你要渲染两个四边形,都是0.5 alpha,那么将会使得T的alpha 1.0,当它应该是0.75时。 – Columbo

+0

@Columbo,我认为你是不正确的。如果quad是一个像素并且具有'color {c,c,c,0.5}',则第一个渲染为T的四元组的alpha将为:'alpha = 1 * srcAlpha +(1 - srcAlpha)* destAlpha'其中' srcAlpha = 0.5'和'destAlpha = 0',因为destAlpha是最初为零的T的alpha。在顶部呈现的第二个Q将是:'srcAlpha = 0.5',现在在T'destAlpha = 0.5'中(从T中的先前呈现的四元组),其从'alpha = 1 * srcAlpha给出'0.75'的T的正确的字母+(1 - srcAlpha)* destAlpha'。我也试过了,看到它有效:-) – keith

+0

对不起。你是对的。 – Columbo

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); 

与源的α确定增加了传入颜色的百分比。

+0

我很感激你花时间回复。我设法弄清楚了这一点。也许我提出的问题很糟糕,但我认为混合方程只做线性插值的假设是不正确的。在解决方案中,我的第二个方程式是'color = src * 1 + dst *(1 - srcAlpha)',它不是线性插值。这只是类似于混合函数f(x)'形式为'a *(x)+ b *(1 - x)',而不是'a + b *(1 - x)'。 – keith

0

我想这样的作品呈现Q入T时:

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

编辑:关于它的思考,我的回答会不会导致屏幕的Alpha通道匹配,当你直接渲染你所描述的alpha通道进入屏幕。直接渲染到屏幕时,您的alpha混合模式非常不寻常。我不确定是否真的希望屏幕的alpha代表您渲染的最后一个纹理的alpha,或者您是否确实不在乎屏幕的alpha通道是什么样子。在大多数渲染情况下,人们并不关心后台缓冲区的alpha通道的状态,希望情况就是这样,我的答案适用于您。