example.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. #include <igl/Viewport.h>
  2. #include <igl/report_gl_error.h>
  3. #include <igl/ReAntTweakBar.h>
  4. #include <igl/trackball.h>
  5. #include <igl/PI.h>
  6. #include <igl/EPS.h>
  7. #include <igl/get_seconds.h>
  8. #include <Eigen/Core>
  9. #include <Eigen/Geometry>
  10. #ifdef WIN32
  11. #include <GL/glut.h>
  12. #else
  13. #include <GLUT/glut.h>
  14. #endif
  15. #include <vector>
  16. #include <stack>
  17. #include <iostream>
  18. class Camera
  19. {
  20. public:
  21. // m_zoom Zoom of camera lens {1}
  22. // m_angle Field of view angle in degrees {15}
  23. // m_aspect Aspect ratio {1}
  24. // m_near near clipping plane {1e-2}
  25. // m_far far clipping plane {100}
  26. // m_rotation Rotation part of rigid transformation of camera {identity}
  27. // m_translation Translation part of rigid transformation of camera
  28. // {(0,0,1)}
  29. double m_zoom, m_angle, m_aspect, m_near, m_far;
  30. Eigen::Quaterniond m_rotation;
  31. Eigen::Vector3d m_translation;
  32. Camera():
  33. m_zoom(1), m_angle(15.0), m_aspect(1), m_near(1e-2), m_far(100),
  34. m_rotation(1,0,0,0),
  35. m_translation(0,0,1)
  36. {
  37. }
  38. Eigen::Vector3d eye() const
  39. {
  40. using namespace Eigen;
  41. Affine3d t = Affine3d::Identity();
  42. t.rotate(m_rotation);
  43. t.translate(m_translation);
  44. return t * Vector3d(0,0,0);
  45. }
  46. Eigen::Vector3d at() const
  47. {
  48. using namespace Eigen;
  49. Affine3d t = Affine3d::Identity();
  50. t.rotate(m_rotation);
  51. t.translate(m_translation);
  52. return t * Vector3d(0,0,-1);
  53. }
  54. Eigen::Vector3d up() const
  55. {
  56. using namespace Eigen;
  57. Affine3d t = Affine3d::Identity();
  58. t.rotate(m_rotation);
  59. return t * Vector3d(0,1,0);
  60. }
  61. void dolly(const double d)
  62. {
  63. using namespace Eigen;
  64. Vector3d dv(0,0,d);
  65. m_translation += m_rotation.conjugate() * dv;
  66. }
  67. void look_at(
  68. const Eigen::Vector3d & eye,
  69. const Eigen::Vector3d & at,
  70. const Eigen::Vector3d & up)
  71. {
  72. using namespace Eigen;
  73. using namespace std;
  74. using namespace igl;
  75. // http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
  76. // Normalize vector from at to eye
  77. const Vector3d F = (eye-at).normalized();
  78. // Project up onto plane orthogonal to F and normalize
  79. const Vector3d proj_up = (up-(up.dot(F))*F).normalized();
  80. Quaterniond a,b;
  81. a.setFromTwoVectors(Vector3d(0,0,-1),-F);
  82. b.setFromTwoVectors(a*Vector3d(0,1,0),proj_up);
  83. m_rotation = a*b;
  84. m_translation = m_rotation.conjugate() * eye;
  85. assert( (eye-this->eye()).squaredNorm() < DOUBLE_EPS);
  86. assert((F-(this->eye()-this->at())).squaredNorm() < DOUBLE_EPS);
  87. assert( (proj_up-this->up()).squaredNorm() < DOUBLE_EPS);
  88. }
  89. };
  90. enum RotationType
  91. {
  92. ROTATION_TYPE_IGL_TRACKBALL = 0,
  93. ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
  94. NUM_ROTATION_TYPES = 2,
  95. } rotation_type = ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP;
  96. int width,height;
  97. #define REBAR_NAME "temp.rbr"
  98. igl::ReTwBar rebar;
  99. struct State
  100. {
  101. int viewing_camera;
  102. std::vector<Camera> cameras;
  103. State():viewing_camera(0),cameras(2){}
  104. } s;
  105. std::stack<State> undo_stack;
  106. bool is_rotating = false;
  107. Camera down_camera;
  108. int down_x,down_y;
  109. std::stack<State> redo_stack;
  110. void push_undo()
  111. {
  112. undo_stack.push(s);
  113. // Clear
  114. redo_stack = std::stack<State>();
  115. }
  116. void undo()
  117. {
  118. if(!undo_stack.empty())
  119. {
  120. redo_stack.push(s);
  121. s = undo_stack.top();
  122. undo_stack.pop();
  123. }
  124. }
  125. void redo()
  126. {
  127. if(!redo_stack.empty())
  128. {
  129. undo_stack.push(s);
  130. s = redo_stack.top();
  131. redo_stack.pop();
  132. }
  133. }
  134. void print(const Camera & camera)
  135. {
  136. using namespace std;
  137. cout<<
  138. "rotation: "<<camera.m_rotation.coeffs().transpose()<<endl<<
  139. "translation: "<<camera.m_translation.transpose()<<endl<<
  140. "eye: "<<camera.eye().transpose()<<endl<<
  141. "at: "<<camera.at().transpose()<<endl<<
  142. "up: "<<camera.up().transpose()<<endl<<
  143. endl;
  144. }
  145. void init_cameras()
  146. {
  147. using namespace Eigen;
  148. using namespace std;
  149. s.cameras[0].look_at(
  150. Vector3d(0,0,1),
  151. Vector3d(0,0,0),
  152. Vector3d(0,1,0));
  153. print(s.cameras[0]);
  154. //s.cameras[1].look_at(
  155. // Vector3d(0,0,-1),
  156. // Vector3d(0,0,0),
  157. // Vector3d(0,1,0));
  158. }
  159. void reshape(int width, int height)
  160. {
  161. ::width = width;
  162. ::height = height;
  163. glViewport(0,0,width,height);
  164. // Send the new window size to AntTweakBar
  165. TwWindowSize(width, height);
  166. }
  167. void display()
  168. {
  169. using namespace igl;
  170. using namespace std;
  171. using namespace Eigen;
  172. glClearColor(1,1,1,0);
  173. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  174. // Update aspect ratios (may have changed since undo/redo)
  175. const double aspect = (double)width/(double)height;
  176. for(auto & camera : s.cameras)
  177. {
  178. camera.m_aspect = aspect;
  179. }
  180. //camera.m_rotation *= Quaterniond(AngleAxisd(0.01,Vector3d(0,1,0)));
  181. auto & camera = s.cameras[s.viewing_camera];
  182. const double theta = cos(2.0*PI*get_seconds()*0.1)*PI*0.05;
  183. const Quaterniond R(AngleAxisd(theta,Vector3d(0,1,0)));
  184. //// Orbit
  185. //camera.look_at(
  186. // R*Vector3d(0,0,1),
  187. // Vector3d(0,0,0),
  188. // Vector3d(0,1,0));
  189. // First person, head rotate
  190. //camera.look_at(
  191. // Vector3d(0,0,1),
  192. // Vector3d(0,0,1)-R*Vector3d(0,0,1),
  193. // Vector3d(0,1,0));
  194. glMatrixMode(GL_PROJECTION);
  195. glPushMatrix();
  196. glLoadIdentity();
  197. gluPerspective(camera.m_angle,camera.m_aspect,camera.m_near,camera.m_far);
  198. glMatrixMode(GL_MODELVIEW);
  199. glPushMatrix();
  200. glLoadIdentity();
  201. gluLookAt(
  202. camera.eye()(0), camera.eye()(1), camera.eye()(2),
  203. camera.at()(0), camera.at()(1), camera.at()(2),
  204. camera.up()(0), camera.up()(1), camera.up()(2));
  205. for(int c = 0;c<(int)s.cameras.size();c++)
  206. {
  207. // draw camera
  208. }
  209. glDisable(GL_LIGHTING);
  210. glEnable(GL_COLOR_MATERIAL);
  211. glLineWidth(3.f);
  212. glColor4f(0,0,0,1);
  213. glutWireCube(0.25);
  214. glColor4f(1,0.5,0.5,1);
  215. glutWireSphere(0.125,20,20);
  216. // Axes
  217. for(int d = 0;d<3;d++)
  218. {
  219. glColor4f(d==0,d==1,d==2,1);
  220. glBegin(GL_LINES);
  221. glVertex3f(0,0,0);
  222. glVertex3f(d==0,d==1,d==2);
  223. glEnd();
  224. }
  225. glMatrixMode(GL_PROJECTION);
  226. glPopMatrix();
  227. glMatrixMode(GL_MODELVIEW);
  228. glPopMatrix();
  229. report_gl_error();
  230. TwDraw();
  231. glutSwapBuffers();
  232. glutPostRedisplay();
  233. }
  234. void mouse_wheel(int wheel, int direction, int mouse_x, int mouse_y)
  235. {
  236. using namespace std;
  237. if(wheel == 0)
  238. {
  239. static double mouse_scroll_y = 0;
  240. const double delta_y = 0.125*direction;
  241. mouse_scroll_y += delta_y;
  242. // absolute scale difference when changing zooms (+1)
  243. const double z_diff = 0.01;
  244. GLint viewport[4];
  245. glGetIntegerv(GL_VIEWPORT,viewport);
  246. if(TwMouseMotion(mouse_x, viewport[3] - mouse_y))
  247. {
  248. TwMouseWheel(mouse_scroll_y);
  249. }else
  250. {
  251. auto & camera = s.cameras[s.viewing_camera];
  252. camera.dolly(double(direction)*z_diff);
  253. //const double min_zoom = 0.01;
  254. //const double max_zoom = 10.0;
  255. //s.camera.zoom = min(max_zoom,max(min_zoom,s.camera.zoom));
  256. }
  257. }else
  258. {
  259. }
  260. }
  261. void mouse(int glutButton, int glutState, int mouse_x, int mouse_y)
  262. {
  263. using namespace std;
  264. using namespace Eigen;
  265. using namespace igl;
  266. bool tw_using = TwEventMouseButtonGLUT(glutButton,glutState,mouse_x,mouse_y);
  267. switch(glutButton)
  268. {
  269. case GLUT_RIGHT_BUTTON:
  270. case GLUT_LEFT_BUTTON:
  271. {
  272. switch(glutState)
  273. {
  274. case 1:
  275. // up
  276. glutSetCursor(GLUT_CURSOR_INHERIT);
  277. is_rotating = false;
  278. break;
  279. case 0:
  280. if(!tw_using)
  281. {
  282. push_undo();
  283. glutSetCursor(GLUT_CURSOR_CYCLE);
  284. // collect information for trackball
  285. is_rotating = true;
  286. down_camera = s.cameras[s.viewing_camera];
  287. down_x = mouse_x;
  288. down_y = mouse_y;
  289. }
  290. break;
  291. }
  292. break;
  293. // Scroll down
  294. case GLUT_WHEEL_DOWN:
  295. {
  296. mouse_wheel(0,-1,mouse_x,mouse_y);
  297. break;
  298. }
  299. // Scroll up
  300. case GLUT_WHEEL_UP:
  301. {
  302. mouse_wheel(0,1,mouse_x,mouse_y);
  303. break;
  304. }
  305. // Scroll left
  306. case GLUT_WHEEL_LEFT:
  307. {
  308. mouse_wheel(1,-1,mouse_x,mouse_y);
  309. break;
  310. }
  311. // Scroll right
  312. case GLUT_WHEEL_RIGHT:
  313. {
  314. mouse_wheel(1,1,mouse_x,mouse_y);
  315. break;
  316. }
  317. }
  318. }
  319. }
  320. void mouse_drag(int mouse_x, int mouse_y)
  321. {
  322. using namespace igl;
  323. using namespace std;
  324. using namespace Eigen;
  325. /*bool tw_using =*/ TwMouseMotion(mouse_x,mouse_y);
  326. if(is_rotating)
  327. {
  328. glutSetCursor(GLUT_CURSOR_CYCLE);
  329. auto & camera = s.cameras[s.viewing_camera];
  330. switch(rotation_type)
  331. {
  332. case ROTATION_TYPE_IGL_TRACKBALL:
  333. {
  334. // Rotate according to trackball
  335. igl::trackball<double>(
  336. width,
  337. height,
  338. 2.0,
  339. down_camera.m_rotation.coeffs().data(),
  340. down_x,
  341. down_y,
  342. mouse_x,
  343. mouse_y,
  344. camera.m_rotation.coeffs().data());
  345. break;
  346. }
  347. case ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP:
  348. {
  349. Quaterniond down_q = down_camera.m_rotation;
  350. Vector3d axis(0,1,0);
  351. const double speed = 2.0;
  352. Quaterniond q;
  353. q = down_q *
  354. Quaterniond(
  355. AngleAxisd(
  356. M_PI*((double)(mouse_x-down_x))/(double)width*speed/2.0,
  357. axis.normalized()));
  358. q.normalize();
  359. {
  360. Vector3d axis(1,0,0);
  361. const double speed = 2.0;
  362. if(axis.norm() != 0)
  363. {
  364. q =
  365. Quaterniond(
  366. AngleAxisd(
  367. M_PI*(mouse_y-down_y)/(double)width*speed/2.0,
  368. axis.normalized())) * q;
  369. q.normalize();
  370. }
  371. }
  372. camera.m_rotation = q;
  373. break;
  374. }
  375. default:
  376. break;
  377. }
  378. const bool orbit = true;
  379. if(orbit)
  380. {
  381. // at should be fixed
  382. // Undo rotation from translation part: translation along view (from
  383. // `at`)
  384. Vector3d t = down_camera.m_rotation * down_camera.m_translation;
  385. // Rotate to match new rotation
  386. camera.m_translation = camera.m_rotation * t;
  387. //assert((down_camera.at() - camera.at()).squaredNorm() < DOUBLE_EPS);
  388. }else
  389. {
  390. // eye should be fixed
  391. // flip rotation?
  392. }
  393. }
  394. }
  395. void key(unsigned char key, int mouse_x, int mouse_y)
  396. {
  397. using namespace std;
  398. int mod = glutGetModifiers();
  399. switch(key)
  400. {
  401. // ESC
  402. case char(27):
  403. rebar.save(REBAR_NAME);
  404. // ^C
  405. case char(3):
  406. exit(0);
  407. case 'z':
  408. case 'Z':
  409. if(mod & GLUT_ACTIVE_COMMAND)
  410. {
  411. if(mod & GLUT_ACTIVE_SHIFT)
  412. {
  413. redo();
  414. }else
  415. {
  416. undo();
  417. }
  418. break;
  419. }
  420. default:
  421. if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y))
  422. {
  423. cout<<"Unknown key command: "<<key<<" "<<int(key)<<endl;
  424. }
  425. }
  426. }
  427. int main(int argc, char * argv[])
  428. {
  429. using namespace std;
  430. using namespace Eigen;
  431. using namespace igl;
  432. // print key commands
  433. cout<<"[Command+Z] Undo."<<endl;
  434. cout<<"[Shift+Command+Z] Redo."<<endl;
  435. cout<<"[^C,ESC] Exit."<<endl;
  436. // Init glut
  437. glutInit(&argc,argv);
  438. if( !TwInit(TW_OPENGL, NULL) )
  439. {
  440. // A fatal error occured
  441. fprintf(stderr, "AntTweakBar initialization failed: %s\n", TwGetLastError());
  442. return 1;
  443. }
  444. // Create a tweak bar
  445. rebar.TwNewBar("bar");
  446. TwDefine("bar label='camera' size='200 550' text=light alpha='200' color='68 68 68'");
  447. rebar.load(REBAR_NAME);
  448. init_cameras();
  449. // Init antweakbar
  450. glutInitDisplayString( "rgba depth double samples>=8");
  451. // Top right corner
  452. glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT)/2.0);
  453. glutInitWindowPosition(glutGet(GLUT_SCREEN_WIDTH)/2.0,-1);
  454. glutCreateWindow("camera");
  455. glutDisplayFunc(display);
  456. glutReshapeFunc(reshape);
  457. glutKeyboardFunc(key);
  458. glutMouseFunc(mouse);
  459. glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
  460. glutMotionFunc(mouse_drag);
  461. glutMainLoop();
  462. return 0;
  463. }