如何在SpriteBatch Draw XNA(2D)中将两个精灵相乘

4
我正在为XNA 3.1编写一个简单的动作角色扮演游戏(hex engine)。我想在英雄附近和火把上照亮地面,就像在暗黑破坏神II中一样。我认为最好的方法是计算视野范围,隐藏玩家看不见的任何图块及其内容,并在任何光源的顶部绘制特殊的“Light”纹理:这个纹理是黑色的,中心有白色模糊的圆圈。
我想将这个纹理与背景相乘(如混合模式:multiply),但很遗憾,在SpriteBatch中我没有看到可以这样做的选项。请问有人能指点我正确的方向吗?
或者也许还有其他更好的方法来实现暗黑破坏神II中的照明模型?
3个回答

7

如果你将光纹理与场景相乘,你会使该区域变暗,而不是变亮。

你可以尝试使用加法混合渲染;这样做看起来不太对,但很容易实现,可能是可以接受的。你需要使用相当低的 alpha 值来绘制光纹理,以避免过度饱和图像的那一部分。

另一种更复杂的照明方法是将所有光纹理(用于场景中所有灯光)以加法方式绘制到第二个渲染目标上,然后将此纹理与场景相乘。这应该会给出更加逼真的照明效果,但性能开销更大且更为复杂。

初始化:

RenderTarget2D lightBuffer = new RenderTarget2D(graphicsDevice, screenWidth, screenHeight, 1, SurfaceFormat.Color);
Color ambientLight = new Color(0.3f, 0.3f, 0.3f, 1.0f);

绘制:

// set the render target and clear it to the ambient lighting
graphicsDevice.SetRenderTarget(0, lightBuffer);
graphicsDevice.Clear(ambientLight)

// additively draw all of the lights onto this texture. The lights can be coloured etc.
spriteBatch.Begin(SpriteBlendMode.Additive);
foreach (light in lights)
    spriteBatch.Draw(lightFadeOffTexture, light.Area, light.Color);
spriteBatch.End();

// change render target back to the back buffer, so we are back to drawing onto the screen
graphicsDevice.SetRenderTarget(0, null);

// draw the old, non-lit, scene
DrawScene();

// multiply the light buffer texture with the scene
spriteBatch.Begin(SpriteBlendMode.Additive, SpriteSortMode.Immediate, SaveStateMode.None);
graphicsDevice.RenderState.SourceBlend = Blend.Zero;
graphicsDevice.RenderState.DestinationBlend = Blend.SourceColor;
spriteBatch.Draw(lightBuffer.GetTexture(), new Rectangle(0, 0, screenWidth, screenHeight), Color.White);
spriteBatch.End();

2
据我所知,没有不使用自定义着色器的方法来实现这一点。
为此,您需要编写一个自定义着色器,步骤如下:
1.将场景渲染到纹理中
2.将灯光渲染到另一个纹理中
3.作为后期处理在一个空白的四边形上采样两个纹理,结果是场景纹理*灯光纹理。
这将输出一个有光照的场景,但它不会产生任何阴影。如果您想要阴影,建议遵循Catalin Zima的这个优秀示例

1

也许可以尝试使用与 BloomEffect组件相同的技术。

基本上,该效果会获取渲染场景,从场景中最亮的区域计算出一个bloom图像,然后对两个图像进行模糊和合并。结果是根据颜色突出显示区域。

在这里可以使用相同的方法。这将更简单,因为您不必根据背景计算bloom图像,只需根据角色的位置即可。

您甚至可以进一步重用此方法,为其他光源(如火炬、魔法效果等)提供突出显示。


这与我建议的类似,但可能更好,因为您可以从 bloom 示例中获取示例代码。 - Martin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接