1 points par GN⁺ 2024-06-06 | 1 commentaires | Partager sur WhatsApp
  • La lune et la planète gazeuse du fond de ciel peuvent afficher leur surface, leur rotation et leur atmosphère avec un simple disque circulaire et un pixel shader, sans véritable mesh sphérique
  • Une UV sphere classique facilite le mapping sur une texture 2×1, mais entraîne aussi des contours anguleux, des pertes d’échantillonnage mipmap, des motifs répétitifs, une seam, des déformations aux pôles et des limites pour le halo atmosphérique
  • L’approche par disque reconstruit la position de la surface sphérique depuis l’UV central, puis produit, au pixel près, une surface qui paraît sphérique via des UV sphériques basées sur asin, une matrice de rotation et une rotation simulée par décalage de la coordonnée u
  • Le shading part d’un éclairage lambertien utilisant la position de surface comme normale ; pour les surfaces rocheuses, on applique une matrice TBN et une normal map, tandis que l’atmosphère approxime la luminosité du halo et l’absorption par canal
  • Les textures statiques de Substance Designer et les textures de rendu dynamiques d’Unreal peuvent être traitées de la même façon, ce qui permet de réduire la charge de performance grâce à des textures dynamiques plus petites et à un ajustement du tiling

Objectif visuel des planètes de skybox

  • La skybox du projet vise à créer un ciel extraterrestre avec une lune animée et une planète gazeuse
  • Les deux planètes tournent, et la planète gazeuse inclut aussi des flux atmosphériques en mouvement
    • Le mouvement réel est subtil, mais la vitesse a été augmentée pour l’effet visuel
  • La direction artistique adopte un style semi-réaliste inspiré de l’art SF des années 1970-80

Entrées de texture de surface et contraintes

  • La surface de la planète gazeuse est générée en temps réel via un pixel shader et une approche render-to-texture
  • La texture de la lune est créée dans Substance Designer, avec possibilité de varier la palette de couleurs et la material seed pour tester différents rendus
  • La planète gazeuse dynamique exige de rendre la texture à chaque frame, ce qui a un coût élevé en performance
    • Doubler la résolution de texture multiplie le coût de rendu par 4
  • Il faut une solution qui fonctionne de façon cohérente à la fois avec les textures statiques de Substance Designer et celles rendues dynamiquement dans Unreal
  • Le cubemap a été envisagé au départ, mais il peut consommer 6 fois plus de ressources qu’une texture carrée et Substance Designer ne prend pas en charge la génération de cubemaps, ce qui le rend peu pratique

Limites constatées avec l’UV sphere

  • L’UV sphere semble être le choix par défaut, car elle s’aligne facilement avec une texture rectangulaire 2×1 et ses coordonnées
  • Comme on ne voit qu’un seul côté de la sphère à la fois, il est aussi possible d’utiliser une texture carrée en tiling au lieu d’une texture rectangulaire unique couvrant toute la sphère
  • En pratique, plusieurs problèmes se cumulent
    • Le contour apparaît nettement anguleux, à moins d’augmenter la subdivision ou de le masquer avec un masque dans le pixel shader
    • La majeure partie de la surface est vue de biais, donc échantillonnée depuis des mipmaps de faible résolution ; avec une texture dynamique, une grande partie des pixels générés à chaque frame est dépensée sur des zones presque invisibles
    • Le tiling doit être augmenté en multiples entiers pour que le motif reste continu, et dès un facteur 2, la répétition devient visible
    • Le tiling fractionnaire crée une seam qui va du pôle Nord au pôle Sud
    • Aux pôles, on obtient du texture pinching et des déformations dues au mapping triangulaire, proches des textures tremblantes de la PSX
    • Comme seule la surface peut être dessinée, un modèle séparé est nécessaire pour le halo atmosphérique
  • L’UV sphere reste utilisable pour modéliser une planète, mais pour une skybox elle demande beaucoup de retouches et de hacks

