소스 검색

generalize CompassEffect

David Rose 23 년 전
부모
커밋
00c4f5adab

+ 0 - 16
panda/src/pgraph/billboardEffect.cxx

@@ -196,22 +196,6 @@ compare_to_impl(const RenderEffect *other) const {
   return 0;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: BillboardEffect::make_default_impl
-//       Access: Protected, Virtual
-//  Description: Intended to be overridden by derived BillboardEffect
-//               types to specify what the default property for a
-//               BillboardEffect of this type should be.
-//
-//               This should return a newly-allocated BillboardEffect of
-//               the same type that corresponds to whatever the
-//               standard default for this kind of BillboardEffect is.
-////////////////////////////////////////////////////////////////////
-RenderEffect *BillboardEffect::
-make_default_impl() const {
-  return new BillboardEffect;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: BillboardEffect::register_with_read_factory
 //       Access: Public, Static

+ 0 - 1
panda/src/pgraph/billboardEffect.h

@@ -63,7 +63,6 @@ public:
 
 protected:
   virtual int compare_to_impl(const RenderEffect *other) const;
-  virtual RenderEffect *make_default_impl() const;
 
 private:
   bool _off;

+ 27 - 0
panda/src/pgraph/compassEffect.I

@@ -25,4 +25,31 @@
 ////////////////////////////////////////////////////////////////////
 INLINE CompassEffect::
 CompassEffect() {
+  _properties = 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CompassEffect::get_reference
+//       Access: Published
+//  Description: Returns the reference node from which the
+//               CompassEffect inherits its transform.  If this is
+//               empty, it means the root of the scene graph.
+////////////////////////////////////////////////////////////////////
+INLINE const NodePath &CompassEffect::
+get_reference() const {
+  return _reference;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CompassEffect::get_properties
+//       Access: Published
+//  Description: 
+
+//               Returns the bitmask of properties that this
+//               CompassEffect object inherits from its reference node
+//               (or from the root).
+////////////////////////////////////////////////////////////////////
+INLINE int CompassEffect::
+get_properties() const {
+  return _properties;
 }

+ 122 - 46
panda/src/pgraph/compassEffect.cxx

@@ -29,12 +29,19 @@ TypeHandle CompassEffect::_type_handle;
 ////////////////////////////////////////////////////////////////////
 //     Function: CompassEffect::make
 //       Access: Published, Static
-//  Description: Constructs a new CompassEffect object.
+//  Description: Constructs a new CompassEffect object.  If the
+//               reference is an empty NodePath, it means the
+//               CompassEffect is relative to the root of the scene
+//               graph; otherwise, it's relative to the indicated
+//               node.  The properties bitmask specifies the set of
+//               properties that the compass node inherits from the
+//               reference instead of from its parent.
 ////////////////////////////////////////////////////////////////////
 CPT(RenderEffect) CompassEffect::
-make(const NodePath &reference) {
+make(const NodePath &reference, int properties) {
   CompassEffect *effect = new CompassEffect;
   effect->_reference = reference;
+  effect->_properties = (properties & P_all);
   return return_new(effect);
 }
 
@@ -57,13 +64,41 @@ safe_to_transform() const {
 ////////////////////////////////////////////////////////////////////
 void CompassEffect::
 output(ostream &out) const {
-  if (!_reference.is_empty()) {
-    RenderEffect::output(out);
+  out << get_type() << ":";
+  if (_properties == 0) {
+    out << " none";
+  }
+  if ((_properties & P_pos) == P_pos) {
+    out << " xyz";
   } else {
-    out << get_type() << ":";
-    if (!_reference.is_empty()) {
-      out << " reference " << _reference;
+    if ((_properties & P_x) != 0) {
+      out << " x";
+    }
+    if ((_properties & P_y) != 0) {
+      out << " y";
+    }
+    if ((_properties & P_z) != 0) {
+      out << " z";
+    }
+  }
+  if ((_properties & P_rot) != 0) {
+    out << " rot";
+  }
+  if ((_properties & P_scale) == P_scale) {
+    out << " scale";
+  } else {
+    if ((_properties & P_sx) != 0) {
+      out << " sx";
+    }
+    if ((_properties & P_sy) != 0) {
+      out << " sy";
     }
+    if ((_properties & P_sz) != 0) {
+      out << " sz";
+    }
+  }
+  if (!_reference.is_empty()) {
+    out << " reference " << _reference;
   }
 }
 
@@ -77,35 +112,85 @@ output(ostream &out) const {
 CPT(TransformState) CompassEffect::
 do_compass(const TransformState *net_transform,
            const TransformState *node_transform) const {
-  if (!net_transform->has_components() || !node_transform->has_quat()) {
-    // If we don't have a decomposable transform, we can't do anything here.
-    pgraph_cat.warning()
-      << "CompassEffect unable to adjust non-decomposable transform\n";
+  if (_properties == 0) {
+    // Nothing to do.
     return TransformState::make_identity();
   }
 
-  // Compute just the rotation part of the transform we want.
-  CPT(TransformState) want_rot = TransformState::make_identity();
-  if (!_reference.is_empty()) {
-    CPT(TransformState) rel_transform = _reference.get_net_transform();
-    if (!rel_transform->has_quat()) {
-      pgraph_cat.warning()
-        << "CompassEffect unable to reference non-decomposable transform\n";
-    } else {
-      want_rot = TransformState::make_quat(rel_transform->get_quat());
-    }
+  // Compute the reference transform: our transform, as applied to the
+  // reference node.
+  CPT(TransformState) ref_transform;
+  if (_reference.is_empty()) {
+    ref_transform = node_transform;
+  } else {
+    ref_transform = _reference.get_net_transform()->compose(node_transform);
   }
 
-  want_rot = 
-    want_rot->compose(TransformState::make_quat(node_transform->get_quat()));
+  // Now compute the transform we actually want to achieve.  This is
+  // all of the components from the net transform we want to inherit
+  // normally from our parent, with all of the components from the ref
+  // transform we want to inherit from our reference.
+  CPT(TransformState) want_transform;
+  if (_properties == P_all) {
+    // If we want to steal the whole transform, that's easy.
+    want_transform = ref_transform;
 
-  // Now compute the net transform we want to achieve.  This is the
-  // same as the net transform we were given, except the rotation
-  // component is replaced by our desired rotation.
-  CPT(TransformState) want_transform = 
-    TransformState::make_pos_quat_scale(net_transform->get_pos(),
-                                        want_rot->get_quat(),
-                                        net_transform->get_scale());
+  } else {
+    // How much of the pos do we want to steal?  We can always
+    // determine a transform's pos, even if it's nondecomposable.
+    LVecBase3f want_pos = net_transform->get_pos();
+    const LVecBase3f &ref_pos = ref_transform->get_pos();
+    if ((_properties & P_x) != 0) {
+      want_pos[0] = ref_pos[0];
+    }
+    if ((_properties & P_y) != 0) {
+      want_pos[1] = ref_pos[1];
+    }
+    if ((_properties & P_z) != 0) {
+      want_pos[2] = ref_pos[2];
+    }
+
+    if ((_properties & ~P_pos) == 0) {
+      // If we only want to steal the pos, that's pretty easy.
+      want_transform = net_transform->set_pos(want_pos);
+  
+    } else if ((_properties & (P_rot | P_scale)) == (P_rot | P_scale)) {
+      // If we want to steal everything *but* the pos, also easy.
+      want_transform = ref_transform->set_pos(want_pos);
+      
+    } else {
+      // For any other combination, we have to be able to decompose both
+      // transforms.
+      if (!net_transform->has_components() || 
+          !ref_transform->has_components()) {
+        // If we can't decompose, just do the best we can: steal
+        // everything but the pos.
+        want_transform = ref_transform->set_pos(want_pos);
+
+      } else {
+        // If we can decompose, then take only the components we want.
+        LQuaternionf want_quat = net_transform->get_quat();
+        if ((_properties & P_rot) != 0) {
+          want_quat = ref_transform->get_quat();
+        }
+
+        LVecBase3f want_scale = net_transform->get_scale();
+        const LVecBase3f &ref_scale = ref_transform->get_scale();
+        if ((_properties & P_sx) != 0) {
+          want_scale[0] = ref_scale[0];
+        }
+        if ((_properties & P_sy) != 0) {
+          want_scale[1] = ref_scale[1];
+        }
+        if ((_properties & P_sz) != 0) {
+          want_scale[2] = ref_scale[2];
+        }
+
+        want_transform =
+          TransformState::make_pos_quat_scale(want_pos, want_quat, want_scale);
+      }
+    }
+  }
 
   // Now compute the transform that will convert net_transform to
   // want_transform.  This is inv(net_transform) * want_transform.
@@ -132,6 +217,9 @@ compare_to_impl(const RenderEffect *other) const {
   const CompassEffect *ta;
   DCAST_INTO_R(ta, other, 0);
 
+  if (_properties != ta->_properties) {
+    return _properties - ta->_properties;
+  }
   int compare = _reference.compare_to(ta->_reference);
   if (compare != 0) {
     return compare;
@@ -139,22 +227,6 @@ compare_to_impl(const RenderEffect *other) const {
   return 0;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: CompassEffect::make_default_impl
-//       Access: Protected, Virtual
-//  Description: Intended to be overridden by derived CompassEffect
-//               types to specify what the default property for a
-//               CompassEffect of this type should be.
-//
-//               This should return a newly-allocated CompassEffect of
-//               the same type that corresponds to whatever the
-//               standard default for this kind of CompassEffect is.
-////////////////////////////////////////////////////////////////////
-RenderEffect *CompassEffect::
-make_default_impl() const {
-  return new CompassEffect;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: CompassEffect::register_with_read_factory
 //       Access: Public, Static
@@ -175,6 +247,9 @@ register_with_read_factory() {
 void CompassEffect::
 write_datagram(BamWriter *manager, Datagram &dg) {
   RenderEffect::write_datagram(manager, dg);
+  dg.add_uint16(_properties);
+  // *** We don't write out the _reference NodePath right now.  Maybe
+  // we should.
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -207,4 +282,5 @@ make_from_bam(const FactoryParams &params) {
 void CompassEffect::
 fillin(DatagramIterator &scan, BamReader *manager) {
   RenderEffect::fillin(scan, manager);
+  _properties = scan.get_uint16();
 }

+ 46 - 5
panda/src/pgraph/compassEffect.h

@@ -27,16 +27,57 @@
 
 ////////////////////////////////////////////////////////////////////
 //       Class : CompassEffect
-// Description : Indicates that geometry at this node should
-//               automatically rotate to face the camera, or any other
-//               arbitrary node.
+// Description : A CompassEffect causes a node to inherit its rotation
+//               (or pos or scale, if specified) from some other
+//               reference node in the graph, or more often from the
+//               root.
+//
+//               In its purest form, a CompassEffect is used to keep
+//               the node's rotation fixed relative to the top of the
+//               scene graph, despite other transforms that may exist
+//               above the node.  Hence the name: the node behaves
+//               like a magnetic compass, always pointing in the same
+//               direction.
+//
+//               As an couple of generalizing extensions, the
+//               CompassEffect may also be set up to always orient its
+//               node according to some other reference node than the
+//               root of the scene graph.  Furthermore, it may
+//               optionally adjust any of pos, rotation, or scale,
+//               instead of necessarily rotation; and it may adjust
+//               individual pos and scale components.  (Rotation may
+//               not be adjusted on an individual component basis;
+//               that's just asking for trouble.)
+//
+//               Be careful when using the pos and scale modes.  In
+//               these modes, it's possible for the CompassEffect to
+//               move its node far from its normal bounding volume,
+//               causing culling to fail.  If this is an issue, you
+//               may need to explicitly set a large (or infinite)
+//               bounding volume on the effect node.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA CompassEffect : public RenderEffect {
 private:
   INLINE CompassEffect();
 
 PUBLISHED:
-  static CPT(RenderEffect) make(const NodePath &reference);
+  enum Properties {
+    P_x     = 0x001,
+    P_y     = 0x002,
+    P_z     = 0x004,
+    P_pos   = 0x007,
+    P_rot   = 0x008,
+    P_sx    = 0x010,
+    P_sy    = 0x020,
+    P_sz    = 0x040,
+    P_scale = 0x070,
+    P_all   = 0x07f,
+  };
+  static CPT(RenderEffect) make(const NodePath &reference, 
+                                int properties = P_rot);
+
+  INLINE const NodePath &get_reference() const;
+  INLINE int get_properties() const;
 
 public:
   virtual bool safe_to_transform() const;
@@ -48,10 +89,10 @@ public:
 
 protected:
   virtual int compare_to_impl(const RenderEffect *other) const;
-  virtual RenderEffect *make_default_impl() const;
 
 private:
   NodePath _reference;
+  int _properties;
 
 public:
   static void register_with_read_factory();

+ 25 - 33
panda/src/pgraph/cullTraverserData.cxx

@@ -35,11 +35,33 @@
 ////////////////////////////////////////////////////////////////////
 void CullTraverserData::
 apply_transform_and_state(CullTraverser *trav) {
-  const TransformState *node_transform = node()->get_transform();
+  CPT(TransformState) node_transform = node()->get_transform();
+
+  // First, compute the _net_transform, because we need it for the
+  // compass and billboard effects.
+  _net_transform = _net_transform->compose(node_transform);
+
+  const RenderEffects *node_effects = node()->get_effects();
+
+  const CompassEffect *compass = node_effects->get_compass();
+  if (compass != (const CompassEffect *)NULL) {
+    CPT(TransformState) compass_transform = 
+      compass->do_compass(_net_transform, node_transform);
+    _net_transform = _net_transform->compose(compass_transform);
+    node_transform = node_transform->compose(compass_transform);
+  }
+
+  const BillboardEffect *billboard = node_effects->get_billboard();
+  if (billboard != (const BillboardEffect *)NULL) {
+    CPT(TransformState) billboard_transform = 
+      billboard->do_billboard(_net_transform, trav->get_camera_transform());
+    _net_transform = _net_transform->compose(billboard_transform);
+    node_transform = node_transform->compose(billboard_transform);
+  }
+    
   if (!node_transform->is_identity()) {
     _render_transform = _render_transform->compose(node_transform);
-    _net_transform = _net_transform->compose(node_transform);
-    
+
     if ((_view_frustum != (GeometricBoundingVolume *)NULL) ||
         (_guard_band != (GeometricBoundingVolume *)NULL)) {
       // We need to move the viewing frustums into the node's
@@ -72,36 +94,6 @@ apply_transform_and_state(CullTraverser *trav) {
 
   const RenderState *node_state = node()->get_state();
   _state = _state->compose(node_state);
-
-  const RenderEffects *node_effects = node()->get_effects();
-
-  const CompassEffect *compass = node_effects->get_compass();
-  if (compass != (const CompassEffect *)NULL) {
-    // Got to apply a compass transform here.
-    CPT(TransformState) compass_transform = 
-      compass->do_compass(_net_transform, node_transform);
-    _render_transform = _render_transform->compose(compass_transform);
-    _net_transform = _net_transform->compose(compass_transform);
-
-    // We can't reliably cull within a compass, because the geometry
-    // might get rotated out of its bounding volume.  So once we get
-    // within a compass, we consider it all visible.
-    _view_frustum = (GeometricBoundingVolume *)NULL;
-  }
-
-  const BillboardEffect *billboard = node_effects->get_billboard();
-  if (billboard != (const BillboardEffect *)NULL) {
-    // Got to apply a billboard transform here.
-    CPT(TransformState) billboard_transform = 
-      billboard->do_billboard(_net_transform, trav->get_camera_transform());
-    _render_transform = _render_transform->compose(billboard_transform);
-    _net_transform = _net_transform->compose(billboard_transform);
-
-    // We can't reliably cull within a billboard, because the geometry
-    // might get rotated out of its bounding volume.  So once we get
-    // within a billboard, we consider it all visible.
-    _view_frustum = (GeometricBoundingVolume *)NULL;
-  }
 }
 
 

+ 0 - 16
panda/src/pgraph/decalEffect.cxx

@@ -69,22 +69,6 @@ compare_to_impl(const RenderEffect *other) const {
   return 0;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: DecalEffect::make_default_impl
-//       Access: Protected, Virtual
-//  Description: Intended to be overridden by derived DecalEffect
-//               types to specify what the default property for a
-//               DecalEffect of this type should be.
-//
-//               This should return a newly-allocated DecalEffect of
-//               the same type that corresponds to whatever the
-//               standard default for this kind of DecalEffect is.
-////////////////////////////////////////////////////////////////////
-RenderEffect *DecalEffect::
-make_default_impl() const {
-  return new DecalEffect;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: DecalEffect::register_with_read_factory
 //       Access: Public, Static

+ 0 - 1
panda/src/pgraph/decalEffect.h

@@ -39,7 +39,6 @@ PUBLISHED:
 protected:
   virtual bool safe_to_combine() const;
   virtual int compare_to_impl(const RenderEffect *other) const;
-  virtual RenderEffect *make_default_impl() const;
 
 public:
   static void register_with_read_factory();