XNA分层精灵问题

时间:2011-01-29 04:35:48

标签: xna rendering

我有一个管理多个精灵对象的游戏对象。每个精灵相互重叠一点,当它们处于100%不透明度时,绘制它们看起来很好。如果我将它们的不透明度设置为50%,那就是当它全部进入底池时,因为任何重叠区域由于多个层而不是50%不透明。

编辑:哎呀!出于某种原因,我认为我无法上传图片。无论如何......

http://postimage.org/image/2fhcmn6s/ - >这里是。猜猜我需要更多的代表来适当包容。

从左到右:
1.多个精灵,100%不透明度。太好了!
2.两者都是50%,但请注意重叠区域如何将它们区分为两个精灵 这是理想的行为。它们是50%不透明,但就合成图像而言。

缓解此问题的最佳方法是什么?渲染目标是个好主意吗?如果我有数百个“多精灵”怎么办?

希望这是有道理的。谢谢!

3 个答案:

答案 0 :(得分:2)

方法1:

如果你关心每个精灵的单个不透明度,那么使用50%或者想要精灵对背景的任何不透明度,将背景上的图像渲染为相同大小的渲染目标纹理。然后使用100%不透明度绘制此rendertarget。

通过这种方式,所有精灵只会在背景中混合,其他精灵将被忽略。

方法2:

如果您不关心设置每个精灵的单个不透明度,那么您只需将具有100%不透明度的所有精灵绘制到渲染目标。然后以50%不透明度在背景上绘制渲染目标。


效果问题:

我提到了两个绘制到渲染图的示例,每个示例都有不同的效果。

方法1:

您希望能够为每个精灵指定不同的不透明度。 如果是这样,您需要将每个sprite渲染为rendertarget,然后将该rendertarget纹理绘制到最终纹理。实际上,这与绘制两倍于您需要的精灵的成本相同。在这种情况下,这是400次绘制调用,这可能非常昂贵。

如果您批量调用,并为所有精灵使用单个大型渲染目标,则可能只需要2次绘制调用(具体取决于精灵的大小和纹理的最大大小)。 / p>

方法2:

每个精灵不需要不同的不透明度。 在这种情况下,无论精灵大小如何,几乎可以肯定只有2次绘制调用。 只需批量精灵的所有绘制调用(具有100%不透明度)来绘制到渲染目标。这是一个平局电话。 现在使用所需的不透明度(例如50%不透明度)在背景图像上绘制该渲染图,并且所有精灵都将具有此不透明度。 这种情况更容易实现。

答案 1 :(得分:0)

您的示例图像提醒我的第一件事是“深度缓冲和半透明表面”问题。

在3D游戏中,您必须从后到前对半透明曲面进行排序,并且只有在渲染了场景的其余部分后才能绘制它们 - 所有这些都打开了深度读取和书写。如果你不这样做,你最终会得到你的3 rd 图像,当你通常想要你的2 nd 图像时,玻璃是透明的,在背后的顶部是半透明的它

但是你想要 3 rd 图像 - 一些透明的表面遮蔽了其他图像 - 所以你可能只是故意造成这个深度问题!

要执行此操作,您需要打开深度读取和写入并设置深度函数,以便在与先前绘制的精灵相同的相同深度处绘制的第二个精灵不会渲染。

要在XNA 4.0中实现此目的,您需要将SpriteBatch.Begin设置为DepthStencilState DepthBufferFunction,将CompareFunction.Less传递给DepthBufferEnable(默认情况下,它小于 - {或等于)并且DepthBufferWriteEnablelayerDepth设置为true。

可能存在与精灵的BasicEffect参数的交互(我不记得它默认如何映射到深度)。

可能还需要使用{{1}}作为精灵批处理的着色器 - 特别是你可以设置一个具有适当的近和远平面的投影矩阵。 This article解释了如何做到这一点。您可能还需要事先清除深度缓冲区。

最后,您需要以正确的顺序绘制精灵 - 首先使用不显眼的精灵。

我不是完全确定这是否有效以及它是否可靠运行(也许你会得到某种深度对抗问题,我不确定)。但我觉得值得一试,因为你可以让你的渲染代码基本上正常,只需调整你的渲染状态。

答案 2 :(得分:0)

你应该首先尝试安德鲁答案中的内容,但是如果这不起作用,你仍然可以将所有精灵(假设它们都具有相同的不透明度)渲染到具有100%不透明度的RenderTarget(2D)上,并且然后将RenderTarget渲染到50%的屏幕。

XNA 4.0中的类似内容:

RenderTarget2D rt = new RenderTarget2D(graphicsDevice, 
                                       graphicsDevice.PresentationParameters.BackBufferWidth,
                                       graphicsDevice.PresentationParameters.BackBufferHeight);
GraphicsDevice.SetRenderTarget(rt);
//Draw sprites
GraphicsDevice.SetRenderTarget(null);
//Then draw rt (also a Texture2D) with 50% opacity. For example:
spriteBatch.Begin();
spriteBatch.Draw(rt, Vector2.Zero, Color.FromArgb(128, Color.White));
spriteBatch.End();