Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 75 additions & 22 deletions Vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,56 +77,108 @@ class Ray {
Vector origin, direction;
};

class Sphere{
class Object {
public:
// Attributs de la classe
Vector O;
double R;
// Albedo rend compte du reflet pour chaque couleur
Vector albedo;
bool is_mirror;
bool is_transparent;
bool is_bulle;

Object(const Vector &couleur, bool is_mirror=false, bool is_transparent=false, bool is_bulle=false) {
albedo = couleur;
is_mirror = is_mirror;
is_transparent = is_transparent;
is_bulle = is_bulle;
};
virtual bool intersection(const Ray& d, Vector& P, Vector& N, double &t) const = 0;

};

class Sphere : public Object {
public:
// Attributs de la classe
Vector O;
double R;

// Constructeur
Sphere(const Vector &origin, double rayon, const Vector &couleur, bool is_mirror=false, bool is_transparent=false, bool is_bulle=false) : O(origin), R(rayon), albedo(couleur), is_mirror(is_mirror), is_transparent(is_transparent), is_bulle(is_bulle) {};
Sphere(const Vector &origin, double rayon, const Vector &couleur, bool is_mirror=false, bool is_transparent=false, bool is_bulle=false) : O(origin), R(rayon), Object(couleur, is_mirror, is_transparent, is_bulle) {
};

bool intersection(const Ray& d, Vector& P, Vector& N, double &t) {
bool intersection(const Ray& d, Vector& P, Vector& N, double &t) const {
// resolution de l equation du 2nd degre
double a = 1.;
double b = 2. * dot(d.direction, d.origin - O);
double c = (d.origin - O).getNorm2() - R*R;
double delta = b*b - 4. * a*c;
if (delta < 0) return false;

double t1 = (-b - sqrt(delta)) / (2. * a);
double t2 = (-b + sqrt(delta)) / (2. * a);

if (t2 < 0) return false;
if (t1 > 0)
t = t1;
else
t = t2;

// P est le point d'intersection entre le rayon incident et la sphere
P = d.origin + t * d.direction;
// N est la normale a la sphere au point P
N = (P - O).getNormalized();
return true;
}
};

class Triangle : public Object {
public:
Vector A, B, C;

Triangle(const Vector& A, const Vector &B, const Vector& C, const Vector &couleur, bool is_mirror=false, bool is_transparent=false, bool is_bulle=false) : A(A), B(B), C(C), Object(couleur, is_mirror, is_transparent, is_bulle) {
};

bool intersection(const Ray& d, Vector& P, Vector& N, double &t) const {
N = cross(B-A, C-A).getNormalized();
t = dot(C - d.origin, N) / dot(d.direction, N);
if (t < 0) return false;
P = d.origin + t * d.direction;
// Formule de Kramer
Vector u = B - A;
Vector v = C - A;
Vector w = P - A;
// Matrice de Kramer
double m11 = u.getNorm2();
double m12 = dot(u, v);
// m21 = m12
double m22 = v.getNorm2();
double detm = m11 * m22 - m12 * m12;
double b11 = dot(w,u);
double b21 = dot(w,v);
// b22 = m22
double detb = b11 * m22 - b21 * m12;
double beta = detb / detm; // Coord barycentrique / a B
double g12 = b11;
double g22 = b21;
double detg = m11 * g22 - m12 * g12; // Coord barycentrique / a C
double gamma = detg / detm;
double alpha = 1 - beta - gamma; // Coord barycentrique / a A
if (alpha < 0 || alpha > 1) return false;
if (beta < 0 || beta > 1) return false;
if (gamma < 0 || gamma > 1) return false;
return true;
}
};

class Scene{
public:
Scene() {};
void addSpheres(const Sphere& s) {spheres.push_back(s);}
void addSpheres(const Sphere& s) {objects.push_back(&s);}
void addTriangle(const Triangle& s) {objects.push_back(&s);}

bool intersection(const Ray& d, Vector& P, Vector& N, int &sphere_id, double& t) {
bool intersection(const Ray& d, Vector& P, Vector& N, int &sphere_id, double& t) const {
bool has_inter = false;
double min_t = 1E99;

for (int i=0; i<spheres.size(); i++) {
for (int i=0; i<objects.size(); i++) {
Vector localP, localN;
bool local_has_inter = spheres[i].intersection(d, localP, localN, t);
bool local_has_inter = objects[i]->intersection(d, localP, localN, t);
if (local_has_inter) {
has_inter = true;
// Teste si la sphere est plus proche que la plus proche actuelle
Expand Down Expand Up @@ -170,6 +222,7 @@ class Scene{
double epsilon = 0.00001;
double intensite_lumiere = 5000000;
Vector position_lumiere(15, 30, -20);
double rayon_lumiere = 5;
Vector intensite_pixel(0,0,0);
Vector P, N;
int sphere_id;
Expand All @@ -184,8 +237,8 @@ class Scene{
P = P + epsilon * N;
if (has_inter) {

bool is_mirror = this->spheres[sphere_id].is_mirror;
bool is_transparent = this->spheres[sphere_id].is_transparent;
bool is_mirror = this->objects[sphere_id]->is_mirror;
bool is_transparent = this->objects[sphere_id]->is_transparent;

if (is_mirror and numero_rebond > 0) {
numero_rebond = numero_rebond - 1;
Expand All @@ -209,7 +262,7 @@ class Scene{
double n1 = n_air;
double n2 = n_sphere;
// Cas d'une bulle
bool is_bulle = this->spheres[sphere_id].is_bulle;
bool is_bulle = this->objects[sphere_id]->is_bulle;
if (is_bulle) {
n1 = n_sphere;
n2 = n_air;
Expand Down Expand Up @@ -266,10 +319,10 @@ class Scene{

// CONTRIBUTION DIRECTE (lumiere spherique)
// Direction aleatoire entre le centre de la lumiere et son hemisphere du cote de P
Vector axe_PO = (P - spheres[0].O).getNormalized();
Vector axe_PO = (P - position_lumiere).getNormalized();
Vector dir_aleatoire = random_cos(axe_PO);
// Point a la surface de la sphere lumineuse
Vector point_aleatoire = dir_aleatoire * spheres[0].R + spheres[0].O;
Vector point_aleatoire = dir_aleatoire * rayon_lumiere + position_lumiere;
Vector wi = (point_aleatoire - P).getNormalized();
double d_light2 = (point_aleatoire - P).getNorm2();
// Normale au point aleatoire
Expand All @@ -287,17 +340,17 @@ class Scene{
intensite_pixel = Vector(0,0,0);
}
else {
intensite_pixel = intensite_lumiere / (4 * M_pi * d_light2) * std::max(0., dot(N, wi)) * std::max(0., dot(Np, -wi)) / proba * this->spheres[sphere_id].albedo;
intensite_pixel = intensite_lumiere / (4 * M_pi * d_light2) * std::max(0., dot(N, wi)) * std::max(0., dot(Np, -wi)) / proba * this->objects[sphere_id]->albedo;
}

// CONTRIBUTION INDIRECTE
if (numero_rebond > 0) {
if (numero_rebond > 100) {
// LUMIERE SPHERIQUE
numero_rebond = numero_rebond - 1;
Vector direction_aleatoire = random_cos(N);
Ray rayon_aleatoire(P, direction_aleatoire);
// Calcul de la couleur du point dont on voit le reflet
intensite_pixel = intensite_pixel + this->spheres[sphere_id].albedo * this->getColor2(rayon_aleatoire, numero_rebond, numero_rebond_transp) / 2;
intensite_pixel = intensite_pixel + this->objects[sphere_id]->albedo * this->getColor2(rayon_aleatoire, numero_rebond, numero_rebond_transp) / 2;
// (diviser par pi)
}
}
Expand All @@ -310,5 +363,5 @@ class Scene{


// Ensemble des spheres de la scene
std::vector<Sphere> spheres;
std::vector<const Object*> objects;
};
70 changes: 30 additions & 40 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,50 +54,27 @@ int main(int argc, char** argv) {
Vector bleu_ciel(210, 235, 233);
bleu_ciel.normalize();

// Avec mur fond courbe
//Sphere s10(Vector(0,30,-160), 70, Vector(0,0,0), true); // Mur fond courbe
//Sphere s9(Vector(0,0,20090), 20000, Vector(1,1,0), true); // Mur invisible avant la camera
//Sphere s6(Vector(-12,-12,-40), 8, Vector(0,1,0), true);
//Sphere s8(Vector(12,-12,-40), 8, Vector(1,0,0), true);

// Avec differentes couleurs
//Sphere s1(Vector(0,-20000-20,0), 20000, violet); // Sol
//Sphere s2(Vector(0,20060,0), 20000, bleu_ciel); // Plafond
//Sphere s3(Vector(-20050,0,0), 20000, orange2); // Mur gauche
//Sphere s4(Vector(20050,0,0), 20000, mauve); // Mur droit

Sphere s1(Vector(0,-20000-20,0), 20000, vert); // Sol
Sphere s2(Vector(0,20060,0), 20000, rose); // Plafond
Sphere s3(Vector(-20050,0,0), 20000, beige); // Mur gauche
Sphere s4(Vector(20050,0,0), 20000, orange); // Mur droit
Sphere s5(Vector(0,0,-20080), 20000, bleu_ciel, true); // Mur fond
Sphere s9(Vector(0,0,20040), 20000, Vector(1,1,0), true); // Mur invisible avant la camera

Sphere s6(Vector(-13,-15,-40), 5, Vector(0,1,0), false, true);
Sphere s8(Vector(13,-15,-40), 5, Vector(1,0,0), true);
// Bulles
Sphere s7(Vector(-10,12,-10), 3.4, Vector(1,1,1), false, true, true);
Sphere s10(Vector(-10,12,-10), 3.5, Vector(1,1,1), false, true);

// Immense bulle qui passe juste devant la camera
//Sphere s11(Vector(0, 7,-2000-5), 2000, Vector(1,1,1), false, true, true);
//Sphere s12(Vector(0,7,-2000-5), 2000.1, Vector(1,1,1), false, true);

// Bulle juste devant la camera
//Sphere s11(Vector(0, 7,33), 2, Vector(1,1,1), false, true, true);
//Sphere s12(Vector(0,7,33), 1.9, Vector(1,1,1), false, true);
Sphere s6(Vector(-13,-15,-40), 5, Vector(0,1,0), false, true); // Sphere de gauche
Sphere s8(Vector(13,-15,-40), 5, Vector(1,0,0), true); // Sphere de droite
//Sphere s7(Vector(-10,12,-10), 3.4, Vector(1,1,1), false, true, true); // Bulle intérieure
//Sphere s10(Vector(-10,12,-10), 3.5, Vector(1,1,1), false, true); // Bulle extérieure
Sphere s11(Vector(0,-10,-28), 10, Vector(1,1,1)); // Sphere blanche pour voir l eclairage indirect

// Sphere transparente juste devant la camera
//Sphere s12(Vector(0,7,33), 1.6, Vector(1,1,1), false, true);

Sphere s11(Vector(0,-10,-28), 10, Vector(1,1,1));
Triangle tri(Vector(-10,0,-20), Vector(10,0,-20), Vector(0,20,-20), Vector(1,0,0));

Vector position_lumiere(15, 30, -20);
Sphere slum(Vector(15, 30, -20), 5, Vector(1,1,1));
//s.lumiere = &slum;

Vector position_camera(0,7,36);

double focus_distance = 36 + 40; // tout ce qui est avant ou apres est flou

Scene s;
s.addSpheres(slum); // A mettre en premiere position
s.addSpheres(s1);
Expand All @@ -106,16 +83,13 @@ int main(int argc, char** argv) {
s.addSpheres(s4);
s.addSpheres(s5);
s.addSpheres(s6);
s.addSpheres(s7);
//s.addSpheres(s7);
s.addSpheres(s8);
s.addSpheres(s9);
s.addSpheres(s10);
//s.addSpheres(s10);
s.addSpheres(s11);
//s.addSpheres(s12);

//s.addTriangle(tri);



int nb_rebonds_max = 5;
int rebounds_max = nb_rebonds_max;
int numero_rebond_transp_max = nb_rebonds_max;
Expand All @@ -130,22 +104,38 @@ int main(int argc, char** argv) {
Vector intensite_pixel(0,0,0);

for (int k=0; k < nrays; k++) {
// Anti-aliasing
// Anti-aliasing - methode Box Muller
double r1 = uniform(engine);
double r2 = uniform(engine);
double R = sqrt(-2 * log(r1));
double dx = R * cos(2 * M_pi * r2);
double dy = R * sin(2 * M_pi * r2);
dx = dy = 0;

// Variation de la profondeur de champ
// ouverture carree
double dx_aperture = (uniform(engine) - 0.5) * 5.;
double dy_aperture = (uniform(engine) - 0.5) * 5.;

// Rayon qui part de la camera et passe par le pixel (i,j)
Vector direction(j - W / 2.0 + 0.5 + dx, i - H / 2.0 + 0.5 + dy, -W / (2 * tan(fov / 2)));
direction.normalize();
Ray r(position_camera, direction);

// Mise au point, flou
Vector destination = position_camera + focus_distance * direction;
Vector new_origin = position_camera + Vector(dx_aperture, dy_aperture, 0);
Ray r(new_origin, (destination - new_origin).getNormalized());

// Sans mise au point
//Ray r(position_camera, direction);
r = Ray(position_camera, direction);

int numero_rebond = rebounds_max;
int numero_rebond_transp = numero_rebond_transp_max;
intensite_pixel = intensite_pixel + s.getColor2(r, numero_rebond, numero_rebond_transp) / nrays;
}



// Enregistrement des couleurs des pixels
image[((H-i-1)*W + j) * 3 + 0] = std::min(255., std::max(0., intensite_pixel[0]));
image[((H-i-1)*W + j) * 3 + 1] = std::min(255., std::max(0., intensite_pixel[1]));
Expand Down