Browse Source

support 32-bit as well as 16-bit AE displacement maps

David Rose 11 years ago
parent
commit
a0fa038ec4

+ 9 - 3
panda/src/grutil/config_grutil.cxx

@@ -90,10 +90,16 @@ ConfigVariableInt pfm_vis_max_indices
           "a single generated mesh.  If the mesh would require more than that, "
           "the mesh is subdivided into smaller pieces."));
 
-ConfigVariableDouble ae_undershift_factor
-("ae-undershift-factor", 1.004,
+ConfigVariableDouble ae_undershift_factor_16
+("ae-undershift-factor-16", 1.004,
  PRC_DESC("Specifies the factor by which After Effects under-applies the specified "
-          "maximum pixel shift when applying a displacement map.  This is used "
+          "maximum pixel shift when applying a displacement map, in a 16-bit project file.  This is used "
+          "to control PfmVizzer::make_displacement()."));
+
+ConfigVariableDouble ae_undershift_factor_32
+("ae-undershift-factor-32", 1.0,
+ PRC_DESC("Specifies the factor by which After Effects under-applies the specified "
+          "maximum pixel shift when applying a displacement map, in a 32-bit project file.  This is used "
           "to control PfmVizzer::make_displacement()."));
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 1
panda/src/grutil/config_grutil.h

@@ -42,7 +42,8 @@ extern ConfigVariableBool movies_sync_pages;
 extern ConfigVariableInt pfm_vis_max_vertices;
 extern ConfigVariableInt pfm_vis_max_indices;
 
-extern ConfigVariableDouble ae_undershift_factor;
+extern ConfigVariableDouble ae_undershift_factor_16;
+extern ConfigVariableDouble ae_undershift_factor_32;
 
 extern EXPCL_PANDA_GRUTIL void init_libgrutil();
 

+ 157 - 5
panda/src/grutil/pfmVizzer.cxx

@@ -450,9 +450,17 @@ calc_max_v_displacement() const {
 //               Use calc_max_u_displacement() and
 //               calc_max_v_displacement() to compute suitable values
 //               for max_u and max_v.
+//
+//               This generates an integer 16-bit displacement image.
+//               It is a good idea, though not necessarily essential,
+//               to check "Preserve RGB" in the interpret footage
+//               section for each displacement image.  Set
+//               for_32bit true if this is meant to be used in a
+//               32-bit project file, and false if it is meant to be
+//               used in a 16-bit project file.
 ////////////////////////////////////////////////////////////////////
 void PfmVizzer::
-make_displacement(PNMImage &result, double max_u, double max_v) const {
+make_displacement(PNMImage &result, double max_u, double max_v, bool for_32bit) const {
   int x_size = _pfm.get_x_size();
   int y_size = _pfm.get_y_size();
   result.clear(x_size, y_size, 3, PNM_MAXMAXVAL);
@@ -462,10 +470,19 @@ make_displacement(PNMImage &result, double max_u, double max_v) const {
   // not exactly 0.5, because they round up.
   static const int midval = (PNM_MAXMAXVAL + 1) / 2;
 
-  // Empirically, After Effects seems to undershift by precisely this
-  // amount.  Curiously, this value is very close to, but not exactly,
-  // 256 / 255.
-  const double scale_factor = ae_undershift_factor;
+  double scale_factor;
+  if (for_32bit) {
+    // There doesn't appear to be an undershift needed on 32-bit
+    // projects, but we have the factor here anyway in case it
+    // develops.
+    scale_factor = ae_undershift_factor_32;
+  } else {
+    // Empirically, After Effects seems to undershift by precisely
+    // this amount (but only in a 16-bit project, not in a 32-bit
+    // project).  Curiously, this value is very close to, but not
+    // exactly, 256 / 255.
+    scale_factor = ae_undershift_factor_16;
+  }
 
   double u_scale = scale_factor * 0.5 * PNM_MAXMAXVAL / max_u;
   double v_scale = scale_factor * 0.5 * PNM_MAXMAXVAL / max_v;
@@ -521,6 +538,102 @@ make_displacement(PNMImage &result, double max_u, double max_v) const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PfmVizzer::make_displacement
+//       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
+//               AfterEffects-style displacement map that represents
+//               the same distortion.  The indicated PNMImage will be
+//               filled in with a displacement map image, with
+//               horizontal shift in the red channel and vertical
+//               shift in the green channel, where a fully bright (or
+//               fully black) pixel indicates a shift of max_u or
+//               max_v pixels.
+//
+//               Use calc_max_u_displacement() and
+//               calc_max_v_displacement() to compute suitable values
+//               for max_u and max_v.
+//
+//               This generates a 32-bit floating-point displacement
+//               image.  It is essential to check "Preserve RGB" in
+//               the interpret footage section for each displacement
+//               image.  Set for_32bit true if this is meant to
+//               be used in a 32-bit project file, and false if it is
+//               meant to be used in a 16-bit project file.
+////////////////////////////////////////////////////////////////////
+void PfmVizzer::
+make_displacement(PfmFile &result, double max_u, double max_v, bool for_32bit) const {
+  int x_size = _pfm.get_x_size();
+  int y_size = _pfm.get_y_size();
+  result.clear(x_size, y_size, 3);
+
+  double scale_factor;
+  if (for_32bit) {
+    // There doesn't appear to be an undershift needed on 32-bit
+    // projects, but we have the factor here anyway in case it
+    // develops.
+    scale_factor = ae_undershift_factor_32;
+  } else {
+    // Empirically, After Effects seems to undershift by precisely
+    // this amount (but only in a 16-bit project, not in a 32-bit
+    // project).  Curiously, this value is very close to, but not
+    // exactly, 256 / 255.
+    scale_factor = ae_undershift_factor_16;
+  }
+
+  double u_scale = scale_factor * 0.5 / max_u;
+  double v_scale = scale_factor * 0.5 / max_v;
+
+  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;
+
+      double x_shift = (nxi - (double)xi);
+      double y_shift = (nyi - (double)yi);
+
+      float u_val = 0.5 + (float)(x_shift * u_scale);
+      float v_val = 0.5 + (float)(y_shift * v_scale);
+
+      // We use the blue channel to mark holes, so we can fill them in
+      // later.
+      result.set_point3(xi, yi, LVecBase3f(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_channel(xi, yi, 2, 0.5);
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmVizzer::uses_aux_pfm
 //       Access: Private
@@ -590,6 +703,45 @@ r_fill_displacement(PNMImage &result, int xi, int yi,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     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(PfmFile &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;
+  }
+
+  float val = result.get_channel(xi, yi, 2);
+  if (val > (float)distance) {
+    // We've found a point that's closer.
+    double x_shift = (nxi - (double)xi);
+    double y_shift = (nyi - (double)yi);
+    float u_val = 0.5 + (float)(x_shift * u_scale);
+    float v_val = 0.5 + (float)(y_shift * v_scale);
+    result.set_point3(xi, yi, LVecBase3f(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);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PfmVizzer::make_vis_mesh_geom
 //       Access: Private

+ 5 - 1
panda/src/grutil/pfmVizzer.h

@@ -86,13 +86,17 @@ PUBLISHED:
 
   BLOCKING double calc_max_u_displacement() const;
   BLOCKING double calc_max_v_displacement() const;
-  BLOCKING void make_displacement(PNMImage &result, double max_u, double max_v) const;
+  BLOCKING void make_displacement(PNMImage &result, double max_u, double max_v, bool for_32bit) const;
+  BLOCKING void make_displacement(PfmFile &result, double max_u, double max_v, bool for_32bit) const;
 
 private:
   bool uses_aux_pfm() const;
   void r_fill_displacement(PNMImage &result, int xi, int yi, 
                            double nxi, double nyi, double u_scale, double v_scale,
                            int distance) const;
+  void r_fill_displacement(PfmFile &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;