L'exécutable : MiniRayTracing.exe
La même scène affichée avec l'algorithme de rendu d'OpenGL et avec un algorithme de lancer de rayons
La même scène affichée avec l'algorithme de rendu d'OpenGL et avec un algorithme de lancer de rayons
Fichier source : MiniRayTracing.cpp
/* Auteur: Nicolas JANEY */
/* nicolas.janey@univ-fcomte.fr */
/* Novembre 2007 */
/* Un mini programme de ray-tracing */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <GL/glut.h>
#include <GL/gl.h>
#include <GL/glu.h>
/* Variables globales de gestion */
/* de l'interactivite clavier et souris */
static int clic = 0;
static int mx;
static int my;
static float rx = 0.0F;
static float ry = 0.0F;
static float csc = 200.0F;
/* Type de stockage d'une position */
typedef struct position {
double x;
double y;
double z;
double t; } position;
/* Type de stockage d'une direction */
typedef struct direction {
double x;
double y;
double z;
double t; } direction;
/* Type de stockage d'une couleur */
typedef struct couleur {
double r;
double v;
double b; } couleur;
/* Type de stockage d'une energie coloree */
typedef struct energie {
double r;
double v;
double b; } energie;
/* Type de stockage d'un materiel avec */
/* - coefficients de diffusion */
/* - coefficients de reflexion */
/* - coefficients de transmission */
/* - indice de refraction */
typedef struct materiel {
couleur kd;
couleur kr;
couleur kt;
double indice; } materiel;
/* Type de stockage d'une sphere */
typedef struct sphere {
position centre;
double rayon;
materiel materiel; } sphere;
/* Type de stockage d'une lumiere ponctuelle */
typedef struct lumierePonctuelle {
position position;
double intensite;
couleur couleur; } lumierePonctuelle;
/* Type de stockage d'une lumiere */
/* directionnelle */
typedef struct lumiereDirectionnelle {
direction direction;
double intensite;
couleur couleur; } lumiereDirectionnelle;
/* Type de stockage d'une scene */
typedef struct scene {
int nbSpheres;
sphere *spheres;
int nbLumieresPonctuelles;
lumierePonctuelle *lumieresPonctuelles;
int nbLumieresDirectionnelles;
lumiereDirectionnelle *lumieresDirectionnelles; } scene;
/* Type de stockage d'un rayon lumineux compose */
/* d'une origine et d'une direction d'emission */
typedef struct rayonLumineux {
position origine;
direction direction; } rayonLumineux;
/* Definition d'une premiere scene en statique */
static sphere spheres1[6] =
{ { { 0.0,0.0,-610.0,1.0 },
40.0,
{ { 1.0,1.0,0.0 },
{ 0.0,0.0,0.0 },
{ 0.0,0.0,0.0 },
1.0 } },
{ { -90.0,90.0,-600.0,1.0 },
40.0,
{ { 1.0,0.0,0.0 },
{ 0.0,0.0,0.0 },
{ 0.0,0.0,0.0 },
1.0 } },
{ { 90.0,-90.0,-600.0,1.0 },
40.0,
{ { 0.0,1.0,0.0 },
{ 0.0,0.0,0.0 },
{ 0.0,0.0,0.0 },
1.0 } },
{ { -90.0,-90.0,-600.0,1.0 },
40.0,
{ { 0.0,0.0,1.0 },
{ 0.0,0.0,0.0 },
{ 0.0,0.0,0.0 },
1.0 } },
{ { 90.0,90.0,-600.0,1.0 },
40.0,
{ { 1.0,1.0,1.0 },
{ 0.0,0.0,0.0 },
{ 0.0,0.0,0.0 },
1.0 } },
{ { 0.0,0.0,-200.0,1.0 },
120.0,
{ { 0.25,0.25,0.25 },
{ 0.0,0.0,0.0 },
{ 0.75,0.75,0.75 },
1.5 } } };
static lumierePonctuelle lumieresPonctuelles1[2] =
{ { { 80.0,20.0,0.0,1.0 },
15000.0,
{ 0.9,0.9,0.0 } },
{ { -80.0,-20.0,0.0,1.0 },
28000.0,
{ 0.8,0.8,0.8 } } };
static lumiereDirectionnelle lumieresDirectionnelles1[3] =
{ { { 0.57735,0.57735,0.57735,0.0 },
3.0,
{ 0.0,0.9,0.9 } },
{ { -0.57735,0.57735,0.57735,0.0 },
1.5,
{ 0.8,0.0,0.8 } },
{ { 0.0,0.707,-0.707,0.0 },
1.5,
{ 0.8,0.0,0.8 } } };
static scene scn1 =
{ 6,
spheres1,
2,
lumieresPonctuelles1,
2,
lumieresDirectionnelles1 };
/* Definition d'une seconde scene en statique */
static sphere spheres2[8] =
{ { { 160.0,50.0,-200.0,1.0 },
90.0,
{ { 0.8,0.8,0.8 },
{ 0.1,0.1,0.1 },
{ 0.1,0.1,0.1 },
1.3 } },
{ { 130.0,115.0,-100.0,1.0 },
20.0,
{ { 0.3,0.3,0.8 },
{ 0.6,0.6,0.1 },
{ 0.1,0.1,0.1 },
1.3 } },
{ { 10.0,-10.0,-150.0,1.0 },
70.0,
{ { 0.1,0.2,0.4 },
{ 0.9,0.8,0.6 },
{ 0.0,0.0,0.0 },
1.5 } },
{ { -150.0,-60.0,-150.0,1.0 },
60.0,
{ { 0.5,0.4,0.3 },
{ 0.1,0.1,0.1 },
{ 0.4,0.5,0.6 },
1.4 } },
{ { -110.0,-80.0,-30.0,1.0 },
30.0,
{ { 0.4,0.3,0.2 },
{ 0.3,0.2,0.4 },
{ 0.2,0.4,0.3 },
1.2 } },
{ { 50.0,20.0,-30.0,1.0 },
10.0,
{ { 0.2,0.3,0.0 },
{ 0.8,0.6,0.7 },
{ 0.0,0.1,0.3 },
1.2 } },
{ { -90.0,90.0,-70.0,1.0 },
50.0,
{ { 1.0,0.5,0.5 },
{ 0.0,0.5,0.5 },
{ 0.0,0.0,0.0 },
1.2 } },
{ { 0.0,65.0,-45.0,1.0 },
44.0,
{ { 0.25,0.25,0.25 },
{ 0.0,0.0,0.0 },
{ 0.75,0.75,0.75 },
1.45 } } };
static lumierePonctuelle lumieresPonctuelles2[2] =
{ { { 80.0,20.0,0.0,1.0 },
15000.0,
{ 0.9,0.9,0.0 } },
{ { -80.0,-20.0,0.0,1.0 },
28000.0,
{ 0.8,0.8,0.8 } } };
static lumiereDirectionnelle lumieresDirectionnelles2[2] =
{ { { 0.57735,0.57735,0.57735,0.0 },
3.0,
{ 0.0,0.9,0.9 } },
{ { -0.57735,0.57735,0.57735,0.0 },
1.5,
{ 0.8,0.0,0.8 } } };
static scene scn2 =
{ 8,
spheres2,
2,
lumieresPonctuelles2,
2,
lumieresDirectionnelles2 };
void liberationScene(scene *scene) {
free(scene->spheres);
free(scene->lumieresPonctuelles);
free(scene->lumieresDirectionnelles);
}
void copieScene(scene *src,scene *dst) {
dst->nbSpheres = src->nbSpheres;
dst->nbLumieresPonctuelles = src->nbLumieresPonctuelles;
dst->nbLumieresDirectionnelles = src->nbLumieresDirectionnelles;
dst->spheres =(sphere *) malloc(dst->nbSpheres*sizeof(sphere));
dst->lumieresPonctuelles =(lumierePonctuelle *) malloc(dst->nbLumieresPonctuelles*sizeof(lumierePonctuelle));
dst->lumieresDirectionnelles =(lumiereDirectionnelle *) malloc(dst->nbLumieresDirectionnelles*sizeof(lumiereDirectionnelle));
memcpy(dst->spheres,
src->spheres,
dst->nbSpheres*sizeof(sphere));
memcpy(dst->lumieresPonctuelles,
src->lumieresPonctuelles,
dst->nbLumieresPonctuelles*sizeof(lumierePonctuelle));
memcpy(dst->lumieresDirectionnelles,
src->lumieresDirectionnelles,
dst->nbLumieresDirectionnelles*sizeof(lumiereDirectionnelle));
}
typedef double vecteur[4];
typedef double matrice[4][4];
#ifndef M_PI
#define M_PI 3.141592653589793238
#endif
/* Initialisation a l'identite */
void toIdentite(matrice a) {
for ( int i = 0 ; i < 4 ; i++ )
for ( int j = 0 ; j < 4 ; j++ )
a[i][j] = ( i == j) ? 1.0 : 0.0;
}
/* Initialisation a la translation (dx,dy,dz) */
void toTranslation(matrice a,double dx,double dy,double dz) {
toIdentite(a);
a[0][3] = dx;
a[1][3] = dy;
a[2][3] = dz;
}
/* Initialisation a la rotation d'angle a */
/* autour de l'axe Ox */
void toRotationX(matrice m,double a) {
toIdentite(m);
double aa = a/180.0*M_PI;
m[2][1] = sin(aa);
m[1][2] = -m[2][1];
m[1][1] = m[2][2] = cos(aa);
}
/* Initialisation a la rotation d'angle a */
/* autour de l'axe Oy */
void toRotationY(matrice m,double a) {
toIdentite(m);
double aa = a/180.0*M_PI;
m[0][2] = sin(aa);
m[2][0] = -m[0][2];
m[0][0] = m[2][2] = cos(aa);
}
/* Produit matrice matrice */
void produitMatriceMatrice(matrice a,matrice b,matrice r) {
matrice rr;
int i,j;
for ( i = 0 ; i < 4 ; i++ )
for ( j = 0 ; j < 4 ; j++ ) {
rr[i][j] = 0.0;
for ( int k = 0 ; k < 4 ; k++ ) {
rr[i][j] += a[i][k]*b[k][j]; } }
for ( i = 0 ; i < 4 ; i++ )
for ( j = 0 ; j < 4 ; j++ )
r[i][j] = rr[i][j];
}
/* Produit matrice vecteur */
void produitMatriceVecteur(matrice m,vecteur v,vecteur r) {
vecteur rr;
int i;
for ( i = 0 ; i < 4 ; i++ ) {
rr[i] = 0.0;
for ( int j = 0 ; j < 4 ; j++ ) {
rr[i] += m[i][j]*v[j]; } }
for ( i = 0 ; i < 4 ; i++ ) {
r[i] = rr[i]; }
}
void orienteScene(scene *scene) {
matrice tr1;
matrice rtx;
matrice rty;
matrice tr2;
matrice m;
toTranslation(tr1,0.0,0.0,csc);
toTranslation(tr2,0.0,0.0,-csc);
toRotationX(rtx,rx);
toRotationY(rty,ry);
produitMatriceMatrice(rty,tr1,m);
produitMatriceMatrice(rtx,m,m);
produitMatriceMatrice(tr2,m,m);
int i;
for ( i = 0 ; i < scene->nbSpheres ; i++ )
produitMatriceVecteur(m,
(double *) &scene->spheres[i].centre,
(double *) &scene->spheres[i].centre);
for ( i = 0 ; i < scene->nbLumieresPonctuelles ; i++ )
produitMatriceVecteur(m,
(double *) &scene->lumieresPonctuelles[i].position,
(double *) &scene->lumieresPonctuelles[i].position);
for ( i = 0 ; i < scene->nbLumieresDirectionnelles ; i++ )
produitMatriceVecteur(m,
(double *) &scene->lumieresDirectionnelles[i].direction,
(double *) &scene->lumieresDirectionnelles[i].direction);
}
/* Definition d'un tableau de 2 scenes */
static scene *scn[2] =
{ &scn1,
&scn2 };
/* Definition d'une structure de stockage */
/* d'une image */
struct image {
int tx;
int ty;
GLubyte **t; };
/* Variables globales de stockage des handles */
/* des deux fenetres */
static int f1;
static int f2;
/* Variables globales */
static int lignesTraitees = 0;
static image ima = { 0,0,NULL } ;
static long nbRayons;
static int sc = 0;
static int mode = 1;
/* Variables globales de gestion du ray-tracing */
static int niveauRecursivite = 10;
static int resolutionX = 480;
static int resolutionY = 300;
static double sensibilite = 100.0;
/* Fonction d'allocation memoire */
/* d'une image bitmap */
void allocationMemoire(int tx,int ty,image *im) {
im->tx = tx;
im->ty = ty;
im->t =(GLubyte **) calloc(ty,sizeof(GLubyte *));
int i;
for ( i = 0 ; i < ty ; i++ ) {
im->t[i] =(GLubyte *) calloc(3*tx,sizeof(GLubyte)); }
}
/* Fonction de desallocation memoire */
/* d'une image bitmap */
void desallocationMemoire(image *im) {
if ( im->t != NULL ) {
for ( int i = 0 ; i < im->ty ; i++ ) {
free(im->t[i]); }
free(im->t); }
}
/* Fonction d'affichage d'une eventuelle */
/* erreur OpenGL */
static void checkError(int line) {
GLenum err = glGetError();
if (err) {
printf("GL Error %s (0x%x) at line %d\n",
gluErrorString(err), (int) err, line); }
}
/* Fonction d'affichage d'une image bitmap */
void affichageImage(image *img) {
for ( int i = 0 ; i < img->ty ; i++ ) {
glRasterPos2f(0,i);
glDrawPixels(img->tx,1,GL_RGB,GL_UNSIGNED_BYTE,img->t[i]); }
}
/* Fonction display GLUT d'affichage */
/* de la bitmap resultat du ray-tracing */
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glClearColor(0.0,0.0,0.0,1.0);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glPixelStorei(GL_PACK_ALIGNMENT,1);
affichageImage(&ima);
glPopMatrix();
glFlush();
checkError(__LINE__);
glutSwapBuffers();
}
/* Fonction d'affectation de la couleur */
/* d'un pixel d'une image a partir */
/* d'une energie et d'une sensibilite */
void affecteEnergieSurPixel(energie *energie,double sensibilite,
image *img,int x,int y) {
GLubyte *p = &img->t[y][x*3];
double r = energie->r*sensibilite+0.5;
double v = energie->v*sensibilite+0.5;
double b = energie->b*sensibilite+0.5;
if ( r > 255.0 )
r = 255.0;
if ( v > 255.0 )
v = 255.0;
if ( b > 255.0 )
b = 255.0;
p[0] =(GLubyte) (r);
p[1] =(GLubyte) (v);
p[2] =(GLubyte) (b);
}
/* Fonction de determination de l'intersection */
/* entre un rayon lumineux et une sphere. */
/* Un int booleen en retour pour indiquer */
/* l'existence ou non d'une intersection. */
/* Un double en passage par adresse pour */
/* retourner la distance entre l'origine */
/* du rayon en l'intersection la plus proche */
/* de l'origine du rayon sur sa trajectoire. */
int intersection(rayonLumineux *rl,sphere *sp,double *d) {
double sx = rl->origine.x - sp->centre.x ;
double sy = rl->origine.y - sp->centre.y;
double sz = rl->origine.z - sp->centre.z;
double a = rl->direction.x*rl->direction.x +
rl->direction.y*rl->direction.y +
rl->direction.z*rl->direction.z;
double b = 2.0F*(rl->direction.x*sx +
rl->direction.y*sy +
rl->direction.z*sz);
double c = sx*sx + sy*sy + sz*sz - sp->rayon*sp->rayon;
double delta = b*b-4*a*c;
if ( delta < 0.0 )
return(0);
if ( delta == 0 ) {
double t = -b/(2.0*a);
if ( t >= 0.000001) {
*d = t;
return(1); }
else
return(0); }
{ double t = (-b-sqrt(delta))/(2.0*a);
if ( t >= 0.000001 ) {
*d = t;
return(1); } }
{ double t = (-b+sqrt(delta))/(2.0*a);
if ( t >= 0.000001 ) {
*d = t;
return(1); } }
return(0);
}
/* Fonction de determination de l'existence */
/* d'une intersection entre un rayon lumineux */
/* et une sphere. */
int intersection(rayonLumineux *rl,sphere *sp) {
double sx = rl->origine.x - sp->centre.x ;
double sy = rl->origine.y - sp->centre.y;
double sz = rl->origine.z - sp->centre.z;
double a = rl->direction.x*rl->direction.x +
rl->direction.y*rl->direction.y +
rl->direction.z*rl->direction.z;
double b = 2.0F*(rl->direction.x*sx +
rl->direction.y*sy +
rl->direction.z*sz);
double c = sx*sx + sy*sy + sz*sz - sp->rayon*sp->rayon;
double delta = b*b-4*a*c;
if ( delta < 0.0F )
return(0);
if ( delta == 0 ) {
double t = -b/(2.0*a);
if ( t >= 0.000001) {
return(1); }
else
return(0); }
{ double t = (-b-sqrt(delta))/(2.0*a);
if ( t >= 0.000001 ) {
return(1); } }
{ double t = (-b+sqrt(delta))/(2.0*a);
if ( t >= 0.000001 ) {
return(1); } }
return(0);
}
/* Fonction de test de nullite d'une couleur */
/* (noir) */
int estNul(couleur *cf) {
return(( cf->r == 0.0 ) && ( cf->v == 0.0 ) && ( cf->b == 0.0 ) );
}
/* Fonction de calcul de la position d'un point */
/* sur un rayon lumineux */
void calculPositionSurRayon(position *p,rayonLumineux *rl,double d) {
p->x = rl->origine.x + d*rl->direction.x;
p->y = rl->origine.y + d*rl->direction.y;
p->z = rl->origine.z + d*rl->direction.z;
p->t = 1.0;
}
/* Fonction de calcul de la normale exterieur */
/* en un point d'une sphere */
void calculNormale(direction *d,position *p,sphere *sp) {
d->x = (p->x - sp->centre.x)/sp->rayon;
d->y = (p->y - sp->centre.y)/sp->rayon;
d->z = (p->z - sp->centre.z)/sp->rayon;
d->t = 0.0;
}
/* Fonction de calcul du carre de la distance */
/* entre deux positions */
double carreDistance(position *p1,position *p2) {
double dx = p2->x-p1->x;
double dy = p2->y-p1->y;
double dz = p2->z-p1->z;
return(dx*dx+dy*dy+dz*dz);
}
/* Fonction de calcul de la distance */
/* entre deux positions */
double distance(position *p1,position *p2) {
return(sqrt(carreDistance(p1,p2)));
}
/* Fonction de normalisation d'une direction */
void normalise(direction *d) {
double l = sqrt(d->x*d->x+d->y*d->y+d->z*d->z);
if ( l != 0 ) {
d->x /= l;
d->y /= l;
d->z /= l; }
}
/* Fonction de calcul du produit scalaire */
/* entre deux directions */
double produitScalaire(direction *d1,direction *d2) {
return(d1->x*d2->x+d1->y*d2->y+d1->z*d2->z);
}
/* Fonction de calcul de la direction */
/* normalisee definie d'une position */
/* a une autre position */
void calculDirectionNormalisee(direction *d,
position *p1,position *p2) {
d->x = p2->x-p1->x;
d->y = p2->y-p1->y;
d->z = p2->z-p1->z;
d->t = 0.0;
normalise(d);
}
/* Fonction de calcul de la quantite d'energie */
/* diffusee sous l'eclairage d'une source */
/* lumineuse ponctuelle */
void calculDiffusion(energie *ed,
position *p,direction *n,
couleur *kd,
lumierePonctuelle *lp) {
if ( estNul(kd) ) {
ed->r = ed->v = ed->b = 0.0;
return; }
direction l;
calculDirectionNormalisee(&l,p,&lp->position);
double ps = produitScalaire(&l,n);
if ( ps <= 0.0 ) {
ed->r = ed->v = ed->b = 0.0;
return; }
double fact = ps*lp->intensite/carreDistance(p,&lp->position);
ed->r = fact*lp->couleur.r*kd->r;
ed->v = fact*lp->couleur.v*kd->v;
ed->b = fact*lp->couleur.b*kd->b;
}
/* Fonction de calcul de la quantite d'energie */
/* diffusee sous l'eclairage d'une source */
/* lumineuse directionnelle */
void calculDiffusion(energie *ed,
direction *n,
couleur *kd,
lumiereDirectionnelle *ld) {
if ( estNul(kd) ) {
ed->r = ed->v = ed->b = 0.0;
return; }
direction l = ld->direction;
normalise(&l);
double ps = produitScalaire(&l,n);
if ( ps <= 0.0 ) {
ed->r = ed->v = ed->b = 0.0;
return; }
double fact = ps*ld->intensite;
ed->r = fact*ld->couleur.r*kd->r;
ed->v = fact*ld->couleur.v*kd->v;
ed->b = fact*ld->couleur.b*kd->b;
}
/* Fonction de test de l'intersection */
/* d'un rayon d'ombre avec l'ensemble */
/* des objets d'une scene */
int intersection(rayonLumineux *rlo,scene *scn) {
for ( int i = 0 ; i < scn->nbSpheres ; i++ )
if ( intersection(rlo,&scn->spheres[i]) ) {
return(1); }
return(0);
}
/* Fonction de test de l'occultation d'un point */
/* eclaire par une lumiere directionnelle */
/* par l'ensemble des objets d'une scene */
int estEclaire(position *p,scene *scn,
lumiereDirectionnelle *ld) {
rayonLumineux rlo;
rlo.origine = *p;
rlo.direction = ld->direction;
normalise(&rlo.direction);
return(!intersection(&rlo,scn));
}
/* Fonction de test de l'intersection */
/* d'un rayon d'ombre avec l'ensemble */
/* des objets d'une scene. */
/* Les intersections candidates sont limitees */
/* a celles situees a une distance de la source */
/* du rayon inferieure a une distance limite. */
int intersection(rayonLumineux *rlo,scene *scn,double d) {
double dist;
for ( int i = 0 ; i < scn->nbSpheres ; i++ )
if ( intersection(rlo,&scn->spheres[i],&dist) ) {
if ( dist < d )
return(1); }
return(0);
}
/* Fonction de test de l'occultation d'un point */
/* eclaire par une source lumineuse ponctuelle */
/* par l'ensemble des objets d'une scene */
int estEclaire(position *p,scene *scn,
lumierePonctuelle *lp,double d) {
rayonLumineux rlo;
rlo.origine = *p;
calculDirectionNormalisee(&rlo.direction,p,&lp->position);
return(!intersection(&rlo,scn,d));
}
/* Fonction de calcul de la quantite d'energie */
/* diffusee en un point d'une sphere */
/* sous l'eclairage de l'ensemble des sources */
/* lumineuses d'une scene */
void calculDiffusion(energie *e,
scene *scn,
sphere *sp,position *p,direction *n) {
e->r = e->v = e->b = 0.0;
int i;
for ( i = 0 ; i < scn->nbLumieresPonctuelles ; i++ ) {
lumierePonctuelle *lp = &scn->lumieresPonctuelles[i];
double d = distance(p,&lp->position);
if ( estEclaire(p,scn,lp,d) ) {
energie ed;
calculDiffusion(&ed,p,n,&sp->materiel.kd,lp);
e->r += ed.r;
e->v += ed.v;
e->b += ed.b; } }
for ( i = 0 ; i < scn->nbLumieresDirectionnelles ; i++ ) {
lumiereDirectionnelle *ld = &scn->lumieresDirectionnelles[i];
if ( estEclaire(p,scn,ld) ) {
energie ed;
calculDiffusion(&ed,n,&sp->materiel.kd,ld);
e->r += ed.r;
e->v += ed.v;
e->b += ed.b; } }
}
/* Fonction de calcul de la direction du rayon */
/* lumineux reflechi cree par un rayon lumineux */
/* incident defini par sa direction */
/* de propagation */
void reflexion(direction *r,direction *i,direction *n) {
double ps2 = 2.0*produitScalaire(n,i);
r->x = ps2*n->x - i->x;
r->y = ps2*n->y - i->y;
r->z = ps2*n->z - i->z;
r->t = 0.0;
}
/* Fonction de calcul du rayon lumineux */
/* reflechi cree par un rayon lumineux incident */
void rayonReflechi(rayonLumineux *rr,
rayonLumineux *ri,
sphere *sp,position *p,direction *n) {
direction i = ri->direction;
i.x *= -1;
i.y *= -1;
i.z *= -1;
rr->origine = *p;
reflexion(&rr->direction,&i,n);
}
/* Fonction de calcul de la direction du rayon */
/* lumineux transmis eventuellement cree */
/* par un rayon lumineux incident defini */
/* par sa direction de propagation */
int transmission(direction *t,direction *i,direction *n,
double niSurnt) {
double ps = produitScalaire(n,i);
double v = 1.0-(niSurnt*niSurnt*(1.0-ps*ps));
if ( v < 0.0 )
return(0);
v = niSurnt*ps-sqrt(v);
t->x = v*n->x - niSurnt*i->x;
t->y = v*n->y - niSurnt*i->y;
t->z = v*n->z - niSurnt*i->z;
t->t = 0.0;
return(1);
}
/* Fonction de calcul du rayon lumineux */
/* transmis genere eventuellement */
/* par un rayon lumineux incident */
int rayonTransmis(rayonLumineux *rt,
rayonLumineux *ri,
sphere *sp,position *p,direction *n,
double niSurnt,int exterieur) {
direction norm = *n;
if ( !exterieur ) {
norm.x *= -1;
norm.y *= -1;
norm.z *= -1; }
direction i = ri->direction;
i.x *= -1;
i.y *= -1;
i.z *= -1;
if ( transmission(&rt->direction,&i,&norm,niSurnt) ) {
rt->origine = *p;
return(1); }
else
return(0);
}
/* Fonction principale recursive de calcul */
/* de ray-tracing */
void rayTracing(energie *e,
rayonLumineux *rl,
scene *scn,
int niveau,
double indiceRefraction,
int exterieur) {
nbRayons++;
e->r = e->v = e->b = 0.0;
double dmin = 1000000000.0;
int obj = -1;
int i;
for ( i = 0 ; i < scn->nbSpheres ; i++ ) {
double dist;
if ( intersection(rl,&scn->spheres[i],&dist) ) {
if ( dist < dmin ) {
dmin = dist;
obj = i; } } }
if ( obj != -1 ) {
position p;
calculPositionSurRayon(&p,rl,dmin);
direction n;
calculNormale(&n,&p,&scn->spheres[obj]);
if ( exterieur ) {
energie ed;
calculDiffusion(&ed,scn,&scn->spheres[obj],&p,&n);
e->r += ed.r;
e->v += ed.v;
e->b += ed.b; }
if ( niveau != 1 ) {
sphere *sp = &scn->spheres[obj];
couleur *kr = &sp->materiel.kr;
couleur *kt = &sp->materiel.kt;
if ( !estNul(kr) && exterieur ) {
rayonLumineux rr;
rayonReflechi(&rr,rl,sp,&p,&n);
energie er;
rayTracing(&er,&rr,scn,niveau-1,indiceRefraction,1);
e->r += er.r*kr->r;
e->v += er.v*kr->v;
e->b += er.b*kr->b; }
if ( !estNul(kt) ) {
rayonLumineux rt;
double niSurnt = indiceRefraction/sp->materiel.indice;
if ( rayonTransmis(&rt,
rl,sp,&p,&n,niSurnt,exterieur) ) {
energie et;
rayTracing(&et,
&rt,
scn,
niveau-1,
(exterieur) ? sp->materiel.indice : 1.0,
!exterieur);
e->r += et.r*kt->r;
e->v += et.v*kt->v;
e->b += et.b*kt->b; } } } }
}
/* Fonction de calcul en ray-tracing */
/* d'une ligne de pixels de l'image */
/* Chaque rayon primaire est dirige en -z */
/* -> projection parallele orthographique */
void traiteLigne(int ligne,image *img) {
for ( int i = 1 ; i < img->tx ; i++ ) {
rayonLumineux rl;
rl.origine.x = (i-img->tx/2.0)/(img->tx/480.0);
rl.origine.y = (ligne-img->ty/2.0)/(img->tx/480.0);
rl.origine.z = 2000.0;
rl.origine.t = 1.0;
rl.direction.x = 0.0;
rl.direction.y = 0.0;
rl.direction.z = -1.0;
rl.direction.t = 0.0;
energie energieRecue;
scene nsc;
copieScene(scn[sc],&nsc);
orienteScene(&nsc);
rayTracing(&energieRecue,&rl,&nsc,niveauRecursivite,1.0,1);
affecteEnergieSurPixel(&energieRecue,sensibilite,img,i,ligne);
liberationScene(&nsc); }
}
/* Fonction idle */
/* Calcul de 20 lignes de pixels en ray-tracing */
/* Arret quand l'image est entierement calculee */
void idle(void) {
for ( int i = 0 ; i < 20 ; i++ ) {
traiteLigne(lignesTraitees,&ima);
lignesTraitees++;
if ( lignesTraitees == resolutionY ) {
glutIdleFunc(NULL);
printf("%d %d\n",niveauRecursivite,nbRayons);
glutPostWindowRedisplay(f1);
return; } }
glutPostWindowRedisplay(f1);
}
/* Fonction executee lors de la frappe */
/* d'une touche alphanumerique du clavier */
void key(unsigned char key,int x,int y) {
switch ( key ) {
case 43 : niveauRecursivite++;
lignesTraitees = 0;
desallocationMemoire(&ima);
allocationMemoire(resolutionX,resolutionY,&ima);
nbRayons = 0;
glutIdleFunc(idle);
break;
case 45 : niveauRecursivite--;
if ( niveauRecursivite < 1 )
niveauRecursivite = 1;
lignesTraitees = 0;
desallocationMemoire(&ima);
allocationMemoire(resolutionX,resolutionY,&ima);
nbRayons = 0;
glutIdleFunc(idle);
break;
case 0x20 : sc = (sc+1)%2;
csc = (sc) ? 150.0F : 200.0F;
glutIdleFunc(NULL);
glutPostWindowRedisplay(f2);
break;
case 0x0D : lignesTraitees = 0;
desallocationMemoire(&ima);
allocationMemoire(resolutionX,resolutionY,&ima);
nbRayons = 0;
glutIdleFunc(idle);
break;
case 0x1B : desallocationMemoire(&ima);
exit(0);
break; }
}
/* Fonction reshape de l'affichage ray-tracing */
void reshape(int w,int h) {
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,w,0,h,-1.0,1.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
resolutionX = w;
resolutionY = h;
desallocationMemoire(&ima);
allocationMemoire(resolutionX,resolutionY,&ima);
glutIdleFunc(NULL);
glutSetWindow(f2);
glutReshapeWindow(w,h);
}
/* Fonction reshape de l'affichage OpenGL */
void reshapeOpenGL(int w,int h) {
glViewport(0,0,w,h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-240.0,240.0,
-240.0*(double) h/w,240.0*(double) h/w,
-5000.0,5000.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
/* Fonction display GLUT d'affichage OpenGL */
/* de la scene */
void displayOpenGL(void) {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_CULL_FACE);
glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
float noir[4] = { 0.0F,0.0F,0.0F,0.0F };
glPushMatrix();
glTranslatef(0.0F,0.0F,-csc);
glRotatef(rx,1.0F,0.0F,0.0F);
glRotatef(ry,0.0F,1.0F,0.0F);
glTranslatef(0.0F,0.0F,csc);
int lum = GL_LIGHT0;
int i;
for ( i = 0 ; i < scn[sc]->nbLumieresPonctuelles ; i++ ) {
lumierePonctuelle *lp = &scn[sc]->lumieresPonctuelles[i];
float fact = lp->intensite * sensibilite / 255.0;
glEnable(lum);
float pos[4] = { lp->position.x,
lp->position.y,
lp->position.z,
1.0F };
glLightfv(lum,GL_POSITION,pos);
glLightf(lum,GL_CONSTANT_ATTENUATION,1.0F);
glLightf(lum,GL_LINEAR_ATTENUATION,1.0F);
glLightf(lum,GL_QUADRATIC_ATTENUATION,1.0F);
float dif[4] = { lp->couleur.r * fact,
lp->couleur.v * fact,
lp->couleur.b * fact,
1.0F };
glLightfv(lum,GL_SPECULAR,noir);
glLightfv(lum,GL_DIFFUSE,dif);
lum++; }
for ( i = 0 ; i < scn[sc]->nbLumieresDirectionnelles ; i++ ) {
lumiereDirectionnelle *ld = &scn[sc]->lumieresDirectionnelles[i];
glEnable(lum);
float dir[4] = { ld->direction.x,
ld->direction.y,
ld->direction.z,
0.0F };
glLightfv(lum,GL_POSITION,dir);
glLightf(lum,GL_CONSTANT_ATTENUATION,1.0F);
glLightf(lum,GL_LINEAR_ATTENUATION,1.0F);
glLightf(lum,GL_QUADRATIC_ATTENUATION,1.0F);
float fact = ld->intensite * sensibilite / 255.0;
float dif[4] = { ld->couleur.r * fact,
ld->couleur.v * fact,
ld->couleur.b * fact,
1.0F };
glLightfv(lum,GL_SPECULAR,noir);
glLightfv(lum,GL_DIFFUSE,dif);
lum++; }
for ( i = 0 ; i < scn[sc]->nbSpheres ; i++ ) {
sphere *sp = &scn[sc]->spheres[i];
float alpha =(sp->materiel.kt.r+
sp->materiel.kt.v+
sp->materiel.kt.b)/3.0F;
glPushMatrix();
glTranslated(sp->centre.x,sp->centre.y,sp->centre.z);
float dif[4] = { sp->materiel.kd.r,
sp->materiel.kd.v,
sp->materiel.kd.b,
1.0F-alpha };
glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,dif);
glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,noir);
glutSolidSphere(sp->rayon,180,180);
glPopMatrix(); }
glPopMatrix();
glFlush();
checkError(__LINE__);
glutSwapBuffers();
}
/* Fonction executee lors d'un clic de souris */
/* dans la fenetre */
void mouse(int bouton,int etat,int x,int y) {
if ( bouton == GLUT_LEFT_BUTTON ) {
if ( etat == GLUT_DOWN ) {
clic = 1;
mx = x;
my = y; }
if ( etat == GLUT_UP ) {
clic = 0; } }
}
/* Fonction executee lors d'un deplacement */
/* de la souris sur la fenetre */
/* avec un bouton appuye */
void motion(int x,int y) {
if ( clic ) {
ry += (x-mx);
rx += (y-my);
mx = x;
my = y;
glutPostWindowRedisplay(f2); }
}
/* Fonction Pricipale */
int main(int argc,char **argv) {
allocationMemoire(resolutionX,resolutionY,&ima);
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
glutInitWindowSize(resolutionX,resolutionY);
glutInitWindowPosition(30,30);
f1 = glutCreateWindow("Mini Ray-Tracing");
glutReshapeFunc(reshape);
glutKeyboardFunc(key);
glutDisplayFunc(display);
glutInitWindowPosition(530,30);
f2 = glutCreateWindow("OpenGL");
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutKeyboardFunc(key);
glutReshapeFunc(reshapeOpenGL);
glutDisplayFunc(displayOpenGL);
glutMainLoop();
return(0);
}