Approche par disque circulaire et pixel shader

  • Les planètes de skybox étant observées de loin depuis un point fixe, un mesh sphérique 3D complexe n’est pas indispensable
  • On utilise un simple disque polygonal plein et on gère le mapping de texture dans le pixel shader
  • Le halo atmosphérique peut aussi être dessiné dans le même mesh
  • L’origine UV du disque doit être placée exactement au centre
    • Si l’on prend un rayon planétaire égal à 1, les coordonnées UV doivent s’étendre au-delà pour laisser de la place au rendu de l’atmosphère

Reconstruction de la surface sphérique

  • Le système de coordonnées suit une convention left-handed, Y-up, cohérente avec DirectX
    • Unreal Engine est lui aussi left-handed, mais avec Z comme axe vertical ; il faut donc vérifier l’orientation et le format de la normal map
  • L’équation de surface mappe une position 2D du plan du disque vers une position 3D sur la surface de la sphère
  • On commence par vérifier si le pixel se trouve à l’intérieur de la surface sphérique, en testant si la longueur du vecteur UV est inférieure au rayon
float CircleMask( float2 uv, float radius)
{
    return length(uv) < radius? 1.0: 0.0;
}
  • Cette méthode ne fonctionne correctement que si les coordonnées UV sont alignées sur le centre du mesh
  • La position locale sur la surface sphérique réutilise directement x et y depuis l’UV, et ne reconstruit que z
float3 ReconstructSurface(float2 uv)
{
    float zSquared = 1.0 - dot(uv, uv);
    float z = sqrt(zSquared);
    return float3(uv, z);
}

Génération des UV sphériques

  • Le mapping d’une texture carrée sur une surface sphérique se déroule en trois étapes
    • Enroulement sur un cylindre
    • Répétition du même traitement sur l’axe y
    • Déformation du résultat pour retrouver une forme sphérique
  • La coordonnée x de texture est proportionnelle à l’angle d’enroulement du cylindre ; on calcule arcsine(x), puis on remappe [-π, π] vers [0, 1]
  • La génératrice correspondant à la largeur locale de la sphère sert à resserrer les coordonnées vers les pôles
float2 GenerateSphericalUV(float3 position)
{
    float width = sqrt(1.0 - position.y * position.y);
    float generatrixX = position.x / width * sign(position.z);
    float2 generatrix = float2(generatrixX, position.y);
    float2 uv = asin(generatrix) / 3.14159 + float2(0.5, 0.5);
    return float2(uv);
}

Inclinaison de l’axe et rotation

  • Pour une composition planétaire plus naturelle, l’axe de la planète est incliné en pitch et roll
    • Dans l’art SF, les planètes sont souvent inclinées, ce qui dynamise la composition et permet de montrer les calottes polaires
  • Le yaw correspond au mouvement de rotation et est traité à part pour éviter les problèmes de seam
  • Avec un mesh sphérique, on transforme généralement la planète via une matrice ; avec l’approche par disque, chaque pixel définit la position de surface, donc une simple matrice 3×3 de rotation suffit
float3x3 CreateRotationMatrix(float pitch, float roll) {
    float cosPitch = cos(pitch);
    float sinPitch = sin(pitch);
    float cosRoll = cos(roll);
    float sinRoll = sin(roll);

    return (float3x3)(
        cosRoll, -sinRoll * cosPitch, sinRoll * sinPitch,
        sinRoll, cosRoll * cosPitch, -cosRoll * sinPitch,
        0.0, sinPitch, cosPitch
    );
}
  • L’éditeur de matériaux d’Unreal ne prend pas en charge les matrices comme type de données, mais il existe des contournements

Gestion du scale, de la seam et du spin

  • Modifier le scale de texture fait réapparaître la seam UV jusque-là cachée au bord de la texture d’origine
  • Il n’est pas simple de la supprimer totalement, mais on peut la déplacer vers l’arrière pour la rendre moins visible
  • La sphère est divisée en quadrants selon le signe de la position, et un offset en u est appliqué aux quadrants arrière-gauche et arrière-droit
