volumetric rendering raymarching .pdf



Nom original: volumetric-rendering-raymarching.pdfTitre: Volumetric Rendering et raymarching avec UnityAuteur: Damien CRECHET

Ce document au format PDF 1.5 a été généré par LaTeX with acmart 2018/07/25 v1.55 Typesetting articles for the Association for Computing Machinery and hyperref 2016/06/24 v6.83q Hypertext links for LaTeX / pdfTeX-1.40.17, et a été envoyé sur fichier-pdf.fr le 10/12/2018 à 10:28, depuis l'adresse IP 81.1.x.x. La présente page de téléchargement du fichier a été vue 344 fois.
Taille du document: 1.3 Mo (8 pages).
Confidentialité: fichier public


Aperçu du document


Volumetric Rendering et raymarching avec Unity
Damien CRECHET
Cnam-ENJMIN
Angoulême, France
damien.crechet@gmail.com

Abstract
Cet article résume ce que j’ai étudié et expérimenté sur
le volumetric rendering, le raymarching et les fonctions distances signées lors de mon mémoire réalisé dans le cadre du
master JMIN. Une implémentation de ces techniques dans le
moteur de jeu Unity est expliquée.
CCS Concepts • Computing methodologies → Rendering; Shape modeling; Volumetric models; Ray tracing;

Figure 1. Scène rendu par Íñigo Quílez à l’aide du raymarching

Keywords Volumetric Rendering, Rendering, Raymarching,
Signed distance fields, Unity

État de l’art

Introduction
Dans le cadre du master Jeux et Médias Interactifs Numériques suivi au Cnam-ENJMIN, je devais réaliser un travail
de recherche pour valider ma première année de master. Le
but était d’étudier une notion, un logiciel ou une technologie
n’ayant pas été abordée en cours. J’ai donc souhaité travailler
sur un domaine que je ne connaissais pas.
Le site ShaderToy permet de créer ses propres shader et
de les visualiser directement depuis le site. En parcourant
les différents shaders, je me suis rendus compte que nombre
d’entre eux sont tagués raymarching ou volumetric et ont
un rendu impressionnant, je me suis alors demandé comment fonctionnait cette technique de rendu. J’ai donc décidé
d’étudier le volumetric rendering, et plus précisément le
raymarching lors de mon travail d’expérimentation.
Dans cet article, je parlerai de ce que j’ai pu apprendre à
propos de cette technique de rendu. J’expliquerai dans un
premier temps les notions de volumetric rendering et de raymarching, puis je présenterai ensuite les fonctions distance
signées qui permettent de modéliser des géométries avec le
raymarching. Enfin je montrerai les techniques d’éclairage
avec le raymarching et comment les objets rendus peuvent
interagir avec des meshes. J’ai décidé d’utiliser Unity pour
l’implémentation de ces techniques. J’aurais pu utiliser le site
ShaderToy, mais je souhaitais d’une part que le travail réalisé
sur ce mémoire puisse servir au développement de jeux, et
d’autre part les nombreuses ressources que j’ai trouvé utilisaient également Unity. Les extraits de code présents dans
cet article seront donc en C# ou dans le langage de shading
de Unity ShaderLab, une variante de HLSL.
Cnam-ENJMIN, Août 2018, Angoulême, France
.

Le raymarching est une technique relativement récente.
Íñigo Quílez a produit de nombreuses images et scènes à
l’aide du raymarching. Il a également écrit plusieurs articles
disponibles sur son site expliquant comme créer des scènes
similaires. Il participe activement à la publication de shaders
sur le site ShaderToy, dont il est l’un des co-créateurs. Ce site
regroupe énormément de shaders utilisant le volumetric rendering et le raymarching. J’ai donc pu y trouver de nombreux
exemples de shaders. J’ai également consulté la thèse de Carl
Lorenz Diener qui parle de la modélisation avec les fonctions distance signées. Mikael Hvidtfeldt Christensen est un
physicien et développeur qui s’intéresse particulièrement à
l’art génératif. Il a publié une série d’articles expliquant comment créer des fractales en utilisant le raymarching. Il existe
enfin plusieurs tutoriels expliquant comment fonctionne le
raymarching et les fonctions distance signées.

1

Volumetric rendering

