example.cpp 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. #include <igl/Camera.h>
  2. #include <igl/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/draw_beach_ball.h>
  12. #include <igl/draw_floor.h>
  13. #include <igl/draw_mesh.h>
  14. #include <igl/draw_skeleton_3d.h>
  15. #include <igl/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/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::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. 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. draw_skeleton_3d(C,BE,T,s.colors,bbd*0.5);
  279. break;
  280. }
  281. case SKEL_STYLE_TYPE_VECTOR_GRAPHICS:
  282. 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. 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. 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. 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. MouseController::VectorXb S;
  423. MouseController::propogate_to_descendants_if(
  424. s.mouse.selection(),P,S);
  425. MouseController::color_if(S,MAYA_SEA_GREEN,MAYA_VIOLET,s.colors);
  426. }
  427. break;
  428. }
  429. case 0:
  430. if(!tw_using)
  431. {
  432. down_x = mouse_x;
  433. down_y = mouse_y;
  434. if(option_down || glutButton==GLUT_RIGHT_BUTTON)
  435. {
  436. glutSetCursor(GLUT_CURSOR_CYCLE);
  437. // collect information for trackball
  438. is_rotating = true;
  439. down_camera = camera;
  440. }else
  441. {
  442. push_undo();
  443. s.mouse.down(mouse_x,mouse_y);
  444. }
  445. }
  446. break;
  447. }
  448. pop_object();
  449. pop_scene();
  450. break;
  451. }
  452. // Scroll down
  453. case 3:
  454. {
  455. mouse_wheel(0,-1,mouse_x,mouse_y);
  456. break;
  457. }
  458. // Scroll up
  459. case 4:
  460. {
  461. mouse_wheel(0,1,mouse_x,mouse_y);
  462. break;
  463. }
  464. // Scroll left
  465. case 5:
  466. {
  467. mouse_wheel(1,-1,mouse_x,mouse_y);
  468. break;
  469. }
  470. // Scroll right
  471. case 6:
  472. {
  473. mouse_wheel(1,1,mouse_x,mouse_y);
  474. break;
  475. }
  476. }
  477. glutPostRedisplay();
  478. }
  479. void mouse_drag(int mouse_x, int mouse_y)
  480. {
  481. using namespace igl;
  482. using namespace std;
  483. using namespace Eigen;
  484. push_scene();
  485. push_object();
  486. if(is_rotating)
  487. {
  488. glutSetCursor(GLUT_CURSOR_CYCLE);
  489. Quaterniond q;
  490. switch(rotation_type)
  491. {
  492. case ROTATION_TYPE_IGL_TRACKBALL:
  493. {
  494. // Rotate according to trackball
  495. igl::trackball(
  496. width,
  497. height,
  498. 2.0,
  499. down_camera.m_rotation_conj,
  500. down_x,
  501. down_y,
  502. mouse_x,
  503. mouse_y,
  504. q);
  505. break;
  506. }
  507. case ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP:
  508. {
  509. // Rotate according to two axis valuator with fixed up vector
  510. two_axis_valuator_fixed_up(
  511. width, height,
  512. 2.0,
  513. down_camera.m_rotation_conj,
  514. down_x, down_y, mouse_x, mouse_y,
  515. q);
  516. break;
  517. }
  518. default:
  519. break;
  520. }
  521. camera.orbit(q.conjugate());
  522. }else if(s.mouse.drag(mouse_x,mouse_y))
  523. {
  524. }
  525. pop_object();
  526. pop_scene();
  527. glutPostRedisplay();
  528. }
  529. void init_relative()
  530. {
  531. using namespace Eigen;
  532. using namespace igl;
  533. using namespace std;
  534. per_face_normals(V,F,N);
  535. const auto Vmax = V.colwise().maxCoeff();
  536. const auto Vmin = V.colwise().minCoeff();
  537. Vmid = 0.5*(Vmax + Vmin);
  538. bbd = (Vmax-Vmin).norm();
  539. camera.push_away(2);
  540. }
  541. void undo()
  542. {
  543. using namespace std;
  544. if(!undo_stack.empty())
  545. {
  546. redo_stack.push(s);
  547. s = undo_stack.top();
  548. undo_stack.pop();
  549. s.mouse.reshape(width,height);
  550. }
  551. }
  552. void redo()
  553. {
  554. using namespace std;
  555. if(!redo_stack.empty())
  556. {
  557. undo_stack.push(s);
  558. s = redo_stack.top();
  559. redo_stack.pop();
  560. s.mouse.reshape(width,height);
  561. }
  562. }
  563. bool save_pose()
  564. {
  565. using namespace std;
  566. using namespace igl;
  567. using namespace Eigen;
  568. string output_filename;
  569. next_filename(output_pose_prefix,4,".dmat",output_filename);
  570. MatrixXd T;
  571. forward_kinematics(C,BE,P,s.mouse.rotations(),T);
  572. if(writeDMAT(output_filename,T))
  573. {
  574. cout<<GREENGIN("Current pose written to "+output_filename+".")<<endl;
  575. return true;
  576. }else
  577. {
  578. cout<<REDRUM("Writing to "+output_filename+" failed.")<<endl;
  579. return false;
  580. }
  581. }
  582. bool save_weights()
  583. {
  584. using namespace std;
  585. using namespace igl;
  586. using namespace Eigen;
  587. if(writeDMAT(output_weights_filename,W))
  588. {
  589. cout<<GREENGIN("Current weights written to "+
  590. output_weights_filename+".")<<endl;
  591. return true;
  592. }else
  593. {
  594. cout<<REDRUM("Writing to "+output_weights_filename+" failed.")<<endl;
  595. return false;
  596. }
  597. }
  598. bool save_mesh()
  599. {
  600. using namespace std;
  601. using namespace igl;
  602. using namespace Eigen;
  603. MatrixXd T;
  604. forward_kinematics(C,BE,P,s.mouse.rotations(),T);
  605. MatrixXd U = M*T;
  606. string output_filename;
  607. next_filename(output_pose_prefix,4,".obj",output_filename);
  608. if(writeOBJ(output_filename,U,F))
  609. {
  610. cout<<GREENGIN("Current mesh written to "+
  611. output_filename+".")<<endl;
  612. return true;
  613. }else
  614. {
  615. cout<<REDRUM("Writing to "+output_filename+" failed.")<<endl;
  616. return false;
  617. }
  618. }
  619. void key(unsigned char key, int mouse_x, int mouse_y)
  620. {
  621. using namespace std;
  622. using namespace igl;
  623. using namespace Eigen;
  624. int mod = glutGetModifiers();
  625. const bool command_down = GLUT_ACTIVE_COMMAND & mod;
  626. const bool shift_down = GLUT_ACTIVE_SHIFT & mod;
  627. switch(key)
  628. {
  629. // ESC
  630. case char(27):
  631. rebar.save(REBAR_NAME);
  632. // ^C
  633. case char(3):
  634. exit(0);
  635. case 'A':
  636. case 'a':
  637. {
  638. panim.is_animating = !panim.is_animating;
  639. panim.pose = s.mouse.rotations();
  640. panim.start_time = get_seconds();
  641. break;
  642. }
  643. case 'D':
  644. case 'd':
  645. {
  646. push_undo();
  647. s.mouse.clear_selection();
  648. break;
  649. }
  650. case 'R':
  651. {
  652. push_undo();
  653. s.mouse.reset_selected_rotations();
  654. break;
  655. }
  656. case 'r':
  657. {
  658. push_undo();
  659. s.mouse.reset_rotations();
  660. break;
  661. }
  662. case 'S':
  663. {
  664. save_mesh();
  665. break;
  666. }
  667. case 's':
  668. {
  669. save_pose();
  670. break;
  671. }
  672. case 'W':
  673. case 'w':
  674. {
  675. save_weights();
  676. break;
  677. }
  678. case 'z':
  679. case 'Z':
  680. is_rotating = false;
  681. if(command_down)
  682. {
  683. if(shift_down)
  684. {
  685. redo();
  686. }else
  687. {
  688. undo();
  689. }
  690. break;
  691. }else
  692. {
  693. push_undo();
  694. Quaterniond q;
  695. snap_to_canonical_view_quat(camera.m_rotation_conj,1.0,q);
  696. camera.orbit(q.conjugate());
  697. }
  698. break;
  699. default:
  700. if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y))
  701. {
  702. cout<<"Unknown key command: "<<key<<" "<<int(key)<<endl;
  703. }
  704. }
  705. glutPostRedisplay();
  706. }
  707. bool clean(
  708. const Eigen::MatrixXd & V,
  709. const Eigen::MatrixXi & F,
  710. Eigen::MatrixXd & CV,
  711. Eigen::MatrixXi & CF)
  712. {
  713. using namespace igl;
  714. using namespace Eigen;
  715. using namespace std;
  716. {
  717. MatrixXi _1;
  718. VectorXi _2,IM;
  719. #ifdef VERBOSE
  720. cout<<"remesh_self_intersections"<<endl;
  721. #endif
  722. igl::cgal::remesh_self_intersections(V,F,{},CV,CF,_1,_2,IM);
  723. for_each(CF.data(),CF.data()+CF.size(),[&IM](int & a){a=IM(a);});
  724. MatrixXd oldCV = CV;
  725. MatrixXi oldCF = CF;
  726. remove_unreferenced(oldCV,oldCF,CV,CF,IM);
  727. }
  728. MatrixXd TV;
  729. MatrixXi TT;
  730. {
  731. MatrixXi _1;
  732. // c convex hull
  733. // Y no boundary steiners
  734. // p polygon input
  735. #ifdef VERBOSE
  736. cout<<"tetrahedralize"<<endl;
  737. #endif
  738. if(igl::tetgen::tetrahedralize(CV,CF,"cYpC",TV,TT,_1) != 0)
  739. {
  740. cout<<REDRUM("CDT failed.")<<endl;
  741. return false;
  742. }
  743. }
  744. {
  745. MatrixXd BC;
  746. barycenter(TV,TT,BC);
  747. VectorXd W;
  748. #ifdef VERBOSE
  749. cout<<"winding_number"<<endl;
  750. #endif
  751. winding_number(V,F,BC,W);
  752. W = W.array().abs();
  753. const double thresh = 0.5;
  754. const int count = (W.array()>thresh).cast<int>().sum();
  755. MatrixXi CT(count,TT.cols());
  756. int c = 0;
  757. for(int t = 0;t<TT.rows();t++)
  758. {
  759. if(W(t)>thresh)
  760. {
  761. CT.row(c++) = TT.row(t);
  762. }
  763. }
  764. assert(c==count);
  765. boundary_facets(CT,CF);
  766. }
  767. return true;
  768. }
  769. bool robust_weights(
  770. const Eigen::MatrixXd & V,
  771. const Eigen::MatrixXi & F,
  772. const Eigen::MatrixXd & C,
  773. const Eigen::MatrixXi & BE,
  774. Eigen::MatrixXd & W)
  775. {
  776. using namespace igl;
  777. using namespace Eigen;
  778. using namespace std;
  779. // clean mesh
  780. MatrixXd CV;
  781. MatrixXi CF;
  782. if(!clean(V,F,CV,CF))
  783. {
  784. return false;
  785. }
  786. MatrixXd TV;
  787. MatrixXi TT;
  788. // compute tet-mesh
  789. {
  790. MatrixXi _1;
  791. #ifdef VERBOSE
  792. cout<<"mesh_with_skeleton"<<endl;
  793. #endif
  794. if(!igl::tetgen::mesh_with_skeleton(CV,CF,C,{},BE,{},10,"pq1.5Y",TV,TT,_1))
  795. {
  796. cout<<REDRUM("tetgen failed.")<<endl;
  797. return false;
  798. }
  799. }
  800. // Finally, tetgen may have still included some insanely small tets.
  801. // Just ignore these during weight computation (and hope they don't isolate
  802. // any vertices).
  803. {
  804. const MatrixXi oldTT = TT;
  805. VectorXd vol;
  806. volume(TV,TT,vol);
  807. const double thresh = 1e-17;
  808. const int count = (vol.array()>thresh).cast<int>().sum();
  809. TT.resize(count,oldTT.cols());
  810. int c = 0;
  811. for(int t = 0;t<oldTT.rows();t++)
  812. {
  813. if(vol(t)>thresh)
  814. {
  815. TT.row(c++) = oldTT.row(t);
  816. }
  817. }
  818. }
  819. // compute weights
  820. VectorXi b;
  821. MatrixXd bc;
  822. if(!boundary_conditions(TV,TT,C,{},BE,{},b,bc))
  823. {
  824. cout<<REDRUM("boundary_conditions failed.")<<endl;
  825. return false;
  826. }
  827. // compute BBW
  828. // Default bbw data and flags
  829. igl::bbw::BBWData bbw_data;
  830. bbw_data.verbosity = 1;
  831. #ifdef IGL_NO_MOSEK
  832. bbw_data.qp_solver = igl::bbw::QP_SOLVER_IGL_ACTIVE_SET;
  833. bbw_data.active_set_params.max_iter = 4;
  834. #else
  835. bbw_data.mosek_data.douparam[MSK_DPAR_INTPNT_TOL_REL_GAP]=1e-14;
  836. bbw_data.qp_solver = igl::bbw::QP_SOLVER_MOSEK;
  837. #endif
  838. // Weights matrix
  839. if(!igl::bbw::bbw(TV,TT,b,bc,bbw_data,W))
  840. {
  841. return false;
  842. }
  843. // Normalize weights to sum to one
  844. normalize_row_sums(W,W);
  845. // keep first #V weights
  846. W.conservativeResize(V.rows(),W.cols());
  847. return true;
  848. }
  849. int main(int argc, char * argv[])
  850. {
  851. using namespace std;
  852. using namespace Eigen;
  853. using namespace igl;
  854. string filename = "../shared/cheburashka.off";
  855. string skel_filename = "../shared/cheburashka.tgf";
  856. string weights_filename = "";
  857. output_pose_prefix = "";
  858. switch(argc)
  859. {
  860. case 5:
  861. output_pose_prefix = argv[4];
  862. //fall through
  863. case 4:
  864. weights_filename = argv[3];
  865. //fall through
  866. case 3:
  867. skel_filename = argv[2];
  868. // Read and prepare mesh
  869. filename = argv[1];
  870. break;
  871. default:
  872. cerr<<"Usage:"<<endl<<" ./example model.obj skeleton.tgf [weights.dmat] [pose-prefix]"<<endl;
  873. cout<<endl<<"Opening default rig..."<<endl;
  874. }
  875. // print key commands
  876. cout<<"[Click] and [drag] Select a bone/Use onscreen widget to rotate bone."<<endl;
  877. cout<<"⌥ +[Click] and [drag] Rotate secene."<<endl;
  878. cout<<"⌫ Delete selected node(s) and incident bones."<<endl;
  879. cout<<"D,d Deselect all."<<endl;
  880. cout<<"R Reset selected rotation."<<endl;
  881. cout<<"r Reset all rotations."<<endl;
  882. cout<<"S Save current posed mesh."<<endl;
  883. cout<<"s Save current skeleton pose."<<endl;
  884. cout<<"W,w Save current weights."<<endl;
  885. cout<<"Z,z Snap to canonical view."<<endl;
  886. cout<<"⌘ Z Undo."<<endl;
  887. cout<<"⇧ ⌘ Z Redo."<<endl;
  888. cout<<"^C,ESC Exit (without saving)."<<endl;
  889. string dir,_1,_2,name;
  890. read_triangle_mesh(filename,V,F,dir,_1,_2,name);
  891. if(output_weights_filename.size() == 0)
  892. {
  893. output_weights_filename = dir+"/"+name+"-weights.dmat";
  894. }
  895. if(output_pose_prefix.size() == 0)
  896. {
  897. output_pose_prefix = dir+"/"+name+"-pose-";
  898. }
  899. {
  900. string output_filename;
  901. next_filename(output_pose_prefix,4,".dmat",output_filename);
  902. cout<<BLUEGIN("Output weights set to start with "<<
  903. output_weights_filename)<<endl;
  904. cout<<BLUEGIN("Output poses set to start with "<<output_filename)<<endl;
  905. }
  906. // Read in skeleton and precompute hierarchy
  907. readTGF(skel_filename,C,BE);
  908. // initialize mouse interface
  909. s.mouse.set_size(BE.rows());
  910. // Rigid parts (not used)
  911. colon<int>(0,BE.rows()-1,RP);
  912. assert(RP.size() == BE.rows());
  913. // Bone parents
  914. bone_parents(BE,P);
  915. if(weights_filename.size() == 0)
  916. {
  917. robust_weights(V,F,C,BE,W);
  918. }else
  919. {
  920. // Read in weights and precompute LBS matrix
  921. readDMAT(weights_filename,W);
  922. }
  923. lbs_matrix(V,W,M);
  924. init_relative();
  925. // Init glut
  926. glutInit(&argc,argv);
  927. if( !TwInit(TW_OPENGL, NULL) )
  928. {
  929. // A fatal error occured
  930. fprintf(stderr, "AntTweakBar initialization failed: %s\n", TwGetLastError());
  931. return 1;
  932. }
  933. // Create a tweak bar
  934. rebar.TwNewBar("TweakBar");
  935. rebar.TwAddVarRW("camera_rotation", TW_TYPE_QUAT4D,
  936. camera.m_rotation_conj.coeffs().data(), "open readonly=true");
  937. TwType RotationTypeTW = igl::anttweakbar::ReTwDefineEnumFromString("RotationType",
  938. "igl_trackball,two-a...-fixed-up");
  939. rebar.TwAddVarCB( "rotation_type", RotationTypeTW,
  940. set_rotation_type,get_rotation_type,NULL,"keyIncr=] keyDecr=[");
  941. rebar.TwAddVarRW("wireframe", TW_TYPE_BOOLCPP,&wireframe,"key=l");
  942. rebar.TwAddVarRW("centroid_is_visible", TW_TYPE_BOOLCPP,&centroid_is_visible,
  943. "keyIncr=C keyDecr=c label='centroid visible?'");
  944. TwType SkelStyleTypeTW = igl::anttweakbar::ReTwDefineEnumFromString("SkelStyleType",
  945. "3d,vector-graphics");
  946. rebar.TwAddVarRW("style",SkelStyleTypeTW,&skel_style,"");
  947. rebar.load(REBAR_NAME);
  948. // Init antweakbar
  949. glutInitDisplayString( "rgba depth double samples>=8 ");
  950. glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT)/2.0);
  951. glutCreateWindow("skeleton-poser");
  952. glutDisplayFunc(display);
  953. glutReshapeFunc(reshape);
  954. glutKeyboardFunc(key);
  955. glutMouseFunc(mouse);
  956. glutMotionFunc(mouse_drag);
  957. glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
  958. glutMainLoop();
  959. return 0;
  960. }