example.cpp 24 KB

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