Эх сурвалжийг харах

finally fixed dolly zoom/ortho in camera

Former-commit-id: efff5fa77c75968622bb2b4b7add5ca447f43c8f
Alec Jacobson 10 жил өмнө
parent
commit
9783ed1c5c

+ 12 - 26
examples/camera/example.cpp

@@ -229,26 +229,6 @@ void draw_scene(const igl::Camera & v_camera,
 
   glMatrixMode(GL_PROJECTION);
   glPushMatrix();
-  glLoadIdentity();
-  if(v_camera.m_angle > IGL_CAMERA_MIN_ANGLE)
-  {
-    gluPerspective(v_camera.m_angle,v_camera.m_aspect,v_camera.m_near,v_camera.m_far);
-  }else
-  {
-    glOrtho(
-      -0.5*v_camera.m_aspect,
-      0.5*v_camera.m_aspect,
-      -0.5,
-      0.5,
-      v_camera.m_near,
-      v_camera.m_far);
-  }
-  //{
-  //  Matrix4d m;
-  //  glGetDoublev(GL_PROJECTION_MATRIX,m.data());
-  //  cout<<matlab_format(m,"glu")<<endl;
-  //}
-
   glLoadIdentity();
   glMultMatrixd(v_camera.projection().data());
   //{
@@ -258,13 +238,13 @@ void draw_scene(const igl::Camera & v_camera,
   //}
   glMatrixMode(GL_MODELVIEW);
   glPushMatrix();
-  //glLoadIdentity();
-  //gluLookAt(
-  //  v_camera.eye()(0), v_camera.eye()(1), v_camera.eye()(2),
-  //  v_camera.at()(0), v_camera.at()(1), v_camera.at()(2),
-  //  v_camera.up()(0), v_camera.up()(1), v_camera.up()(2));
   glLoadIdentity();
-  glMultMatrixd(v_camera.inverse().matrix().data());
+  gluLookAt(
+    v_camera.eye()(0), v_camera.eye()(1), v_camera.eye()(2),
+    v_camera.at()(0), v_camera.at()(1), v_camera.at()(2),
+    v_camera.up()(0), v_camera.up()(1), v_camera.up()(2));
+  //glLoadIdentity();
+  //glMultMatrixd(v_camera.inverse().matrix().data());
 
 
   for(int c = 0;c<(int)s.cameras.size();c++)
@@ -609,6 +589,12 @@ void key(unsigned char key, int mouse_x, int mouse_y)
     // ^C
     case char(3):
       exit(0);
+    case 'o':
+    case 'O':
+      {
+        s.cameras[0].m_orthographic ^= true;
+        break;
+      }
     case 'z':
     case 'Z':
       if(mod & GLUT_ACTIVE_COMMAND)

+ 30 - 49
include/igl/Camera.h

@@ -35,21 +35,16 @@ namespace igl
       //  m_near  near clipping plane {1e-2}
       //  m_far  far clipping plane {100}
       //  m_at_dist  distance of looking at point {1}
+      //  m_orthographic  whether to use othrographic projection {false}
       //  m_rotation_conj  Conjugate of rotation part of rigid transformation of
       //    camera {identity}. Note: we purposefully store the conjugate because
       //    this is what TW_TYPE_QUAT4D is expecting.
       //  m_translation  Translation part of rigid transformation of camera
       //    {(0,0,1)}
       double m_angle, m_aspect, m_near, m_far, m_at_dist;
+      bool m_orthographic;
       Eigen::Quaterniond m_rotation_conj;
       Eigen::Vector3d m_translation;
-    private:
-      // m_at_dist_min_angle  m_at_dist from last time m_angle set to <= IGL_CAMERA_MIN_ANGLE
-      double m_at_dist_min_angle;
-      double m_angle_min_angle;
-    //  // m_last_positive_m_angle
-    //  // m_last_positive_m_angle_m_at_dist
-    //  double m_last_positive_m_angle,m_last_positive_m_angle_m_at_dist;
     public:
       inline Camera();
       inline virtual ~Camera(){}
@@ -154,10 +149,9 @@ namespace igl
 
 inline igl::Camera::Camera():
   m_angle(45.0),m_aspect(1),m_near(1e-2),m_far(100),m_at_dist(1),
+  m_orthographic(false),
   m_rotation_conj(1,0,0,0),
-  m_translation(0,0,1),
-  m_at_dist_min_angle(m_at_dist),
-  m_angle_min_angle(m_angle)
+  m_translation(0,0,1)
 {
 }
 
@@ -165,40 +159,36 @@ inline Eigen::Matrix4d igl::Camera::projection() const
 {
   Eigen::Matrix4d P;
   using namespace std;
+  const double far = m_at_dist + m_far;
+  const double near = m_near;
   // http://stackoverflow.com/a/3738696/148668
-  if(m_angle >= IGL_CAMERA_MIN_ANGLE)
-  {
-    const double yScale = tan(PI*0.5 - 0.5*m_angle*PI/180.);
-    // http://stackoverflow.com/a/14975139/148668
-    const double xScale = yScale/m_aspect;
-    const double far = m_at_dist + m_far;
-    const double near = m_near;
-    P<< 
-      xScale, 0, 0, 0,
-      0, yScale, 0, 0,
-      0, 0, -(far+near)/(far-near), -1,
-      0, 0, -2.*near*far/(far-near), 0;
-    P = P.transpose().eval();
-  }else
+  if(m_orthographic)
   {
     const double f = 0.5;
     const double left = -f*m_aspect;
     const double right = f*m_aspect;
     const double bottom = -f;
     const double top = f;
-    const double near = m_near;
-    const double far = m_at_dist + m_far;
     const double tx = (right+left)/(right-left);
     const double ty = (top+bottom)/(top-bottom);
     const double tz = (far+near)/(far-near);
-    const double z_fix = 
-      0.5/(m_at_dist_min_angle * tan(m_angle_min_angle/2./180.*M_PI))+
-      (-m_at_dist+m_at_dist_min_angle)/m_at_dist_min_angle;
+    const double z_fix = 0.5 /m_at_dist / tan(m_angle*0.5 * (M_PI/180.) );
     P<<
       z_fix*2./(right-left), 0, 0, -tx,
       0, z_fix*2./(top-bottom), 0, -ty,
       0, 0, -z_fix*2./(far-near),  -tz,
       0, 0, 0, 1;
+  }else
+  {
+    const double yScale = tan(PI*0.5 - 0.5*m_angle*PI/180.);
+    // http://stackoverflow.com/a/14975139/148668
+    const double xScale = yScale/m_aspect;
+    P<< 
+      xScale, 0, 0, 0,
+      0, yScale, 0, 0,
+      0, 0, -(far+near)/(far-near), -1,
+      0, 0, -2.*near*far/(far-near), 0;
+    P = P.transpose().eval();
   }
   return P;
 }
@@ -278,34 +268,25 @@ inline void igl::Camera::dolly_zoom(const double da)
   Vector3d old_at = at();
 #endif
   const double old_angle = m_angle;
-  m_angle += da;
-  m_angle = min(89.,max(0.,m_angle));
-  const double eff_angle = (IGL_CAMERA_MIN_ANGLE > m_angle ? IGL_CAMERA_MIN_ANGLE : m_angle);
-  if(old_angle >= IGL_CAMERA_MIN_ANGLE)
+  if(old_angle + da < IGL_CAMERA_MIN_ANGLE)
+  {
+    m_orthographic = true;
+  }else if(old_angle + da > IGL_CAMERA_MIN_ANGLE)
   {
+    m_orthographic = false;
+  }
+  if(!m_orthographic)
+  {
+    m_angle += da;
+    m_angle = min(89.,max(IGL_CAMERA_MIN_ANGLE,m_angle));
     // change in distance
     const double s = 
       (2.*tan(old_angle/2./180.*M_PI)) /
-      (2.*tan(eff_angle/2./180.*M_PI)) ;
+      (2.*tan(m_angle/2./180.*M_PI)) ;
     const double old_at_dist = m_at_dist;
     m_at_dist = old_at_dist * s;
     dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
-    if(eff_angle == IGL_CAMERA_MIN_ANGLE)
-    {
-      m_at_dist_min_angle = m_at_dist;
-      m_angle_min_angle = eff_angle;
-    }
     assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
-  }else if(old_angle < IGL_CAMERA_MIN_ANGLE && m_angle >= IGL_CAMERA_MIN_ANGLE)
-  {
-    // Restore decent length
-    const double z_fix = 
-      // There should be some factor here based on the incoming angle
-      // (m_angle_min_angle) and outgoing angle (m_angle)... For now I set it
-      // to 1. (assumes equality)
-      //0.5/(m_at_dist_min_angle * tan(m_angle_min_angle/2./180.*M_PI))+
-      1.+(-m_at_dist+m_at_dist_min_angle)/m_at_dist_min_angle;
-    m_at_dist = m_at_dist_min_angle / z_fix;
   }
 }