Comment puis-je rendre l'eau plus sombre avec de la profondeur, comme dans Minecraft?


24

Dans Minecraft, lorsque vous regardez l'eau, plus vous regardez profondément, plus elle devient sombre. Est-ce que quelqu'un sait coder quelque chose comme ça?

Minecraft avec effet minecraft avec effet

jeu similaire sans effet jeu similaire sans effet


18
N'est-ce pas fait automagiquement puisque le matériau du cube d'eau est semi-transparent?
pek

Je ne pense pas. J'ai ajouté une photo sans effet pour comparaison.
Xavier

2
Peut-être que c'est un effet de mélange additif appliqué uniquement sur les cubes d'eau? Encore une fois, cela devrait être facile car le matériau est semi-transparent.
pek

1
vous pouvez également changer la couleur des boîtes en fonction de la profondeur.
Ali1S232

Réponses:


51

Il existe essentiellement deux approches différentes pour l'éclairage de l'eau en fonction de la profondeur:

Voxel-Lighting

Minecraft utilise un éclairage à base de voxels, qui fonctionne en propageant la lumière vers les cubes adjacents, en réduisant la luminosité en fonction du type de bloc. Les océans sombres sont un effet secondaire de ce système.

L'eau bloque la lumière du soleil et réduit la lumière de 3 niveaux par bloc (au lieu du niveau par défaut 1), ce qui signifie que la luminosité dans un océan pour chaque distance de la surface est:

0 (surface): 15 (direct sunlight)
1:           12
2:            9
3:            6
4:            3
5 and below:  0 (darkness)

Source: Minecraft Wiki - Lumière

Observation en fonction de la distance

Dans les jeux avec un modèle d'éclairage traditionnel, cet effet peut être créé en mesurant la quantité d'eau qui se trouve entre la source de lumière et le fond de l'océan. La lumière s'estompe ensuite en fonction de cette distance. Il existe plusieurs méthodes pour ce faire:

Calcul direct

Si vous avez une surface plane, vous pouvez facilement calculer la distance que la lumière parcourt dans l'eau si vous passez la surface normale loin du plan d'eau \ vec {n}et le produit scalaire de cette normale et une position de surface sdans le shader de géométrie.

La distance effective de l'eau est

\ max (\ left (s - \ vec {n} \ cdot \ vec {p} \ right), 0) \ cdot \ left (1 + \ tan (\ alpha) \ right)

\ vec {p}est la position du sommet et alphaest l'angle entre la direction de la lumière sous la surface et la surface de l'eau normale vers le plan d'eau.

Au coucher du soleil, alphan'atteint qu'un peu moins de 50 ° car la lumière est réfractée en entrant dans l'eau.
Voici un article de blog avec une bonne explication: L'appareil photo numérique: réflexion interne totale
Un autre article avec plus de détails: L'appareil photo numérique: la loi de Snell de la réfraction

Si vous utilisez une carte de hauteur sur une surface parallèle à l'eau, \ left (s - \ vec {n} \ cdot \ vec {p} \ right)devient \ gauche (s - h \ droite). Le bon facteur est égal à 1 si le soleil est directement au-dessus de la surface de l'eau.
Avec une lumière ponctuelle, vous devez calculer alphapour chaque sommet en fonction de la position relative par rapport à la source de lumière.

Avec un niveau d'eau fixe ou une direction de lumière fixe, des parties de l'équation sont constantes et ne doivent pas être calculées dans le shader pour des raisons de performances.

Avantages:

  • Rapide et précis

Les inconvénients:

  • Ne fonctionne que pour les surfaces d'eau plates ou uniquement pour la lumière directement au-dessus, car une seule surface est normalement prise en compte. (La combinaison d'une surface rugueuse et d'une lumière inclinée pourrait fonctionner dans une certaine mesure avec la cartographie de parallaxe.)
  • Pas de caustiques

Cartographie des ombres

Si vous rendez la surface de l'eau sur une carte de profondeur distincte (vue depuis la source de lumière), vous pouvez utiliser cette texture de profondeur pour calculer la distance parcourue par la lumière dans l'eau avant de toucher la surface.
Pour ce faire, vous projetez chaque sommet dans la projection de vue de la source lumineuse dans le vertex shader et effectuez la recherche de texture dans le pixel shader.

Si la surface est relativement plate, vous devez utiliser une origine de lumière réfractée pour de meilleurs résultats.

Avantages:

  • Fonctionne avec une géométrie de l'eau relativement complexe, tant qu'elle ne se bouche pas. *
  • Peut être réutilisé pour presque tout type de volume partiellement transparent.

