Subversion Repositories gelsvn

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
305 jab 1
#include <iostream>
2
#include <vector>
3
#include <algorithm>
4
#include <cmath>
5
 
6
#include "GL/glut.h"
7
 
8
#include "CGLA/Vec2f.h"
9
#include "CGLA/Vec3i.h"
10
#include "CGLA/Vec3f.h"
11
#include "CGLA/Vec3d.h"
12
#include "CGLA/Mat4x4f.h"
309 jab 13
 
14
#include "HMesh/build_manifold.h"
305 jab 15
#include "Geometry/TriMesh.h"
16
#include "Geometry/obj_load.h"
17
#include "Geometry/Ray.h"
18
#include "Geometry/BSPTree.h"
309 jab 19
#include "GLGraphics/GLViewController.h"
305 jab 20
 
309 jab 21
#include "Geometry/build_bbtree.h"
22
#include "Geometry/AABox.h"
23
#include "Geometry/OBox.h"
24
#include "Util/Timer.h"
305 jab 25
#include "Camera.h"
26
 
310 jrf 27
// #define USE_BSP
309 jab 28
 
305 jab 29
using namespace std;
30
using namespace CGLA;
31
using namespace Geometry;
309 jab 32
using namespace HMesh;
305 jab 33
using namespace GLGraphics;
34
 
309 jab 35
/*
36
 * TODO: 
310 jrf 37
 * - BSP find out why BSP tree is suboptimal for the bunny mesh.
309 jab 38
 * - BBOX remove HMesh dependency - that is crazy.
39
 * - BBox visit child nodes in order of how far away the intersection point on
40
 *        the bbox is. Closest nodes visited first. Cull nodes farther than
41
 *        an actual intersection point.
42
 * - BBox Smooth interpolation of triangle normals. Straightforward.
43
 */
44
 
45
 
305 jab 46
namespace
47
{
310 jrf 48
  const int MAX_OBJECTS = 4;   // Maximum number of triangles in a BSP tree node
305 jab 49
  const int MAX_LEVEL = 20;    // Maximum number of BSP tree subdivisions
50
 
51
  const unsigned int TEX_SIZE = 512;
52
 
53
  bool raytrace = false;
54
  bool done = false;
55
  bool shadow = false;
56
 
57
  unsigned int winx = TEX_SIZE;     // Screen width
58
  unsigned int winy = TEX_SIZE;     // Screen height
59
 
60
  unsigned int PIXEL_SUBDIVS = 1;
61
 
62
  int mouse_state = GLUT_UP;
63
  int mouse_button = 0;
64
  int spin_timer = 20;
65
 
310 jrf 66
  GLViewController *vctrl;
305 jab 67
 
68
  TriMesh mesh;
69
  vector<TriMesh*> mesh_vector(1, &mesh);
70
  vector<Mat4x4f> transforms(1, identity_Mat4x4f());
71
 
72
  double light_pow = 1.0;
73
  Vec3f light_dir = normalize(Vec3f(1.0, 1.0, 1.0));
74
  Vec3d background(0.8, 0.9, 1.0);
75
 
76
  BSPTree tree;
77
  Camera* cam;
78
 
79
  Vec3f image[TEX_SIZE][TEX_SIZE];
80
  unsigned int image_tex;
81
 
82
  // Function to generate a random number between 0 and 1.
83
  // rand() returns a random number ranging from 0 to RAND_MAX.
84
  inline double my_random()
85
  {
86
    return rand()/static_cast<double>(RAND_MAX);
87
  }
309 jab 88
 
310 jrf 89
  AABBTree bb_tree;		
305 jab 90
}
91
 
92
void spin(int x);
93
 
94
//////////////////////////////////////////////////////////////
95
//      I N I T I A L I Z A T I O N               
96
//////////////////////////////////////////////////////////////
97
 
98
void init_texture(unsigned int& tex)
99
{
100
  glGenTextures(1, &tex);
101
 
102
  glBindTexture(GL_TEXTURE_2D, tex);
103
 
104
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
105
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
106
 
107
  // load the texture image
108
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 
109
	       TEX_SIZE, TEX_SIZE,
110
	       0, GL_RGB, GL_FLOAT, image[0][0].get());
111
}
112
 
