Browse Source

Correct scaling of normals during flatten operations

rdb 10 years ago
parent
commit
bac400543a

+ 2 - 2
panda/src/dxgsg9/dxGeomMunger9.cxx

@@ -118,7 +118,7 @@ munge_format_impl(const GeomVertexFormat *orig,
 
   if (normal_type != (const GeomVertexColumn *)NULL) {
     new_array_format->add_column
-      (InternalName::get_normal(), 3, NT_float32, C_vector);
+      (InternalName::get_normal(), 3, NT_float32, C_normal);
     new_format->remove_column(normal_type->get_name());
   }
 
@@ -227,7 +227,7 @@ premunge_format_impl(const GeomVertexFormat *orig) {
 
   if (normal_type != (const GeomVertexColumn *)NULL) {
     new_array_format->add_column
-      (InternalName::get_normal(), 3, NT_float32, C_vector);
+      (InternalName::get_normal(), 3, NT_float32, C_normal);
     new_format->remove_column(normal_type->get_name());
   }
 

+ 1 - 1
panda/src/egg2pg/eggLoader.cxx

@@ -2240,7 +2240,7 @@ make_vertex_data(const EggRenderState *render_state,
   if (vertex_pool->has_normals()) {
     array_format->add_column
       (InternalName::get_normal(), 3,
-       Geom::NT_stdfloat, Geom::C_vector);
+       Geom::NT_stdfloat, Geom::C_normal);
   }
 
   if (!ignore_color) {

+ 3 - 0
panda/src/gobj/geomEnums.cxx

@@ -139,6 +139,9 @@ operator << (ostream &out, GeomEnums::Contents contents) {
 
   case GeomEnums::C_matrix:
     return out << "matrix";
+
+  case GeomEnums::C_normal:
+    return out << "normal";
   }
 
   return out << "**invalid contents (" << (int)contents << ")**";

+ 5 - 1
panda/src/gobj/geomEnums.h

@@ -192,7 +192,7 @@ PUBLISHED:
     C_other,        // Arbitrary meaning, leave it alone
     C_point,        // A point in 3-space or 4-space
     C_clip_point,   // A point pre-transformed into clip coordinates
-    C_vector,       // A surface normal, tangent, or binormal
+    C_vector,       // A surface tangent or binormal (see C_normal for normals)
     C_texcoord,     // A texture coordinate
     C_color,        // 3- or 4-component color, ordered R, G, B, [A]
     C_index,        // An index value into some other table
@@ -201,6 +201,10 @@ PUBLISHED:
     // A transformation matrix.  This is typically three or four
     // columns, but we pretend it's only one for convenience.
     C_matrix,
+
+    // A special version of C_vector that should be used for normal
+    // vectors, which are scaled differently from other vectors.
+    C_normal,
   };
 
   // The type of animation data that is represented by a particular

+ 5 - 2
panda/src/gobj/geomVertexArrayFormat.cxx

@@ -394,8 +394,11 @@ align_columns_for_animation() {
   Columns::const_iterator ci;
   for (ci = orig_columns.begin(); ci != orig_columns.end(); ++ci) {
     GeomVertexColumn *column = (*ci);
-    if ((column->get_contents() == C_point || column->get_contents() == C_vector) &&
-        (column->get_numeric_type() == NT_float32 || column->get_numeric_type() == NT_float64) &&
+    if ((column->get_contents() == C_point ||
+         column->get_contents() == C_vector ||
+         column->get_contents() == C_normal) &&
+        (column->get_numeric_type() == NT_float32 ||
+         column->get_numeric_type() == NT_float64) &&
         column->get_num_components() >= 3) {
       add_column(column->get_name(), 4, column->get_numeric_type(), column->get_contents(), -1, 16);
     } else {

+ 5 - 0
panda/src/gobj/geomVertexColumn.cxx

@@ -340,6 +340,11 @@ make_packer() const {
       break;
     }
     return new Packer_color;
+  case C_normal:
+    if (get_num_values() != 3) {
+      gobj_cat.error()
+        << "GeomVertexColumn with contents C_normal must have 3 components!\n";
+    }
   default:
     // Otherwise, we just read it as a generic value.
     switch (get_numeric_type()) {

+ 64 - 7
panda/src/gobj/geomVertexData.cxx

@@ -1915,10 +1915,37 @@ do_transform_point_column(const GeomVertexFormat *format, GeomVertexRewriter &da
 ////////////////////////////////////////////////////////////////////
 void GeomVertexData::
 do_transform_vector_column(const GeomVertexFormat *format, GeomVertexRewriter &data,
-                          const LMatrix4 &mat, int begin_row, int end_row) {
+                           const LMatrix4 &mat, int begin_row, int end_row) {
   const GeomVertexColumn *data_column = data.get_column();
   int num_values = data_column->get_num_values();
 
+  LMatrix4 xform;
+  bool normalize = false;
+  if (data_column->get_contents() == C_normal) {
+    // This is to preserve perpendicularity to the surface.
+    LVecBase3 scale, shear, hpr;
+    if (decompose_matrix(mat.get_upper_3(), scale, shear, hpr) &&
+        IS_NEARLY_EQUAL(scale[0], scale[1]) &&
+        IS_NEARLY_EQUAL(scale[0], scale[2])) {
+      if (scale[0] == 1) {
+        // No scale to worry about.
+        xform = mat;
+      } else {
+        // Simply take the uniform scale out of the transformation.
+        // Not sure if it might be better to just normalize?
+        compose_matrix(xform, LVecBase3(1, 1, 1), shear, hpr, LVecBase3::zero());
+      }
+    } else {
+      // There is a non-uniform scale, so we need to do all this to
+      // preserve orthogonality to the surface.
+      xform.invert_from(mat);
+      xform.transpose_in_place();
+      normalize = true;
+    }
+  } else {
+    xform = mat;
+  }
+
   if ((num_values == 3 || num_values == 4) &&
       data_column->get_numeric_type() == NT_float32) {
     // The table of vectors is a table of LVector3f's or LVector4f's.
@@ -1929,9 +1956,11 @@ do_transform_vector_column(const GeomVertexFormat *format, GeomVertexRewriter &d
     size_t num_rows = end_row - begin_row;
     unsigned char *datat = data_handle->get_write_pointer();
     datat += data_column->get_start() + begin_row * stride;
-    LMatrix4f matf = LCAST(float, mat);
+    LMatrix4f matf = LCAST(float, xform);
 
-    if (num_values == 3) {
+    if (normalize) {
+      table_xform_normal3f(datat, num_rows, stride, matf);
+    } else if (num_values == 3) {
       table_xform_vector3f(datat, num_rows, stride, matf);
     } else {
       table_xform_vecbase4f(datat, num_rows, stride, matf);
@@ -1939,11 +1968,20 @@ do_transform_vector_column(const GeomVertexFormat *format, GeomVertexRewriter &d
 
   } else {
     // Use the GeomVertexRewriter to transform the vectors.
-
     data.set_row_unsafe(begin_row);
-    for (int j = begin_row; j < end_row; ++j) {
-      LVector3 vertex = data.get_data3();
-      data.set_data3(vertex * mat);
+
+    if (normalize) {
+      for (int j = begin_row; j < end_row; ++j) {
+        LVector3 vector = data.get_data3();
+        vector *= xform;
+        vector.normalize();
+        data.set_data3(vector);
+      }
+    } else {
+      for (int j = begin_row; j < end_row; ++j) {
+        LVector3 vector = data.get_data3();
+        data.set_data3(vector * xform);
+      }
     }
   }
 }
@@ -1965,6 +2003,25 @@ table_xform_point3f(unsigned char *datat, size_t num_rows, size_t stride,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexData::table_xform_normal3f
+//       Access: Private, Static
+//  Description: Transforms each of the LVector3f objects in the
+//               indicated table by the indicated matrix, and also
+//               normalizes them.
+////////////////////////////////////////////////////////////////////
+void GeomVertexData::
+table_xform_normal3f(unsigned char *datat, size_t num_rows, size_t stride,
+                     const LMatrix4f &matf) {
+  // We don't bother checking for the unaligned case here, because in
+  // practice it doesn't matter with a 3-component vector.
+  for (size_t i = 0; i < num_rows; ++i) {
+    LNormalf &vertex = *(LNormalf *)(&datat[i * stride]);
+    vertex *= matf;
+    vertex.normalize();
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexData::table_xform_vector3f
 //       Access: Private, Static

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

@@ -334,6 +334,8 @@ private:
                                   const LMatrix4 &mat, int begin_row, int end_row);
   static void table_xform_point3f(unsigned char *datat, size_t num_rows,
                                   size_t stride, const LMatrix4f &matf);
+  static void table_xform_normal3f(unsigned char *datat, size_t num_rows,
+                                   size_t stride, const LMatrix4f &matf);
   static void table_xform_vector3f(unsigned char *datat, size_t num_rows,
                                    size_t stride, const LMatrix4f &matf);
   static void table_xform_vecbase4f(unsigned char *datat, size_t num_rows,

+ 7 - 6
panda/src/gobj/geomVertexFormat.cxx

@@ -825,6 +825,7 @@ do_register() {
       break;
 
     case C_vector:
+    case C_normal:
       // It's a vector.
       _vectors.push_back(column->get_name());
       break;
@@ -1017,7 +1018,7 @@ make_standard_formats() {
                           (InternalName::get_vertex(), 3,
                            NT_stdfloat, C_point,
                            InternalName::get_normal(), 3,
-                           NT_stdfloat, C_vector));
+                           NT_stdfloat, C_normal));
 
   _v3t2 = register_format(new GeomVertexArrayFormat
                           (InternalName::get_vertex(), 3,
@@ -1029,7 +1030,7 @@ make_standard_formats() {
                             (InternalName::get_vertex(), 3,
                              NT_stdfloat, C_point,
                              InternalName::get_normal(), 3,
-                             NT_stdfloat, C_vector,
+                             NT_stdfloat, C_normal,
                              InternalName::get_texcoord(), 2,
                              NT_stdfloat, C_texcoord));
 
@@ -1044,7 +1045,7 @@ make_standard_formats() {
                             (InternalName::get_vertex(), 3,
                              NT_stdfloat, C_point,
                              InternalName::get_normal(), 3,
-                             NT_stdfloat, C_vector,
+                             NT_stdfloat, C_normal,
                              InternalName::get_color(), 1,
                              NT_packed_dabc, C_color));
 
@@ -1060,7 +1061,7 @@ make_standard_formats() {
                               (InternalName::get_vertex(), 3,
                                NT_stdfloat, C_point,
                                InternalName::get_normal(), 3,
-                               NT_stdfloat, C_vector,
+                               NT_stdfloat, C_normal,
                                InternalName::get_color(), 1,
                                NT_packed_dabc, C_color,
                                InternalName::get_texcoord(), 2,
@@ -1079,7 +1080,7 @@ make_standard_formats() {
                             (InternalName::get_vertex(), 3,
                              NT_stdfloat, C_point,
                              InternalName::get_normal(), 3,
-                             NT_stdfloat, C_vector,
+                             NT_stdfloat, C_normal,
                              InternalName::get_color(), 4,
                              NT_uint8, C_color));
 
@@ -1095,7 +1096,7 @@ make_standard_formats() {
                               (InternalName::get_vertex(), 3,
                                NT_stdfloat, C_point,
                                InternalName::get_normal(), 3,
-                               NT_stdfloat, C_vector,
+                               NT_stdfloat, C_normal,
                                InternalName::get_color(), 4,
                                NT_uint8, C_color,
                                InternalName::get_texcoord(), 2,

+ 1 - 1
panda/src/grutil/geoMipTerrain.cxx

@@ -63,7 +63,7 @@ generate_block(unsigned short mx,
   array->add_column(InternalName::get_texcoord(), 2,
                     Geom::NT_stdfloat, Geom::C_texcoord);
   array->add_column(InternalName::get_normal(), 3,
-                    Geom::NT_stdfloat, Geom::C_vector);
+                    Geom::NT_stdfloat, Geom::C_normal);
 
   PT(GeomVertexFormat) format = new GeomVertexFormat();
   format->add_array(array);

+ 2 - 2
panda/src/grutil/pfmVizzer.cxx

@@ -1062,7 +1062,7 @@ make_array_format(const VisColumns &vis_columns) const {
     case CT_normal3:
       num_components = 3;
       numeric_type = GeomEnums::NT_float32;
-      contents = GeomEnums::C_vector;
+      contents = GeomEnums::C_normal;
       break;
 
     case CT_blend1:
@@ -1072,7 +1072,7 @@ make_array_format(const VisColumns &vis_columns) const {
       break;
     }
     nassertr(num_components != 0, NULL);
-    
+
     array_format->add_column(name, num_components, numeric_type, contents);
   }
 

+ 1 - 1
panda/src/parametrics/ropeNode.cxx

@@ -282,7 +282,7 @@ get_format(bool support_normals) const {
   if (support_normals && get_normal_mode() == NM_vertex) {
     array_format->add_column
       (InternalName::get_normal(), 3, Geom::NT_stdfloat,
-       Geom::C_vector);
+       Geom::C_normal);
   }
   if (get_use_vertex_color()) {
     array_format->add_column