¿Qué tal algo como esto?
No dibujes tu iluminación teñiendo tus sprites de azulejos. Dibuja tus fichas no iluminadas en un objetivo de representación, luego dibuja las luces de la ficha en un segundo objetivo de representación, representando cada una como un rectángulo en escala de grises que cubre el área de la ficha. Para renderizar la escena final, use un sombreador para combinar los dos objetivos de renderizado, oscureciendo cada píxel del primero de acuerdo con el valor del segundo.
Esto producirá exactamente lo que tienes ahora. Eso no te ayuda, así que cambiémoslo un poco.
Cambie las dimensiones de su objetivo de representación de mapa de luz para que cada mosaico esté representado por un solo píxel , en lugar de un área rectangular. Al componer la escena final, use un estado de muestra con filtrado lineal. De lo contrario, deje todo lo demás igual.
Suponiendo que ha escrito su sombreador correctamente, el mapa de luz debe "ampliarse" efectivamente durante la composición. Esto le proporcionará un agradable efecto de degradado de forma gratuita a través de la muestra de textura del dispositivo gráfico.
También es posible que pueda cortar el sombreador y hacer esto de manera más simple con un BlendState 'oscurecedor', pero tendría que experimentar con él antes de poder darle los detalles.
ACTUALIZAR
Hoy tuve algo de tiempo para burlarme de esto. La respuesta anterior refleja mi hábito de usar sombreadores como mi primera respuesta a todo, pero en este caso no son realmente necesarios y su uso complica innecesariamente las cosas.
Como sugerí, puede lograr exactamente el mismo efecto utilizando un BlendState personalizado. Específicamente, este BlendState personalizado:
BlendState Multiply = new BlendState()
{
AlphaSourceBlend = Blend.DestinationAlpha,
AlphaDestinationBlend = Blend.Zero,
AlphaBlendFunction = BlendFunction.Add,
ColorSourceBlend = Blend.DestinationColor,
ColorDestinationBlend = Blend.Zero,
ColorBlendFunction = BlendFunction.Add
};
La ecuación de fusión es
result = (source * sourceBlendFactor) blendFunction (dest * destBlendFactor)
Entonces, con nuestro BlendState personalizado, eso se convierte
result = (lightmapColor * destinationColor) + (0)
Lo que significa que un color de origen de blanco puro (1, 1, 1, 1) conservará el color de destino, un color de origen de negro puro (0, 0, 0, 1) oscurecerá el color de destino a negro puro, y cualquier el tono de gris intermedio oscurecerá el color de destino en una cantidad media.
Para poner esto en práctica, primero haga lo que tenga que hacer para crear su mapa de luz:
var lightmap = GetLightmapRenderTarget();
Luego, dibuje su escena apagada directamente en el backbuffer como lo haría normalmente:
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend);
/* draw the world here */
spriteBatch.End();
Luego dibuje el mapa de luz usando el BlendState personalizado:
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();
Esto multiplicará el color de destino (mosaicos no iluminados) por el color de origen (mapa de luz), oscureciendo adecuadamente los mosaicos no iluminados y creando un efecto de gradiente como resultado de que la textura del mapa de luz se escala al tamaño necesario.