example.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. #include <igl/opengl/OpenGL_convenience.h>
  2. #include <igl/opengl2/draw_floor.h>
  3. #include <igl/opengl2/draw_mesh.h>
  4. #include <igl/normalize_row_lengths.h>
  5. #include <igl/per_face_normals.h>
  6. #include <igl/quat_to_mat.h>
  7. #include <igl/read_triangle_mesh.h>
  8. #include <igl/opengl/report_gl_error.h>
  9. #include <igl/trackball.h>
  10. #include <igl/opengl2/unproject.h>
  11. #include <igl/embree/EmbreeIntersector.h>
  12. #ifdef __APPLE__
  13. # include <GLUT/glut.h>
  14. #else
  15. # include <GL/glut.h>
  16. #endif
  17. #include <Eigen/Core>
  18. #include <vector>
  19. #include <iostream>
  20. // Width and height of window
  21. int width,height;
  22. // Rotation of scene
  23. float scene_rot[4] = {0,0,0,1};
  24. // information at mouse down
  25. float down_scene_rot[4] = {0,0,0,1};
  26. bool trackball_on = false;
  27. int down_mouse_x,down_mouse_y;
  28. // Position of light
  29. float light_pos[4] = {0.1,0.1,-0.9,0};
  30. // Vertex positions, normals, colors and centroid
  31. Eigen::MatrixXd V,N,C,mean;
  32. // Bounding box diagonal length
  33. double bbd;
  34. // Faces
  35. Eigen::MatrixXi F;
  36. // Embree intersection structure
  37. igl::embree::EmbreeIntersector ei;
  38. // Hits collected
  39. std::vector<igl::embree::Hit > hits;
  40. // Ray information, "projection screen" corners
  41. Eigen::Vector3f win_s,s,d,dir,NW,NE,SE,SW;
  42. // Textures and framebuffers for "projection screen"
  43. GLuint tex_id = 0, fbo_id = 0, dfbo_id = 0;
  44. // Initialize textures and framebuffers. Must be called if window changes
  45. // dimension
  46. void init_texture()
  47. {
  48. using namespace igl;
  49. using namespace std;
  50. // Set up a "render-to-texture" frame buffer and texture combo
  51. glDeleteTextures(1,&tex_id);
  52. glDeleteFramebuffersEXT(1,&fbo_id);
  53. glDeleteFramebuffersEXT(1,&dfbo_id);
  54. // http://www.opengl.org/wiki/Framebuffer_Object_Examples#Quick_example.2C_render_to_texture_.282D.29
  55. glGenTextures(1, &tex_id);
  56. glBindTexture(GL_TEXTURE_2D, tex_id);
  57. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  58. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  59. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  60. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  61. //NULL means reserve texture memory, but texels are undefined
  62. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, NULL);
  63. glBindTexture(GL_TEXTURE_2D, 0);
  64. //-------------------------
  65. glGenFramebuffersEXT(1, &fbo_id);
  66. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id);
  67. //Attach 2D texture to this FBO
  68. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, tex_id, 0);
  69. glGenRenderbuffersEXT(1, &dfbo_id);
  70. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, dfbo_id);
  71. glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height);
  72. //-------------------------
  73. //Attach depth buffer to FBO
  74. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, dfbo_id);
  75. //-------------------------
  76. //Does the GPU support current FBO configuration?
  77. GLenum status;
  78. status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  79. switch(status)
  80. {
  81. case GL_FRAMEBUFFER_COMPLETE_EXT:
  82. break;
  83. default:
  84. cout<<"error"<<endl;
  85. }
  86. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
  87. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  88. }
  89. void reshape(int width,int height)
  90. {
  91. using namespace std;
  92. // Save width and height
  93. ::width = width;
  94. ::height = height;
  95. // Re-initialize textures and frame bufferes
  96. init_texture();
  97. glMatrixMode(GL_PROJECTION);
  98. glLoadIdentity();
  99. glViewport(0,0,width,height);
  100. }
  101. // Set up double-sided lights
  102. void lights()
  103. {
  104. using namespace std;
  105. glEnable(GL_LIGHTING);
  106. glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
  107. glEnable(GL_LIGHT0);
  108. glEnable(GL_LIGHT1);
  109. float ones[4] = {1.0,1.0,1.0,1.0};
  110. float zeros[4] = {0.0,0.0,0.0,0.0};
  111. float pos[4];
  112. copy(light_pos,light_pos+4,pos);
  113. glLightfv(GL_LIGHT0,GL_AMBIENT,zeros);
  114. glLightfv(GL_LIGHT0,GL_DIFFUSE,ones);
  115. glLightfv(GL_LIGHT0,GL_SPECULAR,zeros);
  116. glLightfv(GL_LIGHT0,GL_POSITION,pos);
  117. pos[0] *= -1;
  118. pos[1] *= -1;
  119. pos[2] *= -1;
  120. glLightfv(GL_LIGHT1,GL_AMBIENT,zeros);
  121. glLightfv(GL_LIGHT1,GL_DIFFUSE,ones);
  122. glLightfv(GL_LIGHT1,GL_SPECULAR,zeros);
  123. glLightfv(GL_LIGHT1,GL_POSITION,pos);
  124. }
  125. // Set up igl::opengl2::projection and model view of scene
  126. void push_scene()
  127. {
  128. using namespace igl;
  129. glMatrixMode(GL_PROJECTION);
  130. glLoadIdentity();
  131. gluPerspective(45,(double)width/(double)height,1e-2,100);
  132. glMatrixMode(GL_MODELVIEW);
  133. glLoadIdentity();
  134. gluLookAt(0,0,3,0,0,0,0,1,0);
  135. glPushMatrix();
  136. float mat[4*4];
  137. quat_to_mat(scene_rot,mat);
  138. glMultMatrixf(mat);
  139. }
  140. void pop_scene()
  141. {
  142. glPopMatrix();
  143. }
  144. // Scale and shift for object
  145. void push_object()
  146. {
  147. glPushMatrix();
  148. glScaled(2./bbd,2./bbd,2./bbd);
  149. glTranslated(-mean(0,0),-mean(0,1),-mean(0,2));
  150. }
  151. void pop_object()
  152. {
  153. glPopMatrix();
  154. }
  155. const float back[4] = {190.0/255.0,190.0/255.0,190.0/255.0,0};
  156. void display()
  157. {
  158. using namespace Eigen;
  159. using namespace igl;
  160. using namespace std;
  161. glClearColor(back[0],back[1],back[2],0);
  162. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  163. // All smooth points
  164. glEnable( GL_POINT_SMOOTH );
  165. lights();
  166. push_scene();
  167. glEnable(GL_DEPTH_TEST);
  168. glDepthFunc(GL_LEQUAL);
  169. glEnable(GL_NORMALIZE);
  170. glEnable(GL_COLOR_MATERIAL);
  171. glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
  172. push_object();
  173. if(trackball_on)
  174. {
  175. // Draw a "laser" line
  176. glLineWidth(3.0);
  177. glDisable(GL_LIGHTING);
  178. glEnable(GL_DEPTH_TEST);
  179. glBegin(GL_LINES);
  180. glColor3f(1,0,0);
  181. glVertex3fv(s.data());
  182. glColor3f(1,0,0);
  183. glVertex3fv(d.data());
  184. glEnd();
  185. // Draw the start and end points used for ray
  186. glPointSize(10.0);
  187. glBegin(GL_POINTS);
  188. glColor3f(1,0,0);
  189. glVertex3fv(s.data());
  190. glColor3f(0,0,1);
  191. glVertex3fv(d.data());
  192. glEnd();
  193. }
  194. // Draw the model
  195. glEnable(GL_LIGHTING);
  196. igl::opengl2::draw_mesh(V,F,N,C);
  197. // Draw all hits
  198. glBegin(GL_POINTS);
  199. glColor3f(0,0.2,0.2);
  200. for(vector<igl::embree::Hit>::iterator hit = hits.begin();
  201. hit != hits.end();
  202. hit++)
  203. {
  204. const double w0 = (1.0-hit->u-hit->v);
  205. const double w1 = hit->u;
  206. const double w2 = hit->v;
  207. VectorXd hitP =
  208. w0 * V.row(F(hit->id,0)) +
  209. w1 * V.row(F(hit->id,1)) +
  210. w2 * V.row(F(hit->id,2));
  211. glVertex3dv(hitP.data());
  212. }
  213. glEnd();
  214. pop_object();
  215. // Draw a nice floor
  216. glPushMatrix();
  217. glEnable(GL_LIGHTING);
  218. glTranslated(0,-1,0);
  219. igl::opengl2::draw_floor();
  220. glPopMatrix();
  221. // draw a transparent "projection screen" show model at time of hit (aka
  222. // mouse down)
  223. push_object();
  224. if(trackball_on)
  225. {
  226. glColor4f(0,0,0,1.0);
  227. glPointSize(10.0);
  228. glBegin(GL_POINTS);
  229. glVertex3fv(SW.data());
  230. glVertex3fv(SE.data());
  231. glVertex3fv(NE.data());
  232. glVertex3fv(NW.data());
  233. glEnd();
  234. glDisable(GL_LIGHTING);
  235. glEnable(GL_TEXTURE_2D);
  236. glBindTexture(GL_TEXTURE_2D, tex_id);
  237. glColor4f(1,1,1,0.7);
  238. glBegin(GL_QUADS);
  239. glTexCoord2d(0,0);
  240. glVertex3fv(SW.data());
  241. glTexCoord2d(1,0);
  242. glVertex3fv(SE.data());
  243. glTexCoord2d(1,1);
  244. glVertex3fv(NE.data());
  245. glTexCoord2d(0,1);
  246. glVertex3fv(NW.data());
  247. glEnd();
  248. glBindTexture(GL_TEXTURE_2D, 0);
  249. glDisable(GL_TEXTURE_2D);
  250. }
  251. pop_object();
  252. pop_scene();
  253. // Draw a faint point over mouse
  254. if(!trackball_on)
  255. {
  256. glDisable(GL_LIGHTING);
  257. glDisable(GL_COLOR_MATERIAL);
  258. glDisable(GL_DEPTH_TEST);
  259. glEnable(GL_BLEND);
  260. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  261. glColor4f(1.0,0.3,0.3,0.6);
  262. glMatrixMode(GL_PROJECTION);
  263. glLoadIdentity();
  264. gluOrtho2D(0,width,0,height);
  265. glMatrixMode(GL_MODELVIEW);
  266. glLoadIdentity();
  267. glPointSize(20.0);
  268. glBegin(GL_POINTS);
  269. glVertex2fv(win_s.data());
  270. glEnd();
  271. }
  272. igl::opengl::report_gl_error();
  273. glutSwapBuffers();
  274. glutPostRedisplay();
  275. }
  276. // Initialize colors to a boring green
  277. void init_C()
  278. {
  279. C.col(0).setConstant(0.4);
  280. C.col(1).setConstant(0.8);
  281. C.col(2).setConstant(0.3);
  282. }
  283. void mouse_move(int mouse_x, int mouse_y)
  284. {
  285. using namespace std;
  286. using namespace Eigen;
  287. using namespace igl;
  288. using namespace std;
  289. init_C();
  290. glutSetCursor(GLUT_CURSOR_CROSSHAIR);
  291. // Push scene and object
  292. push_scene();
  293. push_object();
  294. // Unproject mouse at 0 depth and some positive depth
  295. win_s = Vector3f(mouse_x,height-mouse_y,0);
  296. Vector3f win_d(mouse_x,height-mouse_y,1);
  297. igl::opengl2::unproject(win_s,s);
  298. igl::opengl2::unproject(win_d,d);
  299. pop_object();
  300. pop_scene();
  301. igl::opengl::report_gl_error();
  302. // Shoot ray at igl::opengl2::unprojected mouse in view direction
  303. dir = d-s;
  304. int num_rays_shot;
  305. ei.intersectRay(s,dir,hits,num_rays_shot);
  306. for(vector<igl::embree::Hit>::iterator hit = hits.begin();
  307. hit != hits.end();
  308. hit++)
  309. {
  310. // Change color of hit faces
  311. C(hit->id,0) = 1;
  312. C(hit->id,1) = 0.4;
  313. C(hit->id,2) = 0.4;
  314. }
  315. }
  316. void mouse(int glutButton, int glutState, int mouse_x, int mouse_y)
  317. {
  318. using namespace std;
  319. using namespace Eigen;
  320. using namespace igl;
  321. switch(glutState)
  322. {
  323. case 1:
  324. // up
  325. glutSetCursor(GLUT_CURSOR_CROSSHAIR);
  326. trackball_on = false;
  327. hits.clear();
  328. init_C();
  329. break;
  330. case 0:
  331. // be sure this has been called recently
  332. mouse_move(mouse_x,mouse_y);
  333. // down
  334. glutSetCursor(GLUT_CURSOR_CYCLE);
  335. // collect information for trackball
  336. trackball_on = true;
  337. copy(scene_rot,scene_rot+4,down_scene_rot);
  338. down_mouse_x = mouse_x;
  339. down_mouse_y = mouse_y;
  340. // Collect "projection screen" locations
  341. push_scene();
  342. push_object();
  343. // igl::opengl2::unproject corners of window
  344. const double depth = 0.999;
  345. Vector3d win_NW( 0,height,depth);
  346. Vector3d win_NE(width,height,depth);
  347. Vector3d win_SE(width,0,depth);
  348. Vector3d win_SW(0,0,depth);
  349. igl::opengl2::unproject(win_NW,NW);
  350. igl::opengl2::unproject(win_NE,NE);
  351. igl::opengl2::unproject(win_SE,SE);
  352. igl::opengl2::unproject(win_SW,SW);
  353. // render to framebuffer
  354. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo_id);
  355. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, dfbo_id);
  356. glClearColor(0,0,0,1);
  357. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  358. // Render the model ---> to the framebuffer attached to the "projection
  359. // screen" texture
  360. glEnable(GL_COLOR_MATERIAL);
  361. glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
  362. glEnable(GL_LIGHTING);
  363. glEnable(GL_DEPTH_TEST);
  364. igl::opengl2::draw_mesh(V,F,N,C);
  365. pop_object();
  366. pop_scene();
  367. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  368. glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
  369. break;
  370. }
  371. }
  372. void mouse_drag(int mouse_x, int mouse_y)
  373. {
  374. using namespace igl;
  375. if(trackball_on)
  376. {
  377. // Rotate according to trackball
  378. trackball<float>(
  379. width,
  380. height,
  381. 2,
  382. down_scene_rot,
  383. down_mouse_x,
  384. down_mouse_y,
  385. mouse_x,
  386. mouse_y,
  387. scene_rot);
  388. }
  389. }
  390. void key(unsigned char key, int mouse_x, int mouse_y)
  391. {
  392. using namespace std;
  393. switch(key)
  394. {
  395. // Ctrl-c and esc exit
  396. case char(3):
  397. case char(27):
  398. exit(0);
  399. default:
  400. cout<<"Unknown key command: "<<key<<" "<<int(key)<<endl;
  401. }
  402. }
  403. int main(int argc, char * argv[])
  404. {
  405. using namespace Eigen;
  406. using namespace igl;
  407. using namespace std;
  408. // init mesh
  409. string filename = "../shared/decimated-knight.obj";
  410. if(argc < 2)
  411. {
  412. cerr<<"Usage:"<<endl<<" ./example input.obj"<<endl;
  413. cout<<endl<<"Opening default mesh..."<<endl;
  414. }else
  415. {
  416. // Read and prepare mesh
  417. filename = argv[1];
  418. }
  419. if(!read_triangle_mesh(filename,V,F))
  420. {
  421. return 1;
  422. }
  423. // Compute normals, centroid, colors, bounding box diagonal
  424. per_face_normals(V,F,N);
  425. normalize_row_lengths(N,N);
  426. mean = V.colwise().mean();
  427. C.resize(F.rows(),3);
  428. init_C();
  429. bbd =
  430. (V.colwise().maxCoeff() -
  431. V.colwise().minCoeff()).maxCoeff();
  432. // Init embree
  433. ei.init(V.cast<float>(),F.cast<int>());
  434. // Init glut
  435. glutInit(&argc,argv);
  436. glutInitDisplayString( "rgba depth double samples>=8 ");
  437. glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT));
  438. glutCreateWindow("embree");
  439. glutDisplayFunc(display);
  440. glutReshapeFunc(reshape);
  441. glutKeyboardFunc(key);
  442. glutMouseFunc(mouse);
  443. glutMotionFunc(mouse_drag);
  444. glutPassiveMotionFunc(mouse_move);
  445. glutMainLoop();
  446. return 0;
  447. }