git clone
https://forge.univ-lyon1.fr/JEAN-CLAUDE.IEHL/gkit3.git
soit avec la base de code gKit2 complete, que
vous avez peut etre deja installé pour d'autres cours, quelques
rappels dans la doc en ligne : "installation"les librairies de la base de code complete gkit2light sont deja installées, il n'y rien a faire. il n'y a pas de différence entre les 2 versions de la base de code.sur votre machine sous linux :
il suffit d'installer les librairies si vous souhaitez utiliser la base de code complete gkit2light. cf la doc / installation.
cf visual studio community 2022 (pas visual studio code, ce n'est pas du tout la meme chose...)
vous ne devez installer les librairies que si vous voulez vraiment utiliser la base de code complete, cf la doc / installation (mais encore une fois ce n'est pas necessaire pour ce cours)
continuez à lire la doc sur l'installation
cf "étape 3 : générer les projets et "étape 5 : créer un projet".
pour démarrer, le plus rapide : créez un fichier tp.cpp dans le
répertoire `projects`, et modifiez le fichier premake4.lua comme
indiqué dans la doc.
générez les makefiles / projets et vérifiez que ce code d'exemple compile et s'exécute, repassez dans "étape 3 générer les projets" si ce n'est pas clair...// exemple de code test a compiler pour verifier que tout est ok
#include "color.h"
#include "image.h"
#include "image_io.h"
int main( )
{
// cree l'image resultat
Image image(1024, 1024);
for(int py= 0; py < image.height(); py++)
for(int px= 0; px < image.width(); px++)
image(px, py)= Red();
write_image(image, "image.png"); // par defaut en .png
return 0;
}
bin/
, pour tester :
./bin/tp
#include "vec.h"
float intersect_plan( /* parametres du plan */ const Point&
a, const Vector& n, /* parametres du rayon */ const
Point& o, const Vector& d )
{
}
// infini
#include <limits>
const float inf=
std::numeric_limits<float>::infinity();
int main( )
{
// rayon
Point o= Point(0, 0, 0);
Vector d= Vector(0, 0, -1);
// plan
Point a= Point(0, 0, -1);
Vector n= Vector(0, 0, 1);
float t= intersect_plan(a,
n, o, d);
std::cout << t
<< std::endl;
if(t != 1) std::cout << "oops,
loupe\n";
else
std::cout << "c'est bon...\n";
return 0;
}
#include <cmath>
#include "vec.h"
float intersect_sphere( /* parametres de la
sphere */ const Point& c, const float r, /* parametres du
rayon */ const Point& o, const Vector& d )
{
float a= ...;
float b= ...;
float k= ...;
float det= b*b - 4*a*k;
...
}
#include "color.h"
#include "image.h"
#include "image_io.h"
int main( )
{
// cree l'image resultat
Image image(1024,
1024); // par exemple...
for(int py= 0;
py < image.height(); py++)
for(int px= 0;
px < image.width(); px++)
{
Point o= Point(0, 0,
0); // origine
Point e=
...
// extremite
Vector d= Vector(o,
e); // direction : extremite - origine
image(px, py)= Red();
}
write_image(image,
"image.png");
return 0;
}
struct Plan
{
Point
a; // point sur le plan
Vector
n; // normale du plan
Color
color; // couleur
};
struct Hit
{
float
t; // position sur le
rayon ou inf
Vector
n; // normale du point
d'intersection, s'il existe
Color
color; // couleur du point d'intersection,
s'il existe
};
Hit intersect( const
Plan& plan, const Point& o, const Vector& d )
{
...
if(t < 0)
return { inf, plan.n,
plan.color }; // l'intersection n'est pas valide /
derriere l'origine du rayon
else
return { t, plan.n,
plan.color }; // renvoie la position de
l'intersection, + la normale et la couleur du plan
}
struct Scene
{
std::vector<Sphere> spheres;
Plan plan;
};
Hit intersect( const
Scene& scene, const Point& o, const Vector& d )
{
for(unsigned i= 0 ; i
< scene.spheres.size(); i++)
{
//
tester la ieme sphere
Hit
h= intersect(scene.spheres[i], o, d);
if(h
... )
}
// et bien sur, on
n'oublie pas le plan...
Hit h=
intersect(scene.plan, o, d);
if(h ...)
}
struct Hit
{
float t;
// position sur le rayon ou inf
Vector n; //
normale du point d'intersection, s'il existe
Color color; // couleur du
point d'intersection, s'il existe
operator bool() { return t >= 0 &&
t < inf; } // renvoie vrai si l'intersection existe et quelle
est valide...
};
Hit h= intersect( ... )
if(h)
{
// faire un truc
avec l'intersection h
}
`if(h)
` appelle la fonction que l'on
vient d'ajouter dans la structure hit, c'est la meme chose que
si l'on ecrit le test à chaque fois
`if(hit.t >= 0
&& hit.t < inf)
` mais c'est plus simple et ça
peut éviter certaines erreurs.
ou encore plus simple :
if(Hit h= intersect( ... ))
{
// faire un
truc avec l'intersection h
}
Point o= p;
Vector d= Vector(o, source);
Point o= p + epsilon * n; // avec epsilon=
0.001 par exemple...
Vector d= Vector(o, source);
Color eclairage_direct( const Point&
p, const Vector& n, const Color& color, const Scene&
scene )
qui regroupe les calculs de lumière et d'ombre. il
ne reste plus qu'à l'utiliser.
#pragma omp parallel for schedule(dynamic, 1)
for(int py= 0; py < image.height(); py++)
for(int px= 0; px < image.width(); px++)
{
...
image(px, py)= { ... };
}
make
config=release tp
, au lieu de make tp
(qui
génère la version debug du programme).
pour visual studio, il faut cocher l'option openmp dans les
propriétes du projet.
temps d'exécution avant (cf make
tp
) : time bin/tp,
1m34smake config=release tp
) :
time bin/tp,
8s
pas mal pour une seule ligne changée dans le programme ! (12
coeurs sur la machine de test et un facteur d'accélération de 11.75,
c'est plutot bien !)
#pragma omp parallel for schedule(dynamic, 1)
for(int py= 0; py < image.height(); py++)
{
// initialiser un generateur de nombre aléatoire pour chaque ligne / chaque thread
for(int px= 0; px < image.width(); px++)
std::random_device hwseed;
std::default_random_engine rng( hwseed() );
std::uniform_real_distribution<float> u;
// chaque thread a une copie privee de ces 3 variables
{
// generer les nombres aleatoires avec u(rng)
float ux= u(rng);
float uy= u(rng);
...
image(px, py)= { ... };
}
}
il est également plus simple de fixer l'emission totale du panneau lumineux et de la répartir sur les n points. comme ça vous aurez à peu près la même image quelque soit le nombre de points...std::vector<Source>& genere_sources( const Point& a, const Vector& u, const Vector& v, const Color& emission, const int n );
Color eclairage_points( /* point d'intersection */ const Point& p, const Vector& n, /* matiere */ const Color& color, /* sources */ const std::vector<Source>& points )
indication : c'est sans doute une bonne idee de créer une struture pour stocker tous les parametres qui decrivent un panneau lumineux.Color eclairage_panneau( /* parametres du point d'intersection */ const Point& p, const Vector& n, /* matiere */ const Color& color,
/* parametres du panneau */ const Point& a, const Vector& u, const Vector& v, const Color& emission, const int n, std::default_random_engine& rng )