M1 - Images


TP2 - rayons et primitives



 

mise à jour de gKit :

compléments de tutos, bugfix, etc.

archives des librairies pour windows

premake4.lua est complet maintenant, cf readme.html


Partie 1 : un rayon par pixel

le programme principal ressemble à ça :

#include <cstdio>
#include <cmath>

#include "vec.h"
#include "mat.h"
#include "color.h"
#include "mesh.h"
#include "wavefront.h"
#include "image.h"
#include "orbiter.h"

struct Ray

{
    Point origin;
    Vector direction;
};

Ray make_ray( const Point& o, const Point& e )
{
    Ray r;
    r.origin= o;
    r.direction= make_vector(o, e);
    return r;
}

struct Hit
{
    Point p;
    Vector n;
    float t;
};


int main( int agc, char **argv )
{
    Orbiter camera = { ... }
   
    // creer l'image resultat
    Image image= create_image(1024, 640, 3, make_color(0, 0, 0));

   
    // creer les objets de la scene
    Plan plan= { ... }
    Sphere sphere= { ... }

   
    for(int y= 0; y < image.height; y++)
    for(int x= 0; x < image.width; x++)
    {
        // generer l'origine et l'extremite du rayon
        Point o= { ... }
        Point e= { ... }
        Ray ray= make_ray(o, e);
       
        // calculer les intersections
        Hit hit;
        if(intersect(plan, ray, hit))

        {
            // calculer une couleur pour le pixel
            Color color= make_color(1, 1, 1);
            image_set_pixel(image, x, y, color);
        }
        // il faudra aussi calculer les intersections avec les autres objets et ne conserver que la plus proche de l'origine du rayon

    }
   
    // enregistrer l'image
    write_image(image, "render.png");

    // nettoyage
    release_image(image);

    return 0;
}


rappel : camera et transformations

c'est vous qui décidez ou placer votre camera. si vos objets sont groupés autour de l'origine du monde, il faut reculer la camera pour les observer. dans ce cas, vous pouvez utiliser une translation, par exemple :

Transform view= make_translation( make_vector(0, 0, 5) );

et utiliser la solution standard pour définir une perspective :

Transform projection= make_perspective(/* fov */ 45, /* aspect */ 1, /* znear */ 0.1, /* zfar */ 100);

la transformation model est l'identité, si vous placez directement les objets dans le monde :

Transform model= make_identity();


rappel :
points, vecteurs et matrices / transformations
Point et Vector sont définis dans vec.h, les operations courantes sont définies également par surcharge des operateurs du c++. ce qui permet d'écrire :

#include "vec.h"
#include "mat.h"

Point o= make_point(0, 0, 0);

Point e= make_point(0, 0, 1);
Vector d= e - o;    // ou d= make_vector(o, e);

float t= 0.5;
Point p= o + t * d;

Transform m= make_translation( make_vector(0, 0, -1) );
Point q= m * p;    // ou q= transform(m, p);

les produits scalaires et vectoriels sont définis par les fonctions dot( ), cross( ), ainsi que les autres opérations length( ), distance( ), etc. consultez la doc de vec.h et de mat.h.


exemple de transformations :

pour placer 2 spheres dans le monde, on peut les créer directement avec des coordonnées exprimées dans le repère du monde :

Sphere s1= make_sphere( make_point(-1, 0, 0), 1 );
Sphere s2= make_sphere( make_point( 1, 0, 0), 1 );

ou, on peut aussi créer une seule sphere placée à l'origine de son repère local et la placer dans le monde à l'aide d'une translation. mais dans ce cas, il faut aussi stocker la transformation dans la structure Sphere :

struct Sphere
{
    Transform model;
    Point center;
    float radius;
};

Sphere make_sphere( const Transform& model, const Point& center, const float radius )
{
    Sphere s;
    s.model= model;
    s.center= center;
    s.radius= radius;
    return s;
}

Transform t1= make_translation( make_vector(-1, 0, 0) );
Transform t2= make_translation( make_vector( 1, 0, 0) );

Sphere s1= make_sphere( t1, make_point(0, 0, 0), 1) );

Sphere s2= make_sphere( t2, make_point(0, 0, 0), 1) );


et modifier la fonction d'intersection pour d'abord calculer les coordonnées du centre de la sphère dans le repère du monde...

indication : les coordonnées transformées se calculent directement avec transform( ) :

Point center= transform(sphere.model, sphere.center);



exercice 1 : intersection rayon / plan

écrivez la fonction d'intersection rayon / plan.
rappel : un plan est défini par un point et une normale.

exercice 2 : intersection rayon / sphere

exemple


écrivez la fonction d'intersection rayon / sphere
rappel : une sphere est définie par un centre et un diametre/rayon.

écrivez également la version utilisant une transformation model.

exercice 3 : plusieurs objets

placez plusieurs objets dans la scène, un plan pour le sol et une sphere au dessus, par exemple.

écrivez une fonction bool intersect( const Ray &ray, Hit& hit ) qui renvoie vrai si le rayon a touché un des objets et que le point d'intersection est bien devant la camera / l'origine du rayon, ainsi que la distance de l'objet le plus proche.

exercice 4 : et avec de la couleur ?

exemple


calculez une couleur en fonction de l'orientation de l'objet intersecte par le rayon.
rappel : vous aurez besoin de connaitre la normale de la surface sur laquelle se trouve le point d'intersection.

quelle direction choisir ? essayez avec la camera (cf cours) ou avec une "source de lumière".


exercice 5 : et avec des ombres ?

créez un autre rayon, qui part du point d'intersection calculé pour le pixel, et qui vise la position d'une source de lumière.
s'il existe une intersection entre le point et la source, le point est à l'ombre, sinon il est éclairé.
indication: utilisez une couleur sombre pour la couleur de l'ombre, ou un petit pourcentage de la couleur éclairée.