En Minecraft cuando miras el agua, cuanto más profunda ves, más oscura se vuelve. ¿Alguien sabe cómo codificar algo así?
Minecraft con efecto
juego similar sin efecto
En Minecraft cuando miras el agua, cuanto más profunda ves, más oscura se vuelve. ¿Alguien sabe cómo codificar algo así?
Minecraft con efecto
juego similar sin efecto
Respuestas:
Básicamente, existen dos enfoques diferentes para iluminar el agua según la profundidad:
Minecraft utiliza iluminación basada en vóxel, que funciona mediante la propagación de la luz a los cubos adyacentes, reduciendo el brillo según el tipo de bloque. Los océanos oscuros son un efecto secundario de este sistema.
El agua bloquea la luz solar y reduce la luz en 3 niveles por bloque (en lugar del nivel predeterminado de 1), lo que significa que el brillo en un océano para cada distancia de la superficie es:
0 (surface): 15 (direct sunlight)
1: 12
2: 9
3: 6
4: 3
5 and below: 0 (darkness)
Fuente: Minecraft Wiki - Light
En los juegos con un modelo de iluminación tradicional, este efecto puede crearse midiendo la cantidad de agua que se encuentra entre la fuente de luz y el fondo del océano. La luz se desvanece en función de esta distancia. Hay algunos métodos para hacer esto:
Si tiene una superficie plana, puede calcular fácilmente la distancia que recorre la luz en el agua si pasa la superficie normal lejos del cuerpo de agua y el producto escalar de esta normal y una posición de superficie en el sombreador de geometría.
La distancia efectiva del agua es
donde es la posición del vértice y es el ángulo entre la dirección de la luz debajo de la superficie y la superficie del agua normal hacia el cuerpo de agua.
Al atardecer, solo alcanza un poco menos de 50 ° porque la luz se refracta al ingresar al agua.
Aquí hay una publicación de blog con una buena explicación: La cámara digital: reflexión interna total
Otra publicación con más detalles: La cámara digital: Ley de refracción de Snell
Si está utilizando un mapa de altura en una superficie paralela al agua, se convierte en . El factor correcto es igual a 1 si el sol está directamente sobre la superficie del agua.
Con un punto de luz, debe calcular para cada vértice en función de la posición relativa a la fuente de luz.
Con un nivel de agua fijo o una dirección de luz fija, partes de la ecuación son constantes y no deben calcularse en el sombreador por razones de rendimiento.
Si representa la superficie del agua en un mapa de profundidad separado (como se ve desde la fuente de luz), puede usar esa textura de profundidad para calcular la distancia que recorre la luz en el agua antes de tocar la superficie.
Para hacer esto, proyecta cada vértice en la proyección de vista de la fuente de luz en el sombreador de vértices y realiza la búsqueda de textura en el sombreador de píxeles.
Si la superficie es relativamente plana, debe usar un origen de luz refractada para obtener mejores resultados.
* Puede determinar la cantidad de agua frente a la superficie sólida más cercana contando la profundidad desde el punto de vista de la luz de la siguiente manera:
La textura resultante ahora contiene la cantidad de agua frente a la luz en el espacio de visualización de la luz, por lo que el valor debe transformarse antes de usarlo. Este método funciona para calcular la luz direccional (menos la refracción), pero conducirá a una luz ambiental incorrecta si las superficies son muy irregulares y hay una gran cantidad de aire entre los cuerpos de agua que afectan los mismos fragmentos.
Los pros y los contras son los mismos que para el mapeo de sombras normal, excepto que necesita un búfer más al calcular la profundidad y el rendimiento es peor porque tiene que dibujar más geometría.
El trazado de rayos es, con mucho, la solución más precisa pero también la más costosa para renderizar volúmenes transparentes. Hay dos formas de hacer esto: 1. Trazar desde el fondo del océano hacia la superficie y 2. Trazar desde la fuente de luz hacia el agua. Se necesitan múltiples rayos para cada punto en el piso para calcular el brillo.
Hay algunas cosas más a tener en cuenta al procesar el agua:
La luz en el agua se dispersa nuevamente mientras viaja hacia el observador, por lo que debe mezclarla hacia un color sólido.
Si el observador está sumergido , solo puede generar niebla en función del resultado final del búfer de profundidad. ¡El color de la niebla, pero no su densidad, debería cambiar con la distancia del observador desde la superficie! (Minecraft solo usa esta parte del efecto).
Si el observador mira el agua desde arriba , debe calcular la niebla en función de la diferencia de profundidad entre la superficie y la geometría bajo el agua. El color de la niebla debería oscurecerse un poco con mayores diferencias de profundidad, pero solo debería cambiar al punto donde la niebla es completamente opaca.
El color de la niebla también debe depender de la dirección de la vista para cada píxel, por lo que es ligeramente más oscuro cuando se mira hacia abajo en ambos casos.
Si utiliza una textura 3D de mosaico sin costuras en lugar de una calcomanía para cáusticos falsos, puede evitar estirarse en superficies verticales. La intensidad de la luz dispersa cerca de la superficie varía en tres dimensiones, por lo que el uso de una textura 2D generalmente produce estiramiento en algún lugar de la escena. Puede modelar los ángulos de luz cambiantes proyectando las posiciones de vértice del piso en un sistema de coordenadas diferente.
Otra posibilidad es calcular la densidad de la luz en función de la posición de la superficie en el sistema de coordenadas de la luz, aunque lo más probable es que cueste algo de rendimiento.
Los cáusticos deberían desvanecerse más rápido que la luz difusa al aumentar la profundidad.
Los colores se dispersan de manera diferente, por lo que el color claro debería cambiar con el aumento de la profundidad. Esto también evita bordes abruptos donde, por ejemplo, una playa se cruza con la superficie del agua.
Debido a la refracción, la luz golpea el fondo del océano mucho más empinada de lo normal. El artículo de Wikipedia sobre la ley de Snell tiene fórmulas para ángulos y vectores.
Creo que el efecto de iluminación del cielo en Minecraft es directo: las cosas se sombrean por lo que está encima de ellos, sin importar dónde esté el sol. Luego, la iluminación local de antorchas, etc., se aplica con un efecto de caída: cuanto más lejos de la fuente de luz, menos luz obtiene un cubo.
Si se hace de esta manera, cada capa de agua sombreará acumulativamente la capa debajo de ella, por lo que cada una se volverá progresivamente más oscura. El follaje de los árboles proporciona sombra como esta, sin embargo, no es acumulativa. Obtiene la misma sombra debajo de un árbol, ya sea 1 o 100 cubos de follaje.
Una pista de que este es el método que se utiliza es que el agua no se oscurece cuando se aleja del espectador, solo a medida que baja. Sí, el efecto de niebla se activa a distancia, pero no el efecto de oscuridad del agua.
Entonces, la fórmula básica para calcular la iluminación sería algo así en pseudocódigo ...
light_on_cube = 1.0
for each cube above target cube, from lowest to highest {
if cube being examined is tree foliage
light_on_cube = 0.5
else if cube being examined is water
light_on_cube = light_on_cube - 0.1
else if cube being examined is solid
light_on_cube = 0
}
Esto no es perfecto para calcular la iluminación debajo de voladizos o en cuevas, ya que con este método se oscurecería bajo un voladizo. Pero uno podría agregar tanto fuentes de luz locales (antorchas, fuegos, etc.) como tratar los bloques iluminados por el sol como fuentes de luz. Algo como esto podría hacerlo ...
La idea aquí es que si un cubo está iluminado por el sol o una antorcha, el cubo al lado también se encenderá de alguna manera. Y cuanto más lejos esté de ese cubo iluminado, menos luz habrá. Es una especie de mala manera de estimar la iluminación difusa, pero creo que (?) Funcionaría.
Tal vez estoy malinterpretando la pregunta, pero ¿por qué no puedes cambiar el color de los bloques dependiendo de su profundidad?
Si tiene la profundidad d (en bloques, comenzando en 0), una ecuación razonable para el brillo sería:
L = (1- m ) e - kd + m
Código: L = (1.0 - m) * exp(-k * d) + m;
k controla qué tan rápido se oscurece (más alto = más rápido). Un valor razonable sería 0.5.
m es el brillo mínimo que desea.
L varía de 0 a 1.
Si no sabe cómo cambiar el color de los bloques en cualquier API de gráficos que esté utilizando, hágalo como una pregunta por separado (indicando qué API utiliza y si está utilizando sombreadores).
e^-kd
bit es solo una disminución exponencial, que es una función estándar para cosas que gradualmente tienden a cero sobre algún valor (profundidad). La multiplicación por (1-m)
y la suma de m
son solo para escalar y compensar la desintegración de modo que termine en un mínimo de m
pero aún comience en 1
. en.wikipedia.org/wiki/Exponential_decay