Kaynağa Gözat

define Lens::extrude_depth() to reverse Lens::project(), and use this in PfmVizzer

David Rose 13 yıl önce
ebeveyn
işleme
eefb99cbc5

+ 5 - 2
panda/src/distort/cylindricalLens.cxx

@@ -149,6 +149,9 @@ do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point
 
   PN_stdfloat focal_length = do_get_focal_length(lens_cdata);
 
+  // Compute the depth as a linear distance in the range 0 .. 1.
+  PN_stdfloat z = (pdist - do_get_near(lens_cdata)) / (do_get_far(lens_cdata) - do_get_near(lens_cdata));
+
   point2d.set
     (
      // The x position is the angle about the Z axis.
@@ -156,8 +159,8 @@ do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point
      // The y position is the Z height divided by the perspective
      // distance.
      p[2] * focal_length / pdist,
-     // Z is the perspective distance scaled into the range (1, -1).
-     (do_get_near(lens_cdata) - pdist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata))
+     // Z is the distance scaled into the range 1 .. -1.
+     1.0 - 2.0 * z
      );
 
   // Now we have to transform the point according to the film

+ 5 - 2
panda/src/distort/fisheyeLens.cxx

@@ -198,11 +198,14 @@ do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point
   PN_stdfloat focal_length = do_get_focal_length(lens_cdata);
   PN_stdfloat factor = r * focal_length / fisheye_k;
 
+  // Compute the depth as a linear distance in the range 0 .. 1.
+  PN_stdfloat z = (dist - do_get_near(lens_cdata)) / (do_get_far(lens_cdata) - do_get_near(lens_cdata));
+
   point2d.set
     (y[0] * factor,
      y[1] * factor,
-     // Z is the distance scaled into the range (1, -1).
-     (do_get_near(lens_cdata) - dist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata))
+     // Z is the distance scaled into the range 1 .. -1.
+     1.0 - 2.0 * z
      );
 
   // Now we have to transform the point according to the film

+ 5 - 2
panda/src/distort/oSphereLens.cxx

@@ -117,14 +117,17 @@ do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point
   // into the XY plane to do this.
   LVector2 xy(v3[0], v3[1]);
 
+  // Compute the depth as a linear distance in the range 0 .. 1.
+  PN_stdfloat z = (dist - do_get_near(lens_cdata)) / (do_get_far(lens_cdata) - do_get_near(lens_cdata));
+
   point2d.set
     (
      // The x position is the angle about the Z axis.
      rad_2_deg(catan2(xy[0], xy[1])) * focal_length / ospherical_k,
      // The y position is the Z height.
      p[2],
-     // Z is the distance scaled into the range (1, -1).
-     (do_get_near(lens_cdata) - dist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata))
+     // Z is the distance scaled into the range 1 .. -1.
+     1.0 - 2.0 * z
      );
 
   // Now we have to transform the point according to the film

+ 5 - 2
panda/src/distort/pSphereLens.cxx

@@ -115,14 +115,17 @@ do_project(const Lens::CData *lens_cdata, const LPoint3 &point3d, LPoint3 &point
   xy.normalize();
   LVector2d yz(v3[0]*xy[0] + v3[1]*xy[1], v3[2]);
 
+  // Compute the depth as a linear distance in the range 0 .. 1.
+  PN_stdfloat z = (dist - do_get_near(lens_cdata)) / (do_get_far(lens_cdata) - do_get_near(lens_cdata));
+
   point2d.set
     (
      // The x position is the angle about the Z axis.
      rad_2_deg(catan2(xy[0], xy[1])) * focal_length / pspherical_k,
      // The y position is the angle about the X axis.
      rad_2_deg(catan2(yz[1], yz[0])) * focal_length / pspherical_k,
-     // Z is the distance scaled into the range (1, -1).
-     (do_get_near(lens_cdata) - dist) / (do_get_far(lens_cdata) - do_get_near(lens_cdata))
+     // Z is the distance scaled into the range 1 .. -1.
+     1.0 - 2.0 * z
      );
 
   // Now we have to transform the point according to the film

+ 26 - 19
panda/src/distort/projectionScreen.cxx

@@ -529,14 +529,14 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) {
   static const LMatrix4 lens_to_uv
     (0.5f, 0.0f, 0.0f, 0.0f,
      0.0f, 0.5f, 0.0f, 0.0f, 
-     0.0f, 0.0f, 0.5f, 0.0f, 
-     0.5f, 0.5f, 0.5f, 1.0f);
+     0.0f, 0.0f, 1.0f, 0.0f, 
+     0.5f, 0.5f, 0.0f, 1.0f);
 
   static const LMatrix4 lens_to_uv_inverted
     (0.5f, 0.0f, 0.0f, 0.0f,
      0.0f,-0.5f, 0.0f, 0.0f, 
-     0.0f, 0.0f, 0.5f, 0.0f, 
-     0.5f, 0.5f, 0.5f, 1.0f);
+     0.0f, 0.0f, 1.0f, 0.0f, 
+     0.5f, 0.5f, 0.0f, 1.0f);
 
   Thread *current_thread = Thread::get_current_thread();
 