113
void initRaytracer()
114
{
115
  Vec3f c;
116
  float r;
117
  mesh.get_bsphere(c, r);
118
  r *= 1.5;
119
 
120
  // Initialize track ball
310 jrf 121
  vctrl = new GLViewController(winx, winy, c, r);
305 jab 122
 
123
  // Initialize corresponding camera
124
  cam = new Camera(c - Vec3f(r), 
125
		   c, 
126
		   Vec3f(0.0f, 1.0f, 0.0f),
127
		   1.0f);
128
 
309 jab 129
#ifdef USE_BDL
130
   cout << "Constructing BSP tree..." << endl;
131
   tree.init(mesh_vector, transforms, MAX_OBJECTS, MAX_LEVEL);
132
   tree.build();
133
#else
134
	// AABB TREE
135
	Manifold m;
136
	vector<int> faces(mesh.geometry.no_faces(), 3);
137
	cout << "Creating manifold" << endl;
138
	build_manifold(m, 
310 jrf 139
				   mesh.geometry.no_vertices(), 
140
				   &mesh.geometry.vertex(0), 
141
				   faces.size(), &faces[0], 
142
				   reinterpret_cast<const int*>(&mesh.geometry.face(0)));
309 jab 143
	cout << "Building tree" << endl;
144
	build_AABBTree(m, bb_tree);
145
#endif
305 jab 146
}
147
 
148
void initGL()
149
{
150
  glShadeModel(GL_SMOOTH); 
309 jab 151
  glDisable(GL_CULL_FACE);
305 jab 152
  glFrontFace(GL_CCW);
153
 
154
  glClearColor(1.0, 1.0, 1.0, 1.0);
155
  glColor3f(0.0, 0.0, 0.0);
156
}
157
 
158
 
159
//////////////////////////////////////////////////////////////
160
//      S H A D E   F U N C T I O N S
161
//////////////////////////////////////////////////////////////
162
 
163
double shadow_shade(Ray& r)
164
{
165
  r.compute_position();
166
  Ray shadow(r.hit_pos, light_dir);
167
  double s = tree.intersect(shadow) ? 0.0 : 1.0;
168
 
169
  r.compute_normal();
170
  return s*light_pow*dot(r.hit_normal, light_dir);
171
}
172
 
173
double lambertian_shade(Ray& r)
174
{
309 jab 175
#ifdef USE_BDL
176
		r.compute_normal();
177
#endif
305 jab 178
  return light_pow*dot(r.hit_normal, light_dir);
179
}
180
 
181
double (*shade_ray[2])(Ray&) = { lambertian_shade,
182
				 shadow_shade      };
183
 
184
//////////////////////////////////////////////////////////////
185
//      D R A W   F U N C T I O N S
186
//////////////////////////////////////////////////////////////
187
 
188
/*
189
void enable_textures(TriMesh& tm)
190
{
191
  for(unsigned int i=0;i<tm.materials.size(); ++i)
192
  {
193
    Material& mat = tm.materials[i];
194
    if(mat.tex_name != "")
195
    {
196
      string name = mat.tex_path + mat.tex_name;
197
 
198
      GLuint tex_id;
199
      if(load_image_into_texture(name, tex_id))
200
	mat.tex_id = tex_id;
201
    }
202
  }
203
}
204
*/
205
 
206
void set_perspective_proj()
207
{
208
  glMatrixMode(GL_PROJECTION);	 
209
  glLoadIdentity();            
210
 
211
  gluPerspective(64.0, 1.0, 0.1, 1000.0);
212
 
213
  glMatrixMode(GL_MODELVIEW);
214
}
215
 
216
void set_ortho_proj()
217
{
218
  glMatrixMode(GL_PROJECTION);	 
219
  glLoadIdentity();             
220
 
221
  glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
222
 
223
  glMatrixMode(GL_MODELVIEW);  
224
}
225
 
226
void draw_texture(unsigned int tex)
227
{
228
  static GLfloat verts[] = { 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0 };
229
 
230
  glColor4f(1.0, 1.0, 1.0, 1.0);
231
 
232
  glBindTexture(GL_TEXTURE_2D, tex);
233
  glEnable(GL_TEXTURE_2D);
234
 
235
  glEnableClientState(GL_VERTEX_ARRAY);
236
  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
237
 
238
  glVertexPointer(2, GL_FLOAT, 0, verts);
239
  glTexCoordPointer(2, GL_FLOAT, 0, verts);
240
 
241
  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
242
 
243
  glDisableClientState(GL_VERTEX_ARRAY);
244
  glDisableClientState(GL_TEXTURE_COORD_ARRAY);
245
 
246
  glDisable(GL_TEXTURE_2D);
247
}
248
 
