URL: https://linuxfr.org/users/killruana/journaux/mathsworld-the-s-expressed-shader-language Title: Mathsworld: the S-expressed shader language Authors: jtremesay Date: 2023年03月17日T19:07:29+01:00 License: CC By-SA Tags: mathsworld, raytracing, raytracer et s-expression Score: 15 TLDR: [Mathsworld](https://mathsworld.jtremesay.org/), un outil web pour faire du raytracing avec des scènes décrite en lisp. Salut 'nal, J'ai encore commis un [code](https://github.com/jtremesay/mathsworld) improbable. En gros, c'est un truc qui prend en entrée une scène écrite sous forme de [S-Expression](https://fr.wikipedia.org/wiki/S-expression) et qui génère un [shader WebGL](https://fr.wikipedia.org/wiki/OpenGL_Shading_Language) [raytraçant](https://fr.wikipedia.org/wiki/Ray_tracing) la scène. Pourquoi ? Parce que ça m'amusait. Et que je voulais apprendre des trucs. Tout à commencé avec mon envie de comprendre comment on générait des images avec des maths (et un ordinateur). J'ai d'abord fait un [raycaster](https://github.com/jtremesay/raycaster) façon Wolfenstein 3D. Ça m'a amené à découvrir et jouer avec les [SDF](https://fr.wikipedia.org/wiki/Fonction_distance_sign%C3%A9e). C'était cool, mais je voulais aller plus loin et passer à la 3D (et oui, bien que le rendu donne une impression de 3D, le moteur est purement 2D). J'ai acheté le livre Computer Graphics From Scratch (contenu disponible gratuitement sur le site de l'auteur [ici](https://www.gabrielgambetta.com/computer-graphics-from-scratch/)) de Gabriel Gambetta et commencé [mon raytracer](https://github.com/jtremesay/raytracer) en rust. Grace au livre, j'ai pu rapidement et facilement faire mes premiers rendus. J'étais content. Mais c'était lent (rendu CPU), et je n'étais pas satisfait du format d'entrée des scènes (YAML). C'est vers cette période là que Joalland< a posté son lien [Painting a Landscape with Maths](https://linuxfr.org/users/joalland/liens/painting-a-landscape-with-maths). Et ça m'a frustré. Parce que les concepts mathématiques sous-jacents sont étonnament simples (accessibles à un niveau Bac, peut-être moins), mais personne n'a envie de d'apprendre à faire de fat shaders GLSL pour pouvoir jouer avec des maths et faire de jolis paysages. Je le sais, parce que moi même j'avais envie de faire de jolis paysages avec des maths sans apprendre à faire de fat shaders GLSL. (Joalland<, tu te demandais comment il avait fait. C'est un [fat shader](https://www.shadertoy.com/view/MdX3Rr). Ces autres créations sont visibles [là](https://www.shadertoy.com/user/iq). Ce sont à chaque fois de fat shaders). Ça m'a aidé à redéfinir le scope du projet : - faire un truc genre [shadertoy](https://www.shadertoy.com/) pour simplifier la distribution afin de le rendre plus accessible qu'un utilitaire CLI en rust - avoir un format de scène facile à utiliser pour les humains ET l'ordinateur, possiblité de scripting, voir de génération procédurale de la scène. - utiliser le GPU pour avoir des performances décentes. - posséder un fort syndrome de [NIH](https://fr.wikipedia.org/wiki/Not_invented_here) Comme format de scène, j'ai choisi les s-expr. C'est plutôt simple à utiliser par un humain, c'est plutot simple à manipuler par l'ordinateur, et ça ouvre des possibilités de scripting for intéressantes pour méta-générer les scènes. Notre scène de référence: ```lisp (scene (camera (vector3 0 0 0) (vector3 1 1 1)) (union (list (sphere (vector3 0 -5001 0) 5000 (material (color 1 1 0) 1000)) (sphere (vector3 0 -1 3) 1 (material (color 1 0 0) 500)) (sphere (vector3 2 0 4) 1 (material (color 0 0 1) 500)) (sphere (vector3 -2 0 4) 1 (material (color 0 1 0) 10)))) (list (ambiant_light 0.2) (omni_directional_light 0.6 (vector3 2 1 0)) (directional_light 0.2 (vector3 1 4 4)))) ``` Un petit truc simple où on déclare 4 sphères colorés et quelques lumières. À terme, je compte utiliser [parenscript](https://parenscript.common-lisp.dev/) qui m'a été recommandé suite à mon dernier [journal](https://linuxfr.org/users/killruana/journaux/lips-lisp-dans-le-navigateur) pour profiter de toute la puissance de Common Lisp et pouvoir décrire des scènes de guedin facilement. Mais pour l'instant, afin de "gagner" du temps, j'ai écrit mon propre parseur. J'avoue, j'avais vraiment envie de découvrir les [parseur LL](https://fr.wikipedia.org/wiki/Analyse_LL). C'est magique ces trucs, ils méritent leurs propre journal. Une fois que j'ai chargé la scène en mémoire, je la transforme en shader GLSL que je dessine dans un context WebGL du navigateur. Là, j'ai fait sale. Je suis allé sur [Using shaders to apply color in WebGL](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL), copié collé le code comme un sagouin et supprimé comme un sauvage les trucs qui semblaient superflus. Vint la parti rigolote où je réimplémenta mon raytracer rust sous forme de fat shader GLSL capable de faire un rendu de la scène donnée plus haut hardcodé dans le shader. Une fois en possession de ce shader de référence, je m'en suis servi pour faire un template dans lequel j'insère la scène voulu par l'utilisateur, je file ça au GPU, et ka-boom, on a des pixels colorés : ![3 sphères colorés vert, rouge et bleu sur un sol jaune](https://github.com/jtremesay/mathsworld/blob/07b581209d85a4a6c4c7b2c70a5101a66bc7471e/linuxfr/canvas.png?raw=true) Tu peux jouer avec [là](https://mathsworld.jtremesay.org/). Comme tu peux le constater, l'UI et l'UX sont inexistantes. Tu as une textarea dans lequel tu peux éditer la scène, le canvas dans lequel le rendu est fait, et une textarea qui contient le shader généré et que tu peux ignorer. Le shader est regénéré à la volé lors de l'édition, les erreurs sont remontés dans la console. Pour l'instant, la syntaxe supporté est la suivante : une expression parenthésée composée d'un identifier et suivi de 0 ou plusieurs arguments pouvant être un nombre ou une expression parenthésée. ``` S ::= SEXPR $ SEXPR ::= ( identifier ARGS ) ARGS ::= ARG ARGS ARGS ::= ε ARG ::= number ARG ::= SEXPR ``` Il n'y a aucun retour en cas d'erreur, hormis un message cryptique dans la console du navigateur. Le format de description de scène est le suivant: ``` scene: Une scène avec une caméra, des lumières et des objets. Doit être la racine de la S-Expr - camera: La caméra - root: Le nœud principal. Peut-être de type `union` ou `sphere` - lights: Une liste de lumières. Peuvent-être de type `ambiant_light`, `omni_directional_light` ou `directional_light` camera: - position: (x, y, z) La position de la caméra dans la scène - view_port: (hauteur, largeur, distance) Les réglages du view port (en trèèèèèès gros, les réglages de zoom) union: Une union d'objets - nodes: Une liste de nœuds à unir. Peuvent être de type `union` ou `sphere` sphere: Une sphere - position: (x, y, z) La position de la sphère dans la scène - radius: Le rayon de la sphère - material: Le matériau de la sphère material: - color: (rouge, vert, bleu) La couleur RGB du matériau. Chaque composante est est défini dans l'intervalle [0, 1] - specular: l'intensité de l'effet de brillance ambiant_light: une lumière ambiante - intensity: intensité de la lumière omni_directional_light: une lumière omnidirectionnelle (une amoule) - intensity: intensité de la lumière - position: (x, y, z directional_light: une lumière directionnelle (le soleil) - intensity: intensité de la lumière - direction: (x, y, z) La direction normalisée de la lumière ``` À terme, je compte ajouter : - plus de formes - possibilité de définir ses propres formes - matériaux procéduraux - le plein support de common lisp pour écrire la scène - réécriture du backend du générateur de shader GLSL parce que là c'est vraiment caca :D - possibilité de faire des animations - une interface plus dans le style de shader toys, avec possibilité d'enregistrer et partager ses créations

AltStyle によって変換されたページ (->オリジナル) /