example.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982
  1. #include <igl/draw_skeleton_3d.h>
  2. #include <igl/draw_skeleton_vector_graphics.h>
  3. #include <igl/two_axis_valuator_fixed_up.h>
  4. #include <igl/readOBJ.h>
  5. #include <igl/readTGF.h>
  6. #include <igl/writeOBJ.h>
  7. #include <igl/writeOFF.h>
  8. #include <igl/writeDMAT.h>
  9. #include <igl/readDMAT.h>
  10. #include <igl/readWRL.h>
  11. #include <igl/report_gl_error.h>
  12. #include <igl/polygon_mesh_to_triangle_mesh.h>
  13. #include <igl/readOFF.h>
  14. #include <igl/readMESH.h>
  15. #include <igl/draw_mesh.h>
  16. #include <igl/draw_floor.h>
  17. #include <igl/pathinfo.h>
  18. #include <igl/list_to_matrix.h>
  19. #include <igl/quat_to_mat.h>
  20. #include <igl/per_face_normals.h>
  21. #include <igl/material_colors.h>
  22. #include <igl/trackball.h>
  23. #include <igl/snap_to_canonical_view_quat.h>
  24. #include <igl/snap_to_fixed_up.h>
  25. #include <igl/REDRUM.h>
  26. #include <igl/Camera.h>
  27. #include <igl/ReAntTweakBar.h>
  28. #include <igl/get_seconds.h>
  29. #include <igl/forward_kinematics.h>
  30. #include <igl/boundary_conditions.h>
  31. #include <igl/lbs_matrix.h>
  32. #include <igl/colon.h>
  33. #include <igl/writeTGF.h>
  34. #include <igl/file_exists.h>
  35. #include <igl/MouseController.h>
  36. #include <igl/STR.h>
  37. #include <igl/bone_parents.h>
  38. #include <igl/cgal/remesh_self_intersections.h>
  39. #include <igl/tetgen/tetrahedralize.h>
  40. #include <igl/barycenter.h>
  41. #include <igl/remove_unreferenced.h>
  42. #include <igl/boundary_facets.h>
  43. #include <igl/winding_number.h>
  44. #include <igl/bbw/bbw.h>
  45. #include <igl/normalize_row_sums.h>
  46. #include <igl/centroid.h>
  47. #include <igl/tetgen/mesh_with_skeleton.h>
  48. #include <igl/draw_beach_ball.h>
  49. #include <Eigen/Core>
  50. #include <Eigen/Geometry>
  51. #ifdef __APPLE__
  52. #include <GLUT/glut.h>
  53. #include <Carbon/Carbon.h>
  54. #else
  55. #include <GL/glut.h>
  56. #endif
  57. #include <string>
  58. #include <vector>
  59. #include <queue>
  60. #include <stack>
  61. #include <iostream>
  62. #include <iomanip>
  63. enum SkelStyleType
  64. {
  65. SKEL_STYLE_TYPE_3D = 0,
  66. SKEL_STYLE_TYPE_VECTOR_GRAPHICS = 1,
  67. NUM_SKEL_STYLE_TYPE = 2
  68. }skel_style;
  69. Eigen::MatrixXd V,N,W,M;
  70. Eigen::Vector3d Vmid;
  71. double bbd = 1.0;
  72. Eigen::MatrixXi F;
  73. igl::Camera camera;
  74. Eigen::MatrixXd C;
  75. Eigen::MatrixXi BE;
  76. Eigen::VectorXi P,RP;
  77. struct State
  78. {
  79. igl::MouseController mouse;
  80. Eigen::MatrixXf colors;
  81. } s;
  82. bool wireframe = false;
  83. // See README for descriptions
  84. enum RotationType
  85. {
  86. ROTATION_TYPE_IGL_TRACKBALL = 0,
  87. ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
  88. NUM_ROTATION_TYPES = 2,
  89. } rotation_type = ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP;
  90. std::stack<State> undo_stack;
  91. std::stack<State> redo_stack;
  92. bool is_rotating = false;
  93. bool centroid_is_visible = true;
  94. int down_x,down_y;
  95. igl::Camera down_camera;
  96. std::string output_prefix;
  97. struct CameraAnimation
  98. {
  99. bool is_animating = false;
  100. double DURATION = 0.5;
  101. double start_time = 0;
  102. Eigen::Quaterniond from_quat,to_quat;
  103. } canim;
  104. typedef std::vector<
  105. Eigen::Quaterniond,
  106. Eigen::aligned_allocator<Eigen::Quaterniond> > RotationList;
  107. struct PoseAnimation
  108. {
  109. bool is_animating = false;
  110. double DURATION = 2;
  111. double start_time = 0;
  112. RotationList pose;
  113. } panim;
  114. int width,height;
  115. Eigen::Vector4f light_pos(-0.1,-0.1,0.9,0);
  116. #define REBAR_NAME "temp.rbr"
  117. igl::ReTwBar rebar;
  118. void push_undo()
  119. {
  120. undo_stack.push(s);
  121. // Clear
  122. redo_stack = std::stack<State>();
  123. }
  124. // No-op setter, does nothing
  125. void TW_CALL no_op(const void * /*value*/, void * /*clientData*/)
  126. {
  127. }
  128. void TW_CALL set_rotation_type(const void * value, void * clientData)
  129. {
  130. using namespace Eigen;
  131. using namespace std;
  132. using namespace igl;
  133. const RotationType old_rotation_type = rotation_type;
  134. rotation_type = *(const RotationType *)(value);
  135. if(rotation_type == ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP &&
  136. old_rotation_type != ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP)
  137. {
  138. push_undo();
  139. canim.from_quat = camera.m_rotation_conj;
  140. snap_to_fixed_up(canim.from_quat,canim.to_quat);
  141. // start animation
  142. canim.start_time = get_seconds();
  143. canim.is_animating = true;
  144. }
  145. }
  146. void TW_CALL get_rotation_type(void * value, void *clientData)
  147. {
  148. RotationType * rt = (RotationType *)(value);
  149. *rt = rotation_type;
  150. }
  151. std::string next_filename(
  152. const std::string & prefix,
  153. const int zeros,
  154. const std::string & suffix)
  155. {
  156. using namespace std;
  157. using namespace igl;
  158. // O(n)
  159. int i = 0;
  160. while(true)
  161. {
  162. string next = STR(prefix << setfill('0') << setw(zeros)<<i<<suffix);
  163. if(!file_exists(next.c_str()))
  164. {
  165. return next;
  166. }
  167. i++;
  168. }
  169. }
  170. void reshape(int width, int height)
  171. {
  172. ::width = width;
  173. ::height = height;
  174. glViewport(0,0,width,height);
  175. // Send the new window size to AntTweakBar
  176. TwWindowSize(width, height);
  177. camera.m_aspect = (double)width/(double)height;
  178. s.mouse.reshape(width,height);
  179. }
  180. void push_scene()
  181. {
  182. using namespace igl;
  183. using namespace std;
  184. glMatrixMode(GL_PROJECTION);
  185. glPushMatrix();
  186. glLoadIdentity();
  187. gluPerspective(camera.m_angle,camera.m_aspect,camera.m_near,camera.m_far);
  188. glMatrixMode(GL_MODELVIEW);
  189. glPushMatrix();
  190. glLoadIdentity();
  191. gluLookAt(
  192. camera.eye()(0), camera.eye()(1), camera.eye()(2),
  193. camera.at()(0), camera.at()(1), camera.at()(2),
  194. camera.up()(0), camera.up()(1), camera.up()(2));
  195. }
  196. void push_object()
  197. {
  198. using namespace igl;
  199. glPushMatrix();
  200. glScaled(2./bbd,2./bbd,2./bbd);
  201. glTranslated(-Vmid(0),-Vmid(1),-Vmid(2));
  202. }
  203. void pop_object()
  204. {
  205. glPopMatrix();
  206. }
  207. void pop_scene()
  208. {
  209. glMatrixMode(GL_PROJECTION);
  210. glPopMatrix();
  211. glMatrixMode(GL_MODELVIEW);
  212. glPopMatrix();
  213. }
  214. // Set up double-sided lights
  215. void lights()
  216. {
  217. using namespace std;
  218. using namespace Eigen;
  219. glEnable(GL_LIGHTING);
  220. glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
  221. glEnable(GL_LIGHT0);
  222. glEnable(GL_LIGHT1);
  223. float WHITE[4] = {0.8,0.8,0.8,1.};
  224. float GREY[4] = {0.4,0.4,0.4,1.};
  225. float BLACK[4] = {0.,0.,0.,1.};
  226. Vector4f pos = light_pos;
  227. glLightfv(GL_LIGHT0,GL_AMBIENT,GREY);
  228. glLightfv(GL_LIGHT0,GL_DIFFUSE,WHITE);
  229. glLightfv(GL_LIGHT0,GL_SPECULAR,BLACK);
  230. glLightfv(GL_LIGHT0,GL_POSITION,pos.data());
  231. pos(0) *= -1;
  232. pos(1) *= -1;
  233. pos(2) *= -1;
  234. glLightfv(GL_LIGHT1,GL_AMBIENT,GREY);
  235. glLightfv(GL_LIGHT1,GL_DIFFUSE,WHITE);
  236. glLightfv(GL_LIGHT1,GL_SPECULAR,BLACK);
  237. glLightfv(GL_LIGHT1,GL_POSITION,pos.data());
  238. }
  239. void display()
  240. {
  241. using namespace igl;
  242. using namespace std;
  243. using namespace Eigen;
  244. const float back[4] = {0.75, 0.75, 0.75,0};
  245. glClearColor(back[0],back[1],back[2],0);
  246. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  247. if(canim.is_animating)
  248. {
  249. double t = (get_seconds() - canim.start_time)/canim.DURATION;
  250. if(t > 1)
  251. {
  252. t = 1;
  253. canim.is_animating = false;
  254. }
  255. Quaterniond q = canim.from_quat.slerp(t,canim.to_quat).normalized();
  256. camera.orbit(q.conjugate());
  257. }
  258. glEnable(GL_DEPTH_TEST);
  259. glDepthFunc(GL_LEQUAL);
  260. glEnable(GL_NORMALIZE);
  261. lights();
  262. push_scene();
  263. // Draw a nice floor
  264. glEnable(GL_DEPTH_TEST);
  265. glPushMatrix();
  266. const double floor_offset =
  267. -2./bbd*(V.col(1).maxCoeff()-Vmid(1));
  268. glTranslated(0,floor_offset,0);
  269. const float GREY[4] = {0.5,0.5,0.6,1.0};
  270. const float DARK_GREY[4] = {0.2,0.2,0.3,1.0};
  271. glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
  272. glEnable(GL_CULL_FACE);
  273. glCullFace(GL_BACK);
  274. draw_floor(GREY,DARK_GREY);
  275. glDisable(GL_CULL_FACE);
  276. glPopMatrix();
  277. push_object();
  278. const auto & draw_skeleton = [](const MatrixXd & T)
  279. {
  280. switch(skel_style)
  281. {
  282. default:
  283. case SKEL_STYLE_TYPE_3D:
  284. {
  285. draw_skeleton_3d(C,BE,T,s.colors);
  286. break;
  287. }
  288. case SKEL_STYLE_TYPE_VECTOR_GRAPHICS:
  289. draw_skeleton_vector_graphics(C,BE,T);
  290. break;
  291. }
  292. };
  293. // Set material properties
  294. glDisable(GL_COLOR_MATERIAL);
  295. glMaterialfv(GL_FRONT, GL_AMBIENT,GOLD_AMBIENT);
  296. glMaterialfv(GL_FRONT, GL_DIFFUSE,GOLD_DIFFUSE);
  297. glMaterialfv(GL_FRONT, GL_SPECULAR,GOLD_SPECULAR);
  298. glMaterialf (GL_FRONT, GL_SHININESS, 128);
  299. glMaterialfv(GL_BACK, GL_AMBIENT,SILVER_AMBIENT);
  300. glMaterialfv(GL_BACK, GL_DIFFUSE,FAST_GREEN_DIFFUSE);
  301. glMaterialfv(GL_BACK, GL_SPECULAR,SILVER_SPECULAR);
  302. glMaterialf (GL_BACK, GL_SHININESS, 128);
  303. if(wireframe)
  304. {
  305. glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
  306. }
  307. glLineWidth(1.0);
  308. MatrixXd T;
  309. RotationList dQ;
  310. if(panim.is_animating)
  311. {
  312. double t = (get_seconds() - panim.start_time)/panim.DURATION;
  313. if(t > 1)
  314. {
  315. t = 1;
  316. panim.is_animating = false;
  317. }
  318. const auto & ease = [](const double t)
  319. {
  320. return 3.*t*t-2.*t*t*t;
  321. };
  322. double f = (t<0.5?ease(2.*t):ease(2.-2.*t));
  323. dQ.resize(panim.pose.size());
  324. for(int e = 0;e<(int)panim.pose.size();e++)
  325. {
  326. dQ[e] = panim.pose[e].slerp(f,Quaterniond::Identity()).normalized();
  327. }
  328. }else
  329. {
  330. dQ = s.mouse.rotations();
  331. }
  332. forward_kinematics(C,BE,P,dQ,T);
  333. MatrixXd U = M*T;
  334. MatrixXd UN;
  335. per_face_normals(U,F,UN);
  336. draw_mesh(U,F,UN);
  337. glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
  338. glDisable(GL_DEPTH_TEST);
  339. draw_skeleton(T);
  340. if(centroid_is_visible)
  341. {
  342. Vector3d cen;
  343. centroid(U,F,cen);
  344. glEnable(GL_DEPTH_TEST);
  345. glPushMatrix();
  346. glTranslated(cen(0),cen(1),cen(2));
  347. glScaled(bbd/2.,bbd/2.,bbd/2.);
  348. glScaled(0.1,0.1,0.1);
  349. glEnable(GL_POLYGON_OFFSET_FILL);
  350. glPolygonOffset(0,-100000);
  351. draw_beach_ball();
  352. glDisable(GL_POLYGON_OFFSET_FILL);
  353. glPopMatrix();
  354. }
  355. // Mouse is always on top
  356. glDisable(GL_DEPTH_TEST);
  357. if(!panim.is_animating)
  358. {
  359. s.mouse.draw();
  360. }
  361. pop_object();
  362. pop_scene();
  363. report_gl_error();
  364. TwDraw();
  365. glutSwapBuffers();
  366. if(canim.is_animating || panim.is_animating)
  367. {
  368. glutPostRedisplay();
  369. }
  370. }
  371. void mouse_wheel(int wheel, int direction, int mouse_x, int mouse_y)
  372. {
  373. using namespace std;
  374. using namespace igl;
  375. using namespace Eigen;
  376. GLint viewport[4];
  377. glGetIntegerv(GL_VIEWPORT,viewport);
  378. if(wheel == 0 && TwMouseMotion(mouse_x, viewport[3] - mouse_y))
  379. {
  380. static double mouse_scroll_y = 0;
  381. const double delta_y = 0.125*direction;
  382. mouse_scroll_y += delta_y;
  383. TwMouseWheel(mouse_scroll_y);
  384. return;
  385. }
  386. push_undo();
  387. if(wheel==0)
  388. {
  389. // factor of zoom change
  390. double s = (1.-0.01*direction);
  391. //// FOV zoom: just widen angle. This is hardly ever appropriate.
  392. //camera.m_angle *= s;
  393. //camera.m_angle = min(max(camera.m_angle,1),89);
  394. camera.push_away(s);
  395. }else
  396. {
  397. // Dolly zoom:
  398. camera.dolly_zoom((double)direction*1.0);
  399. }
  400. glutPostRedisplay();
  401. }
  402. void mouse(int glutButton, int glutState, int mouse_x, int mouse_y)
  403. {
  404. using namespace std;
  405. using namespace Eigen;
  406. using namespace igl;
  407. bool tw_using = TwEventMouseButtonGLUT(glutButton,glutState,mouse_x,mouse_y);
  408. const int mod = (glutButton <=2 ? glutGetModifiers() : 0);
  409. const bool option_down = mod & GLUT_ACTIVE_ALT;
  410. switch(glutButton)
  411. {
  412. case GLUT_RIGHT_BUTTON:
  413. case GLUT_LEFT_BUTTON:
  414. {
  415. push_scene();
  416. push_object();
  417. switch(glutState)
  418. {
  419. case 1:
  420. {
  421. // up
  422. const bool mouse_was_selecting = s.mouse.is_selecting();
  423. is_rotating = false;
  424. s.mouse.up(mouse_x,mouse_y);
  425. glutSetCursor(GLUT_CURSOR_INHERIT);
  426. if(mouse_was_selecting)
  427. {
  428. s.mouse.set_selection_from_last_drag(C,BE,P,RP);
  429. MouseController::VectorXb S;
  430. MouseController::propogate_to_descendants_if(
  431. s.mouse.selection(),P,S);
  432. MouseController::color_if(S,MAYA_SEA_GREEN,MAYA_VIOLET,s.colors);
  433. }
  434. break;
  435. }
  436. case 0:
  437. if(!tw_using)
  438. {
  439. down_x = mouse_x;
  440. down_y = mouse_y;
  441. if(option_down || glutButton==GLUT_RIGHT_BUTTON)
  442. {
  443. glutSetCursor(GLUT_CURSOR_CYCLE);
  444. // collect information for trackball
  445. is_rotating = true;
  446. down_camera = camera;
  447. }else
  448. {
  449. push_undo();
  450. s.mouse.down(mouse_x,mouse_y);
  451. }
  452. }
  453. break;
  454. }
  455. pop_object();
  456. pop_scene();
  457. break;
  458. }
  459. // Scroll down
  460. case 3:
  461. {
  462. mouse_wheel(0,-1,mouse_x,mouse_y);
  463. break;
  464. }
  465. // Scroll up
  466. case 4:
  467. {
  468. mouse_wheel(0,1,mouse_x,mouse_y);
  469. break;
  470. }
  471. // Scroll left
  472. case 5:
  473. {
  474. mouse_wheel(1,-1,mouse_x,mouse_y);
  475. break;
  476. }
  477. // Scroll right
  478. case 6:
  479. {
  480. mouse_wheel(1,1,mouse_x,mouse_y);
  481. break;
  482. }
  483. }
  484. glutPostRedisplay();
  485. }
  486. void mouse_drag(int mouse_x, int mouse_y)
  487. {
  488. using namespace igl;
  489. using namespace std;
  490. using namespace Eigen;
  491. push_scene();
  492. push_object();
  493. if(is_rotating)
  494. {
  495. glutSetCursor(GLUT_CURSOR_CYCLE);
  496. Quaterniond q;
  497. switch(rotation_type)
  498. {
  499. case ROTATION_TYPE_IGL_TRACKBALL:
  500. {
  501. // Rotate according to trackball
  502. igl::trackball<double>(
  503. width,
  504. height,
  505. 2.0,
  506. down_camera.m_rotation_conj.coeffs().data(),
  507. down_x,
  508. down_y,
  509. mouse_x,
  510. mouse_y,
  511. q.coeffs().data());
  512. break;
  513. }
  514. case ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP:
  515. {
  516. // Rotate according to two axis valuator with fixed up vector
  517. two_axis_valuator_fixed_up(
  518. width, height,
  519. 2.0,
  520. down_camera.m_rotation_conj,
  521. down_x, down_y, mouse_x, mouse_y,
  522. q);
  523. break;
  524. }
  525. default:
  526. break;
  527. }
  528. camera.orbit(q.conjugate());
  529. }else if(s.mouse.drag(mouse_x,mouse_y))
  530. {
  531. }
  532. pop_object();
  533. pop_scene();
  534. glutPostRedisplay();
  535. }
  536. void init_relative()
  537. {
  538. using namespace Eigen;
  539. using namespace igl;
  540. using namespace std;
  541. per_face_normals(V,F,N);
  542. const auto Vmax = V.colwise().maxCoeff();
  543. const auto Vmin = V.colwise().minCoeff();
  544. Vmid = 0.5*(Vmax + Vmin);
  545. bbd = (Vmax-Vmin).norm();
  546. camera.push_away(2);
  547. }
  548. void undo()
  549. {
  550. using namespace std;
  551. if(!undo_stack.empty())
  552. {
  553. redo_stack.push(s);
  554. s = undo_stack.top();
  555. undo_stack.pop();
  556. s.mouse.reshape(width,height);
  557. }
  558. }
  559. void redo()
  560. {
  561. using namespace std;
  562. if(!redo_stack.empty())
  563. {
  564. undo_stack.push(s);
  565. s = redo_stack.top();
  566. redo_stack.pop();
  567. s.mouse.reshape(width,height);
  568. }
  569. }
  570. bool save()
  571. {
  572. using namespace std;
  573. using namespace igl;
  574. using namespace Eigen;
  575. string output_filename = next_filename(output_prefix,4,".dmat");
  576. MatrixXd T;
  577. forward_kinematics(C,BE,P,s.mouse.rotations(),T);
  578. if(writeDMAT(output_filename,T))
  579. {
  580. cout<<GREENGIN("Current pose written to "+output_filename+".")<<endl;
  581. return true;
  582. }else
  583. {
  584. cout<<REDRUM("Writing to "+output_filename+" failed.")<<endl;
  585. return false;
  586. }
  587. }
  588. void key(unsigned char key, int mouse_x, int mouse_y)
  589. {
  590. using namespace std;
  591. using namespace igl;
  592. using namespace Eigen;
  593. int mod = glutGetModifiers();
  594. const bool command_down = GLUT_ACTIVE_COMMAND & mod;
  595. const bool shift_down = GLUT_ACTIVE_SHIFT & mod;
  596. switch(key)
  597. {
  598. // ESC
  599. case char(27):
  600. rebar.save(REBAR_NAME);
  601. // ^C
  602. case char(3):
  603. exit(0);
  604. case 'A':
  605. case 'a':
  606. {
  607. panim.is_animating = !panim.is_animating;
  608. panim.pose = s.mouse.rotations();
  609. panim.start_time = get_seconds();
  610. break;
  611. }
  612. case 'D':
  613. case 'd':
  614. {
  615. push_undo();
  616. s.mouse.clear_selection();
  617. break;
  618. }
  619. case 'R':
  620. {
  621. push_undo();
  622. s.mouse.reset_selected_rotations();
  623. break;
  624. }
  625. case 'r':
  626. {
  627. push_undo();
  628. s.mouse.reset_rotations();
  629. break;
  630. }
  631. case 'S':
  632. case 's':
  633. {
  634. save();
  635. break;
  636. }
  637. case 'z':
  638. case 'Z':
  639. is_rotating = false;
  640. if(command_down)
  641. {
  642. if(shift_down)
  643. {
  644. redo();
  645. }else
  646. {
  647. undo();
  648. }
  649. break;
  650. }else
  651. {
  652. push_undo();
  653. Quaterniond q;
  654. snap_to_canonical_view_quat(camera.m_rotation_conj,1.0,q);
  655. camera.orbit(q.conjugate());
  656. }
  657. break;
  658. default:
  659. if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y))
  660. {
  661. cout<<"Unknown key command: "<<key<<" "<<int(key)<<endl;
  662. }
  663. }
  664. glutPostRedisplay();
  665. }
  666. bool clean(
  667. const Eigen::MatrixXd & V,
  668. const Eigen::MatrixXi & F,
  669. Eigen::MatrixXd & CV,
  670. Eigen::MatrixXi & CF)
  671. {
  672. using namespace igl;
  673. using namespace Eigen;
  674. using namespace std;
  675. {
  676. MatrixXi _1;
  677. VectorXi _2,_3;
  678. remesh_self_intersections(V,F,{},CV,CF,_1,_2,_3);
  679. }
  680. MatrixXd TV;
  681. MatrixXi TT;
  682. {
  683. MatrixXi _1;
  684. // c convex hull
  685. // Y no boundary steiners
  686. // p polygon input
  687. if(tetrahedralize(V,F,"cYp",TV,TT,_1) != 0)
  688. {
  689. cout<<REDRUM("CDT failed.")<<endl;
  690. return false;
  691. }
  692. }
  693. {
  694. MatrixXd BC;
  695. barycenter(TV,TT,BC);
  696. VectorXd W;
  697. winding_number(V,F,BC,W);
  698. W = W.array().abs();
  699. const double thresh = 0.5;
  700. const int count = (W.array()>thresh).cast<int>().sum();
  701. MatrixXi CT(count,TT.cols());
  702. int c = 0;
  703. for(int t = 0;t<TT.rows();t++)
  704. {
  705. if(W(t)>thresh)
  706. {
  707. CT.row(c++) = TT.row(t);
  708. }
  709. }
  710. assert(c==count);
  711. boundary_facets(CT,CF);
  712. }
  713. return true;
  714. }
  715. bool robust_weights(
  716. const Eigen::MatrixXd & V,
  717. const Eigen::MatrixXi & F,
  718. const Eigen::MatrixXd & C,
  719. const Eigen::MatrixXi & BE,
  720. Eigen::MatrixXd & W)
  721. {
  722. using namespace igl;
  723. using namespace Eigen;
  724. using namespace std;
  725. // clean mesh
  726. MatrixXd CV;
  727. MatrixXi CF;
  728. if(!clean(V,F,CV,CF))
  729. {
  730. return false;
  731. }
  732. MatrixXd TV;
  733. MatrixXi TT;
  734. // compute tet-mesh
  735. {
  736. MatrixXi _1;
  737. if(!mesh_with_skeleton(V,F,C,{},BE,{},10,TV,TT,_1))
  738. {
  739. cout<<REDRUM("tetgen failed.")<<endl;
  740. return false;
  741. }
  742. }
  743. // compute weights
  744. VectorXi b;
  745. MatrixXd bc;
  746. if(!boundary_conditions(TV,TT,C,{},BE,{},b,bc))
  747. {
  748. cout<<REDRUM("boundary_conditions failed.")<<endl;
  749. return false;
  750. }
  751. // compute BBW
  752. // Default bbw data and flags
  753. BBWData bbw_data;
  754. bbw_data.verbosity = 1;
  755. #ifdef IGL_NO_MOSEK
  756. bbw_data.qp_solver = QP_SOLVER_IGL_ACTIVE_SET;
  757. bbw_data.active_set_params.max_iter = 4;
  758. #else
  759. bbw_data.mosek_data.douparam[MSK_DPAR_INTPNT_TOL_REL_GAP]=1e-14;
  760. bbw_data.qp_solver = QP_SOLVER_MOSEK;
  761. #endif
  762. // Weights matrix
  763. if(!bbw(TV,TT,b,bc,bbw_data,W))
  764. {
  765. return false;
  766. }
  767. // Normalize weights to sum to one
  768. normalize_row_sums(W,W);
  769. // keep first #V weights
  770. W.conservativeResize(V.rows(),W.cols());
  771. return true;
  772. }
  773. int main(int argc, char * argv[])
  774. {
  775. using namespace std;
  776. using namespace Eigen;
  777. using namespace igl;
  778. string filename = "../shared/cheburashka.off";
  779. string skel_filename = "../shared/cheburashka.tgf";
  780. string weights_filename = "";
  781. output_prefix = "";
  782. switch(argc)
  783. {
  784. case 5:
  785. output_prefix = argv[4];
  786. //fall through
  787. case 4:
  788. weights_filename = argv[3];
  789. //fall through
  790. case 3:
  791. skel_filename = argv[2];
  792. // Read and prepare mesh
  793. filename = argv[1];
  794. break;
  795. default:
  796. cerr<<"Usage:"<<endl<<" ./example model.obj skeleton.tgf [weights.dmat] [pose-prefix]"<<endl;
  797. cout<<endl<<"Opening default rig..."<<endl;
  798. }
  799. // print key commands
  800. cout<<"[Click] and [drag] Select a bone/Use onscreen widget to rotate bone."<<endl;
  801. cout<<"⌥ +[Click] and [drag] Rotate secene."<<endl;
  802. cout<<"⌫ Delete selected node(s) and incident bones."<<endl;
  803. cout<<"D,d Deselect all."<<endl;
  804. cout<<"S,s Save current pose."<<endl;
  805. cout<<"R Reset selected rotation."<<endl;
  806. cout<<"r Reset all rotations."<<endl;
  807. cout<<"Z,z Snap to canonical view."<<endl;
  808. cout<<"⌘ Z Undo."<<endl;
  809. cout<<"⇧ ⌘ Z Redo."<<endl;
  810. cout<<"^C,ESC Exit (without saving)."<<endl;
  811. // dirname, basename, extension and filename
  812. string dir,base,ext,name;
  813. pathinfo(filename,dir,base,ext,name);
  814. // Convert extension to lower case
  815. transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
  816. vector<vector<double > > vV,vN,vTC;
  817. vector<vector<int > > vF,vFTC,vFN;
  818. if(ext == "obj")
  819. {
  820. // Convert extension to lower case
  821. if(!igl::readOBJ(filename,vV,vTC,vN,vF,vFTC,vFN))
  822. {
  823. return 1;
  824. }
  825. }else if(ext == "off")
  826. {
  827. // Convert extension to lower case
  828. if(!igl::readOFF(filename,vV,vF,vN))
  829. {
  830. return 1;
  831. }
  832. }else if(ext == "wrl")
  833. {
  834. // Convert extension to lower case
  835. if(!igl::readWRL(filename,vV,vF))
  836. {
  837. return 1;
  838. }
  839. //}else
  840. //{
  841. // // Convert extension to lower case
  842. // MatrixXi T;
  843. // if(!igl::readMESH(filename,V,T,F))
  844. // {
  845. // return 1;
  846. // }
  847. // //if(F.size() > T.size() || F.size() == 0)
  848. // {
  849. // boundary_facets(T,F);
  850. // }
  851. }
  852. if(vV.size() > 0)
  853. {
  854. if(!list_to_matrix(vV,V))
  855. {
  856. return 1;
  857. }
  858. polygon_mesh_to_triangle_mesh(vF,F);
  859. }
  860. if(output_prefix.size() == 0)
  861. {
  862. output_prefix = dir+"/"+name+"-pose-";
  863. }
  864. {
  865. string output_filename = next_filename(output_prefix,4,".dmat");
  866. cout<<BLUEGIN("Output set to start with "<<output_filename)<<endl;
  867. }
  868. // Read in skeleton and precompute hierarchy
  869. readTGF(skel_filename,C,BE);
  870. // initialize mouse interface
  871. s.mouse.set_size(BE.rows());
  872. // Rigid parts (not used)
  873. colon<int>(0,BE.rows()-1,RP);
  874. assert(RP.size() == BE.rows());
  875. // Bone parents
  876. bone_parents(BE,P);
  877. if(weights_filename.size() == 0)
  878. {
  879. robust_weights(V,F,C,BE,W);
  880. }else
  881. {
  882. // Read in weights and precompute LBS matrix
  883. readDMAT(weights_filename,W);
  884. }
  885. lbs_matrix(V,W,M);
  886. init_relative();
  887. // Init glut
  888. glutInit(&argc,argv);
  889. if( !TwInit(TW_OPENGL, NULL) )
  890. {
  891. // A fatal error occured
  892. fprintf(stderr, "AntTweakBar initialization failed: %s\n", TwGetLastError());
  893. return 1;
  894. }
  895. // Create a tweak bar
  896. rebar.TwNewBar("TweakBar");
  897. rebar.TwAddVarRW("camera_rotation", TW_TYPE_QUAT4D,
  898. camera.m_rotation_conj.coeffs().data(), "open readonly=true");
  899. TwType RotationTypeTW = ReTwDefineEnumFromString("RotationType",
  900. "igl_trackball,two-a...-fixed-up");
  901. rebar.TwAddVarCB( "rotation_type", RotationTypeTW,
  902. set_rotation_type,get_rotation_type,NULL,"keyIncr=] keyDecr=[");
  903. rebar.TwAddVarRW("wireframe", TW_TYPE_BOOLCPP,&wireframe,"key=l");
  904. rebar.TwAddVarRW("centroid_is_visible", TW_TYPE_BOOLCPP,&centroid_is_visible,
  905. "keyIncr=C keyDecr=c label='centroid visible?'");
  906. TwType SkelStyleTypeTW = ReTwDefineEnumFromString("SkelStyleType",
  907. "3d,vector-graphics");
  908. rebar.TwAddVarRW("style",SkelStyleTypeTW,&skel_style,"");
  909. rebar.load(REBAR_NAME);
  910. // Init antweakbar
  911. glutInitDisplayString( "rgba depth double samples>=8 ");
  912. glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT)/2.0);
  913. glutCreateWindow("skeleton-poser");
  914. glutDisplayFunc(display);
  915. glutReshapeFunc(reshape);
  916. glutKeyboardFunc(key);
  917. glutMouseFunc(mouse);
  918. glutMotionFunc(mouse_drag);
  919. glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
  920. glutMainLoop();
  921. return 0;
  922. }