Le volumetric rendering est un technique de rendu consistant à afficher une projection 2D de données 3D. Le but est
donc d’afficher des données à l’écran, mais pour cela, il est
impossible d’utiliser des meshes. Par exemple, pour rendre
du gaz ou des nuages il est impossible de créer un mesh, il
faut donc utiliser le volumetric rendering. Les meshes sont
composés de triangles. Dans Unity par exemple, seul la surface visible des objet est affichée. Il n’est pas possible pour la
lumière de pénétrer à l’intérieur d’un volume. Il existe néanmoins des techniques permettant de dépasser cette limite.
La figure 2 montre le rendu classique d’une scène. Le GPU
appelle le fragment shader lorsqu’un triangle est présent
dans le frustum de la caméra. Le fragment shader retourne
ensuite une couleur qui est assignée au pixel. Il est donc
possible de modifier la couleur renvoyée par le shader et
d’assigner une couleur qui ne correspond pas à la géométrie

Cnam-ENJMIN, Août 2018, Angoulême, France

Damien CRECHET

Figure 2. Rendu classique d’une scène

Figure 4. Visualisation d’un raymarching basique. Les
points rouges représentent les pas

Figure 3. Rendu d’un objet volumétrique
de la scène. La figure 3 montre comment cela fonctionne
en rendant un cube. Au lieu de rendre le cube, on pénètre
à l’intérieur et on rend la sphère que l’on a défini dans le
shader. Lorsque le fragment shader est appelé pour obtenir
la couleur du cube, retourner la couleur de la sphère à la
place. Le volumetric rendering permet de simuler des rayons
de lumière à l’intérieur des objets et de créer des effets qui
ne serait pas possible autrement.

2

Figure 5. Visualisation d’un raymarching amélioré. Les
cercles bleus représente la distance minimale avant de rencontrer un objet

4
5
6
7
8

Listing 1. Raymarching avec un pas constant
2.2

1
2
3
4
5
6
7
8

2

b o o l raymarch ( f l o a t 3 p o s i t i o n , f l o a t 3 d i r e c t i o n )
{
f o r ( i n t i = 0 ; i < STEPS ; i + + ) {

Raymarching amélioré

Il est possible d’améliorer cette implémentation. La progression avec un pas constant fait que le rayon peut traverser
une longue distance en ne rencontrant aucun objet. Cela affecte beaucoup les performances du shader, dépendant du
nombre de boucles.
Pour améliorer le raymarching, il faudrait estimer la distance la plus faible de la géométrie de la scène. Cela peut-être
calculé avec des fonctions distance signées. Ces fonctions
renvoie la distance d’un point à la surface d’une géométrie.
Si le point est en dehors de la géométrie, le résultat est positif.
Si le point est à la surface, le résultat est nul. Enfin, si le point
est à l’intérieur, le résultat est négatif. Les fonctions distance
seront abordées dans plus de détail dans la partie 3.

Raymarching basique

Une implémentation basique du raymarching consiste à
lancer un rayon depuis chaque pixel de l’écran. Il faut ensuite
faire progresser le rayon avec un pas constant. A chaque
itération, on vérifie si le point sur le rayon touche un objet
de la scène. Sur la figure 4, on peut voir que l’intersection
trouvée avec l’objet de la scène est peu précise. En effet avec
des pas constants, le rayon peut rentrer dans l’objet. Cette
technique permet toutefois d’obtenir des rendus suffisants.
1

}

Raymarching

Le raymarching est une technique utilisée pour rendre
des scènes en temps réel. Cette technique est similaire au
raytracing car des rayons sont lancés depuis chaque pixel de
l’écran. Le raytracing nécessite des équations d’intersections
pour savoir si un rayon touche un objet. Cette technique nécessite beaucoup de ressources en fonction de la complexité
de la scène et de l’éclairage. De plus, elle ne permet pas de
faire du rendu volumétrique sur des surfaces comme du verre
ou de l’eau.
Il faut donc une autre technique qui ne se base pas sur des
équations d’intersection. Le raymarching est une solution
alternative qui consiste à progresser le long du rayon.
2.1

if ( objetHit ( position ) )
return true ;
p o s i t i o n += d i r e c t i o n ∗ STEP_SIZE ;
}
return f al s e ;

