L'exécutable

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

RETOUR