/* Un mini programme de ray-tracing */ /* */ /* Auteur: Nicolas JANEY */ /* nicolas.janey@univ-fcomte.fr */ /* Novembre 2009 */ #include #include #include #include #include #include #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 = 0 ; 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); }