Les inconvénients:

  • Plus lent que le calcul direct.
  • Nécessite une VRAM supplémentaire pour la carte de profondeur.
  • Pas 100% précis.

* Vous pouvez déterminer la quantité d'eau devant la surface solide la plus proche en comptant la profondeur du POV de la lumière comme suit:

  1. Rendez la géométrie solide de votre scène comme d'habitude. Pour chaque fragment, vous ajoutez la valeur de profondeur à la texture résultante.
  2. Rendez les faces avant de l'eau sans mettre à jour le tampon de profondeur et soustrayez les profondeurs des fragments du résultat.
  3. Rendez les faces arrière de la même manière, mais ajoutez la profondeur du fragment au résultat.

La texture résultante contient maintenant la quantité d'eau devant la lumière dans l'espace de vision de la lumière, donc la valeur doit être retransformée avant de l'utiliser. Cette méthode fonctionne pour calculer la lumière directionnelle (moins la réfraction), mais conduira à une lumière ambiante incorrecte si les surfaces sont très irrégulières et qu'il y a une grande quantité d'air entre les plans d'eau affectant les mêmes fragments.
Les avantages et les inconvénients sont les mêmes que pour le mappage d'ombres normal, sauf que vous avez besoin d'un tampon supplémentaire lors du calcul de la profondeur et que les performances sont pires car vous devez dessiner plus de géométrie.

Tracé laser

Le lancer de rayons est de loin la solution la plus précise mais aussi la plus coûteuse pour le rendu de volumes transparents. Il y a deux façons de procéder: 1. Le traçage depuis le fond de l'océan vers la surface et 2. Le traçage depuis la source lumineuse vers l'eau. Plusieurs rayons sont nécessaires pour chaque point du sol pour calculer la luminosité.

Avantages:

  • Fonctionne correctement avec chaque géométrie.
  • Corriger les caustiques!

Les inconvénients:

  • Lent!

Effets supplémentaires

Il y a quelques autres choses à prendre en compte lors du rendu de l'eau:

Brouillard

La lumière dans l'eau est à nouveau diffusée lors du voyage vers l'observateur, vous devez donc la mélanger vers une couleur unie.

Si l'observateur est submergé , vous pouvez simplement rendre le brouillard en fonction du résultat final du tampon de profondeur. La couleur du brouillard, mais pas sa densité, devrait changer avec la distance de l'observateur à la surface! (Minecraft n'utilise que cette partie de l'effet.)

Si l'observateur regarde l'eau d'en haut , vous devez calculer le brouillard en fonction de la différence de profondeur entre la surface et la géométrie sous l'eau. La couleur du brouillard devrait devenir légèrement plus foncée avec des différences de profondeur plus importantes, mais ne devrait changer qu'au point où le brouillard est entièrement opaque.

La couleur du brouillard doit également dépendre de la direction de la vue pour chaque pixel, elle est donc légèrement plus sombre lorsque l'on regarde vers le bas dans les deux cas.

Fake Caustics

Si vous utilisez une texture 3D en mosaïque transparente au lieu d'un décalque pour les fausses caustiques, vous pouvez éviter de vous étirer sur des surfaces verticales. La force de la lumière diffusée près de la surface varie en trois dimensions, donc l'utilisation d'une texture 2D produit généralement un étirement quelque part dans la scène. Vous pouvez modéliser les angles d'éclairage changeants en projetant les positions des sommets du sol dans un système de coordonnées différent.

Une autre possibilité consiste à calculer la densité de la lumière en fonction de la position de la surface dans le système de coordonnées de la lumière, bien que cela coûterait très probablement des performances.

Les caustiques devraient s'estomper plus rapidement que la lumière diffuse avec une profondeur croissante.

Dégradé de couleur

Les couleurs sont dispersées différemment, de sorte que la couleur de la lumière devrait changer avec une profondeur croissante. Cela empêche également les bords abruptes où, par exemple, une plage coupe la surface de l'eau.

Angle d'incidence

En raison de la réfraction, la lumière frappe le fond de l'océan beaucoup plus raide qu'elle ne le ferait normalement. L' article de Wikipedia sur la loi de Snell contient des formules pour les angles et les vecteurs.


6

Je crois que l'effet d'éclairage du ciel dans Minecraft est direct - les choses sont ombragées par ce qui est au-dessus d'eux, peu importe où se trouve le soleil. Ensuite, l'éclairage local des torches, etc. est appliqué avec un effet de baisse - plus la source de lumière est éloignée, moins le cube reçoit de lumière.

