Le site est en construction. Des incohérences peuvent subsister.

Lancer de rayons

Partagé le par

Introduction

Dans le cadre d'un projet, j'ai eu l'occasion de découvrir GLSL (pour OpenGL Shading Language), et de programmer mes premiers shaders, mon expérience avec le graphisme par ordinateur se résumant jusque là à de la 2D avec SVG et l'élément HTML <canvas></canvas> (ou des technologies équivalentes). L'objectif ici est d'implémenter du lancer de rayon, de la 3D donc. Heureusement, des environnements comme Geoshade ou Shadertoy permettent d'itérer et d'obtenir un retour assez rapidement lors du développement de shaders, ou devrais-je dire, de fragment shaders pour être correct, ces outils ne couvrant pas les vertex shaders, une autre étape majeur du pipeline de rendu d'OpenGL. Le challenge est donc de parvenir à calculer un rendu complet dans un unique shader en faisant abstraction du reste du pipeline.

Les deux shaders présentés ici réalisent donc du lancer de rayons, que je présume physiquement simpliste et plutôt sous-optimal étant données les structures de données utilisées et leurs performances, sur deux types de surfaces, respectivement des sphères et des triangles assemblés en tétrahèdres. Ils n'en restent pas moins essentiellement identiques ; seuls la nature des objets, l'algorithme d'intersection et le calcul d'orientation des surfaces varient entre eux. Pour bénéficier des dernières fonctionnalités de GLSL, les shaders ont été développés et testés sur Shadertoy.

Macros

Les programmes macro-définissent trois constantes : SPHERE_COUNT / TETRAHEDRON_COUNT, RING_COUNT et REFLECTION_COUNT. Celles-ci représentent respectivement :

Voici quelques ensembles de valeurs qui donnent des résultats intéressants :

{SPHERE_COUNT: 27, RING_COUNT: 1, REFLECTION_COUNT: 0}
{TETRAHEDRON_COUNT: 9, RING_COUNT: 1, REFLECTION_COUNT: 0}

Une simple chaîne de sphères mates / tétrahèdres mats tournoyant autour d'une source de lumière

{SPHERE_COUNT: 27, RING_COUNT: 1, REFLECTION_COUNT: 2}
{TETRAHEDRON_COUNT: 9, RING_COUNT: 1, REFLECTION_COUNT: 2}

La même scène, mais avec des surfaces polies

{SPHERE_COUNT: 9, RING_COUNT: 2, REFLECTION_COUNT: 0}
{TETRAHEDRON_COUNT: 3, RING_COUNT: 2, REFLECTION_COUNT: 0}

Deux couches de sphères mates / tétrahèdres mats tournoyant autour d'une source de lumière

{SPHERE_COUNT: 9, RING_COUNT: 2, REFLECTION_COUNT: 2}
{TETRAHEDRON_COUNT: 3, RING_COUNT: 2, REFLECTION_COUNT: 2}

La même scène, mais avec des surfaces polies

Les rendus ci-dessous ont été obtenus avec le dernier ensemble de paramètres. Contrairement aux sphères qui ne sont composées que d'une face, les tétrahèdres en ont quatre, ce qui a clairement une incidence sur les performances du second shader ; c'est pourquoi il convient de réduire le nombre de tétrahèdres.

Bruitage du fond

Le fond à été bruité pseudo-aléatoirement pour éviter de le confondre avec les ombres qui sont quant à elles noires en absence de réflexions.

Perspective

Au lieu d'utiliser une projection orthographique, la scène est rendue en perspective. Pour cela, il est nécessaire de définir la focale de la caméra dont l'objectif est le canevas. Dans le code, il s'agit de la variable perspective. Celle-ci peut être ajustée pour modifier l'impression de profondeur. Il faut noter que dans la démarche de lancer de rayons, le rayon part bien de l'objectif et non du foyer pour éviter d'afficher les objets se situant entre les deux.

Lumière

La source de lumière est ponctuelle et au centre de la scène. L'intensité lumineuse de cette source est calculée de manière à être en tout point inversement proportionnelle au carré de la distance parcourue depuis la source (y compris après une réflexion). La puissance maximale de la source de lumière est stockée dans la variable power et peut être ajustée. Il faut noter que les surfaces sont orientées. Si la source se situe à l'intérieur d'un objet, alors la lumière le traverse mais ne s'y réfléchit pas : il cachera les objets se situant derrière, mais sans faire d'ombre à toute la scène.

Rendus

Rendu d'un lancer de rayons sur des sphères (voir le code source)
Rendu d'un lancer de rayons sur des tétrahèdres (voir le code source)

Une démonstration en direct est aussi disponible ici. À savoir que les calculs sont potentiellement intensifs et des problèmes de rendu sont attendus sur les appareils avec une représentation des nombres à virgule flottante de moyenne / faible précision.