Article: un raytracer de base en C++ - Algo - Programmation
Marsh Posté le 05-08-2003 à 12:00:59
Merci pour ce topic très interessant. Je m'étais un peu interessé à la 3D en DESS ( on a eu un cours dessus pour aller avec les cours de C/C++ ) et je m'étais bien amuser en faisant un paysage de montagne fractale.
Ce serait interessant si tu pouvais aussi expliquer un peu plus de truc sur les lumières, par exemple c'est quoi "Phong, Blinn, Anisotropique" ?
J'avais gardé aussi quelques images en ray-tracing faites par des pote de DESS, ça peut donner une idée de ce qu'on peut faire sans beaucoup s'y connaitre en C/C++ ( on a eu juste un module de 15heures je crois ) : elles sont là tomlameche.free.fr/V2/fractale.htm
( je peux pas donner l'url exact des images car j'ai pas accès à mon site d'où je suis ... )
Marsh Posté le 05-08-2003 à 12:15:49
heu sinon un truc qui ma tjs etonne c la generation de textures
http://theproduct.de/text1.html
qd on voit ce quil arrivent a faire... a partir de rien
sinon jai mit dans un zip tout les outils necessaires ici
http://users.skynet.be/fa218598/tools.zip
si qqn arrive a faire qqch
Marsh Posté le 06-08-2003 à 11:18:58
Voici quelques variations sur les fonctions d'éclairement:
Phong
C'est une méthode empirique développée par un étudiant français (Phong) dans les labos de l'université de l'Utah.
Elle permet de rendre des objets qui refletent la lumière dans une direction privilégiée, dans ce cas la direction privilégiée est celle du vecteur lumière réfléchi par le vecteur normal à la surface.
On parle de terme spéculaire, contrairement au terme de diffusion de Lambert, les termes spéculaires varient en fonction de la position de l'observateur(ce qui se voit dans l'équation qui fait intervenir viewRay.dir).
On ajoute le code suivant au code de calcul de l'éclairement :
Code :
|
Et on obtient une image comme celle-ci:
http://www.massal.net/article/raytrace/page2.html
Blinn/Phong
Blinn était l'un des professeurs de Phong (depuis il travaille chez Microsoft). Il a modifié légèrement le modèle spéculaire de Phong pour rendre compte de certains phénomènes physiques.
Voici le code à ajouter au calcul du terme de Lambert:
Code :
|
Visuellement ils sont assez proches comme on peut le voir sur l'image ci dessous:
http://www.massal.net/article/raytrace/page2.html
Anti-aliasing
Une méthode simple d'antialiasing est le super sampling.
Elle consiste à calculer pour chaque pixel, x fractions de pixels qui contribueront à l'éclairement final.
Le coût de la méthode "naïve" est strictement linéaire au nombre de fractions de pixel à calculer par pixel.
On peut effectuer un supersampling basique (sans jittering, sans overlapping) en ajoutant ces lignes-là dans la boucle de rendu:
Code :
|
Voici le résultat très zoomé du supersampling:
http://www.massal.net/article/raytrace/page2.html
Fonction gamma
Voici le code qui modifie la sortie via une fonction gamma de base:
Code :
|
On peut donc à loisir obtenir une image plus contrastée mais plus sombre ou une image plus claire mais aux teintes plates ou délavées (si l'on pousse trop).
voici le résultat avec un gamma de 0.66 respectivement et 1.5:
http://www.massal.net/article/raytrace/page2.html
Exposition photo
Rajoutons une fonction de calcul d'exposition:
Code :
|
Elle rend compte du fait que le noircissement du papier photo est une fonction non linéaire de la quantité de lumière qui arrive en chacun de ses points: très rapide au départ car il y a beaucoup de réactif disponible, elle devient plus difficile ensuite lorsque la majorité du réactif a migré.
L'intérêt de la fonction d'exposition c'est qu'il n'y a pas d'effet de saturation comme avec la fonction "min naïve".
http://www.massal.net/article/raytrace/page2.html
http://www.massal.net/article/raytrace/page2.html
La première est corrigée par la fonction "autolevels" de Photoshop. (j'avais la flemme de coder une fonction similaire dans le raytracer).
En variant K, le facteur d'exposition on peut arriver à gérer toutes sortes de conditions d'éclairement. En calculant les valeurs d'éclairement sous forme de flottants, on peut évacuer le problème de l'exposition à un calcul final dépendant de l'éclairement global de l'image et certains paramètres plus subjectifs (auto exposition).
Voici le résultat d'une image traitée par saturation (opérateur min) sans fonction d'exposition mais avec une lumière trop forte:
http://www.massal.net/article/raytrace/page2.html
La même scène qui utilise la fonction d'exposition:
http://www.massal.net/article/raytrace/page2.html
Un inconveniant de ces méthodes de correction d'image en post processing c'est qu'elles interférent avec la méthode d'antialiasing par super sampling. Mais c'est un autre probleme..
Un autre jour peut-être..
LeGreg
Marsh Posté le 06-08-2003 à 11:29:38
Euh sinon les idées elles me viennent comme ça
vu que c'est mon premier raytracer
donc si vous avez des envies particulières.
Je pense aborder (si j'ai le courage):
- le postprocessing (convolution, etc..)
- les textures (lecture, generation), géneration des coordonnées, bump mapping/horizon mapping.
- image based rendering.
LeGreg
Marsh Posté le 06-08-2003 à 12:06:17
legreg a écrit : Euh sinon les idées elles me viennent comme ça |
C'est pas trop mal, mais dans l'ordre les trucs à ajouter seraient je pense :
- Autre chose que des sphères
- Des sources de lumière étendues en volume pour des ombres plus naturelles
- Des transformations affines à appliquer aux objets.
- Des matériaux plus évolués : refraction, atténuation suivant la distance ...
Marsh Posté le 06-08-2003 à 12:20:27
Kristoph a écrit : |
En commençant par des plans, comme ça on peut déjà faire pas mal de chose.
Et ensuite des cones ( mais c'est un peu plus compliqué niveau math ).
Je crois qu'à partir de sphère, cones, plan, on peut déjà faire pas mal de truc sympa.
Marsh Posté le 06-08-2003 à 12:31:30
tomlameche a écrit : |
Plus que le cone, le cube je dirais. Mais sans les déformations affines, c'est encore un peu difficile de faire des scènes variées. C'est juste du calcul matriciel très bourrin non
Un autre truc vraiment bien et pas difficile à faire c'est la CSG : Constructive Solid Geometry.
Marsh Posté le 06-08-2003 à 12:33:36
Kristoph a écrit : |
Voui, puis peut être encore avant le cone, le cylindre.
C'est quoi la Constructive Solid Geometry ?
Marsh Posté le 06-08-2003 à 12:36:10
tomlameche a écrit : |
Opération booléaines sur les objets. Des unions, des intersections et des soustractions.
Marsh Posté le 06-08-2003 à 13:01:45
Mouai c'est pas mal.
Bah je rigole biensûr, c'est très beau
Perso ça serait cool si tu pouvais poster un code compilable (le .h entre autre) afin qu'on test. Si tu pouvais aussi montrer comment on fait une boule style chrome (c'est quoi les couleurs ?).
A partir du travail d'un pote qui a fait un raytracing en VTK, on a essayé de faire quelques trucs. Mais c'est très lent, surtout pour les sphères. Car ca test les collisions avec les polygones. En revanche on peut mettre n'importe quoi : cube, cône, ... j'ai lancé un calcul hier soir et voilà ce que ça donne. C'est pas full quality, surtout la sphère, car ca met hyper longtemps à calculer. Je sais pas combien de temps ça a mis, mais surement plusieurs heures (celeron 600). Voici l'image d'origine :
http://www.chez.com/regatbar/vtk/origin.htm
résultat:
http://www.chez.com/regatbar/vtk/result.htm
Plus y'a de polygones, plus c'est lent. Donc la sphere ca fait mal. On va étudier ton code et essayer d'améliorer.
Au fait, ce code fait du ray tracing avec projection conique.
Marsh Posté le 06-08-2003 à 14:22:20
HelloWorld a écrit : Mouai c'est pas mal. |
Dans POV ray et dans tout bon raytracer, les sphères sont de vrai sphères, les cubes sont de vrai cubes et les cylindres de vrai cylindres. Pas de poly ça fait moche.
En plus, une vrai sphère doit être plus rapide à dessiner qu'un simple triangle
Marsh Posté le 06-08-2003 à 14:53:13
Bah ouai. VTK c'est du volume rendering. Ca c'est le truc de base. La sphère je peux la bidouiller genre les CSG, en extraire des tanches.
C'est clair que VTK c'est pas fait pour. Ca permet comme ça de bien se rendre compte des perfs et limites de chaque technique.
Au fait, ca met combien de temps à calculer tes images legreg ?
Marsh Posté le 06-08-2003 à 15:11:32
HelloWorld a écrit : Bah ouai. VTK c'est du volume rendering. Ca c'est le truc de base. La sphère je peux la bidouiller genre les CSG, en extraire des tanches. |
Une image parreil, je lui donne qq secondes pour le calcul. J'ai un ami qui a fait tourner un raytracer en temps réel avec 1-2 sphères reflechissantes ( 1 reflexion max ), une source de lumière et un plan pour 30 FPS en 160x100, ceci sur un Pentium 90 Il l'aurait codé en assembleur que ça ne m'étonnerais pas.
Marsh Posté le 06-08-2003 à 18:45:46
le temps de rendu est de l'ordre de moins d'une seconde pour la premiere image. trois spheres, deux lumières pas de quoi peter
trois pattes a un canard.
Tu multiplies ça par le nombre de pixels supplémentaires en super sampling et tu ajoutes le cout de calcul des exposants, terme speculaire et tu arrives a quelques secondes.
Sinon pour vos suggestions, j'etudierai ça mais bon le but de cet article ce n'est pas d'arriver a un raytracer complet (puisqu'il y a pov ray..). Mais d'aborder les problemes de façon simple(iste) et d'introduire quelques notions utilisées en synthèse d'image.
LeGreg
Marsh Posté le 06-08-2003 à 19:14:58
legreg a écrit : le temps de rendu est de l'ordre de moins d'une seconde pour la premiere image. trois spheres, deux lumières pas de quoi peter |
Il y a 2 sujets qui me plairaient personnellement : la CSG et la génération de textures 3D. Il y a bien sur beaucoup d'autres sujets passionants mais je pense qu'il est possible de traiter ces 2 là de façon assez simple.
Marsh Posté le 06-08-2003 à 20:08:32
Vu que le programme semble encore au stade du "c'est joli mais ça fait pas grand chose", je suggère, juste comme ça, une syntaxe moins limitée et plus lisible, parceque là c'est pas vraiment manipulable.
Je trouve la syntaxe de PovRay assez claire, et vu l'état d'avancement de ce raytracer, y'a de quoi faire sans avoir à faire la moindre modification à la syntaxe.
Pour ceux qui ne connaissent pas povray :
http://www.povray.org
Les sources sont libres, ça peut donner des idées pour certaines fonctions/optimisations.
Marsh Posté le 06-08-2003 à 20:14:50
Sinon, une autre chose qui pourrait être intéressante, serait de rendre multi-thread ce programme. En effet, ce qui pose de gros problèmes sur la plupart des raytracers (notamment povray) c'est l'absence de support pour les architectures multi-processeurs.
Une approche assez simple pour faire du multi-processeur, c'est de faire générer une ligne sur deux par deux threads différents, ou plus (paramétrable). L'avantage de l'architecture multi-thread dans ce cas, par rapport au multi-processus, c'est :
1) support aussi bon sous Windows que sous Linux (Windows gère très mal le multi-process)
2) la scène, le fichier, et l'index des lignes à générer sont communs à tous les threads, donc l'architecture multi-thread simplifie les échanges d'informations entre les threads fils et le thread père.
3) support, sans code particulier de plusieurs processeurs
Marsh Posté le 06-08-2003 à 20:18:58
MagicBuzz a écrit : Vu que le programme semble encore au stade du "c'est joli mais ça fait pas grand chose", je suggère, juste comme ça, une syntaxe moins limitée et plus lisible, parceque là c'est pas vraiment manipulable. |
Le programme ne sera jamais "utile",
comme je le disais il y a pov ray pour ceux qui veulent faire des images.
C'est juste une introduction du genre :
"regardez on peut faire un raytracer en 200 lignes de C++".
Pour info, je ponds ces lignes de code en rentrant du travail (où je code aussi..) le plus souvent assez tard et il y a une limite à ce que je peux pondre à cette période; il n'y a aucune pretention d'utilité comme je le disais à part l'introduction de notions aléatoires comme les calculs de réflexion, l'intersection rayon/sphere, les différentes équations d'éclairage.
Le format de fichier je n'ai vraiment pas envie de passer du temps dessus donc il restera sommaire et illisible .
LeGreg
Marsh Posté le 06-08-2003 à 20:36:56
MagicBuzz a écrit : Sinon, une autre chose qui pourrait être intéressante, serait de rendre multi-thread ce programme. En effet, ce qui pose de gros problèmes sur la plupart des raytracers (notamment povray) c'est l'absence de support pour les architectures multi-processeurs. |
La version multithread va nécessiter quelques modifications
la premiere c'est que l'on ne traite qu'une seule frame dans ce bout de programme: on ne peut pas écrire directement dans le fichier, il faut donc passer par un buffer indépendant.
J'avais pensé a passer par un buffer pour le post processing mais ce n'était pas forcément celui de l'image que j'avais en tête.
pour etre efficace en multithread il faudrait qu'il soit dejà aussi efficace que possible sur chacun des processeurs indépendants, ce qui n'est pas encore le cas.
Si l'on peut obtenir un gain de x2 sur deux proc (ce qui optimiste dans le cas general), il est probable que je pourrais deja atteindre un gain plus important si je m'attachais a la rapidité d'execution des algorithmes utilisés.
Bon on verra, de toute façon le rythme des updates se fera en fonction de ma charge de boulot au bureau..
LeGreg
Marsh Posté le 06-08-2003 à 20:50:40
Je ne vois vraiment pas l'interet de perdre du temps sur une gestion multithread. Dans un raytracer classique, une simple scene ne necessite que très rarement une vitesse de calcul gigantesque. Ce qui coute *vraiment* c'est les animations à générer et il est très facile de parallèliser ce genre de calcul et laissant chaque process le role de calculer une image séparée.
De plus, si on arrive à une scène dont la complexité justifie de mettre en place du calcul distribué, alors le temps de création d'un process deviens complètement négligeable, même sous windows. Il suffit juste de lancer 4 instances du raytracer chargées chacunes de calculer un quart de la scène finale ( très facile à faire en manipulant la caméra de rendu ).
Marsh Posté le 06-08-2003 à 22:03:42
MagicBuzz a écrit : |
En un sens oui. Mais il y a des cas ou cela sert.
Sinon, je maitiens ma position : le multithread ce n'est vraiment pas utile à coder pour un raytracer car il suffit de calculer 2 moitiés de l'image en parallèle puis de les coller après coup et on obtient le même résultat pour un temps de dev bien moindre.
PS : le javascript c'est petit joueur, fais moi ça en RPL sur HP 48. Je dois avoir un programme de comparaison par ici
Marsh Posté le 06-08-2003 à 22:10:35
à propos du mutli-thread: on va pas se lancer dans des histoires win/linux (meme si les pthread sont mieux foutus) => utilisation des thread de boost, jetez un oeil
apres une ligne sur deux, ça me parait pas terrible, et surtout pas bien réguler: c'est evident que certaines lignes vont être traiter plus vite que d'autres. alors faut faire une répartition dynamique. une file d'attente avec des paquets par exemple
anyway, http://boost.org/libs/thread/doc/index.html
Marsh Posté le 06-08-2003 à 22:17:50
Taz a écrit : à propos du mutli-thread: on va pas se lancer dans des histoires win/linux (meme si les pthread sont mieux foutus) => utilisation des thread de boost, jetez un oeil |
oui oui, quand je parlais de "une ligne sur deux", je pensais à "chacun sa ligne", avec une file d'attente évidement, parceque sinon un thread risque de prendre de l'avance, et on se retrouve à devoir stocker toute l'image en mémoire au lieu de la flusher au fur et à mesure
Marsh Posté le 06-08-2003 à 22:19:26
Le raytracing distribué c'est le sujet de these
d'un collègue dans le cube d'à coté donc je lui demanderai son avis si jamais j'ai besoin. (Photon4D pour ceux qui connaissent)
En attendant: pas nécessaire et pas d'amélioration visible du rendu donc en queue de liste des explications à venir.
LeGreg
Marsh Posté le 06-08-2003 à 22:32:12
MagicBuzz a écrit : |
Il y a des fois ou le compilateur a du mal à inférer le type, va générer des warnings lors d'une perte de précision possible, donc j'ai pris l'habitude de le le préciser.
Ici il va peut-etre générer des warnings pour des conversions float/int int/float mais c'est bien ce qu'on veut dans ce cas.
MagicBuzz a écrit : Nan, parceque je m'amuse à transcrire le prog de legreg en javascript pour montrer que le javascript n'est pas aussi nul que ça |
Ca ne prouvera rien. Il est aussi possible de faire un raytracer en BASIC..
sinon le langage de choix pour les raytracer c'est OCAML.
C'est pas moi qui le dit. http://www.cs.cornell.edu/icfp/contest_results.htm
LeGreg
Marsh Posté le 07-08-2003 à 09:38:52
Vi. Post un code complet compilable stp.
Et pour le multithread, je suis pas d'accord. C'est pas le sujet. On pourrait aussi dessiner dans une fenêtre, avec possibilité de sauvegarder en JPEG, etc ... encore que ça se révèlera + utile que le multithread sur un monoproc, ce qui est je pense le cas d'à peu près tout le monde ici.
Je préfère découvrir comment on fait une boule chromée.
Marsh Posté le 07-08-2003 à 12:10:50
no update today.
Pour le .h il s'agit de definition des types vecteur, point, sphere, ray etc..
J'utilise une bibliotheque toute prete c'est la lib std du C++.
(pour les ouvertures de fichier et les fonctions de math de base et les vector (le conteneur))
Si je poursuis ce que j'ai prévu il est possible que j'ajoute
d'autres librairies, comme une lib de fft ou bien un source de tone mapping.
A+
LeGReg
Marsh Posté le 07-08-2003 à 22:31:49
Argh La convertion en JavaScript est "presque" terminée
http://perso.wanadoo.fr/magicbuzz/ray.htm
Seul soucis :
1) C'est très lent, donc je me limite à une image en 32 * 20 (avec des pixels de 5 x 5 ) C'est l'affichage qui plombe tout. Sans l'affichage, ça met moins d'une seconde pour du 64 * 40
2) Doit y avoir un bug, c'est tout noir
-- Edit: J'ai fais pas mal de corrections --
Maintenant, il semblerait qu'il n'y ait plus de "bug". C'est à dire que tout le code se comporte de la façon escomptée par rapport à ce que j'ai écrit.
Par contre, j'ai des valeurs extrêment petites, ce qui fait que je me retrouve avec une image toute noire... Pas terrible en somme.
Voici la scène que j'utilise :
|
En somme j'ai tout divisé par 40 pour que ça soit rapide à calculer en JS.
Si lors de l'affichage je force à blanc dès qu'une des trois couleur est différente de 0, j'obtiens bien mes trois boules. J'ai noté d'ailleurs qu'elles ne sont pas rondes... Il semblerait que j'ai un problème avec la recherche d'ombre (en plus du reste)
En fait, ce que je n'arrive pas à vérifier, c'est le calcul de la normale, et la variable "lambert".
En dehors de ça, ça semble tourner comme il faut.
Juste une question à legreg au fait :
-> Tes tableaux (de matérieux, de sphères et de lumières), ils commencent bien à 0 ? Parceque je suis en train de me dire que j'ai forcément une coquille aussi grosse que ça quelquepart, parceque je ne comprends vraiment pas où ça merde...
PS: pour voir mon source, il suffit de faire view source sur la page que j'ai mis en lien.
-- Enorme optimisation : j'ai abandonné le modèle objet lors des calculs. C'est infiniment plus rapide. Par contre le code est carrément moins lisible --
Marsh Posté le 08-08-2003 à 09:52:19
quick update today: je suis rentré a dix heures du boulot
et je vais probablement faire des heures sup ce week-end.. je sais vous vous fichez de ma vie
Bon j'ai pondu (pour pas dire ch..) une méthode empirique d'autoexposition pour éviter d'avoir a taper la valeur à la main
voici le code de calcul:
Code :
|
L'idée (empirique et probablement pas très rationnelle)
est que l'on mesure la quantité d'énergie moyenne par pixel.
Comme on a juste besoin d'une valeur moyenne, on travaille en basse résolution (128x128) par exemple. on somme le carré des intensités lumineuse (sensé représenter l'énergie reçue par pixel). Puis à la fin on calcule l'intensité correspondante à cette énergie moyenne. Puis on mappe cette intensité calculée
à une valeur de gris intérmédiaire (en applicant l'inverse de la fonction d'exposition à dans cet exemple 0.6f).
C'est bidon mais ça marche à peu près:
http://www.massal.net/article/raytrace/page3.html
LeGreg
ps pour magicbuzz: oui en C comme en C++ tout tableau
est numéroté à partir de zéro.
Marsh Posté le 08-08-2003 à 15:55:59
MagicBuzz a écrit : Argh La convertion en JavaScript est "presque" terminée |
Heu, franchement, j'veux pas te vexer.
Mais, l'intéret de la convertion en Javascript, il est où ?
C pas vraiment fait pr ce genre de trucs le javascript qd même...
Marsh Posté le 10-08-2003 à 20:31:39
update pour l'apéro du dimanche avant le méchoui:
http://www.massal.net/article/raytrace/page3.html
Je posterai le code plus tard.
En gros c'est une technique de génération de coordonnées de texture appelée "cube environment mapping".
Le raytracer va lire dans six tampons représentants un arrière plan fictif mais en ne tenant compte que de la direction (C'est une simplification sinon il aurait aussi besoin de la position absolue et de la position du cube dans la scène ce qui dépasse le cadre de notre mapping).
Ici on utilise la direction du rayon vue modifié par reflection par rapport à la normale à la surface. En pratique on ne modifie rien au code du raytracer proprement dit mais au cas où un rayon vue "réfléchi" ne rencontre aucune sphère, alors cela se termine par un texture lookup (lecture du fichier texture).
LeGreg
PS: le fond gris privient de la cubemap aussi. Je vous laisse deviner pourquoi il est uniforme.
Marsh Posté le 11-08-2003 à 09:01:44
Voici le code:
Code :
|
Comme je l'avais dit, en cas de non intersection du rayon vue avec une sphere, on fait un texture lookup dans la cubemap avec le rayon vue courant.
Le code pour lire dans la cubemap est "straightforward": on a six cas pour les six faces du cube, et on différencie chacun des six cas par des conditions "if":
Code :
|
Comme vous pouvez le voir dans ce code, la texture du cube est simplement chargé dans un tableau où les six faces se suivent dans un ordre défini par les valeurs des énum "up, down, left, right, forward, backward". La taille de chaque face est hardcodée dans cet exemple à 512x512. On utilise ensuite la fonction readtexture qui fait une interpolation bilinéaire pour lire chaque valeur de la texture.
Code :
|
Le rectangle original de la texture est remappées à [0,1] et le motif est simplement répété pour les coordonnées qui sont plus grandes que 1. on peut raffiner en proposant plusieurs modes d'adressages : clamp (les valeurs supérieures à un sont ramenées a 1), mirror (les valeurs sont périodiquement inversées pour les valeurs supérieures à un), repeat (c'est le mode qu'on utilise).
Je ne cherche pas à finauder spécialement dans ce code, ça fait ce qu'on lui demande pour l'instant, j'améliorerai en temps nécessaire.
Note secondaire: on utilise un filtrage bilinéaire pour l'interpolation des valeurs intermédiaires de la texture. Ce filtrage a beaucoup de sens pour des textures codées sur 8 bits à précision fixe. Mais quand on travaille sur des flottants cela perd beaucoup de son sens, surtout quand on postprocess le tout
pour ramener a un intervalle à precision fixe codé sur 8 bits.. J'y reviendrai peut-etre..
LeGreg
ps:Voici un exemple de cubemap avec les six textures du cube mises bout à bout:
http://www.massal.net/article/raytrace/page3.html
Marsh Posté le 12-08-2003 à 09:32:17
On continue sur notre lancée.
Aujourd'hui un peu de textures procédurales pour obtenir quelque chose dans ce genre là:
http://www.massal.net/article/raytrace/page3.html
Ces textures ne sont stockées nulle part en mémoire, elles sont calculées à la volèe.
Les intérêts sont multiples. Le premier c'est qu'on peut définir des matériaux avec une précision qui n'est pas fixé par la taille du fichier texture. Ainsi on peut approcher une structure fractale avec des textures aux détails quasiment infinis.
Le deuxième intéret provient de la méthode utilisée qui repose sur le bruit de Perlin. Cette fonction de bruit est simple à mettre en oeuvre et est réellement tridimensionnelle (ou bidimensionnelle ou monodimensionnelle). Cela évite notamment d'avoir à se prendre la tête sur le mapping de la sphère; pas de distorsion, pas de pôles. C'est comme si l'objet était directement taillé dans un volume texturé.
Voici le code adapté du site web de Ken Perlin:
Code :
|
Le code du bruit de Perlin est livré comme cela, je ne l'expliquerai pas: Pour les explications, référez vous au site web de Perlin ( http://mrl.nyu.edu/~perlin/ ).
Le point d'entrée est la fonction noise(double, double, double), le reste sont des fonctions auxiliaires.
La sphère en haut à gauche utilise une variation entre deux couleurs de diffusion modulées par un coéficient de "turbulence".
Code :
|
Le coté "dur" de la turbulence est créé par l'irrégularité de la dérivabilité apportée par la valeur absolue autour de zéro. Son côté fractal est apporté par l'addition de plusieurs termes du bruit de perlin mais à des niveaux de détails de plus en plus fins (la variable level).
La sphère en bas utilise une fonction similaire pour moduler l'argument d'une fonction sinus. La périodicité de la fonction sinus simule les bandes de matière d'un marbre et le bruit "turbulent" simule la contamination "naturelle" des zones des différents types de marbre.
Code :
|
La sphère en haut a droite est une illustration d'une forme de bump mapping. Le vecteur normal à la surface subit une perturbation modulée par la fonction de bruit différente selon chaque axe. Le résultat est un vecteur normal perturbé que l'on renormalise. Puis ce vecteur est utilisé pour calculer les fonctions d'éclairage et le reflexions ultérieures. L'image refletée par cette sphère est très déformée. En fait il suffit d'une petit variation de toute surface plane pour provoquer un très grand déplacement dans l'image réfléchie.
Code :
|
Voilà. C'est tout pour ce soir.
LeGreg
Marsh Posté le 12-08-2003 à 11:48:44
sinon personne n'a repondu a ma question ... comment ils arrivent a faire leurs textures de ouf dans les demo 4k (voir lien premiere page)
Marsh Posté le 12-08-2003 à 12:26:23
par équations.
un bel exemple ici, tout est équation dans cette démo: http://www.theproduct.de/
Marsh Posté le 12-08-2003 à 18:27:33
legreg a écrit : |
Je sais pas trop. Il me semble que la notion objet est très adaptée dans ce cas alors ça me gène de m'en passer. Plustot que de vois un paquet d'effets spécifiques j'aurais bien aimé voir une archi globale en C++ qu'il serait facile d'étendre pour ajouter de nouvelles formes et de nouveaux materiaux.
Tiens par exemple, un truc très bateau mais assez joli : le materiaux "damier" qui alterne 2 autres materiaux sous forme de cases en 3D.
Marsh Posté le 12-08-2003 à 18:44:08
Kristoph a écrit : |
Ben désolé ce n'est vraiment pas mon but de fournir un framework..
Le but initial comme je l'ai expliqué c'est d'introduire de façon régulière une nouvelle technique liée à la synthèse d'image. Avec un code si possible qui tient en quelque lignes pour chaque "nouvelle feature".
En fait j'avais commencé à programmer en C "pur" puis j'ai décidé d'utiliser des features comme la surcharge d'opérateurs pour avoir un code à l'écriture plus compact c'est tout.
LeGreg
Marsh Posté le 14-08-2003 à 10:34:24
http://www.massal.net/article/raytrace/page3.html
Me demandez pas comment compiler le truc,
référez vous à la doc de votre compilateur.
Deux trois trucs qui ne vont pas marcher chez vous:
- min et max peuvent ne pas avoir le meme sens, en principe ce sont des fonctions template dans <algorithm>. Elles ont peut-etre été renommées _MIN et _MAX.. à vous de voir.
- si #pragma once n'est pas supporté par votre compilateur
utilisez les #ifdef classiques.
- d'autres auxquels je n'ai pas pensé (AMD64 bits, char de moins de 8 bits, machine quantique etc..)
Le programme a été "désoptimisé" afin d'être je l'espère plus facilement compréhensible. J'ai ajouté des commentaires inutiles et modifié des noms de variables, ajouté des opérations intermédiaires supplémentaires etc.. Le résultat c'est qu'il est beaucoup plus lent.
C'est tout pour aujourd'hui.
LeGreg
ps: la cubemap est maintenant dans un zip séparé:
http://www.massal.net/article/raytrace/page3.html
Marsh Posté le 14-08-2003 à 10:49:43
J'ai pensé que les gens auraient envie de faire joujou
avec les cubemap donc j'ai inclu 6 fichiers TGA de 512x512.
Eheh c'était soit ça soit inclure le code de chargement des jpg dans le source qui fait exactement deux mégas
LeGreg
ps: ca y'est j'ai modifié les liens, il n'y a plus que 347 Ko (dont l'executable et le fichier scene).
Marsh Posté le 05-08-2003 à 11:37:59
Voici le code d'un raytraceur basique, j'ai essayé de réduire les fonctionalités au maximum tout en essayant de le conserver intéressant.Update :
Les articles ont été remis à jours et sont disponibles sur mon site web:
premiers pas:
http://www.massal.net/article/raytrace/page1.html
éclairage spéculaire (blinn-phong), post processing et antialiasing:
http://www.massal.net/article/raytrace/page2.html
textures (Perlin noise, cubic environment mapping, bump mapping)
http://www.massal.net/article/raytrace/page3.html
Flou (depth of field), Fresnel, blobs (isosurfaces):
http://www.massal.net/article/raytrace/page4.html
HDR, loi de beer, aberration chromatique:
http://www.massal.net/article/raytrace/page5.html
Global ilumination, photon mapping:
http://www.massal.net/article/raytrace/page6.html
Le code et les commentaires y sont plus récents. Vous pouvez continuer à utiliser ce topic pour les questions
et commentaires.
Voilà, si vous voulez l'historique du sujet, vous pouvez continuer à lire la suite.
Fin de l'Update
Le source
No comment sur le source, les commentaires suivent.
Le rendu
Voici l'output de ce programme:
http://www.massal.net/article/raytrace/page1.html
(note dans cette image on utilise du supersampling
pour lisser les bords, j'expliquerai si j'ai le temps)
à partir d'un fichier scene.txt comme ceci (sans les commentaires):
Que fais le raytracer ?
le lancer de rayon ou raycasting/raytracing est l'une des méthodes de rendu les plus simples qu'on puisse imaginer.
Pour chaque point de l'écran, on envoie un rayon (virtuellement)
et l'on teste pour chaque objet de la scene s'il se trouve sur le chemin du rayon ou pas. Le point visible est le point d'intersection le plus proche.
A partir de ce point on fait des calculs d'éclairages, avec raffinements ou pas (ombres, reflexion, lambert, phong, bump, etc..)
L'essentiel du code est dans la fonction draw.
Le balayage
Ca correspond a la boucle
on parcourt chaque point de l'écran. et ça se termine systématiquement par l'écriture d'une valeur de couleur dans le framebuffer (ici directement sur le disque).
Il est important de noter que le min() pour chaque couleur est une approche "naive", j'y reviendrai.
Le lancer de rayon proprement dit
On commence a initialiser le rayon en fonction du point de l'écran.
ici c'est un rayon qui rentre dans l'écran et qui est perpendiculaire au point de départ. Pas de fancy projection conique, juste la bonne vieille projection orthographique; il faut bien se rendre compte que ça ne CHANGE RIEN AU CODE QUI SUIT.
Le point de départ du rayon est arbitrairement loin derriére l'observateur, l'idéal c'est qu'il n'y ait pas de clipping donc que ce point de départ dépende de la scéne. En pratique il suffit de le prendre suffisamment grand.
NOTA: le probleme est différent en projection conique, les positions derriere l'observateur sont illégales.
L'intersection la plus proche
Le rayon est orienté et paramétré par t, distance arithmétique au point de départ.
On ne se déplace que dans un seul sens, donc on prend le t de départ derriére l'écran le plus loin possible (valeur arbitraire 20000 ce qui englobera toute la scène en tenant compte du point de départ du rayon).
Le code qui détecte les collisions est réduit au minimum.
Pour chaque sphère de la scène on calcule les points d'intersection rayon/sphère qui sont au nombre de deux. On prend le plus proche et l'on compare sa distance au précédent point d'intersection trouvé (ou à la distance de clipping).
La sphère qui a le point d'intersection le plus proche est la sphère courante.
Intersection rayon sphere
C'est la plus simple des intersection (c'est la raison pour laquelle je n'ai pas inclu de cube dans la scène).
Les maths ne sont pas très intéressantes. Cela revient á résoudre une équation polynomiale du second degré (niveau première).
On calcule le delta et si le delta est inférieur à zéro il n'y a aucune solution, le rayon n'intersecte pas la sphère.
Si le delta est positif on a deux distances,
on les compare à la distance de clipping ou celle de la précédente intersection la plus proche.
Calcul de la valeur d'éclairement au point
L'idée c'est d'ajouter la contribution de chaque lumière à l'éclairement final.
Une première élimination rapide, on se débarasse des lumières qui sont du mauvais coté de la surface. (on considère les surfaces à un seul coté, le coté "sortant" ).
Ensuite on détermine si le point est dans l'ombre d'un autre objet de la scène pour cette lumière là.
Le code est similaire à la détection de collision. Le rayon part du point d'intersection avec la sphère et a pour
direction le vecteur qui pointe vers la lumière. Par contre ici on se fiche de savoir a quelle distance on intersecte les autres sphères, on quitte dès qu'une des sphères est touchée par le rayon: on est dans l'ombre, cette lumière ne contribuera pas à l'éclairement total du point.
Lambert
La valeur d'éclairement de Lambert (du nom du Français qui a décrit cette équation) est égale à la quantité de lumière incidente modulo le cosinus de l'angle entre le rayon de lumière incidente et le vecteur de surface.
C'est un modèle valable pour les surface diffuse.
les modèle utilisés ici (Lambert + reflexion parfaite) sont bidon
mais peuvent être complexifiés à l'envi pour representer des matériaux réels. (Phong, Blinn, Anisotropique, BRDF..)
On calcule le cosinus de l'angle par un simple produit scalaire
entre vecteur direction du rayon lumineux et vecteur normal à la surface.
La reflexion
Que serait le raytracing sans une bonne vieille reflexion parfaite (mais irréaliste).
Chaque matériel a un coéfficient de réflexion. Si celui-ci est égal à zéro, la surface n'est pas du tout reflexive et on passe au point suivant. Sinon, on réitère tout le processus précédent mais cette fois
avec un point de départ = le point de la sphère courant et
la direction = la direction courante "reflechie" par le vecteur normal à la surface.
Pour éviter les boucles infinies, on limite le nombre d'itérations par point à dix.
Plus loin
Voilà ce qu'on peut attendre d'un raytracing basique. Le but de ce raytracer c'est de sortir des images sympas de sphères reflexives. Aucun des modèles utilisés n'approche suffisamment de la réalité pour faire du photoréalisme!
Il n'y a aucune optimisation, ce qui rend le code simplissime
(vous êtes juges) mais sur des scènes où il y a plus que trois sphères on peut s'attendre à une galère sévère.
Les pistes pour l'optimisation:
- subdivision de l'espace pour améliorer la détermination
du point d'intersection le plus proche.
- réutilisation des informations calculés sur des points proches, puisqu'il y a une forte cohérence spatiale de ces infos.
- répartition sur plusieurs processeurs/ parallélisme ou utilisation d'un GPU/VPU.
- etc..
Comments ? Questions ? Pas de critique sur le code j'ai autre
chose a foutre.
LeGreg
Message édité par LeGreg le 29-02-2008 à 20:09:01
---------------
voxel terrain render engine | animation mentor