3

9

f i x e d 4 raymarch ( f l o a t 3 p o s i t i o n , f l o a t 3 d i r e c t i o n
) {
f o r ( i n t i = 0 ; i < STEPS ; i + + ) {
float distance = objectDistance ( position ) ;
i f ( d i s t a n c e < MIN_DISTANCE )
return _Color ;
p o s i t i o n += d i s t a n c e ∗ d i r e c t i o n ;
}
return 0;
}

Listing 2. Raymarching avec des fonctions distance signées

Volumetric Rendering et raymarching avec Unity

Cnam-ENJMIN, Août 2018, Angoulême, France
Vector3 topRight = (− Vector3 . forward + toRight
+ toTop ) ;
Vector3 bottomRight = (− Vector3 . forward +
t o R i g h t − toTop ) ;
Vector3 bottomLeft = (− Vector3 . forward −
t o R i g h t − toTop ) ;

15
16
17
18

frustumCorners
frustumCorners
frustumCorners
frustumCorners

19

Figure 6. Visualisation d’un raymarching. L’intensité du
rouge représente le nombre de pas nécessaires au rayon
avant de rencontrer la géométrie.

20
21
22

. SetRow ( 0
. SetRow ( 1
. SetRow ( 2
. SetRow ( 3

,
,
,
,

topLeft ) ;
topRight ) ;
bottomRight ) ;
bottomLeft ) ;

23

return frustumCorners ;

24
25

}

Listing 3. Calcul des coins du frustum
Il faut ensuite passer les rayons au GPU. Avec le script
suivant, il sera possible d’accéder à la matrice contenant les
coins du frustum dans le shader avec la variable F rustumCorners.
1

Figure 7. Debug des rayons lancés par le raymarching. Les
rayons verts sont les quatre vecteurs stockés dans la matrice

Listing 4. Envoi de la matrice contenant les coins du frustum
au shader

Cette technique est bien plus rapide que le raymarching
avec pas constant. Elle est plus lente sur les bords des objets,
mais cela peut-être contrôlée en modifiant la taille minimale
d’un pas.
2.3

Il faut ensuite dire au vertex shader comment interpréter
cette matrice. Chaque vertex du vertex shader doit connaître
quel coin du frustum utiliser. On dessine donc un quad dont
les vertex seront traités par le vertex shader du shader de
post process. Comme le quad est dessiné en projection orthographique, les coordonnées z sont inutilisées et peuvent
donc contenir l’index de la ligne à utiliser dans la matrice du
frustum.

Implémentation dans Unity

Comme le raymarching est lancé sur tous les pixels, un
raymarcher peut-être considéré comme un shader de post
processing dans Unity. Adiran Biagioli propose une implémentation d’un raymarching dans Unity [1].
Il faut d’abord passer les rayons utilisés par l’algorithme
de raymarching au fragment shader. La première étape de
calculer les vecteurs formant le frustum de la caméra, soit
les quatre vecteurs formant les coins du frustum. Ces quatre
vecteurs seront stockés dans une matrice qui sera passé au
shader ensuite. Cela permet de n’envoyer qu’une seule variable au shader au lieu de quatre vecteurs.

E f f e c t M a t e r i a l . SetMatrix ( " _FrustumCorners " ,
G e t F r u s t u m C o r n e r s ( camera ) ) ;

1

GL . B e g i n ( GL . QUADS ) ;

2
3
4

GL . M u l t i T e x C o o r d 2 ( 0 , 0 . 0 f , 0 . 0 f ) ;
GL . V e r t e x 3 ( 0 . 0 f , 0 . 0 f , 3 . 0 f ) ; / / Bottom l e f t

5
6
7

GL . M u l t i T e x C o o r d 2 ( 0 , 1 . 0 f , 0 . 0 f ) ;
GL . V e r t e x 3 ( 1 . 0 f , 0 . 0 f , 2 . 0 f ) ; / / Bottom r i g h t

8
9
10

GL . M u l t i T e x C o o r d 2 ( 0 , 1 . 0 f , 1 . 0 f ) ;
GL . V e r t e x 3 ( 1 . 0 f , 1 . 0 f , 1 . 0 f ) ; / / Top r i g h t

11
1
2
3