float2 GenerateSphericalUV(float3 position, float spin, float scale)
{
    float leftRightSign = sign(position.x);
    float frontBackSign = sign(position.z);
    float width = sqrt(1.0 - position.y * position.y);
    float generatrixX = position.x / width * frontBackSign;
    float2 generatrix = float2 (generatrixX, position.y);
    float2 uv = asin(generatrix) / 3.14159 + float2 (spin, 0.5);
    if(frontBackSign < 0.0)
    {
        uv = float2 (uv.x + 1.0 * leftRightSign, uv.y);
    }
    return float2 (uv / scale);
}
  • La seam relie toujours le pôle Nord au pôle Sud, mais comme elle a été déplacée à l’arrière, elle se voit beaucoup moins
  • La rotation n’est pas obtenue en faisant tourner la sphère elle-même, mais en décalant la texture de surface selon la coordonnée u
float2 GenerateSphericalUV(float3 position, float scale, float spin)
{
    float width = sqrt(1.0 - position.y * position.y);
    float generatrixX = position.x / width * sign(position.z);
    float2 generatrix = float2(generatrixX, position.y);
    float2 uv = asin(generatrix) / 3.14159 * scale + float2(0.5 + spin, 0.5);
    return float2(uv);
}
float2 sphericalVU = GenerateSphericalUV(position, scale, time*speed)

Shading de surface et normal map

  • Pour qu’une planète paraisse ronde, le shading est essentiel
  • Contrairement au shading standard des moteurs, une planète comporte deux couches, la surface et l’atmosphère ; il faut donc définir manuellement l’éclairage et le blending de chacune
  • Avec un rayon égal à 1, la position de surface avant rotation peut servir directement de normale de surface
  • L’éclairage utilise un modèle lambertien simple
    • L’objectif n’est pas le photoréalisme absolu, mais une esthétique de couverture SF stylisée inspirée de photos de la NASA
float LambertianLight(float3 normal, float3 lightDirection) {
    float NdotL = max(dot(normal, lightDirection), 0.0);
    return NdotL;
}
  • Pour une surface lisse comme celle d’une géante gazeuse, une normale simple peut suffire
  • Pour une planète rocheuse, il est plus adapté de simuler le relief — montagnes, crêtes, cratères — avec une normal map
  • L’usage d’une normal map nécessite une matrice TBN composée de Tangent, Bitangent et Normal
    • Sur une sphère, ce calcul doit être effectué au pixel près
    • La matrice TBN sert à convertir les normales de la normal map en World Space Coordinates

Discontinuités UV et artefacts de mipmap

  • Les UV générées dans le pixel shader peuvent poser un problème de discontinuité
  • La seam arrière devrait raccorder parfaitement la composante UV horizontale entre 0.0 et 1.0, mais en pratique des artefacts blocky apparaissent le long de la jonction
  • Cette ligne correspond au DDX des UV
    • DDX et DDY mesurent le taux de variation des UV selon les axes de l’espace écran
    • Le sampler de texture utilise ces valeurs pour choisir le mipmap à employer
    • Une dérivée UV faible correspond à un mipmap haute résolution, une dérivée élevée à un mipmap basse résolution
  • Si les valeurs sautent brutalement de part et d’autre de la seam, le DDX devient grand et l’échantillonnage peut basculer sur le mipmap le plus bas, ce qui apparaît comme une ligne grise
  • Sur cette planète, le problème doit être masqué par un patch polaire, donc ce n’est pas critique ; si cela devient visible, il faut corriger manuellement DDX et DDY de la seam et les transmettre au sampler
  • Le correctif montré n’est qu’un exemple pédagogique ; dans un cas réel, les formules doivent être dérivées en fonction du mapping utilisé

