2

本质上,我想做的(在 DirectX 中)是拍摄两个部分透明的图像并将它们混合在一起。这适用于默认混合,只要它们都显示为重叠等。但是,问题是不透明度在两者相交处显着上升。随着更多精灵重叠,这会导致越来越多的问题。我想做的是保持混合不变,除了为所有这些混合的精灵保持全局不透明度,不管它们如何重叠。

似乎会有一个渲染设置(所有这些精灵在他们的精灵批次中都是单独的,这使得这部分很容易),但如果是这样我不知道。现在我有点在黑暗中拍摄,我尝试了很多不同的东西,但没有一个看起来完全正确。我知道我可能需要某种 D3DBLENDOP 变体,但我只是不知道我真正需要什么样的设置(我已经尝试了很多东西,但现阶段都是猜测)。

这是标准混合实际发生的情况的屏幕截图(我能得到的最好的):http ://arcengames.com/share/FFActual.png这是一个屏幕截图,其中包含我希望如何混合的样机输出(在 Photoshop 中将力场添加到同一层,然后给定一个共享的 alpha 值):http ://arcengames.com/share/FFMockup.png

这就是我在 Photoshop 中的做法: 1. 拍摄两张图像,并移除所有透明度(完全透明的像素除外)。2. 将它们组合成一层,混合颜色但完全没有部分 alpha。3. 现在将该层的全局透明度设置为(比如说)40%。

结果是看起来有点混合在一起的颜色,但重叠部分的不透明度没有增加。

更新:好的,非常感谢下面的 Goz,他建议使用 Z-Buffer。这样可行!总的来说,混合是完美的,正是我想要的。唯一剩下的问题?使用这种新方法,在最后渲染的力场图像边缘周围会出现巨大的伪影。看到这个: http ://www.arcengames.com/share/FFZBuffer.png

更新:以下是 C# (SlimDX) 中的最终解决方案

  1. 每帧将 ZBuffer 清除为黑色、透明或白色都具有相同的效果(这是在调用 BeginScene 之前)

Direct3DWrapper.ClearDevice(SlimDX.Direct3D9.ClearFlags.ZBuffer, Color.Transparent, 0);

  1. 所有其他精灵都在 Z=1 处绘制,并为它们禁用 ZBuffer:

device.SetRenderState(RenderState.ZEnable, ZBufferType.DontUseZBuffer);

  1. 力场精灵在 Z=2 处绘制,启用 ZBuffer 并启用 ZWrite,ZFunc 为 Less:

device.SetRenderState(RenderState.ZEnable, ZBufferType.UseZBuffer); device.SetRenderState(RenderState.ZWriteEnable, true); device.SetRenderState(RenderState.ZFunc, Compare.Less);

  1. 这时候还设置了以下标志,以防止我遇到的黑边神器:

device.SetRenderState(RenderState.AlphaTestEnable, true); device.SetRenderState(RenderState.AlphaFunc, Compare.GreaterEqual); device.SetRenderState(RenderState.AlphaRef, 55);

请注意,AlphaRef 为 55,因为在我使用的特定源图像中设置了 alpha 级别。如果我的源图像具有更高的 alpha 值,那么 AlphaRef 也需要更高。

4

3 回答 3

1

我能说的最好的是力场是一个完整的对象。为什么不最后渲染它们,从前到后顺序,并启用 Z 缓冲。这会给你你想要的效果。

即它没有混合设置那是你的问题。

编辑:那你可以使用渲染到纹理吗?如果这样你就可以轻松地做你在 Photoshop 下所做的事情。将它们一起渲染到纹理中,然后将纹理重新混合到屏幕上。

编辑2:怎么样

ALPHATESTENABLE  = TRUE;
ALPHAFUNC = LESS

ALPHABLENDENABLE = TRUE;
SRCBLEND = SRCALPHA;
DESTBLEND = INVSRCALPHA;

SEPERATEALPHABLENDENABLE = TRUE;
SRCBLENDALPHA = ONE;
DESTBLENDALPHA = ZERO;

您需要确保每帧帧缓冲区中的 alpha 被清除为 0xff。然后你做标准的阿尔法混合。同时将 alpha 值直接传递到后台缓冲区。不过,这是 alpha 测试的用武之地。您可以对照后台缓冲区中的值来测试最终的 alpha 值。如果它小于后缓冲区中的内容,则该像素尚未混合,将被放入帧缓冲区。如果它等于(或更大),那么它已经被混合并且 alpha 值将被丢弃。

也就是说......使用 Z-Buffer 会花费你大量的 RAM,但总体上会更快,因为它能够在管道中更早地丢弃像素。鉴于所有防护罩只需要写入给定的 Z 平面,您甚至不需要经历我之前建议的地狱。如果它接收到的 Z 值小于已经存在的值,那么它会渲染它,如果它大于或等于它就会丢弃它,幸运的是在执行混合计算之前。

也就是说......你也可以通过使用模板缓冲区来做到这一点,无论如何都需要一个 Z 缓冲区。

无论如何......希望其中一种方法能有所帮助。

Edit3:您是否在边缘周围使用某种形式的羽化来渲染力场?边缘很可能是由于 alpha 略微淡化,然后“轻微 alpha”像素被写入 z 缓冲区,因此任何后续绘制都不会覆盖它们。

尝试以下设置

ALPHATESTENABLE = TRUE
ALPHAFUNC = GREATEREQUAL // if this doesn't work try less .. i may be being a retard
ALPHAREF = 255

要微调边缘周围的羽化,请调整 alpharef,但我怀疑您需要保持如上。

于 2009-08-26T06:47:09.053 回答
1

您可以指定将两个图像混合在一起用于 Alpha 通道时使用的D3DBLENDOP 。听起来您D3DBLENDOP_ADD当前正在使用 - 尝试将其切换为D3DBLENDOP_MAX,因为这只会使用“最不透明”图像的不透明度。

于 2009-08-20T17:24:12.680 回答
1

由于两个力场的颜色相同,因此很难从模型中准确说出您要完成的工作;你想混合颜色并限制 alpha 吗?只取其中一种颜色?

根据上面的讨论,不清楚您是否设置了所有相关的渲染状态:

D3DRS_ALPHABLENDENABLE = TRUE(默认值:FALSE)

D3DRS_BLENDOP = D3DBLENDOP_MAX(默认值:D3DBLENDOP_ADD)

D3DRS_SRCBLEND = D3DBLEND_ONE(默认值:D3DBLEND_ONE)

D3DRS_DESTBLEND = D3DBLEND_ONE(默认值:D3DBLEND_ZERO)

听起来您正在设置前两个,但是后两个呢?

于 2009-08-26T02:06:40.337 回答