249
void drawOBJ()
250
{
251
  static bool washere = false;
252
  static unsigned int disp_list;
253
 
254
  if(!washere)
255
  {
256
    disp_list = glGenLists(1);
257
    glNewList(disp_list, GL_COMPILE);
258
 
259
    glBegin(GL_TRIANGLES);
260
      for(int i = 0; i < mesh.geometry.no_faces(); ++i)
261
      {
262
	Vec3i n_face = mesh.normals.face(i);
263
	Vec3i g_face = mesh.geometry.face(i);
264
	for(int j=0;j<3;j++)
265
	{
266
	  double shade = 0.5;
267
 
268
	  if(n_face != Geometry::NULL_FACE)
269
	  {
270
	    Vec3f norm = normalize(mesh.normals.vertex(n_face[j]));
271
	    glNormal3fv(norm.get());
272
	    shade = light_pow*dot(norm, light_dir);
273
	  }
274
 
275
	  glColor3d(shade, shade, shade);
276
	  Vec3f vert = mesh.geometry.vertex(g_face[j]);	  
277
	  glVertex3fv(vert.get());
278
	}
279
      }
280
    glEnd();
281
 
282
    glEndList();
283
    washere = true;
284
  }
285
  glCallList(disp_list);
286
}
287
 
288
 
289
//////////////////////////////////////////////////////////////
290
//      G L U T   C A L L B A C K   F U N C T I O N S                 
291
//////////////////////////////////////////////////////////////
292
 
293
void display()
294
{
295
  static bool first = true;
296
 
297
  if(first)
298
  {
299
    first = false;
300
    glutTimerFunc(spin_timer, spin, 0);
301
  }
302
 
303
  Vec3f eye, focus, up;
309 jab 304
	vctrl->get_view_param(eye, focus, up);
305
	cam->set(eye, focus, up, cam->get_focal_dist());
306
 
305 jab 307
  if(raytrace)
308
  {
309
    raytrace = false;
310
 
311
    cout << "Raytracing";
312
    float win_to_vp = 1.0f/static_cast<float>(TEX_SIZE);
313
    float lowerleft = 0.5 + win_to_vp*0.5;
314
    float step = win_to_vp/static_cast<float>(PIXEL_SUBDIVS);
315
 
316
    vector<Vec2f> jitter(PIXEL_SUBDIVS*PIXEL_SUBDIVS); 
317
    for(unsigned int i = 0; i < PIXEL_SUBDIVS; ++i)
318
      for(unsigned int j = 0; j < PIXEL_SUBDIVS; ++j)
319
      {
310 jrf 320
	    jitter[i*PIXEL_SUBDIVS + j][0] = (my_random() + (j%PIXEL_SUBDIVS))*step; 
321
	    jitter[i*PIXEL_SUBDIVS + j][1] = (my_random() + (i%PIXEL_SUBDIVS))*step; 
305 jab 322
      }
323
 
310 jrf 324
	Util::Timer tim;
325
	tim.start();
305 jab 326
    for(unsigned int i = 0; i < TEX_SIZE; ++i)
327
    {
310 jrf 328
	  for(unsigned int j = 0; j < TEX_SIZE; ++j)
329
	  {
330
		Vec3d sum(0.0f);
331
		Vec2f vp_pos(j*win_to_vp - lowerleft, i*win_to_vp - lowerleft);
305 jab 332
 
310 jrf 333
		for(unsigned int ky = 0; ky < PIXEL_SUBDIVS; ++ky)
334
		  for(unsigned int kx = 0; kx < PIXEL_SUBDIVS; ++kx)
335
		  {
336
			Ray r = cam->get_ray(vp_pos + jitter[ky*PIXEL_SUBDIVS + kx]);
305 jab 337
 
309 jab 338
#ifdef USE_BDL
310 jrf 339
			if(tree.intersect(r))
340
			  sum += Vec3d(shade_ray[shadow](r));
341
			else
342
			  sum += background;
309 jab 343
#else
310 jrf 344
			float t = FLT_MAX;
345
			bb_tree.intersect(r);
346
			if(r.has_hit)
347
			  sum += Vec3d(shade_ray[0](r));
348
			else 
349
			  sum += background;
309 jab 350
#endif		
310 jrf 351
		  }
305 jab 352
 
310 jrf 353
		  image[i][j] = Vec3f(sum/static_cast<double>(PIXEL_SUBDIVS*PIXEL_SUBDIVS));
354
	  }
355
	  if(((i + 1) % 50) == 0) cerr << ".";
356
	}
357
	cout << " - " << tim.get_secs() << " secs " << endl;
305 jab 358
    cout << endl;
359
 
360
    init_texture(image_tex);
361
 
362
    done = true;
363
  }
364
 
365
  if(done)
366
  {
367
    set_ortho_proj();
368
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
369
    glLoadIdentity();
370
 
371
    draw_texture(image_tex);
372
  }
373
  else
374
  {
375
    glEnable(GL_DEPTH_TEST);
376
 
377
    cam->glSetPerspective(winx, winy);
378
 
379
    glClearColor(background[0], background[1], background[2], 1.0);
380
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
381
    glLoadIdentity();
382
 
310 jrf 383
	vctrl->set_gl_modelview();
305 jab 384
 
385
    glColor3f(0.5, 0.5, 0.5);
386
    drawOBJ();
387
 
388
    glDisable(GL_DEPTH_TEST);
389
  }
390
 
391
  glutSwapBuffers();  
392
}
393
 