p r i v a t e M a t r i x 4 x 4 G e t F r u s t u m C o r n e r s ( Camera cam ) {
f l o a t camFov = cam . f i e l d O f V i e w ;
f l o a t camAspect = cam . a s p e c t ;
Matrix4x4 frustumCorners = Matrix4x4 . i d e n t i t y ;

6
7

f l o a t fovWHalf = camFov ∗ 0 . 5 f ;

8
9

f l o a t t a n _ f o v = Mathf . Tan ( fovWHalf ∗ Mathf .
Deg2Rad ) ;

10
11
12

Vector3 toRight = Vector3 . r i g h t ∗ tan_fov ∗
camAspect ;
V e c t o r 3 toTop = V e c t o r 3 . up ∗ t a n _ f o v ;

13
14

13

Vector3 t o p L e f t = (− Vector3 . forward − toRight
+ toTop ) ;

GL . M u l t i T e x C o o r d 2 ( 0 , 0 . 0 f , 1 . 0 f ) ;
GL . V e r t e x 3 ( 0 . 0 f , 1 . 0 f , 0 . 0 f ) ; / / Top l e f t

14
15

4
5

12

16

GL . End ( ) ;
GL . P o p M a t r i x ( ) ;

Listing 5. Quad dessiné devant la caméra
Il reste ensuite à traiter ces données dans le shader. Dans le
vertex shader, on récupère l’indice de la ligne de la matrice en
utilisant la coordonnée z du vertex en entrée. On peut ensuite
récupérer le rayon du frustum correspondant au vertex. On
passe ensuite le rayon en espace monde. Les données sont
ensuite passées au fragment shader. Le rayon est normalisé
pour obtenir la direction et l’origine du rayon est récupéré
en passant la position de la caméra en espace monde dans

Cnam-ENJMIN, Août 2018, Angoulême, France

Damien CRECHET

une variable uniforme. On appelle ensuite l’algorithme de
raymarching et on renvoie la couleur obtenue.
1
2
3
4

v2f vert ( appdata v ) {
v2f o ;
o . pos = mul ( UNITY_MATRIX_MVP , v . v e r t e x ) ;
o . uv = v . uv . xy ;

5

h a l f index = v . vertex . z ;
o . r a y = _ F r u s t u m C o r n e r s E S [ ( i n t ) i n d e x ] . xyz ;
o . r a y = mul ( _CameraInvViewMatrix , o . r a y ) ;

6
7
8

Figure 8. Géométrie rendue avec les opérations de distance

9
11

la géométrie de construction de solide ( Constructive solid
geometry, ou CSG). La CSG permet de combiner des objets
simples à l’aide d’opérations booléennes. La CSG est basée
sur trois opérations : l’union, l’intersection et la différence.
L’union est la combinaison de deux géométries. La distance de l’union de deux surfaces est la distance minimum
de ces surfaces. La distance de l’intersection de deux surfaces est la distance maximum de ces surfaces. La différence
consiste à rendre la partie de l’objet 1 qui n’est pas superposé
par l’objet 2, ou à retirer l’objet 2 de l’objet 1. La différence
de deux surface peut être définie par le maximum entre la
distance à la première surface et l’opposé de la distance à la
deuxième surface.

return o ;

10

}

12
13
14
15

f i x e d 4 f r a g ( v2f i ) : SV_Target {
f l o a t 3 r a y D i r e c t i o n = n o r m a l i z e ( i . r a y . xyz ) ;
f l o a t 3 r a y O r i g i n = _CameraWSPos ;

16

f i x e d 4 c o l o r = raymarch ( r a y O r i g i n ,
rayDirection ) ;

17
18

return color ;

19
20

}

Listing 6. Vertex et fragment shader

3

Fonctions distance signées

Les fonctions distances signées ( Signed distance fields,
ou signed distance functions, ou SDF ) sont basées sur la
représentation de plusieurs primitives par des fonctions. Ces
fonctions prennent un point en paramètre et renvoie la distance à la surface de l’objet.
Il est possible de représenter des primitives simples à l’aide
de fonctions mathématiques. L’exemple ci-dessous est la
fonction distance d’une sphère. Si le point est à l’intérieur
de la sphère, alors la distance est inférieure au rayon, donc
le résultat sera négatif. Si le point est à l’extérieur, alors la
distance est supérieure au rayon et la valeur renvoyée sera
positive. Enfin, la distance du point à la sphère est égale au
rayon si le point est sur la surface de la sphère. Le résultat
de la fonction sera donc nul.
Il est possible de représenter de nombreuses primitives.
Íñigo Quílez a publié une liste de fonctions distances signées
[9], parmi lesquelles les fonctions pour représenter des box,
des torus, ou des capsules par exemple. La plupart des géométries montrées dans cette partie utilisent ses fonctions.
1
2
3

f l o a t sdSphere ( f l o a t 3 position , f l o a t radius ) {
return length ( position ) − radius ;
}

Listing 7. Fonction distance signée d’une sphère
3.1

Opérations de distance

Les opérations de distance permettent d’effectuer des opérations sur plusieurs objets. Elles sont appliquées sur plusieurs distances afin d’en obtenir une. Ces opérations permettent d’obtenir des formes plus complexes et de faire de

1
2
3
4
5
6
7
8
9

f l o a t opU (
return
}
f l o a t opI (
return
}
f l o a t opS (
return
}

f l o a t d1 , f l o a t d2 ) {
min ( d1 , d2 ) ;
f l o a t d1 , f l o a t d2 ) {
max ( d1 , d2 ) ;
f l o a t d1 , f l o a t d2 ) {
max ( d1 , − d2 ) ;

Listing 8. Opérations de distance. Les paramètres d1 et d2
sont les résultats des fonctions distances des deux objets.
La géométrie de la figure 8 peut-être définie par cette
équation :
® =unionSDF (
sceneSDF (p)
® sd f Sphere(p)),
®
di f f erenceSDF (sd f Box(p),
®
sd f Sphere(p)
)
3.2

Opérations de domaine

Les opérations de domaine modifient la position originale
afin d’obtenir une nouvelle position depuis laquelle calculer
l’intersection. Avec les opérations de domaine, il est possible de créer une répétition infinie d’objets sur n’importe
quel axe en utilisant le modulo de la position du point par
l’espacement entre chaque répétition.
Pour appliquer un translation ou une rotation à un objet,
il suffit de multiplier la position par un matrice. On obtient
ainsi un nouveau point qui sera utilisé pour trouver la distance à la primitive. Il est aussi possible de modifier la taille
de l’objet.

Volumetric Rendering et raymarching avec Unity

Cnam-ENJMIN, Août 2018, Angoulême, France

Figure 9. Répétition d’un cube

1
2
3
4
5
6
7
8
9
10
11

Figure 10. Déformation appliquée à l’objet de la figure 8

f l o a t opRep ( f l o a t 3 p , f l o a t 3 s p a c i n g ) {
f l o a t 3 q = fmod ( p , s p a c i n g ) − 0 . 5 ∗ s p a c i n g ;
return primitive ( q ) ;
}
f l o a t opTx ( f l o a t p , f l o a t 4 x 4 m ) {
f l o a t 3 q = m∗ p ;
return primitive ( q ) ;
}
f l o a t opScale ( f l o a t 3 p , f l o a t scale ) {
return primitive ( p/ scale ) ∗ scale ;
}

Figure 11. Blend appliquée à l’union entre deux cubes
minimum peut être contrôlée avec un paramètre k. Le smooth
minimum permet d’améliorer l’union de deux primitives. En
effet avec le minimum classique, l’intersection entre les objet
est très visible. Le smooth minimum permet de la lisser.

Listing 9. Opération de répétition et de transformation d’une
primitive
1

3.3

Déformations de distance

Les déformations de distance vont permettre de déformer
un objet en appliquant un déplacement ou en fusionnant
deux primitives. Comme pour les opérations de distance, les
déformations de distance utilisent deux distances pour en
obtenir une. Pour le déplacement, il faut utiliser une fonction permettant de modifier la surface de l’objet. Sur l’objet de la figure 10, le pattern de déplacement utilisé est :
cos (2.5 ∗ p.x) ∗ sin (p.y) ∗ sin(p.z).
Pour le blend, la distance entre les deux primitives est le
smooth minimum des distances des deux primitives. Cela
permet d’obtenir une union plus lisse entre deux objets.
1
2
3
4
5
6
7
8
9
10

f l o a t opDisplace ( f l o a t 3 p ) {
f l o a t d1 = p r i m i t i v e ( p ) ;
f l o a t d2 = d i s p l a c e m e n t ( p ) ;
r e t u r n d1 + d2 ;
}
f l o a t opBlend ( f l o a t 3 p ) {
f l o a t d1 = p r i m i t i v e A ( p ) ;
f l o a t d2 = p r i m i t i v e B ( p ) ;
r e t u r n smin ( d1 , d2 ) ;
}

Listing 10. Opération de deformations

2
3
4
5

/ / Smooth minimum p o l y n o m i a l ( k = 0 . 1 ) ;
f l o a t smin ( f l o a t a , f l o a t b , f l o a t k ) {
f l o a t h = clamp ( 0 . 5 + 0 . 5 ∗ ( b−a ) / k , 0 . 0 , 1 . 0 ) ;
r e t u r n mix ( b , a , h ) − k ∗ h ∗ ( 1 . 0 − h ) ;
}

Listing 11. Implémentation du smooth minimum
polynomial
3.4

Déformations de domaine

Les déformations de domaine permettent comme les déformations de distance de modifier la forme de l’objet en
calculant une nouvelle position, comme pour les opérations
de domaine. Il est par exemple possible d’appliquer un twist
à un objet ( figure 12 ). Il est possible d’utiliser n’importe
quelle fonction de déformation, comme une fonction pour
plier la géométrie, ou un bruit.
1
2
3
4
5
6
7

f l o a t opTwist ( f l o a t 3 p ) {
f l o a t c = cos ( 2 ∗ p . y ) ;
float s = sin (2∗ p . y ) ;
float2x2 m = float2x2 ( c,−s , s , c ) ;
f l o a t 3 q = f l o a t 3 (m∗ p . xz , p . y ) ;
return primitive ( q ) ;
}

Listing 12. Exemple d’opération de twist
Smooth minimum
Le smooth minimum permet permet de calculer un minimum en enlevant la discontinuité du minimum classique.
Íñigo Quílez propose une implémentations du smooth minimum [12] : le smooth minimum polynomial. Si les deux
valeurs sont suffisamment éloignées, alors le minimum classique est utilisé. Sinon si les deux valeurs sont proches, le
résultat est lissé. La distance maximal pour utiliser le smooth

4

Illumination

Pour simuler la lumière sur les objets rendus, il est possible d’utiliser la réflexion lambertienne. La lumière réfléchie
par une surface lambertienne dépend de l’orientation de la
surface et de la direction de la lumière.

Cnam-ENJMIN, Août 2018, Angoulême, France

Damien CRECHET

Figure 12. Twist appliqué à un torus

Figure 14. Réflexion spéculaire selon le modèle de BlinnPhong

Figure 13. Réflexion lambertienne simple
Figure 15. Illumination d’une sphère avec réflexion spéculaire
I = N ·L
10
1
2
3

f i x e d 4 s i m p l e L a m b e r t ( f i x e d 3 normal ) {
f i x e d 3 l i g h t D i r = _ W o r l d S p a c e L i g h t P o s 0 . xyz ; / /
Light direction
f i x e d 3 l i g h t C o l = _LightColor0 . rgb ;
/ / Light
color

}

Listing 14. Approximation de la normale
On peut ensuite rajouter un reflet spéculaire à la surface.
Pour cela, on peut se référer au modèle de Blinn-Phong.

4
6
7
8
9
10

I = (N · H )specul ar · дloss

f i x e d NdotL = max ( d o t ( normal , l i g h t D i r ) , 0 ) ;
fixed4 c ;
c . r g b = _ C o l o r ∗ l i g h t C o l ∗ NdotL ;
c . a = 1;
return c ;

5

L +V
|L + V |
Il suffit de modifier la fonction simpleLambert. La variable
pecularPower
contrôle la taille de la réflexion spéculaire,
S
et la variable G loss permet de modifier son intensité.
Le résultat de toute ces étapes d’éclairage est visible sur
la figure.
H=

}

