Je suis en train de développer un moteur de jeu qui utilise des champs de distance signés comme technique de rendu pour afficher une géométrie procédurale fluide (généré avec des primitives simples comme celles de votre lien pour l'instant, en vue d'implémenter des fractales Julia et IFS à l'avenir). Étant donné que mon moteur est axé sur la génération procédurale et doit définir les chiffres d'une manière qui les rend conviviaux pour les ray-marcheurs, je pense que je suis bien placé pour répondre à cette question: P.
En ce qui concerne le streaming, la solution simple consiste à utiliser une sorte de tampon typé et à le jeter sur le GPU lorsque vous voulez faire votre ray ray. Chaque élément du tampon est un type complexe (par exemple une structure en C / C ++), et chaque type contient des éléments définissant la fonction que vous devez utiliser pour le représenter, sa position, sa rotation, son échelle, etc., et une couleur moyenne. Le processus se simplifie alors jusqu'à:
- Éliminez votre scène dans un sous-ensemble gérable (notez que l'élimination des troncs et de l'élimination des occlusions est en partie effectuée automatiquement par l'algorithme de défilement des rayons)
- Passez le sous-ensemble dans votre tampon d'entrée de rendu
- Passez le tampon au GPU s'il n'est pas déjà là, puis restituez votre scène avec un ray-marching traditionnel. Vous devrez effectuer une sorte de recherche par étape pour évaluer quel élément du tampon d'entrée est le plus proche de chaque rayon pour chaque itération du ray-marcher, et vous devrez appliquer des transformations à l'un ou l'autre des rayons (dans ce cas vous devrez inverser les rotations des figures avant qu'elles n'atteignent le GPU) ou les fonctions de distance elles-mêmes (déplacement de l'origine de la fonction pour les changements de position, ajustement par exemple des longueurs des côtés cubiques pour les changements d'échelle, etc.) L'approche la plus simple consiste à simplement modifier les rayons avant vous les transmettez à la fonction de distance centrale réelle.
Concernant les couleurs des figures, n'oubliez pas que les shaders vous permettent de définir des types complexes ainsi que des primitives;). Cela vous permet de tout jeter dans une structure de style C, puis de renvoyer ces structures depuis votre fonction de distance.
Dans mon moteur, chaque structure contient une distance, une couleur et un ID qui la lie à la définition de chiffre correspondante dans le tampon d'entrée. Chaque ID est déduit du contexte environnant de la fonction de distance pertinente (puisque ma fonction de mappage parcourt le tampon d'entrée pour trouver la figure la plus proche de chaque rayon pour chaque étape, je peux traiter en toute sécurité la valeur du compteur de boucle lorsque chaque SDF est appelé comme l'ID de la figure pour cette fonction), tandis que les valeurs de distance sont définies à l'aide d'un noyau arbitraire SDF (par exemplepoint - figure.pos
pour une sphère), et les couleurs sont définies soit à partir de la couleur moyenne de l'élément approprié dans le tampon de la figure (d'où la raison pour laquelle il est utile de conserver l'ID de la figure) soit à travers une couleur procédurale pondérée en fonction de la moyenne stockée (un exemple pourrait être de prendre un nombre d'itérations pour un certain point sur le Mandelbulb, mappant votre "couleur moyenne" de l'espace colorimétrique FP à l'espace colorimétrique entier, puis en utilisant la couleur mappée comme une palette en la xorant sur le nombre d'itérations).
Les textures procédurales sont une autre approche, mais je ne les ai jamais utilisées moi-même. iq a fait beaucoup de recherches dans ce domaine et a publié des démonstrations intéressantes sur Shadertoy, ce qui pourrait être un moyen de recueillir des informations supplémentaires.
Que votre couleur soit statique pour chaque figure, générée de manière procédurale ou échantillonnée par magie à partir d'une texture procédurale, la logique de base est la même: les figures abstraites dans une sorte de type complexe intermédiaire (par exemple une structure), stockent à la fois la distance locale et locale color dans une instance de ce type, puis passez le type complexe comme valeur de retour de votre fonction de distance. Selon votre implémentation, la couleur de sortie peut ensuite passer directement à l'écran ou suivre le point de collision dans votre code d'éclairage.
Je ne sais pas si ce qui précède était suffisamment clair ou non, alors ne vous inquiétez pas de demander si quelque chose n'a pas de sens. Je ne peux pas vraiment donner d'échantillons de code GLSL / pixel-shading car je travaille avec HLSL et calcule l'ombrage, mais je suis heureux d'essayer de passer en revue tout ce que je n'ai pas écrit correctement en premier lieu :).