394
void reshape(int w, int h)
395
{
396
  winx = w; winy = h;
397
 
309 jab 398
  vctrl->reshape(winx, winy);
305 jab 399
 
400
  glViewport(0, 0, winx, winy);
401
}
402
 
403
void keyboard(unsigned char key, int x, int y)
404
{
405
  switch(key)
406
  {
407
  case '+':
408
    ++PIXEL_SUBDIVS;
409
    cout << "Rays per pixel: " << PIXEL_SUBDIVS*PIXEL_SUBDIVS << endl;
410
    break;
411
  case '-':
412
    if(PIXEL_SUBDIVS > 1)
413
      --PIXEL_SUBDIVS;
414
    cout << "Rays per pixel: " << PIXEL_SUBDIVS*PIXEL_SUBDIVS << endl;
415
    break;
416
  case 'r':
417
    if(done) done = false;
418
    else raytrace = true;
419
    break;
420
  case 's':
421
    shadow = !shadow;
422
    cout << "Shadow " << (shadow ? "on." : "off.") << endl;
423
    break;
424
  case 27:
309 jab 425
    delete vctrl;
305 jab 426
    delete cam;
427
    exit(0);
428
  }
429
}
430
 
431
void mouse(int btn, int state, int x, int y)
432
{
433
  if(state == GLUT_DOWN) 
434
  {
435
    if(btn == GLUT_LEFT_BUTTON) 
309 jab 436
      vctrl->grab_ball(ROTATE_ACTION, Vec2i(x, y));
305 jab 437
    else if(btn == GLUT_MIDDLE_BUTTON) 
309 jab 438
      vctrl->grab_ball(ZOOM_ACTION, Vec2i(x, y));
305 jab 439
    else if(btn == GLUT_RIGHT_BUTTON) 
309 jab 440
      vctrl->grab_ball(PAN_ACTION, Vec2i(x, y));
305 jab 441
  }
442
  else if(state == GLUT_UP)
309 jab 443
			vctrl->release_ball();
305 jab 444
 
445
  mouse_state = state;
446
  mouse_button = btn;
447
 
448
  glutPostRedisplay();
449
}
450
 
451
void move(int x, int y)
452
{
309 jab 453
    vctrl->roll_ball(Vec2i(x, y));
305 jab 454
 
455
  glutPostRedisplay();
456
}
457
 
458
void spin(int x)
459
{
309 jab 460
  vctrl->try_spin();
305 jab 461
  glutTimerFunc(spin_timer, spin, 0);  
462
  glutPostRedisplay();
463
}
464
 
465
 
466
//////////////////////////////////////////////////////////////
467
//                        M A I N
468
//////////////////////////////////////////////////////////////
469
 
470
int main(int argc, char** argv)
471
{
472
#ifdef __BORLANDC__
473
  _control87(MCW_EM, MCW_EM);  // Borland C++ will crash OpenGL if this
474
                               // magic line is not inserted
475
#endif
476
 
477
  glutInit(&argc, argv);
478
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
479
  glutInitWindowSize(winx, winy);
480
  glutCreateWindow("Press 'r' to raytrace");
481
  glutDisplayFunc(display);
482
  glutReshapeFunc(reshape);
483
  glutKeyboardFunc(keyboard);
484
  glutMouseFunc(mouse);
485
  glutMotionFunc(move);
486
 
487
  // LOAD OBJ
488
  string filename;
489
  if(argc > 1)
490
  {
491
    filename = argv[1];
492
    cout << "Loading " << filename << endl;
493
 
494
    obj_load(filename, mesh);
495
    //if(!mesh.has_normals())
496
    //{
497
      cout << "Computing normals" << endl;
498
      mesh.compute_normals();
499
    //}
500
 
501
    cout << "No. of triangles: " << mesh.geometry.no_faces() << endl;
502
  }
503
  else
504
  {
505
    obj_load("../../data/dolphins.obj", mesh);
506
 
507
	cout << "Computing normals" << endl;
508
    mesh.compute_normals();
509
 
510
	//cout << "Usage: raytrace any_object.obj";
511
    //exit(0);
512
  }
513
 
514
  initRaytracer();
515
  initGL();    
516
 
517
  glutMainLoop();
518
 
519
  return 0;
520
}
521