Rendu du ciel, des couchers de soleil et des planètes
(blog.maximeheckel.com)- Le shader du navigateur combine la diffusion de Rayleigh, la diffusion de Mie et l’absorption par l’ozone pour rendre en temps réel un ciel bleu ainsi que les couchers et levers de soleil
- Il accumule la profondeur optique du rayon de caméra et la transmittance selon la loi de Beer, puis calcule la distribution de la diffusion selon la direction du soleil à l’aide de fonctions de phase
- L’effet de coucher de soleil exécute un light-march distinct vers la direction du soleil à chaque échantillon, afin de prendre en compte la quantité de lumière solaire perdue lors de sa traversée de l’atmosphère
- Le shader de ciel plan devient un effet de post-traitement grâce au depth buffer et à la reconstruction des coordonnées monde, ce qui permet aussi de traiter le brouillard atmosphérique entre les objets de la scène
- À l’échelle planétaire, l’approche s’étend avec un logarithmic depth buffer, l’intersection rayon-sphère, et des LUT de Transmittance, Sky-view et Aerial Perspective
Objectifs du shader de diffusion atmosphérique et références
- L’objectif est de reproduire dans un shader de navigateur des couches rappelant les photos de coucher de soleil en orbite basse de la navette spatiale Endeavour, avec la transition entre le orange sombre, le bleu et le noir du fond spatial dans la haute atmosphère terrestre
- Le périmètre de l’implémentation commence par un sky dome réaliste combinant raymarching, diffusion de Rayleigh, diffusion de Mie et absorption par l’ozone, puis s’étend à une enveloppe atmosphérique autour d’une planète et à des optimisations basées sur des LUT
- Les principales références sont Three Geospatial, A Scalable and Production Ready Sky and Atmosphere Rendering Technique de Sébastien Hillaire, et Atmospheric Scattering (and also just faking it)
Modèle de base du rendu du ciel
-
Pourquoi un simple dégradé ne suffit pas
- La couleur du ciel ne doit pas être traitée comme un simple fond bleu, mais comme le résultat de l’interaction de la lumière avec l’air et ses composants
- Il faut prendre en compte des variables comme l’altitude de l’observateur, la quantité de poussière ou l’heure de la journée, et les calculs se font dans un volume
-
Échantillonnage de la densité atmosphérique
- L’atmosphère est échantillonnée par raymarching, comme pour les volumetric clouds ou la volumetric light
- On lance un rayon depuis la position de la caméra et on avance dans le milieu transparent ; on calcule alors la transmittance, c’est-à-dire la lumière qui survit à la traversée de l’atmosphère, ainsi que la diffusion redirigée vers la caméra à chaque échantillon
- Pour réviser le raymarching, on peut consulter Painting with Math: A Gentle Study of Raymarching
-
Densité de Rayleigh et profondeur optique
- Pour obtenir la transmittance, il faut accumuler la densité atmosphérique rencontrée par le rayon au fil de sa trajectoire afin de calculer la profondeur optique
- La fonction de densité de Rayleigh indique la quantité d’« air » présente à l’altitude
h, et reflète le fait que l’atmosphère se raréfie quand l’altitude augmente - L’implémentation d’exemple utilise
RAYLEIGH_SCALE_HEIGHT = 8.0km,ATMOSPHERE_HEIGHT = 100.0km,VIEW_DISTANCE = 200.0km etPRIMARY_STEPS = 24 rayleighDensity(h)vautexp(-max(h, 0.0) / RAYLEIGH_SCALE_HEIGHT), et l’accumulation dans la boucle se fait avecviewOpticalDepth += dR * stepSize
-
Loi de Beer et bleu du ciel en journée
- À partir de la profondeur optique, on calcule la transmittance
Ten un point donné ;T=1.0signifie qu’il n’y a aucune perte de lumière, etT=0.0que la lumière a complètement disparu - La transmittance est calculée avec la loi de Beer, et le code d’exemple utilise
vec3 transmittance = exp(-rayleighBeta * viewOpticalDepth) rayleighBetaest le coefficient de diffusion de Rayleigh ; dans le shader, il est stocké sous la formevec3(0.0058, 0.0135, 0.0331)- L’angle entre la direction de la lumière solaire et le rayon de vue est modélisé par la fonction de phase de Rayleigh sous la forme
3.0 / (16.0 * PI) * (1.0 + mu * mu) - À cause des coefficients de diffusion de Rayleigh, le rouge est très peu diffusé, le vert l’est davantage, et le bleu l’est le plus, ce qui explique la couleur bleue du ciel en journée
- Si l’on étend cela à un rayon par pixel, l’horizon traverse davantage d’atmosphère et apparaît comme une brume blanche lumineuse, tandis qu’à plus haute altitude la couleur devient un bleu plus profond et plus sombre
- À partir de la profondeur optique, on calcule la transmittance
Diffusion de Mie et absorption par l’ozone
-
Effets insuffisants avec Rayleigh seul
- La diffusion de Rayleigh seule donne déjà des résultats corrects, mais un ciel plus réaliste nécessite des effets atmosphériques supplémentaires
- La diffusion de Mie représente l’interaction de la lumière avec des particules plus grosses, comme la poussière ou les aérosols, et possède une fonction de densité ainsi qu’une fonction de phase décrivant la redistribution selon la direction
- L’absorption par l’ozone retire certaines longueurs d’onde du trajet lumineux dans la haute atmosphère sans les diffuser
- L’absorption par l’ozone approfondit notamment les couleurs du ciel et les décale près de l’horizon, au coucher et au lever du soleil, ainsi que pendant le crépuscule
-
Accumulation de Mie et de l’ozone
- Une implémentation combinant Rayleigh, Mie et ozone accumule leurs profondeurs optiques respectives dans
viewODR,viewODMetviewODO - À chaque échantillon, on calcule
dR = rayleighDensity(h),dM = mieDensity(h)etdO = ozoneDensity(h), puis on construittaucomme la somme deBETA_R * viewODR,BETA_M_EXT * viewODMetBETA_OZONE_ABS * viewODO - La transmittance est calculée via
exp(-tau), etsumR,sumMainsi quesumOaccumulent chaque densité, la transmittance etstepSize - La diffusion finale est calculée sous la forme
SUN_INTENSITY * (phaseR * BETA_R * sumR + phaseM * BETA_M_SCATTER * sumM + BETA_OZONE_SCATTER * sumO)
- Une implémentation combinant Rayleigh, Mie et ozone accumule leurs profondeurs optiques respectives dans
-
Principales constantes et effets
MIE_SCALE_HEIGHTest l’équivalent pour les aérosols deRAYLEIGH_SCALE_HEIGHT; comme les particules sont généralement concentrées près de l’horizon, sa valeur est plus faible, à1.2kmMIE_BETA_SCATTERcontrôle à quel point les particules diffusent la lumière vers la caméra ; comme l’effet est en grande partie indépendant de la longueur d’onde, la valeur choisie estvec3(0.003)MIE_BETA_EXTest le coefficient d’extinction de Mie indiquant la quantité de lumière retirée du trajet, ce qui rend l’atmosphère lointaine plus laiteuseMIE_Gcontrôle l’anisotropie ;0.0signifie une diffusion uniforme, et1.0un biais plus marqué vers la diffusion avantOZONE_BETA_ABSprend la valeurvec3(0.00065, 0.00188, 0.00008)et absorbe davantage les tons verts ainsi que jaune-orange, ce qui déplace les couleurs du ciel vers le bleu, le rouge et le violet- L’intégration de Mie et de l’ozone produit une teinte « sky blue » plus naturelle ainsi qu’un halo lumineux diffus autour du soleil, avec un effet de diffusion de Mie plus visible lorsque le soleil est proche de l’horizon
Trajet de la lumière et coucher·lever du soleil
-
Limites de l’implémentation existante
- Le fragment shader du ciel peut rendre des couleurs naturelles à différentes altitudes et prendre en compte les modèles de transmission de Mie, de Rayleigh et de l’ozone
- Cependant, même si l’on déplace le soleil près de l’horizon, on n’obtient qu’une lueur blanchâtre et diffuse, sans atténuation lumineuse ni effet de coucher ou de lever du soleil
- Cela venait du fait que la boucle de raymarching existante ne calculait l’atténuation de la lumière que le long du rayon de vue, depuis la caméra jusqu’à chaque échantillon
- Il faut aussi calculer à quel point la lumière solaire est perdue en traversant l’atmosphère avant d’atteindre le point échantillonné
-
Boucle imbriquée de light-march
- À chaque point échantillonné, une boucle imbriquée distincte est exécutée dans la direction de la source lumineuse pour échantillonner la transmittance sur ce trajet
- Cette approche est également utilisée dans real-time cloudscapes et volumetric lighting
lightMarch(float start, float sunY)itèreLIGHTMARCH_STEPSfois en accumulantodR,odMetodO- La profondeur optique dans la direction du soleil
sunODest ajoutée aux profondeurs optiques de l’implémentation existanteviewODR,viewODM,viewODO - Le
taufinal est construit en additionnantBETA_R * (viewODR + sunOD.x),BETA_M_EXT * (viewODM + sunOD.y),BETA_OZONE_ABS * (viewODO + sunOD.z) - Cette implémentation permet de rendre le ciel au coucher du soleil, au lever du soleil, avec le soleil au zénith, ainsi que dans les conditions d’éclairage intermédiaires
- Le paramètre uniform
sun anglepermet de faire varier le bleu du ciel au cours de la journée, et la diffusion de Mie mélange naturellement la lumière avec l’horizon au coucher et au lever du soleil - Quand le soleil est bas, l’ozone ajoute une tonalité violacée au ciel
Extension à l’atmosphère planétaire
-
D’un fond plat à un effet de post-traitement
- Le shader créé précédemment fournit un bon arrière-plan de ciel, mais il reste proche d’un fond plat dans une scène React Three Fiber
- L’étape suivante consiste à le transformer en effet de post-traitement (post-processing effect) afin de rendre un volume tenant compte de la profondeur de la scène, ainsi qu’une enveloppe atmosphérique autour du mesh de la planète
- Pour cela, on reconstruit les coordonnées en espace monde à partir des coordonnées
screenUV, puis on intègre le depth buffer de la scène au raymarching
-
Reconstruction de l’espace monde et rayons 3D
- Pour appliquer la diffusion atmosphérique à la scène, il ne suffit pas de dessiner le ciel : il faut remplir l’espace entre la caméra et les objets rendus à l’écran
- Les données nécessaires sont le depth buffer de la scène,
projectionMatrixInverse,matrixWorldetpositionde la caméra, et ces valeurs sont transmises comme uniforms à l’effet de post-traitement getWorldPosition(vec2 uv, float depth)créeclipZavecdepth * 2.0 - 1.0, construit les coordonnées NDC avecuv * 2.0 - 1.0, puis appliqueprojectionMatrixInverseetviewMatrixInverse- Le même procédé est aussi utilisé dans l’effet de post-traitement de volumetric lighting de On Shaping Light
- Une fois la
worldPositiondu pixel courant obtenue,rayOriginprend la position de la caméra etrayDirest calculé avecnormalize(worldPosition - rayOrigin), puis on avance le long du rayon 3D propre à chaque pixel à l’écran
-
Ajustement de l’intervalle de raymarch avec le depth buffer
- Pour prendre en compte la géométrie de la scène, l’intervalle de raymarch du rayon courant doit être déterminé par le depth buffer plutôt que par une valeur fixe
stepSize sceneDepth = depthToRayDistance(uv, depth)permet d’obtenir la profondeur de la scène le long du rayon- Les pixels d’arrière-plan sont détectés avec
depth >= 1.0 - 1e-7, et pour les “sky pixels”, on appliquesceneDepth = atmosphereHeight * SKY_MARCH_DISTANCE_MULTIPLIER - Si le rayon est orienté vers le bas, l’intersection avec le sol est calculée avec
tGround = observerAltitude / max(-rayDir.y, 1e-4)puis limitée avecrayEnd = min(rayEnd, tGround) - Le
stepSizefinal est calculé avec(rayEnd - rayStart) / float(PRIMARY_STEPS) - Les rayons qui touchent des objets proches ou le sol sont échantillonnés plus précisément avec un
stepSizeplus petit, tandis que les rayons qui vont plus loin répartissent le même nombre d’échantillons sur une plus grande distance
- Pour prendre en compte la géométrie de la scène, l’intervalle de raymarch du rayon courant doit être déterminé par le depth buffer plutôt que par une valeur fixe
-
Brouillard atmosphérique dans la scène
- Le shader implémenté comme effet de post-traitement applique la diffusion atmosphérique à l’ensemble du volume de la scène et permet d’utiliser le sky shader en arrière-plan tout en tenant compte de la géométrie de la scène
- Les objets proches de la caméra apparaissent plus nets, tandis que les objets éloignés deviennent plus flous
- Un exemple interactif avec des corps célestes déplaçables via
Raycasterest visible dans le tweet de MaximeHeckel
Rendu des planètes
-
Deux étapes nécessaires
- Pour rendre une atmosphère réaliste autour d’une planète, il faut un logarithmic depth buffer pour gérer les très grandes échelles, ainsi qu’une enveloppe atmosphérique sphérique qui définit où le rayon commence et où il se termine dans l’atmosphère
-
logarithmic depth buffer
- À l’échelle d’une planète, quand on l’observe de loin, le shader peut avoir du mal à distinguer la différence de profondeur entre l’atmosphère et l’enveloppe de la planète, ce qui peut provoquer du depth fighting
- Comme la hauteur de l’atmosphère n’est que de quelques km, il faut ajuster à la fois la définition du depth buffer de la scène et la manière dont il est lu dans les effets de post-traitement
- Dans la prop
glqui enveloppe leCanvasde React Three Fiber, on activelogarithmicDepthBuffer: true - La configuration d’exemple est de la forme
<Canvas shadows gl={{ alpha: true, logarithmicDepthBuffer: true }}> - Dans le shader, le calcul de
sceneDepthest redéfini pour reconvertir le logarithmic depth buffer en distance le long du rayon logDepthToViewZ(depth)utilisepow(2.0, depth * log2(cameraFar + 1.0)) - 1.0et renvoie-d
-
Trouver l’intervalle atmosphérique avec ray-sphere intersection
- On utilise un test de ray-sphere intersection pour trouver les points où le rayon de vue entre dans la sphère atmosphérique (atmospheric sphere) et en sort
- Une fois les deux points d’intersection obtenus, on évite de gaspiller des échantillons hors de l’atmosphère et on peut limiter la boucle de raymarching à cet intervalle seulement
- La planète étant un mesh sphérique entouré d’une sphère atmosphérique légèrement plus grande, on applique le même test d’intersection à la planète elle-même
- Si le rayon touche le sol avant de sortir de l’atmosphère, on utilise le point d’intersection avec le sol comme fin de l’intervalle de raymarching
- L’implémentation de
raySphereIntersectutilisée s’inspire de Ray-Surface intersection functions d’Inigo Quilez
-
Objets de la scène et conditions de fin de l’atmosphère
- L’atmosphère doit s’arrêter lorsqu’elle atteint la surface de la planète, ou lorsqu’elle rencontre un autre objet de la scène avant d’atteindre le sol
- En cas d’impact avec la planète, on s’arrête au sol par défaut avec
atmosphereFar = min(atmosphereFar, planetHit.x) - Si un autre mesh est rendu devant le sol, on le détecte avec la condition
sceneDepth < planetHit.x - 2.0puis on appliqueatmosphereFar = min(atmosphereFar, sceneDepth) - Sans cette logique, la surface de la planète peut apparaître devant l’objet
-
Démo React Three Fiber et glitchs restants
- Une fois ces deux ajustements intégrés au code, on peut implémenter la diffusion atmosphérique comme effet de post-traitement et rendre l’atmosphère autour de la planète
- La scène de démonstration rend un simple « Sun - Earth system » dans React Three Fiber et lui applique un effet personnalisé
- En ajustant la position du soleil et en dézoomant, on peut voir le ciel généré par le shader sous différents angles, du sol jusqu’à l’orbite
- Le même effet a été utilisé pour l’image d’affiche annonçant l’article de début avril, et le rendu a été partagé dans ce tweet
- Le torus de la scène peut encore paraître « lit-up » même après le coucher du soleil
- La cause vient de l’échelle trop petite de la shadow-map ou de la shadow-camera de la directional light principale, qui ne couvre pas le torus trop éloigné
- Comme solution de contournement, il serait possible de réutiliser l’approche de shadow-mapping de l’article sur le volumetric lighting, mais cela n’a pas été réellement tenté
Gestion des éclipses
- Quand un gros corps céleste masque le soleil, on peut l’ajouter en appelant la fonction
sunVisibilityaprèslightMarch, puis en multipliant la transmittance par la valeur de retour[0, 1] - L’idée de base consiste à comparer le produit scalaire entre la direction de la lune et la direction du soleil depuis le point d’échantillonnage courant
- Si les deux directions sont presque identiques et que le produit scalaire est proche de
1.0, la lune masque le soleil ; si elles sont orthogonales et proches de0.0, il n’y a pas d’occultation - Un simple produit scalaire ne suffit pas à refléter la taille et l’échelle des objets dans la scène ; l’implémentation compare donc la distance angulaire entre le soleil et la lune ainsi que leurs rayons angulaires respectifs
sunVisibilitygère les cas où la lune ne masque pas le soleil, où elle le masque en paraissant plus grande ou d’une taille comparable au soleil du point de vue de la caméra, et où elle le masque en entrant dans le rayon apparent du soleil vu par la caméra- La démo ajoute
sunVisibilityet un mesh de lune à l’exemple existant de diffusion atmosphérique, afin que le shader d’Atmospheric Scattering gère la situation de manque de lumière lorsque la lune est alignée avec le soleil - Une simulation plus poussée des éclipses et de la couronne solaire est abordée dans l’article Physically Based Real-Time Rendering of Eclipses, dont l’implémentation n’a pas été portée vers WebGL
Atmosphère d’autres planètes
- Le modèle de densité atmosphérique et de diffusion utilisé est principalement déterminé par quelques constantes comme le rayon de la planète et de l’atmosphère,
RayleighScaleHeight,RayleighBeta,MieScaleHeight,MieBeta,mieBetaExt,mieG,OzoneHeight,OzoneWidth - En ajustant ces valeurs, on peut obtenir un résultat proche d’une atmosphère martienne ou de celle d’autres planètes
- Les valeurs utilisées pour Mars sont approximatives
planetRadius: 3390atmosphereRadius: 3500, soit environ110 kmd’épaisseurrayleighScaleHeight: 11.1rayleighBeta: new THREE.Vector3(0.019, 0.013, 0.0057)mieScaleHeight: 1.5mieBeta: 0.04mieBetaExt: 0.044mieG: 0.65ozoneCenterHeight: 0.0ozoneWidth: 1.0ozoneBetaAbs: new THREE.Vector3(0.0, 0.0, 0.0)sunIntensity: 15.0planetSurfaceColor: '#8B4513'
- Remplacer les constantes existantes par ces valeurs produit une atmosphère plus poussiéreuse et plus orangée, et permet aussi d’obtenir la teinte bleutée caractéristique des couchers de soleil martiens
- On peut se référer à l’article Physically Based Rendering of the Martian Atmosphere
Diffusion atmosphérique basée sur des LUT
-
Approche et raccourcis pris
- Le shader existant permet de rendre de façon intuitive une atmosphère à petite et à grande échelle, mais son coût d’exécution est élevé à cause de la boucle de ray marching avec beaucoup de
PRIMARY_STEPS, de la boucle imbriquée delightmarchinget des calculs à la résolution de l’écran entier - A Scalable and Production Ready Sky and Atmosphere Rendering Technique de Sebastian Hillaire propose une approche basée sur des Look Up Tables (LUTs) qui stocke dans des textures les calculs de diffusion coûteux, puis échantillonne et compose ces textures précalculées dans le rendu final
- Les LUT utilisées ici sont la Transmittance LUT, qui stocke la quantité de lumière survivant à la traversée de l’atmosphère, la Sky-view LUT, qui stocke la couleur du ciel pour une position de caméra donnée, et la Aerial Perspective LUT, qui stocke le haze atmosphérique et la lumière diffusée entre la caméra et la géométrie visible de la scène
- L’implémentation ne reprend pas l’intégralité de l’article à l’identique ; les LUT se prêtent bien aux compute shaders de WebGPU, mais par manque de temps et pour préserver la continuité de l’article, l’auteur a conservé WebGL
- Dans l’article, la Aerial Perspective LUT est une 3D texture, mais l’implémentation utilise une cible de rendu 2D
- Cette approche impose de régénérer les textures à chaque déplacement de la caméra afin d’obtenir les bonnes valeurs de pixel, ce qui rend le précalcul difficile
- Le Multi-Scattering a été omis faute de temps
- Le shader existant permet de rendre de façon intuitive une atmosphère à petite et à grande échelle, mais son coût d’exécution est élevé à cause de la boucle de ray marching avec beaucoup de
-
Transmittance LUT
- Dans le shader précédent, chaque point d’échantillonnage appelait
lightmarchpour calculer quelle quantité de lumière solaire arrivait jusqu’à lui, ce qui coûtait cher - La Transmittance LUT préstocke ces données à basse résolution pour que les autres LUT puissent ensuite les lire lorsqu’elles ont besoin d’informations lumineuses
- L’implémentation définit un Frame Buffer Object dédié en résolution
250 x 64, applique un material shader personnalisé sur un quad plein écran d’une scène dédiéetransmittanceLUTScene, puis transmet la texture de rendu comme uniform aux LUT downstream - À chaque pixel, le ray marching démarre depuis
vec3(0.0, radius, 0.0), oùradiusaugmente deplanetRadiusàatmosphereRadiusle long de la coordonnéevUv.y - L’axe x de la LUT représente l’angle de la lumière, et l’axe y l’altitude ; le blanc pur correspond à une transmittance de
100%, tandis que les zones noires ou colorées indiquent le sol ou les parties où l’air est le plus dense - Les LUT suivantes peuvent alors obtenir « la quantité de lumière qui survit à la traversée de l’atmosphère pour un angle et une altitude donnés » via une simple lecture de texture
- Dans le shader précédent, chaque point d’échantillonnage appelait
-
Sky-view LUT
- La Sky-view LUT calcule la couleur du ciel lorsqu’on regarde vers le haut depuis le sol dans une direction donnée
getSkyViewRayDirmappevUv.xvers l’azimuth[-PI, PI]etvUv.yvers l’elevation[-PI/2, PI/2]afin de définir la direction du ray marching- Pour l’elevation, l’implémentation utilise un mapping quadratique
(vUv.y * vUv.y - 0.5) * PI, un contournement destiné à éviter que la vue du ciel ne scintille trop à grande distance - Si le rayon n’entre pas dans l’atmosphère, la fonction renvoie du noir ; pour les rayons qui touchent la planète, le ray marching ne parcourt que la portion visible de l’atmosphère et s’arrête plus tôt au contact de la planète
- La boucle de diffusion reste la même qu’auparavant, mais progresse cette fois dans la direction de la Sky View et utilise la Transmittance LUT pour la lumière solaire
-
Aerial Perspective LUT
- Contrairement à l’article de Hillaire, le résultat de cette implémentation est une texture 2D, et chaque pixel correspond à un pixel visible de l’écran
- Le depth buffer de la scène est utilisé pour déterminer jusqu’où avancer le long du rayon et accumuler la diffusion
- Le code de diffusion existant est presque entièrement réutilisé, mais chaque échantillon récupère la visibilité de la lumière solaire depuis la Transmittance LUT
- La sortie stocke dans le RGB la diffusion atmosphérique accumulée, et dans l’alpha une valeur de view transmittance compactée à utiliser lors de la composition
- Le flux d’implémentation consiste à lire la profondeur depuis
depthBuffer, reconstruire la position en espace monde du pixel écran avecgetWorldPosition(vUv, depth), puis calculerrayDirdepuis la position de la caméra jusqu’à cette position monde - Ensuite,
logDepthToRayDistance(vUv, depth)convertit la profondeur de scène en distance de rayon, puis l’algorithme calcule les intersections avec l’atmosphère et la planète avant de marcher uniquement dans la portion visible de l’atmosphère
-
Composition
- Une fois la Sky-view LUT et la Aerial Perspective LUT générées, les deux sont combinées dans le dernier pass de post-processing
- L’opération essentielle consiste à convertir le
rayDircourant en coordonnées UV de Sky View - La Aerial Perspective LUT est appliquée à la géométrie de la scène ; le canal alpha sert de view transmittance et le canal RGB de lumière diffusée, ce qui donne
color = color * aerialPerspective.a + aerialPerspective.rgb - Pour les pixels d’arrière-plan, la Sky View LUT est échantillonnée ; si
depth >= 1.0 - 1e-7, le pixel est traité comme un arrière-plan et l’on appliquecolor = inputColor.rgb + sampleSkyViewLUT(rayDir, planetCenter) - Enfin,
ACESFilm(color)puispow(color, vec3(1.0 / 2.2))sont appliqués - L’ensemble du code de cette implémentation atmosphérique basée sur des LUT est disponible via ce Github link
Conclusion
- Le résultat de la diffusion atmosphérique basée sur des LUT peut sembler presque identique à la version précédente en ray marching complet, mais le fonctionnement interne est différent
- Le travail est découpé en LUT plus petites, puis recomposé dans l’effet final, sans recalculer à chaque échantillon un ray marching répété vers le soleil pour déterminer la lumière incidente
- Comme les informations d’éclairage sont récupérées directement depuis la Transmittance LUT, les coûteuses boucles imbriquées sont remplacées par de simples lectures de texture, ce qui apporte un gain de performance non négligeable dans la scène finale
- Cette implémentation reste en retrait par rapport à celle de Sébastian Hillaire et à d’autres réalisations du domaine ; elle présente notamment du banding et du flickering dans la Sky View, et les raccourcis pris nuisent à son optimalité
- Il aurait peut-être fallu partir sur WebGPU dès le début
- Pour une implémentation réellement de niveau production, l’auteur recommande three-geospatial de Shoda Matsuda(@shotamatsuda)
- L’auteur a aussi travaillé à y ajouter des volumetric clouds, mais le résultat reste encore mitigé et pas assez satisfaisant pour être montré dans l’article, ce qui demande encore du travail
1 commentaires
Commentaires sur Hacker News
Il y a quelque chose de particulièrement plaisant à voir des effets visuels se développer et devenir progressivement réalistes, et j’aimerais bien expérimenter moi-même dans ce domaine un jour
Avant, ses vidéos faisaient des millions de vues, alors qu’aujourd’hui elles dépassent à peine les 500 000. C’est peut-être aussi lié au fait que pendant le Covid, tout le monde était chez soi et s’intéressait à des choses aléatoires
En général, je les mets pour m’endormir, et j’aimerais qu’il y ait plus de contenus de ce genre, calmes mais fouillés sur des sujets techniques, au point d’avoir déjà envisagé d’en faire moi-même
Après le coucher du soleil, l’atmosphère au-dessus de nos têtes et la zone au-dessus de l’horizon continuent à recevoir la lumière du soleil pendant un moment, et dans l’atmosphère terrestre, un crépuscule visible subsiste jusqu’à ce que le soleil descende à 18 degrés sous l’horizon. Ce n’est peut-être pas pratique à implémenter en ray tracing, mais il existe des algorithmes courants pour modéliser cela
https://www.threads.com/@mrsharpoblunto/post/DVS4wfYiG8f?xmt...
https://www.threads.com/@mrsharpoblunto/post/C6Vc-S1O9mX?xmt...
https://www.threads.com/@mrsharpoblunto/post/C6apksDRa8q?xmt...
Je me souviens avoir implémenté « Display of The Earth Taking into Account Atmospheric Scattering » de Nishita et al., un article de 1993, quasiment fondateur sur le sujet, et très facile à lire : https://www.researchgate.net/publication/2933032_Display_of_...
Quand j’ai réussi à le faire fonctionner, j’ai eu ce moment de réalisation : « on peut en fait modéliser assez bien ce phénomène complexe du monde réel avec quelques calculs relativement simples ». On est passé en un instant d’une simple skybox bleue statique à un cycle jour-nuit complet
Il fut un temps où je me demandais ce que donnerait le rendu d’un ciel sur le web en superposant plusieurs dégradés. J’ai peut-être obtenu des résultats corrects dans une certaine mesure, mais rien de comparable à ce qui a été fait ici. Le résultat est impressionnant et inspirant
Rien qu’avec ça, j’avais été surpris d’obtenir un cycle coucher/lever de soleil assez crédible, et si je me souviens bien, le soleil lui-même en émergeait d’une manière assez naturelle. J’utilisais XNA, la plateforme de développement de jeux en C# de Microsoft, en suivant l’excellente série de tutoriels de Riemer, dont on trouve une archive ici : https://github.com/SimonDarksideJ/XNAGameStudio/wiki/Riemers...
Je n’y vois toutefois rien sur la diffusion, donc j’ai peut-être pris cette partie ailleurs. Je me souviens en tout cas d’avoir lu des articles avec des formules
https://spaceengine.org/
À la question « Combien d’objets y a-t-il dans SpaceEngine ? », la réponse est quelque chose comme : l’intégralité du catalogue d’étoiles Hipparcos, toutes les exoplanètes connues, plus de dix mille galaxies et la plupart des objets du système solaire, soit 130 000 au total, auxquels s’ajoutent plus de galaxies et de systèmes stellaires qu’il n’en existe réellement dans l’univers observable. À « Comment une planète océan peut-elle être chaude ? », la réponse est que l’eau de la haute atmosphère est de la vapeur brûlante, mais qu’en descendant, elle passe en douceur à l’état liquide sous haute pression, puis plus en profondeur à l’état solide appelé ice VII. À « Comment se déplacer ? », la réponse est : avec les touches WASD
C’est un excellent jeu, et même s’il date déjà un peu, je n’ai toujours rien vu d’aussi réussi
Cet article m’a immédiatement fait penser à SpaceEngine
L’un de mes articles préférés : http://www.graphics.stanford.edu/papers/bssrdf/bssrdf.pdf
Je crois que c’est là que j’ai appris pour la première fois à quel point le rendu du lait est un problème difficile
Je n’en ai probablement compris qu’environ 5 %, mais j’ai été profondément admiratif
Et si c’est sous licence MIT, alors mon problème de skybox pour mon jeu est pratiquement réglé. La perspective sera fixe, donc il me suffit d’avoir un rendu du soleil traversant le ciel, puis d’étendre cela avec un cycle sinusoïdal pour faire varier l’angle du soleil au fil de l’année