Listing 13. Calcul de réflexion lambertienne
Il reste maintenant à calculer la normale de la surface.
Les fonctions distances ne contiennent pas cette information. Íñigo Quílez propose une technique pour approximer
la normale [11]. Elle consiste à calculer la distance à des
points proches pour trouver la courbure de la surface. La
variable eps correspond à la distance entre les points utilisés pour calculer le gradient de la surface. Cette technique
fonctionne bien si la surface est suffisamment lisse. S’il y
a des discontinuités, alors la normale ne sera pas calculée
précisément.
1
2
3
4
5
6
7
8
9

f l o a t 3 normal ( f l o a t 3 p ) {
const f l o a t eps = 0 . 0 1 ;
return normalize
( float3
( map ( p + f l o a t 3 ( eps , 0 , 0 ) ) − map ( p − f l o a t 3
( eps , 0 , 0 ) ) ,
map ( p + f l o a t 3 ( 0 , eps , 0 ) ) − map ( p − f l o a t 3
( 0 , eps , 0 ) ) ,
map ( p + f l o a t 3 ( 0 , 0 , e p s ) ) − map ( p − f l o a t 3
( 0 , 0 , eps ) )
)
);

1
2
3
4

fixed3 h = ( lightDir − viewDirection ) / 2 . ;
f i x e d s = pow ( d o t ( normal , h ) , _ S p e c u l a r P o w e r ) ∗
_Gloss ;
c . r g b = _ C o l o r ∗ l i g h t C o l ∗ NdotL + s ;
c . a = 1;

Listing 15. Calcul du reflet spéculaire

5

Interaction avec des meshes

Dans le cadre d’un jeu, il est intéressant de pouvoir utiliser
le raymarching avec des meshes. Les objets rendus avec le
raymarching ont actuellement l’air de flotter par dessus les
meshes ( figure 16 ) car le raymarching ne prend pas en
compte la profondeur.
Pour résoudre ce problème, il faut trouver pour chaque
rayon la distance minimale avant de rencontrer un mesh.
Si celle-ci est inférieure à la distance minimale d’un objet
volumétrique, alors on n’affiche pas ce dernier. Le depth
buffer nous permet de trouver cette distance.

Volumetric Rendering et raymarching avec Unity

Cnam-ENJMIN, Août 2018, Angoulême, France

Figure 18. Affichage correct lors de l’interaction avec un
mesh

Figure 16. Problème d’affichage lors de l’interaction avec
un mesh

ret = fixed4 (0 , 0 , 0 , 0) ;
break ;

5
6

}
float distance = objectDistance ( position ) ;
i f ( d i s t a n c e < MIN_DISTANCE )
return _Color ;
p o s i t i o n += d i s t a n c e ∗ d i r e c t i o n ;
t o t a l += d i s t a n c e ;