@@ -546,8 +546,9 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) {
   const LMatrix4 &to_uv = _invert_uvs ? lens_to_uv_inverted : lens_to_uv;
 
   // Iterate through all the vertices in the Geom.
+  CPT(GeomVertexData) vdata = geom->get_vertex_data(current_thread);
+  vdata = vdata->animate_vertices(true, current_thread);
 
-  CPT(GeomVertexData) vdata = geom->get_vertex_data();
   CPT(GeomVertexFormat) vformat = vdata->get_format();
   if (!vformat->has_column(_texcoord_name) || (_texcoord_3d && vformat->get_column(_texcoord_name)->get_num_components() < 3)) {
     // We need to add a new column for the new texcoords.
@@ -582,12 +583,14 @@ recompute_geom(Geom *geom, const LMatrix4 &rel_mat) {
     LVertex vert = vertex.get_data3();
     
     // For each vertex, project to the film plane.
+    LPoint3 vert3d = vert * rel_mat;
     LPoint3 film(0.0f, 0.0f, 0.0f);
-    bool good = lens->project(vert * rel_mat, film);
+    bool good = lens->project(vert3d, film);
     
     // Now the lens gives us coordinates in the range [-1, 1].
     // Rescale these to [0, 1].
-    texcoord.set_data3(film * to_uv);
+    LPoint3 uvw = film * to_uv;
+    texcoord.set_data3(uvw);
     
     // If we have vignette color in effect, color the vertex according
     // to whether it fell in front of the lens or not.
@@ -615,17 +618,18 @@ make_mesh_node(PandaNode *result_parent, const WorkingNodePath &np,
                const NodePath &camera,
                LMatrix4 &rel_mat, bool &computed_rel_mat) {
   PandaNode *node = np.node();
-  if (!node->safe_to_flatten()) {
-    // If we can't safely flatten this node, ignore it (and all of its
-    // children) completely.  It's got no business being here anyway.
-    return NULL;
-  }
 
   PT(PandaNode) new_node;
   if (node->is_geom_node()) {
     new_node = make_mesh_geom_node(np, camera, rel_mat, computed_rel_mat);
-  } else {
+  } else if (node->safe_to_flatten()) {
     new_node = node->make_copy();
+    new_node->clear_transform();
+  } else {
+    // If we can't safely flatten the node, just make a plain node in
+    // its place.
+    new_node = new PandaNode(node->get_name());
+    new_node->set_state(node->get_state());
   }
 
   // Now attach the new node to the result.
@@ -666,9 +670,11 @@ make_mesh_children(PandaNode *new_node, const WorkingNodePath &np,
                                  rel_mat, computed_rel_mat);
     }
 
-    // Copy all of the render state (except TransformState) to the
-    // new arc.
-    new_child->set_state(child->get_state());
+    if (new_child != NULL) {
+      // Copy all of the render state (except TransformState) to the
+      // new arc.
+      new_child->set_state(child->get_state());
+    }
   }
 }
 
@@ -719,15 +725,16 @@ make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4 &rel_mat) {
   PT(Geom) new_geom = geom->make_copy();
 
   GeomVertexRewriter vertex(new_geom->modify_vertex_data(), 
-                              InternalName::get_vertex());
+                            InternalName::get_vertex());
   while (!vertex.is_at_end()) {
     LVertex vert = vertex.get_data3();
     
     // Project each vertex into the film plane, but use three
     // dimensions so the Z coordinate remains meaningful.
+    LPoint3 vert3d = vert * rel_mat;
     LPoint3 film(0.0f, 0.0f, 0.0f);
-    lens->project(vert * rel_mat, film);
-    
+    lens->project(vert3d, film);
+
     vertex.set_data3(film);
   }      
   

+ 15 - 0
panda/src/gobj/lens.I

