example.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. #include <igl/svd3x3/arap.h>
  2. #include <igl/OpenGL_convenience.h>
  3. #include <igl/per_face_normals.h>
  4. #include <igl/per_vertex_normals.h>
  5. #include <igl/two_axis_valuator_fixed_up.h>
  6. #include <igl/normalize_row_lengths.h>
  7. #include <igl/draw_mesh.h>
  8. #include <igl/draw_floor.h>
  9. #include <igl/quat_to_mat.h>
  10. #include <igl/report_gl_error.h>
  11. #include <igl/readOBJ.h>
  12. #include <igl/readDMAT.h>
  13. #include <igl/readOFF.h>
  14. #include <igl/readMESH.h>
  15. #include <igl/jet.h>
  16. #include <igl/readWRL.h>
  17. #include <igl/trackball.h>
  18. #include <igl/list_to_matrix.h>
  19. #include <igl/snap_to_canonical_view_quat.h>
  20. #include <igl/snap_to_fixed_up.h>
  21. #include <igl/triangulate.h>
  22. #include <igl/material_colors.h>
  23. #include <igl/barycenter.h>
  24. #include <igl/matlab_format.h>
  25. #include <igl/ReAntTweakBar.h>
  26. #include <igl/pathinfo.h>
  27. #include <igl/Camera.h>
  28. #include <igl/get_seconds.h>
  29. #include <igl/PI.h>
  30. #include <igl/STR.h>
  31. #include <YImage.hpp>
  32. #ifdef __APPLE__
  33. # include <GLUT/glut.h>
  34. #else
  35. # include <GL/glut.h>
  36. #endif
  37. #include <Eigen/Core>
  38. #include <vector>
  39. #include <iostream>
  40. #include <algorithm>
  41. struct State
  42. {
  43. igl::Camera camera;
  44. } s;
  45. enum RotationType
  46. {
  47. ROTATION_TYPE_IGL_TRACKBALL = 0,
  48. ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
  49. NUM_ROTATION_TYPES = 2,
  50. } rotation_type;
  51. bool is_rotating = false;
  52. int down_x,down_y;
  53. igl::Camera down_camera;
  54. bool is_animating = false;
  55. double animation_start_time = 0;
  56. double ANIMATION_DURATION = 0.5;
  57. Eigen::Quaterniond animation_from_quat;
  58. Eigen::Quaterniond animation_to_quat;
  59. // Use vector for range-based `for`
  60. std::vector<State> undo_stack;
  61. std::vector<State> redo_stack;
  62. void push_undo()
  63. {
  64. undo_stack.push_back(s);
  65. // Clear
  66. redo_stack = std::vector<State>();
  67. }
  68. void undo()
  69. {
  70. using namespace std;
  71. if(!undo_stack.empty())
  72. {
  73. redo_stack.push_back(s);
  74. s = undo_stack.front();
  75. undo_stack.pop_back();
  76. }
  77. }
  78. void redo()
  79. {
  80. using namespace std;
  81. if(!redo_stack.empty())
  82. {
  83. undo_stack.push_back(s);
  84. s = redo_stack.front();
  85. redo_stack.pop_back();
  86. }
  87. }
  88. void TW_CALL set_rotation_type(const void * value, void * clientData)
  89. {
  90. using namespace Eigen;
  91. using namespace std;
  92. using namespace igl;
  93. const RotationType old_rotation_type = rotation_type;
  94. rotation_type = *(const RotationType *)(value);
  95. if(rotation_type == ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP &&
  96. old_rotation_type != ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP)
  97. {
  98. push_undo();
  99. animation_from_quat = s.camera.m_rotation_conj;
  100. snap_to_fixed_up(animation_from_quat,animation_to_quat);
  101. // start animation
  102. animation_start_time = get_seconds();
  103. is_animating = true;
  104. }
  105. }
  106. void TW_CALL get_rotation_type(void * value, void *clientData)
  107. {
  108. RotationType * rt = (RotationType *)(value);
  109. *rt = rotation_type;
  110. }
  111. // Width and height of window
  112. int width,height;
  113. // Position of light
  114. float light_pos[4] = {0.1,0.1,-0.9,0};
  115. // Vertex positions, normals, colors and centroid
  116. Eigen::MatrixXd V,U,N,mid;
  117. Eigen::VectorXi S;
  118. igl::ARAPData arap_data;
  119. Eigen::MatrixXi F;
  120. int selected_col = 0;
  121. // Faces
  122. // Bounding box diagonal length
  123. double bbd;
  124. int tot_num_samples = 0;
  125. #define REBAR_NAME "temp.rbr"
  126. igl::ReTwBar rebar; // Pointer to the tweak bar
  127. bool flip_y = false;
  128. bool rotate_xy = false;
  129. int num_in_selection(const Eigen::VectorXi & S)
  130. {
  131. int count = 0;
  132. for(int v = 0;v<S.rows(); v++)
  133. {
  134. if(S(v) >= 0)
  135. {
  136. count++;
  137. }
  138. }
  139. return count;
  140. }
  141. bool init_arap()
  142. {
  143. using namespace igl;
  144. using namespace Eigen;
  145. using namespace std;
  146. VectorXi b(num_in_selection(S));
  147. assert(S.rows() == V.rows());
  148. // get b from S
  149. {
  150. int bi = 0;
  151. for(int v = 0;v<S.rows(); v++)
  152. {
  153. if(S(v) >= 0)
  154. {
  155. b(bi++) = v;
  156. }
  157. }
  158. }
  159. // Store current mesh
  160. U = V;
  161. return arap_precomputation(V,F,b,arap_data);
  162. }
  163. bool update_arap()
  164. {
  165. using namespace Eigen;
  166. using namespace igl;
  167. using namespace std;
  168. MatrixXd bc(num_in_selection(S),V.cols());
  169. // get b from S
  170. {
  171. int bi = 0;
  172. for(int v = 0;v<S.rows(); v++)
  173. {
  174. if(S(v) >= 0)
  175. {
  176. bc.row(bi) = V.row(v);
  177. switch(S(v))
  178. {
  179. case 0:
  180. {
  181. const double r = mid(0)*0.25;
  182. bc(bi,0) += r*cos(0.5*get_seconds()*2.*PI);
  183. bc(bi,1) -= r+r*sin(0.5*get_seconds()*2.*PI);
  184. break;
  185. }
  186. case 1:
  187. {
  188. const double r = mid(1)*0.15;
  189. bc(bi,1) += r+r*cos(0.15*get_seconds()*2.*PI);
  190. bc(bi,2) -= r*sin(0.15*get_seconds()*2.*PI);
  191. break;
  192. }
  193. default:
  194. break;
  195. }
  196. bi++;
  197. }
  198. }
  199. }
  200. if(!arap_solve(bc,arap_data,U))
  201. {
  202. cerr<<"arap_solve failed."<<endl;
  203. return false;
  204. }
  205. per_face_normals(U,F,N);
  206. return true;
  207. }
  208. void reshape(int width,int height)
  209. {
  210. using namespace std;
  211. // Save width and height
  212. ::width = width;
  213. ::height = height;
  214. glMatrixMode(GL_PROJECTION);
  215. glLoadIdentity();
  216. glViewport(0,0,width,height);
  217. // Send the new window size to AntTweakBar
  218. TwWindowSize(width, height);
  219. // Set aspect for all cameras
  220. s.camera.m_aspect = (double)width/(double)height;
  221. for(auto & s : undo_stack)
  222. {
  223. s.camera.m_aspect = (double)width/(double)height;
  224. }
  225. for(auto & s : redo_stack)
  226. {
  227. s.camera.m_aspect = (double)width/(double)height;
  228. }
  229. }
  230. void push_scene()
  231. {
  232. using namespace igl;
  233. using namespace std;
  234. glMatrixMode(GL_PROJECTION);
  235. glPushMatrix();
  236. glLoadIdentity();
  237. auto & camera = s.camera;
  238. gluPerspective(camera.m_angle,camera.m_aspect,camera.m_near,camera.m_far);
  239. glMatrixMode(GL_MODELVIEW);
  240. glPushMatrix();
  241. glLoadIdentity();
  242. gluLookAt(
  243. camera.eye()(0), camera.eye()(1), camera.eye()(2),
  244. camera.at()(0), camera.at()(1), camera.at()(2),
  245. camera.up()(0), camera.up()(1), camera.up()(2));
  246. }
  247. void pop_scene()
  248. {
  249. glMatrixMode(GL_PROJECTION);
  250. glPopMatrix();
  251. glMatrixMode(GL_MODELVIEW);
  252. glPopMatrix();
  253. }
  254. void pop_object()
  255. {
  256. glPopMatrix();
  257. }
  258. // Scale and shift for object
  259. void push_object()
  260. {
  261. glPushMatrix();
  262. glScaled(2./bbd,2./bbd,2./bbd);
  263. glTranslated(-mid(0,0),-mid(0,1),-mid(0,2));
  264. }
  265. // Set up double-sided lights
  266. void lights()
  267. {
  268. using namespace std;
  269. glEnable(GL_LIGHTING);
  270. glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
  271. glEnable(GL_LIGHT0);
  272. glEnable(GL_LIGHT1);
  273. float amb[4];
  274. amb[0] = amb[1] = amb[2] = 0;
  275. amb[3] = 1.0;
  276. float diff[4] = {0.0,0.0,0.0,0.0};
  277. diff[0] = diff[1] = diff[2] = (1.0 - 0/0.4);;
  278. diff[3] = 1.0;
  279. float zeros[4] = {0.0,0.0,0.0,0.0};
  280. float pos[4];
  281. copy(light_pos,light_pos+4,pos);
  282. glLightfv(GL_LIGHT0,GL_AMBIENT,amb);
  283. glLightfv(GL_LIGHT0,GL_DIFFUSE,diff);
  284. glLightfv(GL_LIGHT0,GL_SPECULAR,zeros);
  285. glLightfv(GL_LIGHT0,GL_POSITION,pos);
  286. pos[0] *= -1;
  287. pos[1] *= -1;
  288. pos[2] *= -1;
  289. glLightfv(GL_LIGHT1,GL_AMBIENT,amb);
  290. glLightfv(GL_LIGHT1,GL_DIFFUSE,diff);
  291. glLightfv(GL_LIGHT1,GL_SPECULAR,zeros);
  292. glLightfv(GL_LIGHT1,GL_POSITION,pos);
  293. }
  294. const float back[4] = {30.0/255.0,30.0/255.0,50.0/255.0,0};
  295. void display()
  296. {
  297. using namespace Eigen;
  298. using namespace igl;
  299. using namespace std;
  300. // Update
  301. update_arap();
  302. glClearColor(back[0],back[1],back[2],0);
  303. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  304. if(is_animating)
  305. {
  306. double t = (get_seconds() - animation_start_time)/ANIMATION_DURATION;
  307. if(t > 1)
  308. {
  309. t = 1;
  310. is_animating = false;
  311. }
  312. const Quaterniond q = animation_from_quat.slerp(t,animation_to_quat).normalized();
  313. s.camera.orbit(q.conjugate());
  314. }
  315. glDisable(GL_LIGHTING);
  316. lights();
  317. push_scene();
  318. glEnable(GL_DEPTH_TEST);
  319. glDepthFunc(GL_LESS);
  320. glEnable(GL_NORMALIZE);
  321. push_object();
  322. // Draw the model
  323. // Set material properties
  324. glDisable(GL_COLOR_MATERIAL);
  325. glMaterialfv(GL_FRONT, GL_AMBIENT, GOLD_AMBIENT);
  326. glMaterialfv(GL_FRONT, GL_DIFFUSE, GOLD_DIFFUSE );
  327. glMaterialfv(GL_FRONT, GL_SPECULAR, GOLD_SPECULAR);
  328. glMaterialf (GL_FRONT, GL_SHININESS, 128);
  329. glMaterialfv(GL_BACK, GL_AMBIENT, SILVER_AMBIENT);
  330. glMaterialfv(GL_BACK, GL_DIFFUSE, FAST_GREEN_DIFFUSE );
  331. glMaterialfv(GL_BACK, GL_SPECULAR, SILVER_SPECULAR);
  332. glMaterialf (GL_BACK, GL_SHININESS, 128);
  333. draw_mesh(U,F,N);
  334. glDisable(GL_COLOR_MATERIAL);
  335. pop_object();
  336. // Draw a nice floor
  337. glPushMatrix();
  338. const double floor_offset =
  339. -2./bbd*(V.col(1).maxCoeff()-mid(1));
  340. glTranslated(0,floor_offset,0);
  341. const float GREY[4] = {0.5,0.5,0.6,1.0};
  342. const float DARK_GREY[4] = {0.2,0.2,0.3,1.0};
  343. draw_floor(GREY,DARK_GREY);
  344. glPopMatrix();
  345. pop_scene();
  346. report_gl_error();
  347. TwDraw();
  348. glutSwapBuffers();
  349. //if(is_animating)
  350. //{
  351. glutPostRedisplay();
  352. //}
  353. }
  354. void mouse_wheel(int wheel, int direction, int mouse_x, int mouse_y)
  355. {
  356. using namespace std;
  357. using namespace igl;
  358. using namespace Eigen;
  359. GLint viewport[4];
  360. glGetIntegerv(GL_VIEWPORT,viewport);
  361. if(wheel == 0 && TwMouseMotion(mouse_x, viewport[3] - mouse_y))
  362. {
  363. static double mouse_scroll_y = 0;
  364. const double delta_y = 0.125*direction;
  365. mouse_scroll_y += delta_y;
  366. TwMouseWheel(mouse_scroll_y);
  367. return;
  368. }
  369. push_undo();
  370. auto & camera = s.camera;
  371. if(wheel==0)
  372. {
  373. // factor of zoom change
  374. double s = (1.-0.01*direction);
  375. //// FOV zoom: just widen angle. This is hardly ever appropriate.
  376. //camera.m_angle *= s;
  377. //camera.m_angle = min(max(camera.m_angle,1),89);
  378. camera.push_away(s);
  379. }else
  380. {
  381. // Dolly zoom:
  382. camera.dolly_zoom((double)direction*1.0);
  383. }
  384. }
  385. void mouse(int glutButton, int glutState, int mouse_x, int mouse_y)
  386. {
  387. using namespace std;
  388. using namespace Eigen;
  389. using namespace igl;
  390. bool tw_using = TwEventMouseButtonGLUT(glutButton,glutState,mouse_x,mouse_y);
  391. switch(glutButton)
  392. {
  393. case GLUT_RIGHT_BUTTON:
  394. case GLUT_LEFT_BUTTON:
  395. {
  396. switch(glutState)
  397. {
  398. case 1:
  399. // up
  400. glutSetCursor(GLUT_CURSOR_LEFT_ARROW);
  401. is_rotating = false;
  402. break;
  403. case 0:
  404. // down
  405. if(!tw_using)
  406. {
  407. glutSetCursor(GLUT_CURSOR_CYCLE);
  408. // collect information for trackball
  409. is_rotating = true;
  410. down_camera = s.camera;
  411. down_x = mouse_x;
  412. down_y = mouse_y;
  413. }
  414. break;
  415. }
  416. break;
  417. }
  418. // Scroll down
  419. case 3:
  420. {
  421. mouse_wheel(0,-1,mouse_x,mouse_y);
  422. break;
  423. }
  424. // Scroll up
  425. case 4:
  426. {
  427. mouse_wheel(0,1,mouse_x,mouse_y);
  428. break;
  429. }
  430. // Scroll left
  431. case 5:
  432. {
  433. mouse_wheel(1,-1,mouse_x,mouse_y);
  434. break;
  435. }
  436. // Scroll right
  437. case 6:
  438. {
  439. mouse_wheel(1,1,mouse_x,mouse_y);
  440. break;
  441. }
  442. }
  443. glutPostRedisplay();
  444. }
  445. void mouse_drag(int mouse_x, int mouse_y)
  446. {
  447. using namespace igl;
  448. using namespace Eigen;
  449. if(is_rotating)
  450. {
  451. glutSetCursor(GLUT_CURSOR_CYCLE);
  452. Quaterniond q;
  453. auto & camera = s.camera;
  454. switch(rotation_type)
  455. {
  456. case ROTATION_TYPE_IGL_TRACKBALL:
  457. {
  458. // Rotate according to trackball
  459. igl::trackball<double>(
  460. width,
  461. height,
  462. 2.0,
  463. down_camera.m_rotation_conj.coeffs().data(),
  464. down_x,
  465. down_y,
  466. mouse_x,
  467. mouse_y,
  468. q.coeffs().data());
  469. break;
  470. }
  471. case ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP:
  472. {
  473. // Rotate according to two axis valuator with fixed up vector
  474. two_axis_valuator_fixed_up(
  475. width, height,
  476. 2.0,
  477. down_camera.m_rotation_conj,
  478. down_x, down_y, mouse_x, mouse_y,
  479. q);
  480. break;
  481. }
  482. default:
  483. break;
  484. }
  485. camera.orbit(q.conjugate());
  486. }else
  487. {
  488. TwEventMouseMotionGLUT(mouse_x, mouse_y);
  489. }
  490. glutPostRedisplay();
  491. }
  492. void key(unsigned char key, int mouse_x, int mouse_y)
  493. {
  494. using namespace std;
  495. switch(key)
  496. {
  497. // ESC
  498. case char(27):
  499. rebar.save(REBAR_NAME);
  500. // ^C
  501. case char(3):
  502. exit(0);
  503. default:
  504. if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y))
  505. {
  506. cout<<"Unknown key command: "<<key<<" "<<int(key)<<endl;
  507. }
  508. }
  509. glutPostRedisplay();
  510. }
  511. int main(int argc, char * argv[])
  512. {
  513. using namespace Eigen;
  514. using namespace igl;
  515. using namespace std;
  516. // init mesh
  517. string filename = "../shared/decimated-knight.obj";
  518. string sfilename = "../shared/decimated-knight-selection.dmat";
  519. if(argc < 3)
  520. {
  521. cerr<<"Usage:"<<endl<<" ./example input.obj selection.dmat"<<endl;
  522. cout<<endl<<"Opening default mesh..."<<endl;
  523. }else
  524. {
  525. // Read and prepare mesh
  526. filename = argv[1];
  527. sfilename = argv[2];
  528. }
  529. vector<vector<double > > vV,vN,vTC;
  530. vector<vector<int > > vF,vTF,vFN;
  531. // Convert extension to lower case
  532. if(!igl::readOBJ(filename,vV,vTC,vN,vF,vTF,vFN))
  533. {
  534. return 1;
  535. }
  536. if(vV.size() > 0)
  537. {
  538. if(!list_to_matrix(vV,V))
  539. {
  540. cerr<<"Bad V"<<endl;
  541. return 1;
  542. }
  543. triangulate(vF,F);
  544. }
  545. per_face_normals(V,F,N);
  546. if(!readDMAT(sfilename,S))
  547. {
  548. return 1;
  549. }
  550. // Compute normals, centroid, colors, bounding box diagonal
  551. mid = 0.5*(V.colwise().maxCoeff() + V.colwise().minCoeff());
  552. bbd = (V.colwise().maxCoeff() - V.colwise().minCoeff()).maxCoeff();
  553. // Init glut
  554. glutInit(&argc,argv);
  555. if( !TwInit(TW_OPENGL, NULL) )
  556. {
  557. // A fatal error occured
  558. fprintf(stderr, "AntTweakBar initialization failed: %s\n", TwGetLastError());
  559. return 1;
  560. }
  561. // Create a tweak bar
  562. rebar.TwNewBar("TweakBar");
  563. rebar.TwAddVarRW("camera_rotation", TW_TYPE_QUAT4D,
  564. s.camera.m_rotation_conj.coeffs().data(), "open readonly=true");
  565. s.camera.push_away(3);
  566. s.camera.dolly_zoom(25-s.camera.m_angle);
  567. TwType RotationTypeTW = ReTwDefineEnumFromString("RotationType",
  568. "igl_trackball,two-a...-fixed-up");
  569. rebar.TwAddVarCB( "rotation_type", RotationTypeTW,
  570. set_rotation_type,get_rotation_type,NULL,"keyIncr=] keyDecr=[");
  571. rebar.TwAddVarRW("flip_y", TW_TYPE_BOOLCPP, &flip_y,"key=f");
  572. rebar.TwAddVarRW("rotate_xy", TW_TYPE_BOOLCPP, &rotate_xy,"key=r");
  573. rebar.load(REBAR_NAME);
  574. glutInitDisplayString( "rgba depth double samples>=8 ");
  575. glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT));
  576. glutCreateWindow("colored-mesh");
  577. glutDisplayFunc(display);
  578. glutReshapeFunc(reshape);
  579. glutKeyboardFunc(key);
  580. glutMouseFunc(mouse);
  581. glutMotionFunc(mouse_drag);
  582. glutPassiveMotionFunc(
  583. [](int x, int y)
  584. {
  585. TwEventMouseMotionGLUT(x,y);
  586. glutPostRedisplay();
  587. });
  588. static std::function<void(int)> timer_bounce;
  589. auto timer = [] (int ms) {
  590. timer_bounce(ms);
  591. };
  592. timer_bounce = [&] (int ms) {
  593. glutTimerFunc(ms, timer, ms);
  594. glutPostRedisplay();
  595. };
  596. glutTimerFunc(500, timer, 500);
  597. if(!init_arap())
  598. {
  599. cerr<<"Initializing arap failed."<<endl;
  600. return 1;
  601. }
  602. glutMainLoop();
  603. return 0;
  604. }