7
8
9
10
11

Figure 17. Données renvoyés par le depth buffer

12

}
return 0;

13
14

Sur la figure 17, la magnitude du r est la valeur qu’il nous
faut. Au delà de cette valeur, les objets volumétriques ne
doivent pas être affichés. La magnitude de d est la valeur
renvoyée par le depth buffer. Supposons r n le vecteur avec la
même direction que r mais de longueur 1 dans la direction z.
On peut définir r n comme :
rd
rd .z
Dans cette équation, rd est un vecteur avec la même direction que r qui correspond au rayon qui est passé au shader. r
et r n forment deux triangles similaires, donc en multipliant
r n par d, nous pouvons retrouver |r |.
rn =

|r | r n
=
d
1
|r | = r n d
Dans le shader, il faut donc passer r n au fragment shader
au lieu de rd . Il faut normaliser le rayon passé en entrée sur
l’axe z, en le divisant par sa coordonnée z.
1
2

f l o a t d e p t h = L i n e a r E y e D e p t h ( tex2D (
_CameraDepthTexture , uv ) . r ) ;
depth ∗= l e n g t h ( i . ray ) ;

15

}

Listing 17. Fonction de raymarching corrigé pour les mesh
apparaissent correctement
Il faut ensuite passer la profondeur maximale à la fonction
raymarch. Dans la boucle de raymarching, on s’arrête si la
distance parcourue par le rayon est supérieure à la profondeur maximale renvoyée par le depth buffer. La fonction
renvoie alors une couleur complètement transparente. On
peut maintenant voir sur la figure 18 que le cube rendu par
le raymarching s’affiche correctement avec le cylindre qui
est un mesh.

