/* Un mini programme de ray-tracing */ /* */ /* Auteur: Nicolas JANEY */ /* nicolas.janey@univ-fcomte.fr */ /* Mars 2014 */ #if defined(WIN32) || defined(WIN64) #define _CRTDBG_MAP_ALLOC #if defined(_DEBUG) #define _AFXDLL #include #endif #endif #include #if defined(WIN32) || defined(WIN64) #include #endif #include #include #include #include #include #include "Image.h" #include "Couleur.h" #include "Materiel.h" #include "Sphere.h" #include "Scene.h" #include "RayonLumineux.h" #include "LumierePonctuelle.h" #include "LumiereDirectionnelle.h" #include "Dir3D.h" #include "Pos3D.h" #include "Rt3D.h" #include "Tr3D.h" #include "TG3D.h" /* Variables globales de stockage des handles */ /* des deux fenetres */ static int f1; static int f2; /* 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; /* Variables globales */ static int lignesTraitees = 0; static long nbRayons; static long nbRayonsOmbre; static int sc = 0; static int mode = 1; /* Definition d'un tableau de 2 scenes */ static Scene *scn[3] = { NULL,NULL,NULL }; /* Variables globales de gestion du ray-tracing */ static int niveauRecursivite = 10; static int resolutionX = 480; static int resolutionY = 300; static double sensibilite = 100.0; /* Variables globales de stockage de l'image calculee */ static Image *ima = NULL ; /* Fonction de nettoyage memoire */ void clean(void) { if ( ima ) { delete(ima); ima = NULL; } if ( scn[0] ) { delete(scn[0]); scn[0] = NULL; } if ( scn[1] ) { delete(scn[1]); scn[1] = NULL; } if ( scn[2] ) { delete(scn[2]); scn[2] = NULL; } } /* 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); ima->affichage(); glPopMatrix(); glFlush(); checkError(__LINE__); glutSwapBuffers(); } void orienteScene(Scene *scene) { Tr3D tr1(0.0,0.0,csc); Rt3D rtx(rx,1.0,0.0,0.0); Rt3D rty(ry,0.0,1.0,0.0); Tr3D tr2(0.0,0.0,-csc); TG3D m0(&rty,&tr1); TG3D m1(&rtx,&m0); TG3D m(&tr2,&m1); int i; for ( i = 0 ; i < scene->nbObjets ; i++ ) scene->objets[i]->centre->transformation(&m); for ( i = 0 ; i < scene->nbLumieres ; i++ ) scene->lumieres[i]->transforme(&m); } /* 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 = new RayonLumineux(); 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->direction->x = 0.0; rl->direction->y = 0.0; rl->direction->z = -1.0; Energie energieRecue; Scene *nsc = new Scene(scn[sc]); orienteScene(nsc); nsc->rayTracing(&energieRecue,rl,niveauRecursivite,1.0,1,&nbRayons,&nbRayonsOmbre); img->affecteEnergieSurPixel(&energieRecue,sensibilite,i,ligne); delete(nsc); delete(rl); } } /* 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("%3d : %10d %10d : %10d\n",niveauRecursivite,nbRayons,nbRayonsOmbre,nbRayons+nbRayonsOmbre); 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; delete(ima); ima = new Image(resolutionX,resolutionY); nbRayons = 0; nbRayonsOmbre = 0; glutIdleFunc(idle); break; case 45 : niveauRecursivite--; if ( niveauRecursivite < 1 ) niveauRecursivite = 1; lignesTraitees = 0; delete(ima); ima = new Image(resolutionX,resolutionY); nbRayons = 0; nbRayonsOmbre = 0; glutIdleFunc(idle); break; case 0x20 : sc = (sc+1)%3; csc = (sc == 1) ? 150.0F : 200.0F; glutIdleFunc(NULL); glutPostWindowRedisplay(f2); break; case 0x0D : lignesTraitees = 0; delete(ima); ima = new Image(resolutionX,resolutionY); nbRayons = 0; nbRayonsOmbre = 0; glutIdleFunc(idle); break; case 0x1B : clean(); 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; delete(ima); ima = new Image(resolutionX,resolutionY); 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) { glClearColor(0.0F,0.0F,0.0F,1.0F); 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 < 8 ; i++ ) { glDisable(lum); lum++; } lum = GL_LIGHT0; for ( i = 0 ; i < scn[sc]->nbLumieres ; i++ ) { Lumiere *l = scn[sc]->lumieres[i]; float fact = l->intensite * sensibilite / 255.0; glEnable(lum); l->modeliseOpenGL(lum); glLightf(lum,GL_CONSTANT_ATTENUATION,1.0F); glLightf(lum,GL_LINEAR_ATTENUATION,1.0F); glLightf(lum,GL_QUADRATIC_ATTENUATION,1.0F); float dif[4] = { (float) l->c->r * fact, (float) l->c->v * fact, (float) l->c->b * fact, 1.0F }; glLightfv(lum,GL_SPECULAR,noir); glLightfv(lum,GL_DIFFUSE,dif); lum++; } for ( i = 0 ; i < scn[sc]->nbObjets ; i++ ) { Objet *o = scn[sc]->objets[i]; float alpha =(o->materiel->kt->r+ o->materiel->kt->v+ o->materiel->kt->b)/3.0F; glPushMatrix(); glTranslatef(o->centre->x,o->centre->y,o->centre->z); float dif[4] = { (float) o->materiel->kd->r, (float) o->materiel->kd->v, (float) o->materiel->kd->b, 1.0F-alpha }; glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,dif); glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,noir); glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,noir); o->modeliseOpenGL(); 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) { #if defined(WIN32) || defined(WIN64) _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF ); //_crtBreakAlloc = 472; #endif atexit(clean); { Scene *scene0 = new Scene(); scn[0] = scene0; { Pos3D *pos = new Pos3D(-90.0,90.0,-600.0); Couleur *kd = new Couleur(1.0,0.0,0.0); Couleur *kr = new Couleur(0.0,0.0,0.0); Couleur *kt = new Couleur(0.0,0.0,0.0); Materiel *m = new Materiel(kd,kr,kt,1.0); Sphere *sp = new Sphere(pos,40.0,m); scene0->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(90.0,-90.0,-600.0); Couleur *kd = new Couleur(0.0,1.0,0.0); Couleur *kr = new Couleur(0.0,0.0,0.0); Couleur *kt = new Couleur(0.0,0.0,0.0); Materiel *m = new Materiel(kd,kr,kt,1.0); Sphere *sp = new Sphere(pos,40.0,m); scene0->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(-90.0,-90.0,-600.0); Couleur *kd = new Couleur(0.0,0.0,1.0); Couleur *kr = new Couleur(0.0,0.0,0.0); Couleur *kt = new Couleur(0.0,0.0,0.0); Materiel *m = new Materiel(kd,kr,kt,1.0); Sphere *sp = new Sphere(pos,40.0,m); scene0->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(90.0,90.0,-600.0); Couleur *kd = new Couleur(1.0,1.0,1.0); Couleur *kr = new Couleur(0.0,0.0,0.0); Couleur *kt = new Couleur(0.0,0.0,0.0); Materiel *m = new Materiel(kd,kr,kt,1.0); Sphere *sp = new Sphere(pos,40.0,m); scene0->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(0.0,0.0,-610.0); Couleur *kd = new Couleur(1.0,1.0,0.0); Couleur *kr = new Couleur(0.0,0.0,0.0); Couleur *kt = new Couleur(0.0,0.0,0.0); Materiel *m = new Materiel(kd,kr,kt,1.0); Sphere *sp = new Sphere(pos,40.0,m); scene0->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(0.0,0.0,-200.0); Couleur *kd = new Couleur(0.25,0.25,0.25); Couleur *kr = new Couleur(0.0,0.0,0.0); Couleur *kt = new Couleur(0.75,0.75,0.75); Materiel *m = new Materiel(kd,kr,kt,1.5); Sphere *sp = new Sphere(pos,120.0,m); scene0->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Dir3D *dir = new Dir3D(0.0,0.707,-0.707); Couleur *coul = new Couleur(0.8,0.0,0.8); LumiereDirectionnelle *ld = new LumiereDirectionnelle(dir,1.5,coul); scene0->add(ld); delete(ld); delete(dir); delete(coul); } { Dir3D *dir = new Dir3D(-0.57735,0.57735,0.57735); Couleur *coul = new Couleur(0.8,0.0,0.8); LumiereDirectionnelle *ld = new LumiereDirectionnelle(dir,1.5,coul); scene0->add(ld); delete(ld); delete(dir); delete(coul); } { Dir3D *dir = new Dir3D(0.57735,0.57735,0.57735); Couleur *coul = new Couleur(0.0,0.9,0.9); LumiereDirectionnelle *ld = new LumiereDirectionnelle(dir,3.0,coul); scene0->add(ld); delete(ld); delete(dir); delete(coul); } { Pos3D *pos = new Pos3D(80.0,20.0,0.0); Couleur *coul = new Couleur(0.9,0.9,0.0); LumierePonctuelle *lp = new LumierePonctuelle(pos,15000.0,coul); scene0->add(lp); delete(lp); delete(pos); delete(coul); } { Pos3D *pos = new Pos3D(-80.0,-20.0,0.0); Couleur *coul = new Couleur(0.8,0.8,0.8); LumierePonctuelle *lp = new LumierePonctuelle(pos,28000.0,coul); scene0->add(lp); delete(lp); delete(pos); delete(coul); } } { Scene *scene1 = new Scene(); scn[1] = scene1; { Pos3D *pos = new Pos3D(160.0,50.0,-200.0); Couleur *kd = new Couleur(0.8,0.8,0.8); Couleur *kr = new Couleur(0.1,0.1,0.1); Couleur *kt = new Couleur(0.1,0.1,0.1); Materiel *m = new Materiel(kd,kr,kt,1.3); Sphere *sp = new Sphere(pos,90.0,m); scene1->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(130.0,115.0,-100.0); Couleur *kd = new Couleur(0.3,0.3,0.8); Couleur *kr = new Couleur(0.6,0.6,0.1); Couleur *kt = new Couleur(0.1,0.1,0.1); Materiel *m = new Materiel(kd,kr,kt,1.3); Sphere *sp = new Sphere(pos,20.0,m); scene1->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(10.0,-10.0,-150.0); Couleur *kd = new Couleur(0.1,0.2,0.4); Couleur *kr = new Couleur(0.9,0.8,0.6); Couleur *kt = new Couleur(0.0,0.0,0.0); Materiel *m = new Materiel(kd,kr,kt,1.5); Sphere *sp = new Sphere(pos,70.0,m); scene1->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(-150.0,-60.0,-150.0); Couleur *kd = new Couleur(0.5,0.4,0.3); Couleur *kr = new Couleur(0.1,0.1,0.1); Couleur *kt = new Couleur(0.4,0.5,0.6); Materiel *m = new Materiel(kd,kr,kt,1.4); Sphere *sp = new Sphere(pos,60.0,m); scene1->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(-110.0,-80.0,-30.0); Couleur *kd = new Couleur(0.4,0.3,0.2); Couleur *kr = new Couleur(0.3,0.2,0.4); Couleur *kt = new Couleur(0.2,0.4,0.3); Materiel *m = new Materiel(kd,kr,kt,1.2); Sphere *sp = new Sphere(pos,30.0,m); scene1->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(50.0,20.0,-30.0); Couleur *kd = new Couleur(0.2,0.3,0.0); Couleur *kr = new Couleur(0.8,0.6,0.7); Couleur *kt = new Couleur(0.0,0.1,0.3); Materiel *m = new Materiel(kd,kr,kt,1.2); Sphere *sp = new Sphere(pos,10.0,m); scene1->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(-90.0,90.0,-70.0); Couleur *kd = new Couleur(1.0,0.5,0.5); Couleur *kr = new Couleur(0.0,0.5,0.5); Couleur *kt = new Couleur(0.0,0.0,0.0); Materiel *m = new Materiel(kd,kr,kt,1.2); Sphere *sp = new Sphere(pos,50.0,m); scene1->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Pos3D *pos = new Pos3D(0.0,65.0,-45.0); Couleur *kd = new Couleur(0.25,0.25,0.25); Couleur *kr = new Couleur(0.0,0.0,0.0); Couleur *kt = new Couleur(0.75,0.75,0.75); Materiel *m = new Materiel(kd,kr,kt,1.45); Sphere *sp = new Sphere(pos,44.0,m); scene1->add(sp); delete(pos); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } { Dir3D *dir = new Dir3D(-0.57735,0.57735,0.57735); Couleur *coul = new Couleur(0.8,0.0,0.8); LumiereDirectionnelle *ld = new LumiereDirectionnelle(dir,1.5,coul); scene1->add(ld); delete(ld); delete(dir); delete(coul); } { Dir3D *dir = new Dir3D(0.57735,0.57735,0.57735); Couleur *coul = new Couleur(0.0,0.9,0.9); LumiereDirectionnelle *ld = new LumiereDirectionnelle(dir,3.0,coul); scene1->add(ld); delete(ld); delete(dir); delete(coul); } { Pos3D *pos = new Pos3D(80.0,20.0,0.0); Couleur *coul = new Couleur(0.9,0.9,0.0); LumierePonctuelle *lp = new LumierePonctuelle(pos,15000.0,coul); scene1->add(lp); delete(lp); delete(pos); delete(coul); } { Pos3D *pos = new Pos3D(-80.0,-20.0,0.0); Couleur *coul = new Couleur(0.8,0.8,0.8); LumierePonctuelle *lp = new LumierePonctuelle(pos,28000.0,coul); scene1->add(lp); delete(lp); delete(pos); delete(coul); } } { Scene *scene = new Scene(); scn[2] = scene; { for ( double x = -100.0 ; x < 105.0 ; x += 100.0 ) { for ( double y = -100.0 ; y <105.0 ; y += 100.0 ) { for ( double z = -100.0 ; z <105.0 ; z += 100.0 ) { Pos3D *pos = new Pos3D(x,y,z-200.0); switch (rand()%5) { case 0 : case 1 : case 2 : { Couleur *kd = new Couleur(( rand()%3 != 0 ) ? 1.0 : 0.0, ( rand()%3 != 0 ) ? 1.0 : 0.0, ( rand()%3 != 0 ) ? 1.0 : 0.0); Couleur *kr = new Couleur(0.1,0.1,0.1); Couleur *kt = new Couleur(0.1,0.1,0.1); Materiel *m = new Materiel(kd,kr,kt,1.5); Sphere *sp = new Sphere(pos,30.0,m); scene->add(sp); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } break; case 3 : { Couleur *kd = new Couleur(0.1,0.1,0.1); Couleur *kr = new Couleur(1.0,1.0,1.0); Couleur *kt = new Couleur(0.1,0.1,0.1); Materiel *m = new Materiel(kd,kr,kt,1.5); Sphere *sp = new Sphere(pos,30.0,m); scene->add(sp); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } break; case 4 : { Couleur *kd = new Couleur(0.1,0.1,0.1); Couleur *kr = new Couleur(0.1,0.1,0.1); Couleur *kt = new Couleur(1.0,1.0,1.0); Materiel *m = new Materiel(kd,kr,kt,1.5); Sphere *sp = new Sphere(pos,30.0,m); scene->add(sp); delete(kd); delete(kr); delete(kt); delete(m); delete(sp); } break; } delete(pos); } } } } { Dir3D *dir = new Dir3D(-0.57735,0.57735,0.57735); Couleur *coul = new Couleur(0.8,0.8,0.8); LumiereDirectionnelle *ld = new LumiereDirectionnelle(dir,1.5,coul); scene->add(ld); delete(ld); delete(dir); delete(coul); } { Dir3D *dir = new Dir3D(0.57735,0.57735,0.57735); Couleur *coul = new Couleur(0.9,0.9,0.9); LumiereDirectionnelle *ld = new LumiereDirectionnelle(dir,3.0,coul); scene->add(ld); delete(ld); delete(dir); delete(coul); } { Pos3D *pos = new Pos3D(80.0,20.0,0.0); Couleur *coul = new Couleur(0.9,0.9,0.9); LumierePonctuelle *lp = new LumierePonctuelle(pos,15000.0,coul); scene->add(lp); delete(lp); delete(pos); delete(coul); } { Pos3D *pos = new Pos3D(-80.0,-20.0,0.0); Couleur *coul = new Couleur(0.8,0.8,0.8); LumierePonctuelle *lp = new LumierePonctuelle(pos,28000.0,coul); scene->add(lp); delete(lp); delete(pos); delete(coul); } } ima = new Image(resolutionX,resolutionY); 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); }