¿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.
Bien, aquí hay un método muy simple para crear un rayo 2D simple y suave, renderizado en tres pasos:
En el pase 1 dibujas todos los sprites y el terreno.
En el pase 2 dibujas un segundo grupo de sprites que son las fuentes de luz. Deberían tener un aspecto similar a este:
inicialice el objetivo de renderizado con negro y dibuje esos sprites sobre él con la combinación máxima o aditiva.
En el pase 3, combina los dos pases anteriores. Hay múltiples formas diferentes de cómo se pueden combinar. Pero el método más simple y menos artístico es combinarlos a través de Multiply. Esto se vería así:
fuente
El segundo enlace que publicó parece una especie de niebla de guerra , hay algunas otras preguntas sobre esto
Eso me parece una textura , donde "borras" partes de la superposición negra (estableciendo el alfa de esos píxeles a 0) a medida que el jugador avanza.
Yo diría que la persona debe haber usado un tipo de "borrado" donde el jugador ha explorado.
fuente
Vértices claros (esquinas entre mosaicos) en lugar de mosaicos. Combina la iluminación en cada mosaico en función de sus cuatro vértices.
Haga pruebas de línea de visión a cada vértice para determinar qué tan iluminado está (puede hacer que un bloque detenga toda la luz o disminuya la luz, por ejemplo, cuente cuántas intersecciones a cada vértice combinadas con la distancia para calcular un valor de luz en lugar de usar un prueba binaria pura visible / no visible).
Al renderizar un mosaico, envíe el valor de luz para cada vértice a la GPU. Puede usar fácilmente un sombreador de fragmentos para tomar el valor de luz interpolado en cada fragmento en el sprite del mosaico para iluminar cada píxel sin problemas. Ha pasado suficiente tiempo desde que toqué GLSL que no me sentiría cómodo dando una muestra de código real, pero en pseudocódigo sería tan simple como:
El sombreador de vértices simplemente tiene que pasar los valores de entrada al sombreador de fragmentos, nada ni remotamente complicado.
Obtendrá una iluminación aún más suave con más vértices (por ejemplo, si cada mosaico se representa como cuatro mosaicos secundarios), pero puede que no valga la pena el esfuerzo dependiendo de la calidad que esté buscando. Pruébalo de la manera más simple primero.
fuente
line-of sight tests to each vertex
? Eso va a ser costoso.