Procházet zdrojové kódy

add CollisionSolid::set_effective_normal

David Rose před 22 roky
rodič
revize
2536db25f4

+ 3 - 4
panda/src/collide/collisionPlane.cxx

@@ -54,8 +54,7 @@ make_copy() {
 void CollisionPlane::
 xform(const LMatrix4f &mat) {
   _plane = _plane * mat;
-  mark_viz_stale();
-  mark_bound_stale();
+  CollisionSolid::xform(mat);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -130,7 +129,7 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
 
   LVector3f from_normal = get_normal() * entry.get_inv_wrt_mat();
 
-  new_entry->set_surface_normal(get_normal());
+  new_entry->set_surface_normal(has_effective_normal() ? get_effective_normal() : get_normal());
   new_entry->set_surface_point(from_center - get_normal() * dist);
   new_entry->set_interior_point(from_center - get_normal() * from_radius);
 
@@ -171,7 +170,7 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
 
   LPoint3f into_intersection_point = from_origin + t * from_direction;
-  new_entry->set_surface_normal(get_normal());
+  new_entry->set_surface_normal(has_effective_normal() ? get_effective_normal() : get_normal());
   new_entry->set_surface_point(into_intersection_point);
 
   return new_entry;

+ 4 - 5
panda/src/collide/collisionPolygon.cxx

@@ -228,8 +228,7 @@ xform(const LMatrix4f &mat) {
     setup_points(verts_begin, verts_end);
   }
 
-  mark_viz_stale();
-  mark_bound_stale();
+  CollisionSolid::xform(mat);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -513,7 +512,7 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
     into_depth = from_radius - dist_to_plane(orig_center);
   }
 
-  new_entry->set_surface_normal(get_normal());
+  new_entry->set_surface_normal(has_effective_normal() ? get_effective_normal() : get_normal());
   new_entry->set_surface_point(from_center - get_normal() * dist);
   new_entry->set_interior_point(from_center - get_normal() * (dist + into_depth));
 
@@ -581,7 +580,7 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
   }
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
 
-  new_entry->set_surface_normal(get_normal());
+  new_entry->set_surface_normal(has_effective_normal() ? get_effective_normal() : get_normal());
   new_entry->set_surface_point(plane_point);
 
   return new_entry;
@@ -650,7 +649,7 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
   }
   PT(CollisionEntry) new_entry = new CollisionEntry(entry);
 
-  new_entry->set_surface_normal(get_normal());
+  new_entry->set_surface_normal(has_effective_normal() ? get_effective_normal() : get_normal());
   new_entry->set_surface_point(plane_point);
 
   return new_entry;

+ 2 - 2
panda/src/collide/collisionRay.cxx