Patch polaire et correction du pinching

  • La déformation aux pôles est masquée avec une méthode éprouvée : le polar patch
  • Sur une planète ou une lune, les régions polaires sont souvent couvertes de glace et visuellement distinctes du reste, ce qui permet à un patch de texture séparé de cacher le problème tout en ajoutant de l’intérêt visuel
  • Le polar patch peut être ajouté en le mappant sur un plan perpendiculaire à l’axe de rotation, puis en faisant tourner les coordonnées obtenues
float2 PolarPatchMapping(float3 position, float scale, float spin)
{
    float cosSpin = cos(spin);
    float sinSpin = sin(spin);
    float scale = 0.4;

    float2 uv = float2(position.x, position.z) * scale;
    float2 spinningUV = float2(uv.x * cosSpin - uv.y * sinSpin,
                               uv.x * sinSpin + uv.y * cosSpin);

    return spinningUV;
}
  • Comme l’UV map n’est pas stockée dans les sommets mais générée pour chaque pixel, la correction du pinching aux pôles gagne en flexibilité
  • Une simple division permet de corriger l’aspect ratio de la texture polaire
uv = float2(uv.x, uv.y/pow(width, 1/3));
  • Le résultat de cette correction peut ressembler à un autre artefact, mais dans une scène réaliste il s’enchaîne plus naturellement avec le polar patch et réduit les incohérences visuelles

Approximation du halo atmosphérique

  • Comme la surface planétaire n’occupe pas toute la zone du disque, l’espace restant peut servir à dessiner un halo atmosphérique
  • Dessiner le halo dans le même shader permet de le fusionner naturellement avec l’atmosphère visible au-dessus de la planète
  • Le rendu atmosphérique physique repose souvent sur la diffusion de Rayleigh et le raymarching, mais ce n’est pas utilisé ici
  • À la place, une approximation similaire au trick d’éclairage des objets dynamiques dans Quake 1 et 2 est employée
    • Dans Quake, l’éclairage statique était pré-calculé via des lightmaps
    • Les monstres dynamiques échantillonnaient la lightmap située sous eux pour ajuster leur couleur ; ce n’était pas physiquement exact, mais cela les intégrait visuellement à leur environnement
  • De la même manière, la surface planétaire sert ici à approximer l’éclairage du halo atmosphérique
    • On étend la normale de surface avant bump mapping pour calculer la luminosité du halo
    • En remappant différemment la luminosité selon les canaux, on simule simplement l’absorption différente des longueurs d’onde lumineuses
    • Comme l’atmosphère est plus visible sous un angle rasant, on remappe la composante Z de la normale de surface
    • La distance à la surface sphérique est aussi calculée pour produire l’effet de fondu du halo
  • À la fin, la surface et l’atmosphère sont fusionnées via alpha blending

Résultat final et usages

  • Même si cela a demandé plus d’étapes que prévu, le résultat final ressemble à une sphère complète et permet les manipulations voulues sur les textures et les shaders
  • Un seul graph Substance Designer suffit à produire la texture de surface, sans post-traitement supplémentaire
  • Les textures animées peuvent être gérées exactement de la même manière
    • On peut utiliser des textures plus petites pour économiser en performance
    • Le tiling peut être ajusté autant que nécessaire
  • Le résultat en vidéo est visible dans Video 3

