¿Cómo puedo implementar una iluminación suave basada en baldosas?

8

He estado trabajando en un juego de fichas 2D y he implementado una iluminación de bordes duros:

ingrese la descripción de la imagen aquí

Quiero que se suavice un poco. No necesito sombras ni nada, solo iluminación simple. Me gustaría que se parezca más a esto:

ingrese la descripción de la imagen aquí

Mi sistema actual utiliza niveles de luz para cada mosaico en el mundo y se recalculan cuando se coloca o elimina un mosaico. Estoy usando batch.setColor(...)para sombrear los azulejos. ¿Cuál es una buena manera de lograr esta iluminación suave?

No quiero usar el método de superposición de mapas claros, ya lo intenté y no estaba contento con el resultado. Quiero poder establecer cuánta luz puede pasar a través de un bloque. Por ejemplo, un bloque de tierra debería absorber algo de la luz, pero un bloque de vidrio no debería bloquear ninguna luz. Esto no fue realmente posible con el método de superposición de mapa de luz. ACTUALIZACIÓN: no entendí qué es realmente este método. Entiendo ahora. Estaba pensando en el camino equivocado. ¡Lo siento!

ProRed
fuente
Para ser sincero, se ve más elegante con una iluminación de bordes duros.
S. Tarık Çetin
No me gusta tanto, también es un poco difícil diferenciar los mosaicos de fondo y los mosaicos de primer plano con este estilo.
ProRed

Respuestas:

15

Una forma simple de lograr una iluminación suave en un juego basado en fichas es dibujar un "mapa de luz" en un objetivo de renderizado y luego dibujar este objetivo de renderizado sobre la escena mientras se mezcla alfa.

El objetivo de representación de su mapa de luz sería del tamaño de su mapa de mosaico, pero en píxeles. Cada píxel representaría el color claro de su mosaico correspondiente. Esta textura de renderizado se vería así (textura superior izquierda en blanco y negro):

ingrese la descripción de la imagen aquí

Una vez que tenga esta textura ligera del mapa, puede dibujarla como una superposición sobre su mundo de juego (extendido). Tendrás que sujetarlo correctamente, para que se extienda perfectamente sobre tus fichas en el mundo del juego.

Entonces es una cuestión de alfa mezclar esta textura en su mundo de juego en libGDX. Para combinar LibGDX (personalmente no sé cómo), es posible que tenga que mirar la Gdx.gl.glBlendFuncfunción.

jgallant
fuente
2
Puede controlar la iluminación de la manera que desee con este sistema. No estoy seguro de a qué se refiere cuando dice que no puede bloquear la luz. Además, no estoy completamente seguro de cómo planea suavizar su sistema actual, ya que literalmente solo está coloreando sus mosaicos.
jgallant
44
Por cierto, este sistema es la forma en que Starbound lo hace.
Qqwy
2
Este es un gran enfoque y permite flexibilidad donde se necesita. Lo uso en mi juego basado en fichas, donde no tengo acceso a sombreadores, ¡y funciona muy bien!
Tyyppi_77
1
ACTUALIZACIÓN : Este parece ser el camino a seguir, entendí mal este método y ahora entiendo completamente ¡Intentaré implementar este método ahora y lo marcaré como la mejor respuesta y te daré la recompensa!
ProRed
2
Si tiene más preguntas sobre cómo hacerlo, no dude en preguntar. He implementado esto, y @ Tyyppi_77 también lo ha hecho recientemente. Lo hice en XNA / Monogame y Unity. Tyyppi lo ha hecho en SDL.
jgallant
4

Una forma agnóstica del motor para hacerlo es utilizar el mapeo de luz promedio. Primero, debe generar un mapa en blanco y negro como una matriz 2D de booleanos del tamaño del mundo donde los bloques son Verdaderos y los vacíos es Falso.

Así (1 es negro, 0 es blanco): mapa

Luego, debe crear una nueva matriz 2D que tenga el mismo tamaño que la primera matriz pero que sea una matriz de flotadores. Luego pasa del bloque negro (Verdadero) al bloque negro en la matriz y promedia el valor muestreado cercano (explicado a continuación)

Esta imagen ayudará: promediado

Esta imagen representa el muestreo (donde + significa falso y | significa verdadero). lo que hacemos es tratar los valores verdaderos como 1 y los valores falsos como 0. Luego, promedia los 9 números y los coloca en la parte correcta de la matriz. NOTA: Asegúrese de que cuando muestrea aristas utilice los valores externos como sensibles al contexto. Por ejemplo: bajo tierra, el mapa fuera del mundo podría ser 1 y el cielo debería ser 0.

Debería verse así (tomado de otra publicación):final

Entonces, todo lo que tiene que hacer es teñir cada bloque de la matriz con