@@ -63,8 +63,8 @@ void CollisionRay::
 xform(const LMatrix4f &mat) {
   _origin = _origin * mat;
   _direction = _direction * mat;
-  mark_viz_stale();
-  mark_bound_stale();
+
+  CollisionSolid::xform(mat);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/collide/collisionSegment.cxx

@@ -65,8 +65,8 @@ void CollisionSegment::
 xform(const LMatrix4f &mat) {
   _a = _a * mat;
   _b = _b * mat;
-  mark_viz_stale();
-  mark_bound_stale();
+
+  CollisionSolid::xform(mat);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 62 - 7
panda/src/collide/collisionSolid.I

@@ -19,7 +19,7 @@
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionSolid::set_tangible
-//       Access: Public
+//       Access: Published
 //  Description: Sets the current state of the 'tangible' flag.  Set
 //               this true to make the solid tangible, so that a
 //               CollisionHandlerPusher will not allow another object
@@ -29,15 +29,17 @@
 ////////////////////////////////////////////////////////////////////
 INLINE void CollisionSolid::
 set_tangible(bool tangible) {
-  if (tangible != _tangible) {
-    _tangible = tangible;
-    mark_viz_stale();
+  if (tangible) {
+    _flags |= F_tangible;
+  } else {
+    _flags &= ~F_tangible;
   }
+  mark_viz_stale();
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionSolid::is_tangible
-//       Access: Public
+//       Access: Published
 //  Description: Returns whether the solid is considered 'tangible' or
 //               not.  An intangible solid has no effect in a
 //               CollisionHandlerPusher (except to throw an event);
@@ -46,7 +48,60 @@ set_tangible(bool tangible) {
 ////////////////////////////////////////////////////////////////////
 INLINE bool CollisionSolid::
 is_tangible() const {
-  return _tangible;
+  return (_flags & F_tangible) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionSolid::set_effective_normal
+//       Access: Published
+//  Description: Records a false normal for this CollisionSolid that
+//               will be reported by the collision system with all
+//               collisions into it, instead of its actual normal.
+//               This is useful as a workaround for the problem of an
+//               avatar wanting to stand on a sloping ground; by
+//               storing a false normal, the ground appears to be
+//               perfectly level, and the avatar does not tend to
+//               slide down it.
+////////////////////////////////////////////////////////////////////
+INLINE void CollisionSolid::
+set_effective_normal(const LVector3f &effective_normal) {
+  _effective_normal = effective_normal;
+  _flags |= F_effective_normal;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionSolid::clear_effective_normal
+//       Access: Published
+//  Description: Removes the normal previously set by
+//               set_effective_normal().
+////////////////////////////////////////////////////////////////////
+INLINE void CollisionSolid::
+clear_effective_normal() {
+  _flags &= ~F_effective_normal;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionSolid::has_effective_normal
+//       Access: Published
+//  Description: Returns true if a special normal was set by
+//               set_effective_normal(), false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool CollisionSolid::
+has_effective_normal() const {
+  return (_flags & F_effective_normal) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionSolid::get_effective_normal
+//       Access: Published
+//  Description: Returns the normal that was set by
+//               set_effective_normal().  It is an error to call this
+//               unless has_effective_normal() returns true.
+////////////////////////////////////////////////////////////////////
+INLINE const LVector3f &CollisionSolid::
+get_effective_normal() const {
+  nassertr(has_effective_normal(), LVector3f::zero());
+  return _effective_normal;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -59,5 +114,5 @@ is_tangible() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void CollisionSolid::
 mark_viz_stale() {
-  _viz_geom_stale = true;
+  _flags |= F_viz_geom_stale;
 }

+ 51 - 24
panda/src/collide/collisionSolid.cxx

@@ -16,7 +16,6 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-
 #include "collisionSolid.h"
 #include "config_collide.h"
 #include "collisionSphere.h"
@@ -43,8 +42,7 @@ TypeHandle CollisionSolid::_type_handle;
 ////////////////////////////////////////////////////////////////////
 CollisionSolid::
 CollisionSolid() {
-  _viz_geom_stale = true;
-  _tangible = true;
+  _flags = F_viz_geom_stale | F_tangible;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -54,10 +52,10 @@ CollisionSolid() {
 ////////////////////////////////////////////////////////////////////
 CollisionSolid::
 CollisionSolid(const CollisionSolid &copy) :
-  _tangible(copy._tangible)
+  _effective_normal(copy._effective_normal),
+  _flags(copy._flags)
 {
-  // Actually, there's not a whole lot here we want to copy.
-  _viz_geom_stale = true;
+  _flags &= ~F_viz_geom_stale;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -84,6 +82,21 @@ test_intersection(const CollisionEntry &) const {
   return NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CollisionSolid::xform
+//       Access: Public, Virtual
+//  Description: Transforms the solid by the indicated matrix.
+////////////////////////////////////////////////////////////////////
+void CollisionSolid::
+xform(const LMatrix4f &mat) {
+  if (has_effective_normal()) {
+    _effective_normal = _effective_normal * mat;
+  }
+
+  mark_viz_stale();
+  mark_bound_stale();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CollisionSolid::get_viz
 //       Access: Public, Virtual
@@ -94,14 +107,14 @@ test_intersection(const CollisionEntry &) const {
 ////////////////////////////////////////////////////////////////////
 PT(PandaNode) CollisionSolid::
 get_viz(const CullTraverserData &) const {
-  if (_viz_geom_stale) {
+  if ((_flags & F_viz_geom_stale) != 0) {
     if (_viz_geom == (GeomNode *)NULL) {
       ((CollisionSolid *)this)->_viz_geom = new GeomNode("viz");
     } else {
       _viz_geom->remove_all_geoms();
     }
     ((CollisionSolid *)this)->fill_viz_geom();
-    ((CollisionSolid *)this)->_viz_geom_stale = false;
+    ((CollisionSolid *)this)->_flags &= ~F_viz_geom_stale;
   }
   return _viz_geom.p();
 }
@@ -246,9 +259,13 @@ report_undefined_from_intersection(TypeHandle from_type) {
 //               the particular object to a Datagram
 ////////////////////////////////////////////////////////////////////
 void CollisionSolid::
-write_datagram(BamWriter *, Datagram &me)
-{
-  me.add_uint8(_tangible);
+write_datagram(BamWriter *, Datagram &me) {
+  // For now, we need only 8 bits of flags.  If we need to expand this
+  // later, we will have to increase the bam version.
+  me.add_uint8(_flags);
+  if ((_flags & F_effective_normal) != 0) {
+    _effective_normal.write_datagram(me);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -260,9 +277,11 @@ write_datagram(BamWriter *, Datagram &me)
 //               place
 ////////////////////////////////////////////////////////////////////
 void CollisionSolid::
-fillin(DatagramIterator& scan, BamReader*)
-{
-  _tangible = (scan.get_uint8() != 0);
+fillin(DatagramIterator &scan, BamReader*) {
+  _flags = scan.get_uint8();
+  if ((_flags & F_effective_normal) != 0) {
+    _effective_normal.read_datagram(scan);
+  }
 }
 
 
@@ -296,21 +315,29 @@ get_solid_viz_state() {
        TransparencyAttrib::make(TransparencyAttrib::M_alpha));
   }
 
-  if (_tangible) {
-    static CPT(RenderState) tangible_state = (const RenderState *)NULL;
-    if (tangible_state == (const RenderState *)NULL) {
-      tangible_state = base_state->add_attrib
-        (ColorAttrib::make_flat(Colorf(1.0f, 1.0f, 1.0f, 0.5f)));
-    }
-    return tangible_state;
-
-  } else {
+  if (!is_tangible()) {
     static CPT(RenderState) intangible_state = (const RenderState *)NULL;
     if (intangible_state == (const RenderState *)NULL) {
       intangible_state = base_state->add_attrib
         (ColorAttrib::make_flat(Colorf(1.0f, 0.3f, 0.5f, 0.5f)));
     }
     return intangible_state;
+
+  } else if (has_effective_normal()) {
+    static CPT(RenderState) fakenormal_state = (const RenderState *)NULL;
+    if (fakenormal_state == (const RenderState *)NULL) {
+      fakenormal_state = base_state->add_attrib
+        (ColorAttrib::make_flat(Colorf(0.5f, 0.5f, 1.0f, 0.5f)));
+    }
+    return fakenormal_state;
+
+  } else {
+    static CPT(RenderState) tangible_state = (const RenderState *)NULL;
+    if (tangible_state == (const RenderState *)NULL) {
+      tangible_state = base_state->add_attrib
+        (ColorAttrib::make_flat(Colorf(1.0f, 1.0f, 1.0f, 0.5f)));
+    }
+    return tangible_state;
   }
 }
 
@@ -335,7 +362,7 @@ get_wireframe_viz_state() {
        TransparencyAttrib::make(TransparencyAttrib::M_none));
   }
 
-  if (_tangible) {
+  if (is_tangible()) {
     static CPT(RenderState) tangible_state = (const RenderState *)NULL;
     if (tangible_state == (const RenderState *)NULL) {
       tangible_state = base_state->add_attrib

+ 16 - 3
panda/src/collide/collisionSolid.h

@@ -62,11 +62,16 @@ PUBLISHED:
   INLINE void set_tangible(bool tangible);
   INLINE bool is_tangible() const;
 
+  INLINE void set_effective_normal(const LVector3f &effective_normal);
+  INLINE void clear_effective_normal();
+  INLINE bool has_effective_normal() const;
+  INLINE const LVector3f &get_effective_normal() const;
+
 public:
   virtual PT(CollisionEntry)
   test_intersection(const CollisionEntry &entry) const;
 
-  virtual void xform(const LMatrix4f &mat)=0;
+  virtual void xform(const LMatrix4f &mat);
 
   virtual PT(PandaNode) get_viz(const CullTraverserData &data) const;
 
@@ -94,8 +99,16 @@ protected:
   CPT(RenderState) get_other_viz_state();
 
   PT(GeomNode) _viz_geom;
-  bool _viz_geom_stale;
-  bool _tangible;
+
+private:
+  LVector3f _effective_normal;
+
+  enum Flags {
+    F_tangible         = 0x01,
+    F_effective_normal = 0x02,
+    F_viz_geom_stale   = 0x04,
+  };
+  int _flags;
 
 public:
   virtual void write_datagram(BamWriter* manager, Datagram &me);

+ 1 - 2
panda/src/collide/collisionSphere.cxx

@@ -67,7 +67,6 @@ xform(const LMatrix4f &mat) {
   // non-uniform scale.
   LVector3f radius_v = LVector3f(_radius, 0.0f, 0.0f) * mat;
   _radius = length(radius_v);
-
   mark_viz_stale();
   mark_bound_stale();
 }
@@ -156,7 +155,7 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
     surface_normal = vec / vec_length;
   }
 
-  new_entry->set_surface_normal(surface_normal);
+  new_entry->set_surface_normal(has_effective_normal() ? get_effective_normal() : surface_normal);
   new_entry->set_surface_point(into_center + surface_normal * into_radius);
   new_entry->set_interior_point(from_center - surface_normal * from_radius);
 

+ 2 - 4
panda/src/collide/collisionTube.cxx

@@ -62,6 +62,7 @@ xform(const LMatrix4f &mat) {
   _radius = length(radius_v);
 
   recalc_internals();
+  CollisionSolid::xform(mat);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -367,9 +368,6 @@ recalc_internals() {
   look_at(_mat, direction, LVector3f(0.0f, 0.0f, 1.0f), CS_zup_right);
   _mat.set_row(3, _a);
   _inv_mat.invert_from(_mat);
-
-  mark_viz_stale();
-  mark_bound_stale();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -693,8 +691,8 @@ set_intersection_point(CollisionEntry *new_entry,
   // our collision was tangential.
   LPoint3f orig_point = into_intersection_point - normal * extra_radius;
 
+  new_entry->set_surface_normal(has_effective_normal() ? get_effective_normal() : normal);
   new_entry->set_surface_point(point);
-  new_entry->set_surface_normal(normal);
   new_entry->set_interior_point(orig_point);
 }
 

+ 11 - 10
panda/src/collide/collisionVisualizer.cxx

@@ -146,19 +146,20 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
       const CollisionSolid *solid = (*si).first;
       const SolidInfo &solid_info = (*si).second;
       PT(PandaNode) node = solid->get_viz(xform_data);
+      if (node != (PandaNode *)NULL) {
+        CullTraverserData next_data(xform_data, node);
         
-      CullTraverserData next_data(xform_data, node);
+        // We don't want to inherit the render state from above for
+        // these guys.  Instead, we choose the state according to
+        // whether a collision was detected or not.
+        if (solid_info._detected_count > 0) {
+          next_data._state = get_detected_state();
+        } else {
+          next_data._state = get_tested_state();
+        }
         
-      // We don't want to inherit the render state from above for
-      // these guys.  Instead, we choose the state according to
-      // whether a collision was detected or not.
-      if (solid_info._detected_count > 0) {
-        next_data._state = get_detected_state();
-      } else {
-        next_data._state = get_tested_state();
+        trav->traverse(next_data);
       }
-        
-      trav->traverse(next_data);
     }
 
     // Now draw all of the detected points.

+ 7 - 13
panda/src/doc/eggSyntax.txt

@@ -971,19 +971,6 @@ GROUPING ENTRIES
       The geometry represents a sphere.  The vertices in the group are
       averaged together to determine the sphere's center and radius.
 
-    InverseSphere
-
-      The geometry represents a sphere with the normal inverted, to
-      make a hollow spherical shell.
-
-    Geode
-
-      The geometry is not a collision surface after all, but is in
-      fact true geometry.  This is intended to be used in conjunction
-      with one or more flags to define collision properties for normal
-      geometry.
-
-
 
     The flags may be any zero or more of:
 
@@ -1038,6 +1025,13 @@ GROUPING ENTRIES
       can go forwards but not back.  Presently, this is only
       implemented for planes, polygons, and polysets.
 
+    level
+
+      Stores a special effective normal with the collision solid that
+      points up, regardless of the actual shape or orientation of the
+      solid.  This can be used to allow an avatar to stand on a
+      sloping surface without having a tendency to slide downward.
+
 
   <ObjectType> { type }
 

+ 6 - 8
panda/src/egg/eggGroup.cxx

@@ -781,10 +781,6 @@ string_cs_type(const string &string) {
     return CST_polyset;
   } else if (cmp_nocase_uh(string, "sphere") == 0) {
     return CST_sphere;
-  } else if (cmp_nocase_uh(string, "inversesphere") == 0) {
-    return CST_inverse_sphere;
-  } else if (cmp_nocase_uh(string, "geode") == 0) {
-    return CST_geode;
   } else if (cmp_nocase_uh(string, "tube") == 0) {
     return CST_tube;
   } else {
@@ -817,6 +813,8 @@ string_collide_flags(const string &string) {
     return CF_center;
   } else if (cmp_nocase_uh(string, "turnstile") == 0) {
     return CF_turnstile;
+  } else if (cmp_nocase_uh(string, "level") == 0) {
+    return CF_level;
   } else {
     return CF_none;
   }
@@ -1155,10 +1153,6 @@ ostream &operator << (ostream &out, EggGroup::CollisionSolidType t) {
     return out << "Polyset";
   case EggGroup::CST_sphere:
     return out << "Sphere";
-  case EggGroup::CST_inverse_sphere:
-    return out << "InverseSphere";
-  case EggGroup::CST_geode:
-    return out << "Geode";
   case EggGroup::CST_tube:
     return out << "Tube";
   }
@@ -1206,5 +1200,9 @@ ostream &operator << (ostream &out, EggGroup::CollideFlags t) {
     out << space << "turnstile";
     space = " ";
   }
+  if (bits & EggGroup::CF_level) {
+    out << space << "level";
+    space = " ";
+  }
   return out;
 }

+ 3 - 4
panda/src/egg/eggGroup.h

@@ -78,9 +78,7 @@ PUBLISHED:
     CST_polygon              = 0x00020000,
     CST_polyset              = 0x00030000,
     CST_sphere               = 0x00040000,
-    CST_inverse_sphere       = 0x00050000,
-    CST_geode                = 0x00060000,
-    CST_tube                 = 0x00070000,
+    CST_tube                 = 0x00050000,
   };
   enum CollideFlags {
     // The bits here must correspond to those in Flags, below.
@@ -92,6 +90,7 @@ PUBLISHED:
     CF_solid                 = 0x00800000,
     CF_center                = 0x01000000,
     CF_turnstile             = 0x02000000,
+    CF_level                 = 0x04000000,
   };
 
   EggGroup(const string &name = "");
@@ -256,7 +255,7 @@ private:
     F_decal_flag             = 0x00002000,
     F_direct_flag            = 0x00004000,
     F_cs_type                = 0x00070000,
-    F_collide_flags          = 0x03f80000,
+    F_collide_flags          = 0x07f80000,
   };
   enum Flags2 {
     F2_collide_mask          = 0x00000001,

+ 4 - 11
panda/src/egg2pg/eggLoader.cxx

@@ -1555,8 +1555,7 @@ make_node(EggGroup *egg_group, PandaNode *parent) {
     CharacterMaker char_maker(egg_group, *this);
     node = char_maker.make_node();
 
-  } else if (egg_group->get_cs_type() != EggGroup::CST_none &&
-             egg_group->get_cs_type() != EggGroup::CST_geode) {
+  } else if (egg_group->get_cs_type() != EggGroup::CST_none) {
     // A collision group: create collision geometry.
     node = new CollisionNode(egg_group->get_name());
 
@@ -1771,18 +1770,9 @@ make_collision_solids(EggGroup *start_group, EggGroup *egg_group,
 
   switch (start_group->get_cs_type()) {
   case EggGroup::CST_none:
-  case EggGroup::CST_geode:
     // No collision flags; do nothing.  Don't even traverse further.
     return;
 
-  case EggGroup::CST_inverse_sphere:
-    // These aren't presently supported.
-    egg2pg_cat.error()
-      << "Not presently supported: <Collide> { "
-      << egg_group->get_cs_type() << " }\n";
-    _error = true;
-    break;
-
   case EggGroup::CST_plane:
     make_collision_plane(egg_group, cnode, start_group->get_collide_flags());
     break;
@@ -2159,6 +2149,9 @@ apply_collision_flags(CollisionSolid *solid,
   if ((flags & EggGroup::CF_intangible) != 0) {
     solid->set_tangible(false);
   }
+  if ((flags & EggGroup::CF_level) != 0) {
+    solid->set_effective_normal(LVector3f::up());
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 1
panda/src/putil/bam.h

@@ -34,13 +34,14 @@ static const unsigned short _bam_major_ver = 4;
 // Bumped to major version 3 on 12/8/00 to change float64's to float32's.
 // Bumped to major version 4 on 4/10/02 to store new scene graph.
 
-static const unsigned short _bam_minor_ver = 6;
+static const unsigned short _bam_minor_ver = 7;
 // Bumped to minor version 1 on 4/10/03 to add CullFaceAttrib::reverse.
 // Bumped to minor version 2 on 4/12/03 to add num_components to texture.
 // Bumped to minor version 3 on 4/15/03 to add ImageBuffer::_alpha_file_channel
 // Bumped to minor version 4 on 6/12/03 to add PandaNode::set_tag().
 // Bumped to minor version 5 on 7/09/03 to add rawdata mode to texture.
 // Bumped to minor version 6 on 7/22/03 to add shear to scene graph and animation data.
+// Bumped to minor version 7 on 11/10/03 to add CollisionSolid::_effective_normal
 
 
 #endif