Si cela est fait de cette façon, chaque couche d'eau assombrirait cumulativement la couche en dessous, de sorte que chacune devient progressivement plus sombre. Le feuillage des arbres fournit de l'ombre comme celle-ci, mais il n'est pas cumulatif. Vous obtenez la même ombre sous un arbre que ce soit 1 ou 100 cubes de feuillage.

Un indice que c'est la méthode utilisée est que l'eau ne s'assombrit pas plus loin du spectateur - seulement lorsque vous descendez. Oui, l'effet de brouillard se déclenche à distance, mais pas l'effet sombre de l'eau.

Donc, la formule de base pour calculer l'éclairage serait quelque chose comme ça dans le pseudo-code ...

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
}

Ce n'est pas parfait pour calculer l'éclairage sous les surplombs ou dans les grottes, car il serait très sombre sous un surplomb en utilisant cette méthode. Mais on pourrait ajouter à la fois des sources de lumière locales (torches, incendies, etc.) ainsi que le traitement des blocs éclairés par le soleil comme sources de lumière. Quelque chose comme ça pourrait le faire ...

  1. Calculez la lumière du soleil directement au-dessus (via le pseudo-code ci-dessus) pour chaque cube.
  2. Si un cube a une source de lumière à côté de lui, considérez-le comme complètement éclairé (1.0)
  3. Si un cube ne reçoit pas de soleil directement du dessus, éclairez-le en fonction de sa distance par rapport à un cube entièrement éclairé. Plus près signifie plus de lumière, plus loin signifie moins (jusqu'à zéro).

L'idée ici est que si un cube est éclairé par le soleil ou une torche, le cube à côté de lui sera également allumé d'une manière ou d'une autre. Et plus vous vous éloignez de ce cube éclairé, moins il y aura de lumière. C'est en quelque sorte une manière compliquée d'estimer un éclairage diffus, mais je pense (?) Que cela fonctionnerait.


1
Ouais, je suis presque sûr que c'est le ticket. J'ai fait quelque chose de similaire dans mon jeu.
MichaelHouse

Au fait, je viens d'ajouter votre blog à ma liste de lecteurs Google Byte56 - blogs de développeurs FTW!
Tim Holt

Oh, pourquoi merci. Toujours hors sujet de cette question, mais je viens de lire votre blog sur la classe du professeur Bailey. J'étais dans cette classe l'année dernière! Je suis presque sûr que vous avez également fait cette présentation l'an dernier. Je pensais que ton nom était familier. Petit monde :)
MichaelHouse

3

Peut-être que je comprends mal la question, mais pourquoi ne pouvez-vous pas simplement changer la couleur des blocs en fonction de leur profondeur?

Si vous avez la profondeur d (en blocs, à partir de 0), alors une équation raisonnable pour la luminosité serait:

L = (1- m ) e - kd + m

Code: L = (1.0 - m) * exp(-k * d) + m;

k contrôle la vitesse à laquelle il s'assombrit (plus haut = plus vite). Une valeur raisonnable serait de 0,5.
m est la luminosité minimale souhaitée.
L varie de 0 à 1.

Si vous ne savez pas comment changer la couleur des blocs dans l'API graphique que vous utilisez, veuillez poser cette question séparément (en indiquant quelle API vous utilisez et si vous utilisez ou non des shaders).


Je n'ai tout simplement pas pensé à faire ça. Par simple curiosité, où avez-vous obtenu cette équation?
Xavier

1
@Xavier: Je viens de l'inventer. Le e^-kdbit est juste une décroissance exponentielle, qui est une fonction standard pour les choses qui tendent progressivement vers zéro sur une certaine valeur (profondeur). La multiplication par (1-m)et l'ajout de msont juste à l'échelle et compensent la décroissance de sorte qu'elle se termine au minimum mmais commence toujours à 1. en.wikipedia.org/wiki/Exponential_decay
Peter Alexander

Le fait est que les blocs d'une teinte plus profonde ne seront visibles que si les blocs ont des couleurs alpha; dans ce cas, il n'est pas nécessaire de changer la couleur du bloc, l'alpha créera automatiquement l'effet.
Jonathan Connell

@Jonathan: Vous ne restituez pas les blocs d'eau, vous rendez les blocs sur le fond marin avec la couleur qui s'assombrit et puis vous n'avez qu'une seule couche alpha à la surface de l'eau.
Peter Alexander

@Peter Alexander Ok, j'ai supposé que dans ces jeux de blocs, même l'eau était faite de blocs.
Jonathan Connell
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.