rgba(tint,tint,tint,1)

(tint = el valor de bloque promedio actual en la segunda matriz y alfa no importa). Nota: esto supone que la pseudofunción rgba toma flotantes de 0-1 en lugar de 0-255, si es así, simplemente haga esto:

rgba(tint*255,tint*255,tint*255,255)

Espero que esto tenga un poco de sentido :) Si quieres código, por favor pregunte!

UDXS
fuente
Gracias por tu respuesta, pero la cosa es que ya tengo iluminación dura en mi juego ( aquí ). Pregunté cómo podría cambiar esto para que se vea más suave ( así )
ProRed
1

Como estás hablando de cosas que bloquean la luz, supongo que tienes algún modelo de cómo debería extenderse la luz. Por ejemplo, todo lo que no tiene bloques encima está completamente iluminado, la luz se extiende a todas las celdas vecinas pero pierde una cierta cantidad de brillo.

Debería poder implementar esas reglas con bastante facilidad en el lado del software, al menos la parte de suavizado es solo una cuestión de arrojar algo de sombreador en el mapa de luz que ha generado.

Los métodos que otros han sugerido para superponer un mapa de luz es algo que debe hacer de todos modos. Pero puede cambiar cómo genera este mapa de luz. Inicialmente puede llenarlo solo con la información del bloque, pero luego puede escalarlo y suavizarlo en un sombreador, por ejemplo. Un beneficio adicional del enfoque del mapa de luz es que simplemente puede dibujar luces dinámicas en su mapa de luz para resaltar explosiones o lo que sea que tenga, y naturalmente se combinará con el resto de su mundo.

Aditivo mezcla cosas en tu mapa de luz y luego multiplicativa mezcla tu mapa de luz con el mundo del juego.

Hice esto hace un tiempo que usa los mismos principios. Este sistema no admite que la caída de luz sea diferente para diferentes tipos de terreno, pero al menos debería ilustrar la utilidad de superponer un mapa de luz.

Nils Ole Timm
fuente
Ya veo, ¿entonces renderizaría los niveles de luz en forma de rectángulos que son exactamente del tamaño del mosaico correspondiente a un segundo objetivo de renderizado? ¿Y cómo haría para suavizarlo?
ProRed
Puede dejar que la GPU lo maneje disminuyendo el muestreo, ya que al renderizarlo se interpolará linealmente por usted. Si eso no es lo suficientemente bueno, puede ejecutar algún tipo de desenfoque sobre él en un sombreador. También puede considerar renderizar con una granularidad más fina que la resolución de mosaico si desea dibujarlo de manera diferente dependiendo de los mosaicos adyacentes. Básicamente, la parte difícil es encontrar las reglas específicas que desea para qué área se debe iluminar cuánto. Si escribe esas reglas, generalmente encontrará una manera bastante sencilla de hacerlo.
Nils Ole Timm
1

Es bastante fácil para una antorcha: usando un sombreador de píxeles personalizado, calcula la distancia entre cada fragmento y la antorcha; A continuación, puede calcular dónde está el primer mosaico denso que bloquea la luz que proviene de la antorcha. Luego calcula la distancia donde la luz no está bloqueada, multiplique eso por algo <1 para que la antorcha no encienda el sol, reste eso de la distancia total y repita por el resto de la distancia (donde la luz fue bloqueada por menos un mosaico) con un valor de multiplicación mucho más pequeño ... Sé cómo hacer esta matemática y no es demasiado complicado de implementar en opengl.

EDITAR: para una fuente de luz simple con un punto central específico, mi método es extremadamente simple. Sin embargo, el mío no funciona con la luz solar, pero si bien el mapa alfa funciona muy bien para la luz solar, NO sería una buena idea para una antorcha, dado que es potencialmente un objeto en movimiento, y hacer un nuevo mapa en cada cuadro no es agradable. experiencia de vida. La mejor solución en mi opinión es una combinación: cálculo de distancia para luces específicas que en realidad son objetos en el juego, un sombreador separado que simplemente arrojas sobre el mapa alfa que generaste procesalmente usando la técnica mencionada anteriormente: una textura de todos los mosaicos alfa de tu sombreado duro, como muchos cuadrados, y desordenar con técnicas para suavizarlo.

Paul Boursin
fuente
0

¿Su renderizado usa colores de vértice (o puede cambiarlo)?

Suponiendo que cada bloque es un cuadrado de 4 vértices, eso le daría un par de opciones, por ejemplo:

Si su algoritmo de iluminación actual le da un valor de luz por bloque, puede cambiarlo para obtener un valor por vértice. Alternativamente, en cada vértice puede promediar el color de la luz del bloque actual más sus tres vecinos. Cualquiera de las soluciones sería económica.

Programador de juegos crónicos
fuente