瀏覽代碼

add make_flat_mesh

David Rose 24 年之前
父節點
當前提交
98d11f914d
共有 2 個文件被更改,包括 185 次插入0 次删除
  1. 174 0
      panda/src/distort/projectionScreen.cxx
  2. 11 0
      panda/src/distort/projectionScreen.h

+ 174 - 0
panda/src/distort/projectionScreen.cxx

@@ -214,6 +214,39 @@ generate_screen(LensNode *projector, const string &screen_name,
   return geom_node;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::make_flat_mesh
+//       Access: Published
+//  Description: Generates a deep copy of the hierarchy at the
+//               ProjectionScreen node and below, with vertices
+//               flattened into two dimensions as if they were seen by
+//               the indicated camera node.
+//
+//               This is useful for rendering an image as seen through
+//               a non-linear lens.  The resulting mesh will have
+//               vertices in the range [-1, 1] in both x and y, and
+//               may be then rendered with an ordinary orthographic
+//               lens, to generate the effect of seeing the image
+//               through the specified non-linear lens.
+//
+//               The returned node has no parent; it is up to the user
+//               to caller to parent it somewhere or store it so that
+//               it does not get dereferenced and deleted.
+////////////////////////////////////////////////////////////////////
+PT_Node ProjectionScreen::
+make_flat_mesh(LensNode *camera) {
+  nassertr(camera != (LensNode *)NULL, NULL);
+  nassertr(camera->get_lens() != (Lens *)NULL, NULL);
+
+  PT_Node top = new NamedNode(get_name());
+
+  LMatrix4f rel_mat;
+  bool computed_rel_mat = false;
+  make_mesh_children(top, this, camera, rel_mat, computed_rel_mat);
+
+  return top;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ProjectionScreen::recompute
 //       Access: Published
@@ -374,3 +407,144 @@ recompute_geom(Geom *geom, const LMatrix4f &rel_mat) {
     geom->set_colors(_colors, G_PER_VERTEX, color_index);
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::make_mesh_node
+//       Access: Private
+//  Description: Recurses over all geometry at the indicated node and
+//               below, and generates a corresponding node hierarchy
+//               with all the geometry copied, but flattened into 2-d,
+//               as seen from the indicated camera.  Returns the newly
+//               created, arc, or NULL if no arc was created.
+////////////////////////////////////////////////////////////////////
+NodeRelation *ProjectionScreen::
+make_mesh_node(Node *result_parent, Node *node, LensNode *camera,
+               LMatrix4f &rel_mat, bool &computed_rel_mat) {
+  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(Node) new_node;
+  if (node->is_of_type(GeomNode::get_class_type())) {
+    new_node =
+      make_mesh_geom_node(DCAST(GeomNode, node), camera,
+                          rel_mat, computed_rel_mat);
+  } else {
+    new_node = node->make_copy();
+  }
+
+  // Now attach the new node to the result.
+  RenderRelation *arc = new RenderRelation(result_parent, new_node);
+  make_mesh_children(new_node, node, camera, rel_mat, computed_rel_mat);
+  return arc;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::make_mesh_children
+//       Access: Private
+//  Description: Walks over the list of children for the indicated
+//               node, calling make_mesh_node() on each one.
+////////////////////////////////////////////////////////////////////
+void ProjectionScreen::
+make_mesh_children(Node *new_node, Node *node, LensNode *camera,
+                   LMatrix4f &rel_mat, bool &computed_rel_mat) {
+  int num_children = node->get_num_children(RenderRelation::get_class_type());
+  for (int i = 0; i < num_children; i++) {
+    NodeRelation *arc = node->get_child(RenderRelation::get_class_type(), i);
+    NodeRelation *new_arc;
+
+    if (arc->has_transition(TransformTransition::get_class_type())) {
+      // This arc has a transform; therefore, we must recompute the
+      // relative matrix from this point.
+      LMatrix4f new_rel_mat;
+      bool computed_new_rel_mat = false;
+      new_arc = make_mesh_node(new_node, arc->get_child(), camera,
+                               new_rel_mat, computed_new_rel_mat);
+    } else {
+      // This arc has no transform, so we can use the same transform
+      // space from before.
+      new_arc = make_mesh_node(new_node, arc->get_child(), camera,
+                               rel_mat, computed_rel_mat);
+    }
+
+    // Copy all of the attributes (except TransformTransition) to the
+    // new arc.
+    new_arc->copy_transitions_from(arc);
+    new_arc->clear_transition(TransformTransition::get_class_type());
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::make_mesh_geom_node
+//       Access: Private
+//  Description: Makes a new GeomNode, just like the given one, except
+//               flattened into two dimensions as seen by the
+//               indicated camera.
+////////////////////////////////////////////////////////////////////
+PT(GeomNode) ProjectionScreen::
+make_mesh_geom_node(GeomNode *node, LensNode *camera,
+                    LMatrix4f &rel_mat, bool &computed_rel_mat) {
+  PT(GeomNode) new_node = new GeomNode;
+  new_node->set_name(node->get_name());
+
+  if (!computed_rel_mat) {
+    // All right, time to compute the matrix.
+    get_rel_mat(node, camera, rel_mat);
+    computed_rel_mat = true;
+  }
+
+  int num_geoms = node->get_num_geoms();
+  for (int i = 0; i < num_geoms; i++) {
+    dDrawable *drawable = node->get_geom(i);
+    if (drawable->is_of_type(Geom::get_class_type())) {
+      PT(dDrawable) new_drawable = 
+        make_mesh_geom(DCAST(Geom, drawable), camera->get_lens(), rel_mat);
+      if (new_drawable != (dDrawable *)NULL) {
+        new_node->add_geom(new_drawable);
+      }
+    }
+  }
+
+  return new_node;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ProjectionScreen::make_mesh_geom
+//       Access: Private
+//  Description: Makes a new Geom, just like the given one, except
+//               flattened into two dimensions as seen by the
+//               indicated lens.
+////////////////////////////////////////////////////////////////////
+PT(dDrawable) ProjectionScreen::
+make_mesh_geom(Geom *geom, Lens *lens, LMatrix4f &rel_mat) {
+  Geom *new_geom = geom->make_copy();
+  PT(dDrawable) result = new_geom;
+
+  PTA_Vertexf coords;
+  GeomBindType bind;
+  PTA_ushort vindex;
+
+  new_geom->get_coords(coords, bind, vindex);
+
+  PTA_Vertexf new_coords;
+  new_coords.reserve(coords.size());
+  for (int i = 0; i < (int)coords.size(); i++) {
+    const Vertexf &vert = coords[i];
+
+    // Project each vertex into the film plane, but use three
+    // dimensions so the Z coordinate remains meaningful.
+    LPoint3f film(0.0f, 0.0f, 0.0f);
+    lens->project(vert * rel_mat, film);
+
+    // Invert the Z coordinate.  We like -1 being closer than 1.
+    film[2] = -film[2];
+
+    new_coords.push_back(film);
+  }
+
+  new_geom->set_coords(new_coords, bind, vindex);
+
+  return result;
+}

+ 11 - 0
panda/src/distort/projectionScreen.h

@@ -63,6 +63,7 @@ PUBLISHED:
 
   GeomNode *generate_screen(LensNode *projector, const string &screen_name,
                             int num_x_verts, int num_y_verts, float distance);
+  PT_Node make_flat_mesh(LensNode *camera);
 
   INLINE void set_vignette_on(bool vignette_on);
   INLINE bool get_vignette_on() const;
@@ -80,6 +81,16 @@ private:
   void recompute_geom_node(GeomNode *node, LMatrix4f &rel_mat, bool &computed_rel_mat);
   void recompute_geom(Geom *geom, const LMatrix4f &rel_mat);
 
+  NodeRelation *
+  make_mesh_node(Node *result_parent, Node *node, LensNode *camera,
+                 LMatrix4f &rel_mat, bool &computed_rel_mat);
+  void make_mesh_children(Node *new_node, Node *node, LensNode *camera,
+                          LMatrix4f &rel_mat, bool &computed_rel_mat);
+  PT(GeomNode) make_mesh_geom_node(GeomNode *node, LensNode *camera,
+                                   LMatrix4f &rel_mat, bool &computed_rel_mat);
+  PT(dDrawable) make_mesh_geom(Geom *geom, Lens *lens, LMatrix4f &rel_mat);
+
+
   PT(LensNode) _projector;
   bool _vignette_on;
   Colorf _vignette_color;