Conclusion
Le volumetric rendering et le raymarching permettent
d’effectuer des rendus qui seraient impossibles à effectuer
normalement. Les fonctions distance signées permettent
de modéliser des géométries et de créer des scènes avec
un rendu réaliste. Cette technique pourrait se démocratiser
même si la tendance va plutôt vers le raytracing avec l’annonce des prochaines cartes graphiques de Nvidia. Ce travail
d’expérimentation m’aura permis d’étudier cette technique
et d’apprendre à l’utiliser dans un moteur de jeu.

Listing 16. Approximation de la normale

Remerciements
Il faut ensuite accéder au depth buffer. Pour cela, on utilise
la variable uniform de Unity C ameraDepthT exture et on la
convertit en espace caméra. On multiplie ensuite la profondeur par la longueur de r n qui a été passée depuis le vertex
shader. L’équation ci-dessus est donc satisfaite.
1
2
3
4

f i x e d 4 raymarch ( f l o a t 3 p o s i t i o n , f l o a t 3 d i r e c t i o n
, f l o a t maxDepth ) {
float total = 0;
f o r ( i n t i = 0 ; i < STEPS ; i + + ) {
i f ( t o t a l >= maxDepth ) {

J’aimerais remercier Thomas Giro pour les références qu’il
m’a donné sur le sujet.

Références
[1] Adrian Biagioli. 2016. Raymarching Distance Fields : Concepts and
Implementation in Unity. (2016). http://flafla2.github.io/2016/10/01/
raymarching.html
[2] Simen Haugo. 2013. Raymarching Distance Fields. (2013). http:
//9bitscience.blogspot.com/2013/07/raymarching-distance-fields_14.
html

Cnam-ENJMIN, Août 2018, Angoulême, France
[3] Sehyun Av Kim. 2018.
Ray Marching Metaball in
Unity3D.
(2018).
https://medium.com/@avseoul/
ray-marching-metaball-in-unity3d-fc6f83766c5d
[4] Erik Nordeus. 2018. Volume render a Death Star. (2018). https://www.
habrador.com/tutorials/shaders/1-volume-rendering-death-star/
[5] Michael Pohoreski. 2015. HOWTO : Ray Marching. (2015). https:
//www.shadertoy.com/view/XllGW4
[6] Andrew Schneider and Nathan Vos. 2015. The real-time volumetric
cloudscapes of Horizon Zero Dawn. (2015). https://www.alanzucconi.
com/2016/07/01/volumetric-rendering/
[7] Jamie Wong. 2016.
Ray Marching and Signed Distance
Functions.
(2016).
http://jamie-wong.com/2016/07/15/
ray-marching-signed-distance-functions/
[8] Alan Zucconi. 2016. Volumetric Rendering. (2016). https://www.
alanzucconi.com/2016/07/01/volumetric-rendering/
[9] Íñigo Quílez. 2008. Modeling with distance functions. (2008). http:
//www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
[10] Íñigo Quílez. 2008. Raymarching distance fields. (2008). http://www.
iquilezles.org/www/articles/raymarchingdf/raymarchingdf.htm
[11] Íñigo Quílez. 2008. Rendering Worlds With Two Triangles. (2008).
http://www.iquilezles.org/www/material/nvscene2008/rwwtt.pdf
[12] Íñigo Quílez. 2013. Smooth minimum. (2013). http://www.iquilezles.
org/www/articles/smin/smin.htm

Damien CRECHET


Aperçu du document volumetric-rendering-raymarching.pdf - page 1/8

 
volumetric-rendering-raymarching.pdf - page 3/8
volumetric-rendering-raymarching.pdf - page 4/8
volumetric-rendering-raymarching.pdf - page 5/8
volumetric-rendering-raymarching.pdf - page 6/8
 




Télécharger le fichier (PDF)


Télécharger
Formats alternatifs: ZIP Texte



Documents similaires


volumetric rendering raymarching
td3 me2 2012
capesext composition de physique avec applications 2002 capes phys chm 1
projet aspirator2 v3
anais simonnet resume
fichier pdf sans nom

Sur le même sujet..




🚀  Page générée en 0.012s