Le source : RayTracingSurSpheres.cpp
/* Auteur: Nicolas JANEY */
/* nicolas.janey@univ-fcomte.fr */
/* Decembre 2008 */
/* 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>
#include "RayTracing-Position.h"
#include "RayTracing-Direction.h"
#include "RayTracing-Scene.h"
#include "RayTracing-Sphere.h"
#include "RayTracing-LumierePonctuelle.h"
#include "RayTracing-LumiereDirectionnelle.h"
#include "RayTracing-Image.h"
#include "RayTracing-MathematiquesMatricielles.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;
/* 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 };
/* Definition d'un tableau de 2 scenes */
static scene *scn[2] =
{ &scn1,
&scn2 };
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);
}
/* 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'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 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 de test de nullite d'une couleur */
/* (noir) */
static 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 */
static 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 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);
}
Tous les fichiers : RayTracing.zip