@@ -58,6 +58,21 @@ extrude(const LPoint3 &point2d, LPoint3 &near_point, LPoint3 &far_point) const {
   return do_extrude(cdata, point2d, near_point, far_point);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::extrude_depth
+//       Access: Published
+//  Description: Uses the depth component of the 3-d result from
+//               project() to compute the original point in 3-d space
+//               corresponding to a particular point on the lens.
+//               This exactly reverses project(), assuming the point
+//               does fall legitimately within the lens.
+////////////////////////////////////////////////////////////////////
+INLINE bool Lens::
+extrude_depth(const LPoint3 &point2d, LPoint3 &point3d) const {
+  CDReader cdata(_cycler);
+  return do_extrude_depth(cdata, point2d, point3d);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Lens::extrude_vec
 //       Access: Published

+ 37 - 6
panda/src/gobj/lens.cxx

@@ -1242,6 +1242,37 @@ do_extrude(const CData *cdata,
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::do_extrude_depth
+//       Access: Protected, Virtual
+//  Description: This is the generic implementation, which is based on
+//               do_extrude() and assumes a linear distribution of
+//               depth values between the near and far points.
+////////////////////////////////////////////////////////////////////
+bool Lens::
+do_extrude_depth(const CData *cdata,
+                 const LPoint3 &point2d, LPoint3 &point3d) const {
+  LPoint3 near_point, far_point;
+  bool result = extrude(point2d, near_point, far_point);
+  point3d = near_point + (far_point - near_point) * point2d[2];
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::do_extrude_depth_with_mat
+//       Access: Protected
+//  Description: Implements do_extrude_depth() by using the projection
+//               matrix.  This is efficient, but works only for a
+//               linear (Perspective or Orthographic) lens.
+////////////////////////////////////////////////////////////////////
+bool Lens::
+do_extrude_depth_with_mat(const CData *cdata,
+                          const LPoint3 &point2d, LPoint3 &point3d) const {
+  const LMatrix4 &projection_mat_inv = do_get_projection_mat_inv(cdata);
+  point3d = projection_mat_inv.xform_point_general(point2d);
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Lens::do_extrude_vec
 //       Access: Protected, Virtual
@@ -1572,15 +1603,15 @@ do_compute_film_mat(CData *cdata) {
   PN_stdfloat scale_x = 2.0f / film_size[0];
   PN_stdfloat scale_y = 2.0f / film_size[1];
   cdata->_film_mat.set(scale_x,      0.0f,   0.0f,  0.0f,
-                   0.0f,   scale_y,   0.0f,  0.0f,
-                   0.0f,      0.0f,   1.0f,  0.0f,
-        -film_offset[0] * scale_x, -film_offset[1] * scale_y, 0.0f,  1.0f);
+                       0.0f,   scale_y,   0.0f,  0.0f,
+                       0.0f,      0.0f,   1.0f,  0.0f,
+                       -film_offset[0] * scale_x, -film_offset[1] * scale_y, 0.0f,  1.0f);
 
   if ((cdata->_user_flags & UF_keystone) != 0) {
     cdata->_film_mat = LMatrix4(1.0f, 0.0f, cdata->_keystone[0], cdata->_keystone[0],
-                          0.0f, 1.0f, cdata->_keystone[1], cdata->_keystone[1],
-                          0.0f, 0.0f, 1.0f, 0.0f,
-                          0.0f, 0.0f, 0.0f, 1.0f) * cdata->_film_mat;
+                                0.0f, 1.0f, cdata->_keystone[1], cdata->_keystone[1],
+                                0.0f, 0.0f, 1.0f, 0.0f,
+                                0.0f, 0.0f, 0.0f, 1.0f) * cdata->_film_mat;
   }
 
   do_adjust_comp_flags(cdata, CF_film_mat_inv, CF_film_mat);

+ 5 - 0
panda/src/gobj/lens.h

@@ -62,6 +62,7 @@ PUBLISHED:
                       LPoint3 &near_point, LPoint3 &far_point) const;
   INLINE bool extrude(const LPoint3 &point2d,
                       LPoint3 &near_point, LPoint3 &far_point) const;
+  INLINE bool extrude_depth(const LPoint3 &point2d, LPoint3 &point3d) const;
   INLINE bool extrude_vec(const LPoint2 &point2d, LVector3 &vec3d) const;
   INLINE bool extrude_vec(const LPoint3 &point2d, LVector3 &vec3d) const;
   INLINE bool project(const LPoint3 &point3d, LPoint3 &point2d) const;
@@ -216,6 +217,10 @@ protected:
 
   virtual bool do_extrude(const CData *cdata, const LPoint3 &point2d,
                           LPoint3 &near_point, LPoint3 &far_point) const;
+  virtual bool do_extrude_depth(const CData *cdata, const LPoint3 &point2d,
+                                LPoint3 &point3d) const;
+  bool do_extrude_depth_with_mat(const CData *cdata, const LPoint3 &point2d,
+                                 LPoint3 &point3d) const;
   virtual bool do_extrude_vec(const CData *cdata,
                               const LPoint3 &point2d, LVector3 &vec) const;
   virtual bool do_project(const CData *cdata,

+ 13 - 0
panda/src/gobj/orthographicLens.cxx

@@ -64,6 +64,19 @@ write(ostream &out, int indent_level) const {
   indent(out, indent_level) << get_type() << " film size = " << get_film_size() << "\n";
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: OrthographicLens::do_extrude_depth
+//       Access: Protected, Virtual
+//  Description: This is the generic implementation, which is based on
+//               do_extrude() and assumes a linear distribution of
+//               depth values between the near and far points.
+////////////////////////////////////////////////////////////////////
+bool OrthographicLens::
+do_extrude_depth(const CData *cdata,
+                 const LPoint3 &point2d, LPoint3 &point3d) const {
+  return do_extrude_depth_with_mat(cdata, point2d, point3d);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: OrthographicLens::do_compute_projection_mat
 //       Access: Protected, Virtual

+ 2 - 0
panda/src/gobj/orthographicLens.h

@@ -47,6 +47,8 @@ public:
   virtual void write(ostream &out, int indent_level = 0) const;
 
 protected:
+  virtual bool do_extrude_depth(const CData *cdata, const LPoint3 &point2d,
+                                LPoint3 &point3d) const;
   virtual void do_compute_projection_mat(Lens::CData *lens_cdata);
 
 public:

+ 13 - 0
panda/src/gobj/perspectiveLens.cxx

@@ -53,6 +53,19 @@ is_perspective() const {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PerspectiveLens::do_extrude_depth
+//       Access: Protected, Virtual
+//  Description: This is the generic implementation, which is based on
+//               do_extrude() and assumes a linear distribution of
+//               depth values between the near and far points.
+////////////////////////////////////////////////////////////////////
+bool PerspectiveLens::
+do_extrude_depth(const CData *cdata,
+                 const LPoint3 &point2d, LPoint3 &point3d) const {
+  return do_extrude_depth_with_mat(cdata, point2d, point3d);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PerspectiveLens::do_compute_projection_mat
 //       Access: Protected, Virtual

+ 2 - 0
panda/src/gobj/perspectiveLens.h

@@ -39,6 +39,8 @@ public:
   virtual bool is_perspective() const;
 
 protected:
+  virtual bool do_extrude_depth(const CData *cdata, const LPoint3 &point2d,
+                                LPoint3 &point3d) const;
   virtual void do_compute_projection_mat(Lens::CData *lens_cdata);
 
   virtual PN_stdfloat fov_to_film(PN_stdfloat fov, PN_stdfloat focal_length, bool horiz) const;

+ 84 - 36
panda/src/grutil/pfmVizzer.cxx

@@ -89,55 +89,103 @@ project(const Lens *lens) {
 void PfmVizzer::
 extrude(const Lens *lens) {
   nassertv(_pfm.is_valid());
-  nassertv(lens->is_linear());
 
   static LMatrix4 from_uv(2.0, 0.0, 0.0, 0.0,
                           0.0, 2.0, 0.0, 0.0,
-                          0.0, 0.0, 2.0, 0.0,
-                          -1.0, -1.0, -1.0, 1.0);
-  const LMatrix4 &proj_mat_inv = lens->get_projection_mat_inv();
+                          0.0, 0.0, 1.0, 0.0,
+                          -1.0, -1.0, 0.0, 1.0);
 
   PfmFile result;
   result.clear(_pfm.get_x_size(), _pfm.get_y_size(), 3);
   result.set_zero_special(true);
 
-  if (_pfm.get_num_channels() == 1) {
-    // Create an implicit UV coordinate for each point.
-    LPoint2 uv_scale(1.0, 1.0);
-    if (_pfm.get_x_size() > 1) {
-      uv_scale[0] = 1.0 / PN_stdfloat(_pfm.get_x_size());
-    }
-    if (_pfm.get_y_size() > 1) {
-      uv_scale[1] = 1.0 / PN_stdfloat(_pfm.get_y_size());
-    }
-    for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
-      for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
-        if (!_pfm.has_point(xi, yi)) {
-          continue;
+  if (lens->is_linear()) {
+    // If the lens is linear (Perspective or Orthographic), we can
+    // take the slightly faster approach of extruding all the points
+    // via a transform matrix.
+    const LMatrix4 &proj_mat_inv = lens->get_projection_mat_inv();
+
+    if (_pfm.get_num_channels() == 1) {
+      // Create an implicit UV coordinate for each point.
+      LPoint2 uv_scale(1.0, 1.0);
+      if (_pfm.get_x_size() > 1) {
+        uv_scale[0] = 1.0 / PN_stdfloat(_pfm.get_x_size());
+      }
+      if (_pfm.get_y_size() > 1) {
+        uv_scale[1] = 1.0 / PN_stdfloat(_pfm.get_y_size());
+      }
+      for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
+        for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
+          if (!_pfm.has_point(xi, yi)) {
+            continue;
+          }
+          LPoint3 p, rp;
+          p.set(((PN_stdfloat)xi + 0.5) * uv_scale[0],
+                ((PN_stdfloat)yi + 0.5) * uv_scale[1],
+                (PN_stdfloat)_pfm.get_point1(xi, yi));
+          
+          from_uv.xform_point_in_place(p);
+          rp = proj_mat_inv.xform_point_general(p);
+          result.set_point(xi, yi, rp);
+        }
+      }
+    } else {
+      // Use the existing UV coordinate for each point.
+      for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
+        for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
+          if (!_pfm.has_point(xi, yi)) {
+            continue;
+          }
+          LPoint3 p, rp;
+          p = LCAST(PN_stdfloat, _pfm.get_point(xi, yi));
+          
+          from_uv.xform_point_in_place(p);
+          rp = proj_mat_inv.xform_point_general(p);
+          result.set_point(xi, yi, rp);
         }
-        LPoint3 p;
-        p.set(((PN_stdfloat)xi + 0.5) * uv_scale[0],
-              ((PN_stdfloat)yi + 0.5) * uv_scale[1],
-              (PN_stdfloat)_pfm.get_point1(xi, yi));
-        
-        from_uv.xform_point_in_place(p);
-        proj_mat_inv.xform_point_general_in_place(p);
-        result.set_point(xi, yi, p);
       }
     }
   } else {
-    // Use the existing UV coordinate for each point.
-    for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
-      for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
-        if (!_pfm.has_point(xi, yi)) {
-          continue;
+    // If the lens is some non-linear specialty lens, we have to call
+    // Lens::extrude_depth() to correctly extrude each point.
+    if (_pfm.get_num_channels() == 1) {
+      // Create an implicit UV coordinate for each point.
+      LPoint2 uv_scale(1.0, 1.0);
+      if (_pfm.get_x_size() > 1) {
+        uv_scale[0] = 1.0 / PN_stdfloat(_pfm.get_x_size());
+      }
+      if (_pfm.get_y_size() > 1) {
+        uv_scale[1] = 1.0 / PN_stdfloat(_pfm.get_y_size());
+      }
+      for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
+        for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
+          if (!_pfm.has_point(xi, yi)) {
+            continue;
+          }
+          LPoint3 p, rp;
+          p.set(((PN_stdfloat)xi + 0.5) * uv_scale[0],
+                ((PN_stdfloat)yi + 0.5) * uv_scale[1],
+                (PN_stdfloat)_pfm.get_point1(xi, yi));
+          
+          from_uv.xform_point_in_place(p);
+          lens->extrude_depth(p, rp);
+          result.set_point(xi, yi, rp);
+        }
+      }
+    } else {
+      // Use the existing UV coordinate for each point.
+      for (int yi = 0; yi < _pfm.get_y_size(); ++yi) {
+        for (int xi = 0; xi < _pfm.get_x_size(); ++xi) {
+          if (!_pfm.has_point(xi, yi)) {
+            continue;
+          }
+          LPoint3 p, rp;
+          p = LCAST(PN_stdfloat, _pfm.get_point(xi, yi));
+          
+          from_uv.xform_point_in_place(p);
+          lens->extrude_depth(p, rp);
+          result.set_point(xi, yi, rp);
         }
-        LPoint3 p;
-        p = LCAST(PN_stdfloat, _pfm.get_point(xi, yi));
-        
-        from_uv.xform_point_in_place(p);
-        proj_mat_inv.xform_point_general_in_place(p);
-        result.set_point(xi, yi, p);
       }
     }
   }