David Rose 13 лет назад
Родитель
Сommit
85014ba179
3 измененных файлов с 129 добавлено и 44 удалено
  1. 104 24
      panda/src/grutil/pfmVizzer.cxx
  2. 4 0
      panda/src/grutil/pfmVizzer.h
  3. 21 20
      panda/src/pnmimage/pfmFile.cxx

+ 104 - 24
panda/src/grutil/pfmVizzer.cxx

@@ -105,10 +105,10 @@ extrude(const Lens *lens) {
     // 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() - 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() - 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) {
@@ -116,8 +116,8 @@ extrude(const Lens *lens) {
           continue;
         }
         LPoint3 p;
-        p.set((PN_stdfloat)xi * uv_scale[0],
-              (PN_stdfloat)yi * uv_scale[1],
+        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);
@@ -221,10 +221,10 @@ generate_vis_points() const {
 
   LPoint2f uv_scale(1.0, 1.0);
   if (_pfm.get_x_size() > 1) {
-    uv_scale[0] = 1.0f / PN_float32(_pfm.get_x_size() - 1);
+    uv_scale[0] = 1.0f / PN_float32(_pfm.get_x_size());
   }
   if (_pfm.get_y_size() > 1) {
-    uv_scale[1] = 1.0f / PN_float32(_pfm.get_y_size() - 1);
+    uv_scale[1] = 1.0f / PN_float32(_pfm.get_y_size());
   }
 
   int num_points = 0;
@@ -235,8 +235,8 @@ generate_vis_points() const {
       }
 
       const LPoint3f &point = _pfm.get_point(xi, yi);
-      LPoint2f uv(PN_float32(xi) * uv_scale[0],
-                  PN_float32(yi) * uv_scale[1]);
+      LPoint2f uv((PN_float32(xi) + 0.5) * uv_scale[0],
+                  (PN_float32(yi) + 0.5) * uv_scale[1]);
       if (_vis_inverse) {
         vertex.add_data2f(uv);
         texcoord.add_data3f(point);
@@ -306,7 +306,7 @@ generate_vis_mesh(MeshFace face) const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmVizzer::calc_max_u_displacement
-//       Access: Private
+//       Access: Published
 //  Description: Computes the maximum amount of shift, in pixels
 //               either left or right, of any pixel in the distortion
 //               map.  This can be passed to make_displacement(); see
@@ -326,7 +326,7 @@ calc_max_u_displacement() const {
       }
 
       const LPoint3f &point = _pfm.get_point(xi, yi);
-      double nxi = point[0] * (double)(x_size - 1);
+      double nxi = point[0] * (double)x_size - 0.5;
 
       max_u = max(max_u, cabs(nxi - (double)xi));
     }
@@ -337,7 +337,7 @@ calc_max_u_displacement() const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmVizzer::calc_max_v_displacement
-//       Access: Private
+//       Access: Published
 //  Description: Computes the maximum amount of shift, in pixels
 //               either up or down, of any pixel in the distortion
 //               map.  This can be passed to make_displacement(); see
@@ -357,7 +357,7 @@ calc_max_v_displacement() const {
       }
 
       const LPoint3f &point = _pfm.get_point(xi, yi);
-      double nyi = point[1] * (double)(y_size - 1);
+      double nyi = point[1] * (double)y_size - 0.5;
 
       max_v = max(max_v, cabs(nyi - (double)yi));
     }
@@ -368,7 +368,7 @@ calc_max_v_displacement() const {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmVizzer::make_displacement
-//       Access: Private
+//       Access: Published
 //  Description: Assuming the underlying PfmFile is a 2-d distortion
 //               mesh, with the U and V in the first two components
 //               and the third component unused, this computes an
@@ -389,7 +389,17 @@ make_displacement(PNMImage &result, double max_u, double max_v) const {
   int x_size = _pfm.get_x_size();
   int y_size = _pfm.get_y_size();
   result.clear(x_size, y_size, 3, PNM_MAXMAXVAL);
-  result.fill(0.5);
+  result.fill_val(0, 0, PNM_MAXMAXVAL);
+
+  // After Effects defines this as the zero (no-change) value.  It's
+  // not exactly 0.5, because they round up.
+  static const int midval = (PNM_MAXMAXVAL + 1) / 2;
+
+  // After Effects seems to always undershift by exactly this amount.
+  static const double scale_factor = 256.0 / 255.0;
+
+  double u_scale = scale_factor * 0.5 * (PNM_MAXMAXVAL - 1) / max_u;
+  double v_scale = scale_factor * 0.5 * (PNM_MAXMAXVAL - 1) / max_v;
 
   for (int yi = 0; yi < y_size; ++yi) {
     for (int xi = 0; xi < x_size; ++xi) {
@@ -398,16 +408,86 @@ make_displacement(PNMImage &result, double max_u, double max_v) const {
       }
 
       const LPoint3f &point = _pfm.get_point(xi, yi);
-      double nxi = point[0] * (double)(x_size - 1);
-      double nyi = point[1] * (double)(y_size - 1);
+      double nxi = point[0] * (double)x_size - 0.5;
+      double nyi = point[1] * (double)y_size - 0.5;
+
+      double x_shift = (nxi - (double)xi);
+      double y_shift = (nyi - (double)yi);
 
-      double u_shift = (nxi - (double)xi) / max_u;
-      double v_shift = (nyi - (double)yi) / max_v;
+      int u_val = midval + (int)cfloor(x_shift * u_scale + 0.5);
+      int v_val = midval + (int)cfloor(y_shift * v_scale + 0.5);
 
-      result.set_red(xi, yi, u_shift * 0.5 + 0.5);
-      result.set_green(xi, yi, v_shift * 0.5 + 0.5);
+      // We use the blue channel to mark holes, so we can fill them in
+      // later.
+      result.set_xel_val(xi, yi, u_val, v_val, 0);
     }
   }
+
+  // Now fill in holes.
+  for (int yi = 0; yi < y_size; ++yi) {
+    for (int xi = 0; xi < x_size; ++xi) {
+      if (!_pfm.has_point(xi, yi)) {
+        continue;
+      }
+
+      const LPoint3f &point = _pfm.get_point(xi, yi);
+      double nxi = point[0] * (double)x_size - 0.5;
+      double nyi = point[1] * (double)y_size - 0.5;
+
+      r_fill_displacement(result, xi - 1, yi, nxi, nyi, u_scale, v_scale, 1);
+      r_fill_displacement(result, xi + 1, yi, nxi, nyi, u_scale, v_scale, 1);
+      r_fill_displacement(result, xi, yi - 1, nxi, nyi, u_scale, v_scale, 1);
+      r_fill_displacement(result, xi, yi + 1, nxi, nyi, u_scale, v_scale, 1);
+    }
+  }
+
+  // Finally, reset the blue channel for cleanliness.
+  for (int yi = 0; yi < y_size; ++yi) {
+    for (int xi = 0; xi < x_size; ++xi) {
+      result.set_blue_val(xi, yi, midval);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PfmVizzer::r_fill_displacement
+//       Access: Private
+//  Description: Recursively fills in holes with the color of their
+//               nearest neighbor after processing the image.  This
+//               avoids sudden discontinuities in the displacement map
+//               at the edge of the screen geometry.
+////////////////////////////////////////////////////////////////////
+void PfmVizzer::
+r_fill_displacement(PNMImage &result, int xi, int yi, 
+                    double nxi, double nyi, double u_scale, double v_scale,
+                    int distance) const {
+  if (xi < 0 || yi < 0 ||
+      xi >= result.get_x_size() || yi >= result.get_y_size()) {
+    // Stop at the edge.
+    return;
+  }
+
+  if (distance > 1000) {
+    // Avoid runaway recursion.
+    return;
+  }
+
+  int val = result.get_blue_val(xi, yi);
+  if (val > distance) {
+    // We've found a point that's closer.
+    static const int midval = (PNM_MAXMAXVAL + 1) / 2;
+
+    double x_shift = (nxi - (double)xi);
+    double y_shift = (nyi - (double)yi);
+    int u_val = midval + (int)cfloor(x_shift * u_scale + 0.5);
+    int v_val = midval + (int)cfloor(y_shift * v_scale + 0.5);
+    result.set_xel_val(xi, yi, u_val, v_val, distance);
+
+    r_fill_displacement(result, xi - 1, yi, nxi, nyi, u_scale, v_scale, distance + 1);
+    r_fill_displacement(result, xi + 1, yi, nxi, nyi, u_scale, v_scale, distance + 1);
+    r_fill_displacement(result, xi, yi - 1, nxi, nyi, u_scale, v_scale, distance + 1);
+    r_fill_displacement(result, xi, yi + 1, nxi, nyi, u_scale, v_scale, distance + 1);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -710,8 +790,8 @@ add_data(const PfmVizzer &vizzer, GeomVertexWriter &vwriter, int xi, int yi, boo
   switch (_source) {
   case CT_texcoord2:
     { 
-      LPoint2f uv(PN_float32(xi) / PN_float32(pfm.get_x_size() - 1),
-                  PN_float32(yi) / PN_float32(pfm.get_y_size() - 1));
+      LPoint2f uv((PN_float32(xi) + 0.5) / PN_float32(pfm.get_x_size()),
+                  (PN_float32(yi) + 0.5) / PN_float32(pfm.get_y_size()));
       transform_point(uv);
       vwriter.set_data2f(uv);
     }
@@ -719,8 +799,8 @@ add_data(const PfmVizzer &vizzer, GeomVertexWriter &vwriter, int xi, int yi, boo
 
   case CT_texcoord3:
     {
-      LPoint3f uv(PN_float32(xi) / PN_float32(pfm.get_x_size() - 1),
-                  PN_float32(yi) / PN_float32(pfm.get_y_size() - 1), 
+      LPoint3f uv((PN_float32(xi) + 0.5) / PN_float32(pfm.get_x_size()),
+                  (PN_float32(yi) + 0.5) / PN_float32(pfm.get_y_size()), 
                   0.0f);
       transform_point(uv);
       vwriter.set_data3f(uv);

+ 4 - 0
panda/src/grutil/pfmVizzer.h

@@ -79,6 +79,10 @@ PUBLISHED:
   BLOCKING void make_displacement(PNMImage &result, double max_u, double max_v) const;
 
 private:
+  void r_fill_displacement(PNMImage &result, int xi, int yi, 
+                           double nxi, double nyi, double u_scale, double v_scale,
+                           int distance) const;
+
   void make_vis_mesh_geom(GeomNode *gnode, bool inverted) const;
 
 

+ 21 - 20
panda/src/pnmimage/pfmFile.cxx

@@ -748,10 +748,10 @@ resize(int new_x_size, int new_y_size) {
   PN_float32 y_scale = 1.0;
 
   if (new_x_size > 1) {
-    x_scale = (PN_float32)(_x_size - 1) / (PN_float32)(new_x_size - 1);
+    x_scale = (PN_float32)_x_size / (PN_float32)new_x_size;
   }
   if (new_y_size > 1) {
-    y_scale = (PN_float32)(_y_size - 1) / (PN_float32)(new_y_size - 1);
+    y_scale = (PN_float32)_y_size / (PN_float32)new_y_size;
   }
 
   switch (_num_channels) {
@@ -759,12 +759,12 @@ resize(int new_x_size, int new_y_size) {
     {
       from_y0 = 0.0;
       for (int to_y = 0; to_y < new_y_size; ++to_y) {
-        from_y1 = (to_y + 0.5) * y_scale;
+        from_y1 = (to_y + 1.0) * y_scale;
         from_y1 = min(from_y1, (PN_float32) _y_size);
         
         from_x0 = 0.0;
         for (int to_x = 0; to_x < new_x_size; ++to_x) {
-          from_x1 = (to_x + 0.5) * x_scale;
+          from_x1 = (to_x + 1.0) * x_scale;
           from_x1 = min(from_x1, (PN_float32) _x_size);
           
           // Now the box from (from_x0, from_y0) - (from_x1, from_y1)
@@ -784,12 +784,12 @@ resize(int new_x_size, int new_y_size) {
     {
       from_y0 = 0.0;
       for (int to_y = 0; to_y < new_y_size; ++to_y) {
-        from_y1 = (to_y + 0.5) * y_scale;
+        from_y1 = (to_y + 1.0) * y_scale;
         from_y1 = min(from_y1, (PN_float32) _y_size);
         
         from_x0 = 0.0;
         for (int to_x = 0; to_x < new_x_size; ++to_x) {
-          from_x1 = (to_x + 0.5) * x_scale;
+          from_x1 = (to_x + 1.0) * x_scale;
           from_x1 = min(from_x1, (PN_float32) _x_size);
           
           // Now the box from (from_x0, from_y0) - (from_x1, from_y1)
@@ -811,12 +811,12 @@ resize(int new_x_size, int new_y_size) {
     {
       from_y0 = 0.0;
       for (int to_y = 0; to_y < new_y_size; ++to_y) {
-        from_y1 = (to_y + 0.5) * y_scale;
+        from_y1 = (to_y + 1.0) * y_scale;
         from_y1 = min(from_y1, (PN_float32) _y_size);
         
         from_x0 = 0.0;
         for (int to_x = 0; to_x < new_x_size; ++to_x) {
-          from_x1 = (to_x + 0.5) * x_scale;
+          from_x1 = (to_x + 1.0) * x_scale;
           from_x1 = min(from_x1, (PN_float32) _x_size);
           
           // Now the box from (from_x0, from_y0) - (from_x1, from_y1)
@@ -956,7 +956,7 @@ xform(const LMatrix4f &transform) {
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::forward_distort
 //       Access: Published
-//  Description: Applys the distortion indicated in the supplied dist
+//  Description: Applies the distortion indicated in the supplied dist
 //               map to the current map.  The dist map is understood
 //               to be a mapping of points in the range 0..1 in the
 //               first two dimensions.  Each (u,v) point in the
@@ -994,8 +994,8 @@ forward_distort(const PfmFile &dist) {
         continue;
       }
       LPoint2f uv = dist_p->get_point2(xi, yi);
-      int dist_xi = int(uv[0] * (_x_size - 1));
-      int dist_yi = int(uv[1] * (_y_size - 1));
+      int dist_xi = (int)cfloor(uv[0] * (double)_x_size);
+      int dist_yi = (int)cfloor(uv[0] * (double)_y_size);
       if (dist_xi < 0 || dist_xi >= _x_size || 
           dist_yi < 0 || dist_yi >= _y_size) {
         continue;
@@ -1015,7 +1015,7 @@ forward_distort(const PfmFile &dist) {
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmFile::reverse_distort
 //       Access: Published
-//  Description: Applys the distortion indicated in the supplied dist
+//  Description: Applies the distortion indicated in the supplied dist
 //               map to the current map.  The dist map is understood
 //               to be a mapping of points in the range 0..1 in the
 //               first two dimensions.  Each (x,y) point in the
@@ -1055,8 +1055,8 @@ reverse_distort(const PfmFile &dist) {
         continue;
       }
       LPoint2f uv = dist_p->get_point2(xi, yi);
-      int dist_xi = int(uv[0] * (_x_size - 1));
-      int dist_yi = int(uv[1] * (_y_size - 1));
+      int dist_xi = (int)cfloor(uv[0] * (double)_x_size);
+      int dist_yi = (int)cfloor(uv[0] * (double)_y_size);
       if (dist_xi < 0 || dist_xi >= _x_size || 
           dist_yi < 0 || dist_yi >= _y_size) {
         continue;
@@ -1163,17 +1163,18 @@ clear_to_texcoords(int x_size, int y_size) {
   clear(x_size, y_size, 3);
 
   LPoint2f uv_scale(1.0, 1.0);
-  if (_x_size > 1) {
-    uv_scale[0] = 1.0f / PN_float32(_x_size - 1);
+  if (_x_size > 0) {
+    uv_scale[0] = 1.0f / PN_float32(_x_size);
   }
-  if (_y_size > 1) {
-    uv_scale[1] = 1.0f / PN_float32(_y_size - 1);
+  if (_y_size > 0) {
+    uv_scale[1] = 1.0f / PN_float32(_y_size);
   }
 
   for (int yi = 0; yi < _y_size; ++yi) {
     for (int xi = 0; xi < _x_size; ++xi) {
-      LPoint3f uv(PN_float32(xi) * uv_scale[0],
-                  PN_float32(yi) * uv_scale[1], 0.0f);
+      LPoint3f uv(PN_float32(xi) * uv_scale[0] + 0.5,
+                  PN_float32(yi) * uv_scale[1] + 0.5, 
+                  0.0f);
       set_point(xi, yi, uv);
     }
   }