这样的事情怎么样?
不要通过着色瓷砖精灵来绘制照明。将未照亮的图块绘制到渲染目标,然后将图块灯光绘制到第二个渲染目标,每个渲染目标均表示为覆盖图块区域的灰度矩形。若要渲染最终场景,请使用着色器组合两个渲染目标,根据第二个目标的值使第一个目标的每个像素变暗。
这将产生您现在所拥有的一切。这对您没有帮助,所以让我们对其进行一些更改。
更改光照贴图渲染目标的尺寸,以便每个图块由单个像素而不是矩形区域表示。合成最终场景时,请使用带有线性滤波的采样器状态。否则,其他所有内容均保持不变。
假设您正确地编写了着色器,则在合成期间应该有效地“放大”光照贴图。通过图形设备的纹理采样器,可以免费获得漂亮的渐变效果。
您也许还可以切出着色器,并使用“变暗”的BlendState更简单地执行此操作,但是我必须先对其进行试验,然后才能提供详细信息。
更新
我今天有一段时间实际上可以模拟这个。上面的答案反映了我使用着色器作为对所有内容的第一个答案的习惯,但是在这种情况下,它们实际上不是必需的,并且不必要地使事情变得复杂。
正如我建议的那样,您可以使用自定义BlendState来实现完全相同的效果。具体来说,此自定义BlendState:
BlendState Multiply = new BlendState()
{
AlphaSourceBlend = Blend.DestinationAlpha,
AlphaDestinationBlend = Blend.Zero,
AlphaBlendFunction = BlendFunction.Add,
ColorSourceBlend = Blend.DestinationColor,
ColorDestinationBlend = Blend.Zero,
ColorBlendFunction = BlendFunction.Add
};
混合方程为
result = (source * sourceBlendFactor) blendFunction (dest * destBlendFactor)
因此,使用我们的自定义BlendState,
result = (lightmapColor * destinationColor) + (0)
这意味着纯白色(1,1,1,1)的源颜色将保留目标颜色,纯黑色(0,0,0,1)的源颜色将使目标颜色变暗为纯黑色,并且任何介于两者之间的灰色阴影会使目标颜色变暗中等数量。
为了将其付诸实践,请首先执行创建光照贴图所需的所有操作:
var lightmap = GetLightmapRenderTarget();
然后只需像通常那样将未照明的场景直接绘制到后缓冲区即可:
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
/* draw the world here */
spriteBatch.End();
然后使用自定义BlendState绘制光照贴图:
var offsetX = 0; // you'll need to set these values to whatever offset is necessary
var offsetY = 0; // to align the lightmap with the map tiles currently being drawn
var width = lightmapWidthInTiles * tileWidth;
var height = lightmapHeightInTiles * tileHeight;
spriteBatch.Begin(SpriteSortMode.Immediate, Multiply);
spriteBatch.Draw(lightmap, new Rectangle(offsetX, offsetY, width, height), Color.White);
spriteBatch.End();
这会将目标颜色(未照明的图块)乘以源颜色(光照图),适当地使未照明的图块变暗,并由于将光照图纹理放大到所需的大小而产生渐变效果。