1 commentaires

 
GN⁺ 2024-06-06
Commentaires sur Hacker News
  • L’auteur semble avoir écarté les cube maps un peu trop vite ; pour le rendu d’une planète gazeuse dynamique dans un projet perso, c’était la solution la plus simple que j’aie trouvée
    Utiliser des cube maps ne multiplie pas la mémoire par 6 ; on découpe simplement une grande texture rectangulaire en 6 petites faces rectangulaires, donc le niveau global de détail de texture reste le même
    L’avantage, c’est qu’on n’a pas à se soucier de l’écrasement aux pôles, et qu’il est facile de créer avec une fonction de bruit 3D ou 4D un champ de flux sans couture pour l’animation/la déformation des textures
    https://www.junkship.net/News/2016/06/09/jupiter-jazz

    • Pour éviter d’étranges artefacts de jointure, il peut être préférable d’utiliser deux hémisphères en projection stéréographique
      Chaque hémisphère est projeté sur un disque, mais on peut remplir la texture jusqu’aux limites carrées et faire se chevaucher une partie de chaque hémisphère dans les coins de la texture opposée
      Il y a un écart d’échelle de 1:2 entre le centre du disque et son bord, donc on peut considérer qu’il y a un gaspillage de pixels au regard du détail minimal, mais comme c’est une projection conforme, cela rend beaucoup moins délicat l’échantillonnage de la couleur du pixel visé sous des perspectives extrêmes, et les calculs aller/retour ne demandent qu’une division et quelques additions/multiplications par point projeté, ce qui est même moins coûteux que la projection centrale d’une cube map
      Si l’on veut une méthode conforme qui réduise davantage les variations d’échelle et le gaspillage de pixels dans les coins sans devenir trop compliquée conceptuellement, on peut utiliser deux projections de Mercator légèrement chevauchantes et perpendiculaires pour couvrir la sphère comme deux pièces de cuir de balle de baseball
      Chaque pièce peut être une texture rectangulaire, et certains articles du NOAA proposent cette approche pour les grilles d’équations différentielles dans les simulations météo terrestres
      La projection la plus efficace en pixels que je connaisse consiste à diviser la sphère en octaèdre, puis à couvrir chaque octant par une grille hexagonale de pixels basée sur des « coordonnées d’aire sphérique »
      Chaque octant peut être représenté dans une image classique à pixels carrés comme un demi-carré, c’est-à-dire un triangle rectangle 45-45-90, ce qui donne des résultats comme https://observablehq.com/@jrus/sac-quincuncial et permet aussi d’utiliser des grilles hexagonales comme https://observablehq.com/@jrus/sphere-resample
      En revanche, la gestion détaillée de l’échantillonnage à travers les frontières est bien plus pénible qu’avec l’approche à deux projections stéréographiques, et des artefacts de jointure peuvent aussi apparaître
    • https://en.wikipedia.org/wiki/Peirce_quincuncial_projection
    • Si l’on veut réduire encore la distorsion, on peut aussi regrouper les faces triangulaires d’un icosaèdre régulier en 10 losanges, puis couvrir chaque losange avec une texture carrée
      Cela demande plus de mathématiques, mais à moins de prévoir de subdiviser davantage la surface pour d’autres raisons, cela n’en vaut généralement pas la peine
    • Je pourrais essayer ce bruit de rotationnel pour générer des nuages dans le jeu à l’échelle planétaire que je suis en train de faire
  • L’écrasement de texture aux pôles n’est en réalité qu’une forme extrême d’une distorsion présente sur toute la surface
    En général, cela ne se voit nettement qu’aux pôles, mais si l’on subdivise adaptativement la sphère en triangles, la distorsion varie aussi quand le niveau de subdivision change, donc cela peut devenir visible ailleurs
    Le problème vient du fait que la sphère est découpée en quadrilatères, et que chaque quadrilatère est représenté dans l’espace UV par deux triangles de même aire, alors qu’en espace 3D l’un des triangles — surtout celui dont l’arête horizontale est la plus proche du pôle — est plus petit
    Pourtant, les UV sont interpolés linéairement à l’intérieur des triangles, donc la moitié de la texture est comprimée et l’autre moitié étirée
    Aux pôles, l’aire 3D d’un des triangles devient effectivement nulle, donc seule la moitié de la texture est rendue, et la jointure entre triangles devient très visible
    La bonne solution consiste à calculer les coordonnées UV par pixel dans le pixel shader au lieu d’utiliser une interpolation linéaire par sommet ; si c’est bien fait, même les pôles sont gérés sans couture

    • Je commence tout juste à toucher au rendu, aux shaders et au développement de jeux, donc si vous avez des pistes, mots-clés ou liens à explorer, je suis preneur
    • Est-ce qu’on ne pourrait pas corriger ce problème en mettant W à l’échelle au lieu de le fixer à 1 dans l’élément XYZ ?
    • Est-ce qu’on rend parfois une sphère avec plusieurs pôles de rendu pour réduire ce type d’écrasement ?
      Par exemple, pour une sphère avec un pôle « nord vrai », on utiliserait le pôle de rendu du nord vrai quand on la regarde de côté, et un rendu équatorial à 0',0’ quand on la regarde depuis une zone proche du nord vrai
  • Cela me donne envie de revisiter le displacement mapping
    Ce n’est peut-être pas une alternative au problème que l’auteur essaie de résoudre, mais c’est plus simple et plutôt amusant
    Il y a environ 25 ans, j’ai créé pour SoundJam un visualiseur musical appelé « Eclipse », dont les entrées étaient un tableau de niveaux dans les fréquences audibles et les canaux gauche/droite
    L’objectif était d’obtenir l’apparence d’un soleil éclipsé avec une couronne rayonnante, et les données musicales constituaient ces « éjections »
    La fréquence des données déterminait où elles apparaissaient autour du disque solaire
    Avec le temps, les éjections s’éloignaient du soleil et « refroidissaient » jusqu’à disparaître dans le noir ; les signaux forts commençaient en blanc, puis devenaient jaunes, orange, rouges et bruns à mesure qu’ils faiblissaient
    Il fallait conserver un tableau de valeurs sonores dans un tampon circulaire suffisamment grand pour contenir toute la durée avant que les éjections ne disparaissent dans le noir
    L’ensemble d’« Eclipse » et l’affichage des éjections étaient en fin de compte une displacement map, et j’avais précalculé un bitmap dont chaque valeur de pixel servait de décalage dans le tampon de niveaux sonores
    Les pixels proches de la surface du soleil pointaient vers les offsets des données nouvellement entrées, tandis que les pixels extérieurs pointaient vers les offsets proches de la fin du tampon, sur le point d’expirer
    Comme il fallait mapper des éjections circulaires et radiales en coordonnées cartésiennes, la génération des valeurs de déplacement demandait un peu de mathématiques
    La boucle principale recevait les nouvelles valeurs sonores, écrasait les plus anciennes, puis parcourait la displacement map par lignes et colonnes pour récupérer les données sonores correspondantes, les mapper à une couleur dans une palette fixe et les placer dans le tampon d’affichage
    Ce n’était pas aussi spectaculaire que d’autres visualiseurs, mais cela avait une beauté calme et reflétait assez bien les données musicales
    Ce n’était pas comme ces visualiseurs ultérieurs qui semblent incapables de rester immobiles, même quand on leur donne du silence

  • L’article est génial, mais plus on fait défiler vers le bas, plus il charge de shaders, au point que le navigateur peut presque se figer si la machine n’est pas très puissante

    • Qu’est-ce que tu entends par « machine très puissante » ? Même le GPU intégré d’un portable de moins de 10 ans aurait du mal à rendre ce genre de chose ?
  • Il est intéressant de voir à quel point les gens interprètent différemment le « réalisme ».
    Dans les jeux d’une époque où les ressources étaient bien plus limitées, cet écart était particulièrement net, et certains titres, avec leurs graphismes anguleux, pixelisés et à palette réduite, procuraient plus d’immersion que les jeux AAA d’aujourd’hui.

    the gas giant’s surface texture will be generated in realtime using a pixel
    shader and a render-to-texture approach
    Il est intéressant de voir quelqu’un partir d’une approche impraticable et sans garde-fous dès le départ, chercher le moyen de créer un goulot d’étranglement de performance, puis continuer encore et s’enfoncer dans le terrier du lapin.
    Je me demande au final si l’auteur du billet original a réellement réussi à faire fonctionner tout ça.
    C’est peut-être aussi la différence entre un projet avec des contraintes réelles et un projet hobby.
    On peut utiliser une texture animée pré-rendue pour les géantes gazeuses, passer au reste du projet, puis, une fois l’ensemble opérationnel, revenir plus tard en mode cosplay de Slartibartfast.

    • Si les jeux à faible fidélité étaient plus immersifs, c’est peut-être parce qu’ils laissaient plus de place à l’imagination.
      J’ai l’impression que cela poussait à s’immerger plus activement.
  • Cet article sur une approche similaire me revient en tête : https://bgolus.medium.com/rendering-a-sphere-on-a-quad-13c92...

  • N’existe-t-il pas, dans les GPU ou les bibliothèques 3D, une fonction qui balaie horizontalement chaque ligne d’un cercle et mappe les X,Y de la texture vers une position « 3D » sur une sphère ?
    Une sphère, c’est un cercle, et les algorithmes pour dessiner un cercle sont simples ; faire tourner et projeter un million de sommets pour des triangles ressemble à un énorme gaspillage de ressources.
    Il suffit de balayer horizontalement, descendre d’une ligne et continuer pour dessiner toutes les lignes.
    Je me souviens avoir fait ce genre de choses à la fin des années 80 pour précalculer des effets comme la loupe de Second Reality.

    • C’est probablement parce que l’interpolation sphérique linéaire est plus lente et plus spécialisée que l’interpolation linéaire.
      Toute la pipeline de rendu est déjà conçue pour traiter l’interpolation linéaire.
      Avec un seul shader et un seul triangle, on peut déjà dessiner une sphère parfaitement anti-aliasée.
    • Les GPU ne rastérisent pas ligne par ligne comme les anciens moteurs de rendu logiciel ; fondamentalement, ils ne savent faire que de la rastérisation de triangles.
      Si l’on rend sur GPU, l’approche de l’article paraît plutôt bonne malgré sa complexité apparente.
      Il existe une excellente série d’articles sur l’architecture du rendu sur GPU : https://fgiesen.wordpress.com/2011/07/09/a-trip-through-the-...
      Le sixième volet traite de la rastérisation.
    • Le code fourni par GPT calculait le z pour chaque pixel dans le cercle, appliquait une rotation, puis utilisait atan2 et asin pour obtenir les coordonnées de texture avant de colorer le pixel, et à l’exécution, cela semblait fonctionner.
  • Les planètes imposteurs 2D en pixel shader sur arrière-plan sont vraiment d’une grande aide pour les projets avec beaucoup de planètes, comme un univers procédural.
    À cause de la mémoire et de la bande passante GPU, je limite les planètes basées sur des cubesphères à une seule instance, et je dessine les corps proches avec une technique d’arrière-plan.
    Dans l’espace, il existe une distance à peu près à mi-chemin entre deux corps célestes où les deux sont rendus comme des imposteurs, puis le corps le plus proche est traité avec une approche en quadtree sphérique.
    Ce n’est pas parfait, mais l’illusion est presque irréprochable.
    Comme tout est sur un plan, il devient aussi plus facile d’ajouter de légers effets physiques de lentille de caméra pour des galaxies ou corps célestes lointains.
    Par exemple, faire paraître la lune plus grande qu’elle ne l’est lorsqu’elle se lève, ou donner à une galaxie lointaine un aspect courbé par la gravité.

  • J’aime bien cette page liée aux géantes gazeuses : https://emildziewanowski.com/flowfields/

  • Une icosphère peut être dépliée beaucoup plus proprement, et la position des sommets comme la taille des éléments sont régulières.
    Le dépliage n’est pas trivial, mais c’est faisable.