replace set_velocity() with set_fluid_pos()

This commit is contained in:
David Rose 2003-10-08 19:08:53 +00:00
parent 4650d62c0d
commit 3c3f2f4432
33 changed files with 734 additions and 550 deletions

View File

@ -7,11 +7,12 @@ class Mopath(PandaObject):
nameIndex = 1
def __init__(self, name = None):
def __init__(self, name = None, fluid = 1):
if (name == None):
name = 'mopath%d' % self.nameIndex
self.nameIndex = self.nameIndex + 1
self.name = name
self.fluid = fluid
self.tPoint = Point3(0)
self.posPoint = Point3(0)
self.hprPoint = Point3(0)
@ -97,7 +98,10 @@ class Mopath(PandaObject):
self.playbackTime = self.calcTime(CLAMP(time, 0.0, self.maxT))
if (self.xyzNurbsCurve != None):
self.xyzNurbsCurve.getPoint(self.playbackTime, self.posPoint)
node.setPos(self.posPoint)
if self.fluid:
node.setFluidPos(self.posPoint)
else:
node.setPos(self.posPoint)
if (self.hprNurbsCurve != None):
self.hprNurbsCurve.getPoint(self.playbackTime, self.hprPoint)
node.setHpr(self.hprPoint)

View File

@ -17,7 +17,8 @@ class LerpNodePathInterval(CLerpNodePathInterval):
# affect a property on a NodePath, like pos or hpr.
lerpNodePathNum = 1
def __init__(self, name, duration, blendType, bakeInStart, node, other):
def __init__(self, name, duration, blendType, bakeInStart, fluid,
node, other):
if name == None:
name = '%s-%d' % (self.__class__.__name__, self.lerpNodePathNum)
LerpNodePathInterval.lerpNodePathNum += 1
@ -29,7 +30,7 @@ class LerpNodePathInterval(CLerpNodePathInterval):
other = NodePath()
CLerpNodePathInterval.__init__(self, name, duration, blendType,
bakeInStart, node, other)
bakeInStart, fluid, node, other)
def anyCallable(self, *params):
# Returns true if any of the parameters listed is a callable
@ -70,14 +71,21 @@ class LerpNodePathInterval(CLerpNodePathInterval):
## delta since the last time the interval ran, which allows show code
## to manipulate the node even while it is being lerped.
##
## If fluid is true for a LerpPos-style interval, then the pos is set
## via NodePath.setFluidPos() instead of NodePath.setPos(), causing
## the collision system to treat the motion as continuous and test
## for collisions against the entire motion path, instead of as
## discrete position updates. This has no meaning for Lerp intervals
## that do not adjust pos.
##
#####################################################################
class LerpPosInterval(LerpNodePathInterval):
def __init__(self, node, duration, pos, startPos = None,
other = None, blendType = 'noBlend',
bakeInStart = 1, name = None):
bakeInStart = 1, fluid = 0, name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
bakeInStart, node, other)
bakeInStart, fluid, node, other)
# Check for functors in the input parameters.
self.paramSetup = self.anyCallable(pos, startPos)
@ -102,9 +110,9 @@ class LerpPosInterval(LerpNodePathInterval):
class LerpHprInterval(LerpNodePathInterval):
def __init__(self, node, duration, hpr, startHpr = None,
other = None, blendType = 'noBlend',
bakeInStart = 1, name = None):
bakeInStart = 1, fluid = 0, name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
bakeInStart, node, other)
bakeInStart, fluid, node, other)
# Check for functors in the input parameters.
self.paramSetup = self.anyCallable(hpr, startHpr)
@ -128,9 +136,9 @@ class LerpHprInterval(LerpNodePathInterval):
class LerpScaleInterval(LerpNodePathInterval):
def __init__(self, node, duration, scale, startScale = None,
other = None, blendType = 'noBlend',
bakeInStart = 1, name = None):
bakeInStart = 1, fluid = 0, name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
bakeInStart, node, other)
bakeInStart, fluid, node, other)
# Check for functors in the input parameters.
self.paramSetup = self.anyCallable(scale, startScale)
if self.paramSetup:
@ -153,9 +161,9 @@ class LerpScaleInterval(LerpNodePathInterval):
class LerpShearInterval(LerpNodePathInterval):
def __init__(self, node, duration, shear, startShear = None,
other = None, blendType = 'noBlend',
bakeInStart = 1, name = None):
bakeInStart = 1, fluid = 0, name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
bakeInStart, node, other)
bakeInStart, fluid, node, other)
# Check for functors in the input parameters.
self.paramSetup = self.anyCallable(shear, startShear)
if self.paramSetup:
@ -179,9 +187,9 @@ class LerpPosHprInterval(LerpNodePathInterval):
def __init__(self, node, duration, pos, hpr,
startPos = None, startHpr = None,
other = None, blendType = 'noBlend',
bakeInStart = 1, name = None):
bakeInStart = 1, fluid = 0, name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
bakeInStart, node, other)
bakeInStart, fluid, node, other)
# Check for functors in the input parameters.
self.paramSetup = self.anyCallable(pos, startPos, hpr, startHpr)
if self.paramSetup:
@ -212,9 +220,9 @@ class LerpHprScaleInterval(LerpNodePathInterval):
def __init__(self, node, duration, hpr, scale,
startHpr = None, startScale = None,
other = None, blendType = 'noBlend',
bakeInStart = 1, name = None):
bakeInStart = 1, fluid = 0, name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
bakeInStart, node, other)
bakeInStart, fluid, node, other)
# Check for functors in the input parameters.
self.paramSetup = self.anyCallable(hpr, startHpr, scale, startScale)
@ -246,9 +254,9 @@ class LerpPosHprScaleInterval(LerpNodePathInterval):
def __init__(self, node, duration, pos, hpr, scale,
startPos = None, startHpr = None, startScale = None,
other = None, blendType = 'noBlend',
bakeInStart = 1, name = None):
bakeInStart = 1, fluid = 0, name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
bakeInStart, node, other)
bakeInStart, fluid, node, other)
# Check for functors in the input parameters.
self.paramSetup = self.anyCallable(pos, startPos, hpr, startHpr, scale, startScale)
if self.paramSetup:
@ -286,9 +294,9 @@ class LerpPosHprScaleShearInterval(LerpNodePathInterval):
def __init__(self, node, duration, pos, hpr, scale, shear,
startPos = None, startHpr = None, startScale = None, startShear = None,
other = None, blendType = 'noBlend',
bakeInStart = 1, name = None):
bakeInStart = 1, fluid = 0, name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
bakeInStart, node, other)
bakeInStart, fluid, node, other)
# Check for functors in the input parameters.
self.paramSetup = self.anyCallable(pos, startPos, hpr, startHpr, scale, startScale, shear, startShear)
if self.paramSetup:
@ -332,9 +340,9 @@ class LerpPosHprScaleShearInterval(LerpNodePathInterval):
class LerpColorScaleInterval(LerpNodePathInterval):
def __init__(self, node, duration, colorScale, startColorScale = None,
other = None, blendType = 'noBlend',
bakeInStart = 1, name = None):
bakeInStart = 1, fluid = 0, name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
bakeInStart, node, other)
bakeInStart, fluid, node, other)
self.setEndColorScale(colorScale)
if startColorScale != None:
self.setStartColorScale(startColorScale)
@ -342,9 +350,9 @@ class LerpColorScaleInterval(LerpNodePathInterval):
class LerpColorInterval(LerpNodePathInterval):
def __init__(self, node, duration, color, startColor = None,
other = None, blendType = 'noBlend',
bakeInStart = 1, name = None):
bakeInStart = 1, fluid = 0, name = None):
LerpNodePathInterval.__init__(self, name, duration, blendType,
bakeInStart, node, other)
bakeInStart, fluid, node, other)
self.setEndColor(color)
if startColor != None:
self.setStartColor(startColor)

View File

@ -54,11 +54,14 @@ TypeHandle CLerpNodePathInterval::_type_handle;
// "smart" behavior allows code to manipulate the object
// event while it is being lerped, and the lerp
// continues to apply in a sensible way.
//
// If fluid is true, the prev_transform is not adjusted
// by the lerp; otherwise, it is reset.
////////////////////////////////////////////////////////////////////
CLerpNodePathInterval::
CLerpNodePathInterval(const string &name, double duration,
CLerpInterval::BlendType blend_type,
bool bake_in_start,
bool bake_in_start, bool fluid,
const NodePath &node, const NodePath &other) :
CLerpInterval(name, duration, blend_type),
_node(node),
@ -68,6 +71,9 @@ CLerpNodePathInterval(const string &name, double duration,
if (bake_in_start) {
_flags |= F_bake_in_start;
}
if (fluid) {
_flags |= F_fluid;
}
_prev_d = 0.0;
}
@ -119,6 +125,9 @@ priv_step(double t) {
_state = S_started;
double d = compute_delta(t);
// Save this in case we want to restore it later.
CPT(TransformState) prev_transform = _node.get_prev_transform();
if ((_flags & (F_end_pos | F_end_hpr | F_end_scale | F_end_shear)) != 0) {
// We have some transform lerp.
CPT(TransformState) transform;
@ -297,6 +306,13 @@ priv_step(double t) {
}
}
if ((_flags & F_fluid) != 0) {
// If we have the fluid flag set, we shouldn't mess with the prev
// transform. Therefore, restore it to what it was before we
// started messing with it.
_node.set_prev_transform(prev_transform);
}
if ((_flags & (F_end_color | F_end_color_scale)) != 0) {
// We have some render state lerp.
CPT(RenderState) state;

View File

@ -32,6 +32,7 @@ class EXPCL_DIRECT CLerpNodePathInterval : public CLerpInterval {
PUBLISHED:
CLerpNodePathInterval(const string &name, double duration,
BlendType blend_type, bool bake_in_start,
bool fluid,
const NodePath &node, const NodePath &other);
INLINE const NodePath &get_node() const;
@ -79,6 +80,7 @@ private:
F_start_color_scale = 0x1000,
F_start_shear = 0x2000,
F_fluid = 0x4000,
F_bake_in_start = 0x8000,
};

View File

@ -179,13 +179,11 @@ class NonPhysicsWalker(DirectObject.DirectObject):
# our previous heading.
rotMat=Mat3.rotateMatNormaxis(self.avatarNodePath.getH(), Vec3.up())
step=rotMat.xform(self.vel)
self.avatarNodePath.setPos(Point3(self.avatarNodePath.getPos()+step))
self.avatarNodePath.setFluidPos(Point3(self.avatarNodePath.getPos()+step))
self.avatarNodePath.setH(self.avatarNodePath.getH()+rotation)
messenger.send("avatarMoving")
else:
self.vel.set(0.0, 0.0, 0.0)
# Set collision sphere node:
self.cSphereNode.setVelocity(self.vel)
return Task.cont
def enableAvatarControls(self):

View File

@ -305,17 +305,12 @@ class PhysicsWalker(DirectObject.DirectObject):
self.__vel.set(0.0, 0.0, 0.0)
# Clear the contact vector so we can tell if we contact something next frame:
self.actorNode.setContactVector(Vec3.zero())
# Set collision sphere node:
v=physObject.getImplicitVelocity()
v=rotAvatarToPhys.xform(v)
self.cSphereNode.setVelocity(Vec3(v))
return Task.cont
def resetPhys(self):
assert(self.debugPrint("resetPhys()"))
self.actorNode.getPhysicsObject().resetPosition(self.avatarNodePath.getPos())
self.actorNode.setContactVector(Vec3.zero())
self.cSphereNode.setVelocity(Vec3(0.0))
def enableAvatarControls(self):
"""

View File

@ -793,6 +793,18 @@ class ShowBase(DirectObject.DirectObject):
music.setLoop(looping)
music.play()
def resetPrevTransform(self, state):
# Clear out the previous velocity deltas now, after we have
# rendered (the previous frame). We do this after the render,
# so that we have a chance to draw a representation of spheres
# along with their velocities. At the beginning of the frame
# really means after the command prompt, which allows the user
# to interactively query these deltas meaningfully.
if self.cTrav:
self.cTrav.resetPrevTransform(self.render)
return Task.cont
def dataloop(self, state):
# traverse the data graph. This reads all the control
# inputs (from the mouse and keyboard, for instance) and also
@ -845,6 +857,8 @@ class ShowBase(DirectObject.DirectObject):
def restart(self):
self.shutdown()
# resetPrevTransform goes at the very beginning of the frame.
self.taskMgr.add(self.resetPrevTransform, 'resetPrevTransform', priority = -51)
# give the dataloop task a reasonably "early" priority,
# so that it will get run before most tasks
self.taskMgr.add(self.dataloop, 'dataloop', priority = -50)
@ -868,6 +882,7 @@ class ShowBase(DirectObject.DirectObject):
self.taskMgr.remove('shadowCollisionLoop')
self.taskMgr.remove('collisionloop')
self.taskMgr.remove('dataloop')
self.taskMgr.remove('resetPrevTransform')
self.taskMgr.remove('ivalloop')
self.eventMgr.shutdown()

View File

@ -179,6 +179,7 @@ class TaskManagerWidget(PandaObject):
name = self.currentTask.name
ok = 1
if ((name == 'dataloop') or
(name == 'resetPrevTransform') or
(name == 'tkloop') or
(name == 'eventManager') or
(name == 'igloop')):
@ -195,6 +196,7 @@ class TaskManagerWidget(PandaObject):
name = self.taskListBox.getcurselection()[0]
ok = 1
if ((name == 'dataloop') or
(name == 'resetPrevTransform') or
(name == 'tkloop') or
(name == 'eventManager') or
(name == 'igloop')):

View File

@ -19,17 +19,21 @@
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::Constructor
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE CollisionEntry::
CollisionEntry() {
_flags = 0;
_from_space = TransformState::make_identity();
_into_space = TransformState::make_identity();
_wrt_space = TransformState::make_identity();
_inv_wrt_space = TransformState::make_identity();
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_from
// Access: Public
// Access: Published
// Description: Returns the CollisionSolid pointer for the particular
// solid that triggered this collision.
////////////////////////////////////////////////////////////////////
@ -40,7 +44,7 @@ get_from() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::has_into
// Access: Public
// Access: Published
// Description: Returns true if the "into" solid is, in fact, a
// CollisionSolid, and its pointer is known (in which
// case get_into() may be called to retrieve it). If
@ -55,7 +59,7 @@ has_into() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_into
// Access: Public
// Access: Published
// Description: Returns the CollisionSolid pointer for the particular
// solid was collided into. This pointer might be NULL
// if the collision was into a piece of visible
@ -69,7 +73,7 @@ get_into() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_from_node
// Access: Public
// Access: Published
// Description: Returns the node that contains the CollisionSolid
// that triggered this collision. This will be a node
// that has been added to a CollisionTraverser via
@ -80,22 +84,9 @@ get_from_node() const {
return _from_node;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_from_space
// Access: Public
// Description: Returns the global coordinate space of the
// CollisionNode returned by get_from_node(), as of the
// time of the collision. This will be equivalent to a
// wrt() from the node to render.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4f &CollisionEntry::
get_from_space() const {
return _from_space;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_into_node
// Access: Public
// Access: Published
// Description: Returns the node that contains the CollisionSolid
// that was collided into. This returns a PandaNode
// pointer instead of something more specific, because
@ -110,7 +101,7 @@ get_into_node() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_into_node_path
// Access: Public
// Access: Published
// Description: Returns the NodePath that represents the specific
// CollisionNode or GeomNode instance that was collided
// into. This is the same node returned by
@ -124,78 +115,139 @@ get_into_node_path() const {
return _into_node_path;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_from_space
// Access: Published
// Description: Returns the global coordinate space of the
// CollisionNode returned by get_from_node(), as of the
// time of the collision. This will be equivalent to a
// wrt() from the node to render.
////////////////////////////////////////////////////////////////////
INLINE const TransformState *CollisionEntry::
get_from_space() const {
return _from_space;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_into_space
// Access: Public
// Access: Published
// Description: Returns the global coordinate space of the
// CollisionNode or GeomNode returned by
// get_into_node(), as of the time of the collision.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4f &CollisionEntry::
INLINE const TransformState *CollisionEntry::
get_into_space() const {
return _into_space;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_wrt_space
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4f &CollisionEntry::
INLINE const TransformState *CollisionEntry::
get_wrt_space() const {
return _wrt_space;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_inv_wrt_space
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4f &CollisionEntry::
INLINE const TransformState *CollisionEntry::
get_inv_wrt_space() const {
return _inv_wrt_space;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::set_from_velocity
// Access: Public
// Description: Indicates the velocity associated with the "from"
// Function: CollisionEntry::get_from_mat
// Access: Published
// Description: Returns the global coordinate space of the
// CollisionNode returned by get_from_node(), as of the
// time of the collision. This will be equivalent to a
// wrt() from the node to render.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4f &CollisionEntry::
get_from_mat() const {
return _from_space->get_mat();
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_into_mat
// Access: Published
// Description: Returns the global coordinate space of the
// CollisionNode or GeomNode returned by
// get_into_node(), as of the time of the collision.
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4f &CollisionEntry::
get_into_mat() const {
return _into_space->get_mat();
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_wrt_mat
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4f &CollisionEntry::
get_wrt_mat() const {
return _wrt_space->get_mat();
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_inv_wrt_mat
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4f &CollisionEntry::
get_inv_wrt_mat() const {
return _inv_wrt_space->get_mat();
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::set_from_pos_delta
// Access: Published
// Description: Indicates the pos_delta associated with the "from"
// object, in the object's coordinate space.
////////////////////////////////////////////////////////////////////
INLINE void CollisionEntry::
set_from_velocity(const LVector3f &vel) {
_from_velocity = vel;
_flags |= F_has_from_velocity;
set_from_pos_delta(const LVector3f &vel) {
_from_pos_delta = vel;
_flags |= F_has_from_pos_delta;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::has_from_velocity
// Access: Public
// Description: Returns true if the "from" object had an indicated
// velocity, false otherwise.
// Function: CollisionEntry::has_from_pos_delta
// Access: Published
// Description: Returns true if the objects appeared to be moving
// relative to each other, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool CollisionEntry::
has_from_velocity() const {
return (_flags & F_has_from_velocity) != 0;
has_from_pos_delta() const {
return (_flags & F_has_from_pos_delta) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_from_velocity
// Access: Public
// Description: Returns the instantaneous velocity of the "from"
// object, in its own coordinate space. This represents
// the delta between its current position and its
// position last frame.
// Function: CollisionEntry::get_from_pos_delta
// Access: Published
// Description: Returns the position delta between the two objects,
// in the coordinate space of the "from" object. This
// is the delta between their relative position in the
// previous frame and their relative position this
// frame.
////////////////////////////////////////////////////////////////////
INLINE const LVector3f &CollisionEntry::
get_from_velocity() const {
nassertr(has_from_velocity(), _from_velocity);
return _from_velocity;
get_from_pos_delta() const {
if (!has_from_pos_delta()) {
return LVector3f::zero();
}
return _from_pos_delta;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::set_into_intersection_point
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void CollisionEntry::
@ -206,7 +258,7 @@ set_into_intersection_point(const LPoint3f &point) {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::has_into_intersection_point
// Access: Public
// Access: Published
// Description: Returns true if the detected collision knows its
// intersection point in the coordinate space of the
// collided-into object, false otherwise.
@ -218,7 +270,7 @@ has_into_intersection_point() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_into_intersection_point
// Access: Public
// Access: Published
// Description: Returns the intersection point in the coordinate
// space of the collided-into object. It is an error to
// call this if has_into_intersection_point() returns
@ -232,7 +284,7 @@ get_into_intersection_point() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::has_from_intersection_point
// Access: Public
// Access: Published
// Description: Returns true if the detected collision knows its
// intersection point in the coordinate space of the
// colliding object, false otherwise.
@ -246,7 +298,7 @@ has_from_intersection_point() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_from_intersection_point
// Access: Public
// Access: Published
// Description: Returns the intersection point in the coordinate
// space of the colliding object. It is an error to
// call this if has_from_intersection_point() returns
@ -254,12 +306,12 @@ has_from_intersection_point() const {
////////////////////////////////////////////////////////////////////
INLINE LPoint3f CollisionEntry::
get_from_intersection_point() const {
return get_into_intersection_point() * get_inv_wrt_space();
return get_into_intersection_point() * get_inv_wrt_mat();
}
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::set_into_surface_normal
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void CollisionEntry::
@ -270,7 +322,7 @@ set_into_surface_normal(const LVector3f &normal) {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::has_into_surface_normal
// Access: Public
// Access: Published
// Description: Returns true if the detected collision knows the
// surface normal of the collided-into object at the
// point of the collision, false otherwise.
@ -282,7 +334,7 @@ has_into_surface_normal() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_into_surface_normal
// Access: Public
// Access: Published
// Description: Returns the surface normal of the collided-into
// object at the point of the collision. It is an error
// to call this if has_into_surface_normal() returns
@ -296,7 +348,7 @@ get_into_surface_normal() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::set_from_surface_normal
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void CollisionEntry::
@ -307,7 +359,7 @@ set_from_surface_normal(const LVector3f &normal) {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::has_from_surface_normal
// Access: Public
// Access: Published
// Description: Returns true if the detected collision knows the
// surface normal of the collided-into object at the
// point of the collision, false otherwise.
@ -319,7 +371,7 @@ has_from_surface_normal() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_from_surface_normal
// Access: Public
// Access: Published
// Description: Returns the surface normal of the collided-into
// object at the point of the collision, in the space of
// the collided-from object. It is an error to call
@ -337,7 +389,7 @@ get_from_surface_normal() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::set_into_depth
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void CollisionEntry::
@ -348,7 +400,7 @@ set_into_depth(float depth) {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::has_into_depth
// Access: Public
// Access: Published
// Description: Returns true if the collision entry knows how "deep"
// the collision was into the collided-into object; that
// is, how far into the surface of the collided-into
@ -361,7 +413,7 @@ has_into_depth() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_into_depth
// Access: Public
// Access: Published
// Description: Returns how "deep" the collision was into the
// collided-into object; that is, how far into the
// surface of the collided-into object the colliding
@ -376,7 +428,7 @@ get_into_depth() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::set_from_depth
// Access: Public
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void CollisionEntry::
@ -387,7 +439,7 @@ set_from_depth(float depth) {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::has_from_depth
// Access: Public
// Access: Published
// Description: Returns true if the collision entry knows how "deep"
// the collision was from the collided-from object; that
// is, how far from the surface of the collided-from
@ -400,7 +452,7 @@ has_from_depth() const {
////////////////////////////////////////////////////////////////////
// Function: CollisionEntry::get_from_depth
// Access: Public
// Access: Published
// Description: Returns how "deep" the collision was from the
// collided-from object; that is, how far from the
// surface of the collided-from object the colliding

View File

@ -37,6 +37,7 @@ CollisionEntry(const CollisionEntry &copy) :
_wrt_space(copy._wrt_space),
_inv_wrt_space(copy._inv_wrt_space),
_flags(copy._flags),
_from_pos_delta(copy._from_pos_delta),
_into_intersection_point(copy._into_intersection_point),
_into_surface_normal(copy._into_surface_normal),
_into_depth(copy._into_depth)
@ -60,6 +61,7 @@ operator = (const CollisionEntry &copy) {
_wrt_space = copy._wrt_space;
_inv_wrt_space = copy._inv_wrt_space;
_flags = copy._flags;
_from_pos_delta = copy._from_pos_delta;
_into_intersection_point = copy._into_intersection_point;
_into_surface_normal = copy._into_surface_normal;
_into_depth = copy._into_depth;
@ -74,6 +76,6 @@ operator = (const CollisionEntry &copy) {
////////////////////////////////////////////////////////////////////
void CollisionEntry::
compute_from_surface_normal() {
_from_surface_normal = get_into_surface_normal() * get_inv_wrt_space();
_from_surface_normal = get_into_surface_normal() * get_inv_wrt_mat();
_flags |= F_has_from_surface_normal;
}

View File

@ -26,6 +26,7 @@
#include "collisionNode.h"
#include "collisionRecorder.h"
#include "transformState.h"
#include "typedReferenceCount.h"
#include "luse.h"
#include "pointerTo.h"
@ -60,14 +61,19 @@ PUBLISHED:
INLINE PandaNode *get_into_node() const;
INLINE const NodePath &get_into_node_path() const;
INLINE const LMatrix4f &get_from_space() const;
INLINE const LMatrix4f &get_into_space() const;
INLINE const LMatrix4f &get_wrt_space() const;
INLINE const LMatrix4f &get_inv_wrt_space() const;
INLINE const TransformState *get_from_space() const;
INLINE const TransformState *get_into_space() const;
INLINE const TransformState *get_wrt_space() const;
INLINE const TransformState *get_inv_wrt_space() const;
INLINE void set_from_velocity(const LVector3f &vel);
INLINE bool has_from_velocity() const;
INLINE const LVector3f &get_from_velocity() const;
INLINE const LMatrix4f &get_from_mat() const;
INLINE const LMatrix4f &get_into_mat() const;
INLINE const LMatrix4f &get_wrt_mat() const;
INLINE const LMatrix4f &get_inv_wrt_mat() const;
INLINE void set_from_pos_delta(const LVector3f &vel);
INLINE bool has_from_pos_delta() const;
INLINE const LVector3f &get_from_pos_delta() const;
INLINE void set_into_intersection_point(const LPoint3f &point);
INLINE bool has_into_intersection_point() const;
@ -103,10 +109,10 @@ private:
PT(CollisionNode) _from_node;
PT(PandaNode) _into_node;
NodePath _into_node_path;
LMatrix4f _from_space;
LMatrix4f _into_space;
LMatrix4f _wrt_space;
LMatrix4f _inv_wrt_space;
CPT(TransformState) _from_space;
CPT(TransformState) _into_space;
CPT(TransformState) _wrt_space;
CPT(TransformState) _inv_wrt_space;
enum Flags {
F_has_into_intersection_point = 0x0001,
@ -114,12 +120,12 @@ private:
F_has_from_surface_normal = 0x0004,
F_has_into_depth = 0x0008,
F_has_from_depth = 0x0010,
F_has_from_velocity = 0x0020,
F_has_from_pos_delta = 0x0020,
};
int _flags;
LVector3f _from_velocity;
LVector3f _from_pos_delta;
LPoint3f _into_intersection_point;
LVector3f _into_surface_normal;
LVector3f _from_surface_normal;

View File

@ -133,6 +133,7 @@ handle_entries() {
LVecBase3f pos = trans->get_pos();
pos[2] += adjust;
def._node->set_transform(trans->set_pos(pos));
} else {
// Otherwise, go ahead and do the matrix math to do things
// the old and clumsy way.

View File

@ -167,10 +167,10 @@ get_node(int n) const {
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4f &CollisionLevelState::
INLINE const TransformState *CollisionLevelState::
get_space(int n) const {
nassertr(n >= 0 && n < (int)_colliders.size(), LMatrix4f::ident_mat());
nassertr(has_collider(n), LMatrix4f::ident_mat());
nassertr(n >= 0 && n < (int)_colliders.size(), TransformState::make_identity());
nassertr(has_collider(n), TransformState::make_identity());
return _colliders[n]._space;
}
@ -180,14 +180,40 @@ get_space(int n) const {
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE const LMatrix4f &CollisionLevelState::
INLINE const TransformState *CollisionLevelState::
get_inv_space(int n) const {
nassertr(n >= 0 && n < (int)_colliders.size(), LMatrix4f::ident_mat());
nassertr(has_collider(n), LMatrix4f::ident_mat());
nassertr(n >= 0 && n < (int)_colliders.size(), TransformState::make_identity());
nassertr(has_collider(n), TransformState::make_identity());
return _colliders[n]._inv_space;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionLevelState::get_prev_space
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE const TransformState *CollisionLevelState::
get_prev_space(int n) const {
nassertr(n >= 0 && n < (int)_colliders.size(), TransformState::make_identity());
nassertr(has_collider(n), TransformState::make_identity());
return _colliders[n]._prev_space;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionLevelState::get_delta
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE const LVector3f &CollisionLevelState::
get_delta(int n) const {
nassertr(n >= 0 && n < (int)_colliders.size(), LVector3f::zero());
nassertr(has_collider(n), LVector3f::zero());
return _colliders[n]._delta;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionLevelState::get_local_bound
// Access: Public

View File

@ -64,20 +64,20 @@ prepare_collider(const ColliderDef &def) {
GeometricBoundingVolume *gbv;
DCAST_INTO_V(gbv, bv.make_copy());
if (def._node->has_velocity()) {
// If the node has a velocity, we have to include the starting
if (def._delta != LVector3f::zero()) {
// If the node has a delta, we have to include the starting
// point in the volume as well.
// Strictly speaking, we should actually transform gbv backward
// by get_velocity(), and extend by *that* volume, instead of
// by the delta(), and extend by *that* volume, instead of
// just extending by the single point at -get_velocity().
// However, assuming the solids within a moving CollisionNode
// tend to be near the origin, this will generally produce the
// same results, and is much easier to compute.
gbv->extend_by(LPoint3f(-def._node->get_velocity()));
gbv->extend_by(LPoint3f(-def._delta));
}
gbv->xform(def._space);
gbv->xform(def._space->get_mat());
_local_bounds.push_back(gbv);
}

View File

@ -26,7 +26,8 @@
#include "geometricBoundingVolume.h"
#include "nodePath.h"
#include "workingNodePath.h"
#include "transformState.h"
#include "pointerTo.h"
#include "plist.h"
class CollisionSolid;
@ -44,8 +45,10 @@ public:
public:
CollisionSolid *_collider;
CollisionNode *_node;
LMatrix4f _space;
LMatrix4f _inv_space;
CPT(TransformState) _space;
CPT(TransformState) _inv_space;
CPT(TransformState) _prev_space;
LVector3f _delta;
};
INLINE CollisionLevelState(const NodePath &node_path);
@ -72,8 +75,10 @@ public:
INLINE CollisionSolid *get_collider(int n) const;
INLINE CollisionNode *get_node(int n) const;
INLINE const LMatrix4f &get_space(int n) const;
INLINE const LMatrix4f &get_inv_space(int n) const;
INLINE const TransformState *get_space(int n) const;
INLINE const TransformState *get_inv_space(int n) const;
INLINE const TransformState *get_prev_space(int n) const;
INLINE const LVector3f &get_delta(int n) const;
INLINE const GeometricBoundingVolume *get_local_bound(int n) const;
INLINE const GeometricBoundingVolume *get_parent_bound(int n) const;

View File

@ -216,10 +216,15 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
trav->traverse(next_data);
}
if (has_velocity()) {
// Determine the previous frame's position, relative to the
// current position.
NodePath node_path = data._node_path.get_node_path();
CPT(TransformState) transform = node_path.get_net_transform()->invert_compose(node_path.get_net_prev_transform());
if (!transform->is_identity()) {
// If we have a velocity, also draw the previous frame's position,
// ghosted.
CPT(TransformState) transform = TransformState::make_pos(-get_velocity());
for (si = _solids.begin(); si != _solids.end(); ++si) {
CollisionSolid *solid = (*si);
PandaNode *node = solid->get_viz();

View File

@ -108,9 +108,9 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
const CollisionSphere *sphere;
DCAST_INTO_R(sphere, entry.get_from(), 0);
LPoint3f from_center = sphere->get_center() * entry.get_wrt_space();
LPoint3f from_center = sphere->get_center() * entry.get_wrt_mat();
LVector3f from_radius_v =
LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_space();
LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_mat();
float from_radius = length(from_radius_v);
float dist = dist_to_plane(from_center);
@ -126,7 +126,7 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
}
PT(CollisionEntry) new_entry = new CollisionEntry(entry);
LVector3f from_normal = get_normal() * entry.get_inv_wrt_space();
LVector3f from_normal = get_normal() * entry.get_inv_wrt_mat();
float from_depth = from_radius - dist;
new_entry->set_into_surface_normal(get_normal());
@ -147,8 +147,8 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
const CollisionRay *ray;
DCAST_INTO_R(ray, entry.get_from(), 0);
LPoint3f from_origin = ray->get_origin() * entry.get_wrt_space();
LVector3f from_direction = ray->get_direction() * entry.get_wrt_space();
LPoint3f from_origin = ray->get_origin() * entry.get_wrt_mat();
LVector3f from_direction = ray->get_direction() * entry.get_wrt_mat();
float t;
if (!_plane.intersects_line(t, from_origin, from_direction)) {

View File

@ -273,15 +273,15 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
const CollisionSphere *sphere;
DCAST_INTO_R(sphere, entry.get_from(), 0);
LPoint3f orig_center = sphere->get_center() * entry.get_wrt_space();
LPoint3f orig_center = sphere->get_center() * entry.get_wrt_mat();
LPoint3f from_center = orig_center;
bool moved_from_center = false;
if (entry.has_from_velocity()) {
// If we have a velocity indication, we use that to determine some
if (entry.has_from_pos_delta()) {
// If we have a pos_delta indication, we use that to determine some
// more properties of the collision.
LPoint3f b = from_center;
LPoint3f a = (sphere->get_center() - entry.get_from_velocity()) * entry.get_wrt_space();
LPoint3f a = (sphere->get_center() - entry.get_from_pos_delta()) * entry.get_wrt_mat();
LVector3f delta = b - a;
// First, there is no collision if the "from" object is moving in
@ -316,7 +316,7 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
}
LVector3f from_radius_v =
LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_space();
LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_mat();
float from_radius = length(from_radius_v);
float dist = dist_to_plane(from_center);
@ -408,8 +408,8 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
new_entry->set_into_surface_normal(get_normal());
new_entry->set_into_depth(into_depth);
LVector3f from_normal = get_normal() * entry.get_inv_wrt_space();
LVector3f from_depth_vec = (get_normal() * into_depth) * entry.get_inv_wrt_space();
LVector3f from_normal = get_normal() * entry.get_inv_wrt_mat();
LVector3f from_depth_vec = (get_normal() * into_depth) * entry.get_inv_wrt_mat();
new_entry->set_from_surface_normal(from_normal);
new_entry->set_from_depth(from_depth_vec.length());
@ -434,8 +434,8 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
const CollisionRay *ray;
DCAST_INTO_R(ray, entry.get_from(), 0);
LPoint3f from_origin = ray->get_origin() * entry.get_wrt_space();
LVector3f from_direction = ray->get_direction() * entry.get_wrt_space();
LPoint3f from_origin = ray->get_origin() * entry.get_wrt_mat();
LVector3f from_direction = ray->get_direction() * entry.get_wrt_mat();
float t;
if (!get_plane().intersects_line(t, from_origin, from_direction)) {
@ -483,8 +483,8 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
const CollisionSegment *segment;
DCAST_INTO_R(segment, entry.get_from(), 0);
LPoint3f from_a = segment->get_point_a() * entry.get_wrt_space();
LPoint3f from_b = segment->get_point_b() * entry.get_wrt_space();
LPoint3f from_a = segment->get_point_a() * entry.get_wrt_mat();
LPoint3f from_b = segment->get_point_b() * entry.get_wrt_mat();
LPoint3f from_direction = from_b - from_a;
float t;

View File

@ -121,9 +121,9 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
const CollisionSphere *sphere;
DCAST_INTO_R(sphere, entry.get_from(), 0);
LPoint3f from_center = sphere->get_center() * entry.get_wrt_space();
LPoint3f from_center = sphere->get_center() * entry.get_wrt_mat();
LVector3f from_radius_v =
LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_space();
LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_mat();
float from_radius = length(from_radius_v);
LPoint3f into_center = _center;
@ -161,7 +161,7 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
new_entry->set_into_intersection_point(into_intersection_point);
new_entry->set_into_depth(into_depth);
LVector3f from_depth_vec = (into_normal * into_depth) * entry.get_inv_wrt_space();
LVector3f from_depth_vec = (into_normal * into_depth) * entry.get_inv_wrt_mat();
new_entry->set_from_depth(from_depth_vec.length());
return new_entry;
@ -177,8 +177,8 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
const CollisionRay *ray;
DCAST_INTO_R(ray, entry.get_from(), 0);
LPoint3f from_origin = ray->get_origin() * entry.get_wrt_space();
LVector3f from_direction = ray->get_direction() * entry.get_wrt_space();
LPoint3f from_origin = ray->get_origin() * entry.get_wrt_mat();
LVector3f from_direction = ray->get_direction() * entry.get_wrt_mat();
double t1, t2;
if (!intersects_line(t1, t2, from_origin, from_direction)) {
@ -223,8 +223,8 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
const CollisionSegment *segment;
DCAST_INTO_R(segment, entry.get_from(), 0);
LPoint3f from_a = segment->get_point_a() * entry.get_wrt_space();
LPoint3f from_b = segment->get_point_b() * entry.get_wrt_space();
LPoint3f from_a = segment->get_point_a() * entry.get_wrt_mat();
LPoint3f from_b = segment->get_point_b() * entry.get_wrt_mat();
LVector3f from_direction = from_b - from_a;
double t1, t2;

View File

@ -17,6 +17,36 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: CollisionTraverser::set_respect_prev_transform
// Access: Public
// Description: Sets the flag that indicates whether the
// prev_transform stored on a node (as updated via
// set_fluid_pos(), etc.) is respected to calculate
// collisions. If this is true, certain types of
// collision tests will be enhanced by the information
// about objects in motion. If this is false, objects
// are always considered to be static. The default is
// false.
////////////////////////////////////////////////////////////////////
INLINE void CollisionTraverser::
set_respect_prev_transform(bool flag) {
_respect_prev_transform = flag;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionTraverser::get_respect_prev_transform
// Access: Public
// Description: Returns the flag that indicates whether the
// prev_transform stored on a node is respected to
// calculate collisions. See
// set_respect_prev_transform().
////////////////////////////////////////////////////////////////////
INLINE bool CollisionTraverser::
get_respect_prev_transform() const {
return _respect_prev_transform;
}
#ifdef DO_COLLISION_RECORDING
////////////////////////////////////////////////////////////////////

View File

@ -41,6 +41,7 @@ PStatCollector CollisionTraverser::_collisions_pcollector("App:Collisions");
////////////////////////////////////////////////////////////////////
CollisionTraverser::
CollisionTraverser() {
_respect_prev_transform = false;
#ifdef DO_COLLISION_RECORDING
_recorder = (CollisionRecorder *)NULL;
#endif
@ -262,17 +263,6 @@ traverse(const NodePath &root) {
}
}
if (auto_clear_velocity) {
// Clear all the velocities for next time.
OrderedColliders::iterator ci;
for (ci = _ordered_colliders.begin();
ci != _ordered_colliders.end();
++ci) {
CollisionNode *node = (*ci);
node->clear_velocity();
}
}
#ifdef DO_COLLISION_RECORDING
if (has_recorder()) {
get_recorder()->end_traversal();
@ -280,6 +270,20 @@ traverse(const NodePath &root) {
#endif // DO_COLLISION_RECORDING
}
////////////////////////////////////////////////////////////////////
// Function: CollisionTraverser::reset_prev_transform
// Access: Public
// Description: Once the collision traversal has finished, resets all
// of the velocity deltas in the scene graph by setting
// the "previous" transform to the current transform.
// This must be called at least once per frame for
// collisions to respect this velocity setting properly.
////////////////////////////////////////////////////////////////////
void CollisionTraverser::
reset_prev_transform(const NodePath &root) {
r_reset_prev_transform(root.node());
}
#ifdef DO_COLLISION_RECORDING
////////////////////////////////////////////////////////////////////
// Function: CollisionTraverser::set_recorder
@ -381,16 +385,22 @@ prepare_colliders(CollisionLevelState &level_state) {
CollisionLevelState::ColliderDef def;
def._node = cnode;
NodePath root;
NodePath cnode_path(cnode);
def._space = cnode_path.get_mat(root);
def._inv_space = root.get_mat(cnode_path);
def._space = cnode_path.get_net_transform();
def._inv_space = def._space->invert_compose(TransformState::make_identity());
def._prev_space = cnode_path.get_net_prev_transform();
if (_respect_prev_transform) {
def._delta = cnode_path.get_pos_delta();
} else {
def._delta = LVector3f::zero();
}
#ifndef NDEBUG
if (def._space.is_nan()) {
if (def._space->is_invalid()) {
collide_cat.error()
<< "Collider " << *cnode
<< " has become NaN. Dropping from traverser.\n";
<< " has become invalid. Dropping from traverser.\n";
// This is safe to do while traversing the list of colliders,
// because we do not increment i in this case.
remove_collider(cnode);
@ -435,7 +445,7 @@ r_traverse(CollisionLevelState &level_state) {
CollisionEntry entry;
entry._into_node = cnode;
entry._into_node_path = level_state.get_node_path();
entry._into_space = entry._into_node_path.get_mat(NodePath());
entry._into_space = entry._into_node_path.get_net_transform();
int num_colliders = level_state.get_num_colliders();
for (int c = 0; c < num_colliders; c++) {
@ -447,16 +457,26 @@ r_traverse(CollisionLevelState &level_state) {
entry._from = level_state.get_collider(c);
entry._from_space = level_state.get_space(c);
if (entry._from_node->has_velocity()) {
entry.set_from_velocity(entry._from_node->get_velocity());
}
LVector3f from_delta = level_state.get_delta(c);
NodePath root;
const LMatrix4f &into_space_inv =
root.get_mat(entry._into_node_path);
entry._wrt_space = entry._from_space * into_space_inv;
entry._inv_wrt_space =
entry._into_space * level_state.get_inv_space(c);
entry._wrt_space = entry._into_space->invert_compose(entry._from_space);
entry._inv_wrt_space = entry._from_space->invert_compose(entry._into_space);
if (_respect_prev_transform) {
CPT(TransformState) from_prev_space = level_state.get_prev_space(c);
CPT(TransformState) inv_wrt_prev_space = from_prev_space->invert_compose(entry._into_node_path.get_net_prev_transform());
LVector3f into_delta = entry._inv_wrt_space->get_pos() - inv_wrt_prev_space->get_pos();
LVector3f delta = from_delta - into_delta;
if (delta != LVector3f::zero()) {
/*
if (entry._from_node->get_name() == "cSphereNode" && entry._into_node->get_name() == "MickeyBlatherSphere") {
cerr << "from_delta = " << from_delta << " into_delta = "
<< into_delta << " delta = " << delta << "\n";
}
*/
entry.set_from_pos_delta(delta);
}
}
compare_collider_to_node(entry,
level_state.get_parent_bound(c),
@ -485,7 +505,7 @@ r_traverse(CollisionLevelState &level_state) {
CollisionEntry entry;
entry._into_node = gnode;
entry._into_node_path = level_state.get_node_path();
entry._into_space = entry._into_node_path.get_mat(NodePath());
entry._into_space = entry._into_node_path.get_net_transform();
int num_colliders = level_state.get_num_colliders();
for (int c = 0; c < num_colliders; c++) {
@ -495,12 +515,8 @@ r_traverse(CollisionLevelState &level_state) {
entry._from = level_state.get_collider(c);
entry._from_space = level_state.get_space(c);
NodePath root;
const LMatrix4f &into_space_inv =
root.get_mat(entry._into_node_path);
entry._wrt_space = entry._from_space * into_space_inv;
entry._inv_wrt_space =
entry._into_space * level_state.get_inv_space(c);
entry._wrt_space = entry._into_space->invert_compose(entry._from_space);
entry._inv_wrt_space = entry._from_space->invert_compose(entry._into_space);
compare_collider_to_geom_node(entry,
level_state.get_parent_bound(c),
@ -716,12 +732,6 @@ remove_handler(CollisionTraverser::Handlers::iterator hi) {
nassertr(_ordered_colliders.size() == _colliders.size(), false);
if (auto_clear_velocity) {
// Clear the velocity on the removed node, to be consistent
// with nodes that were not removed.
node->clear_velocity();
}
} else {
// This collider references some other handler; keep it.
++ci;
@ -730,3 +740,17 @@ remove_handler(CollisionTraverser::Handlers::iterator hi) {
return hi;
}
////////////////////////////////////////////////////////////////////
// Function: CollisionTraverser::r_reset_prev_transform
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void CollisionTraverser::
r_reset_prev_transform(PandaNode *node) {
node->reset_prev_transform();
int num_children = node->get_num_children();
for (int i = 0; i < num_children; i++) {
r_reset_prev_transform(node->get_child(i));
}
}

View File

@ -53,6 +53,9 @@ PUBLISHED:
CollisionTraverser();
~CollisionTraverser();
INLINE void set_respect_prev_transform(bool flag);
INLINE bool get_respect_prev_transform() const;
void add_collider(CollisionNode *node, CollisionHandler *handler);
bool remove_collider(CollisionNode *node);
bool has_collider(CollisionNode *node) const;
@ -62,6 +65,7 @@ PUBLISHED:
void clear_colliders();
void traverse(const NodePath &root);
void reset_prev_transform(const NodePath &root);
#ifdef DO_COLLISION_RECORDING
void set_recorder(CollisionRecorder *recorder);
@ -93,6 +97,8 @@ private:
const GeometricBoundingVolume *from_node_gbv,
const GeometricBoundingVolume *solid_gbv);
void r_reset_prev_transform(PandaNode *node);
private:
PT(CollisionHandler) _default_handler;
TypeHandle _graph_type;
@ -107,6 +113,7 @@ private:
Handlers::iterator remove_handler(Handlers::iterator hi);
bool _respect_prev_transform;
#ifdef DO_COLLISION_RECORDING
CollisionRecorder *_recorder;
#endif // DO_COLLISION_RECORDING

View File

@ -130,17 +130,17 @@ test_intersection_from_sphere(const CollisionEntry &entry) const {
const CollisionSphere *sphere;
DCAST_INTO_R(sphere, entry.get_from(), 0);
LPoint3f from_a = sphere->get_center() * entry.get_wrt_space();
LPoint3f from_a = sphere->get_center() * entry.get_wrt_mat();
LPoint3f from_b = from_a;
if (entry.has_from_velocity()) {
from_a = (sphere->get_center() - entry.get_from_velocity()) * entry.get_wrt_space();
if (entry.has_from_pos_delta()) {
from_a = (sphere->get_center() - entry.get_from_pos_delta()) * entry.get_wrt_mat();
}
LVector3f from_direction = from_b - from_a;
LVector3f from_radius_v =
LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_space();
LVector3f(sphere->get_radius(), 0.0f, 0.0f) * entry.get_wrt_mat();
float from_radius = length(from_radius_v);
double t1, t2;
@ -187,8 +187,8 @@ test_intersection_from_ray(const CollisionEntry &entry) const {
const CollisionRay *ray;
DCAST_INTO_R(ray, entry.get_from(), 0);
LPoint3f from_origin = ray->get_origin() * entry.get_wrt_space();
LVector3f from_direction = ray->get_direction() * entry.get_wrt_space();
LPoint3f from_origin = ray->get_origin() * entry.get_wrt_mat();
LVector3f from_direction = ray->get_direction() * entry.get_wrt_mat();
double t1, t2;
if (!intersects_line(t1, t2, from_origin, from_direction, 0.0f)) {
@ -233,8 +233,8 @@ test_intersection_from_segment(const CollisionEntry &entry) const {
const CollisionSegment *segment;
DCAST_INTO_R(segment, entry.get_from(), 0);
LPoint3f from_a = segment->get_point_a() * entry.get_wrt_space();
LPoint3f from_b = segment->get_point_b() * entry.get_wrt_space();
LPoint3f from_a = segment->get_point_a() * entry.get_wrt_mat();
LPoint3f from_b = segment->get_point_b() * entry.get_wrt_mat();
LVector3f from_direction = from_b - from_a;
double t1, t2;
@ -689,7 +689,7 @@ set_intersection_point(CollisionEntry *new_entry,
new_entry->set_into_surface_normal(normal);
new_entry->set_into_depth(depth);
LVector3f from_depth_vec = (normal * depth) * new_entry->get_inv_wrt_space();
LVector3f from_depth_vec = (normal * depth) * new_entry->get_inv_wrt_mat();
new_entry->set_from_depth(from_depth_vec.length());
}

View File

@ -43,11 +43,6 @@ ConfigureFn(config_collide) {
init_libcollide();
}
// Set this false to stop the CollisionTraverser from automatically
// clearing the velocity associated with its CollisionNodes after it
// has traversed them. Mainly useful for visualizing the velocities.
const bool auto_clear_velocity = config_collide.GetBool("auto-clear-velocity", true);
////////////////////////////////////////////////////////////////////
// Function: init_libcollide
// Description: Initializes the library. This must be called at

View File

@ -24,8 +24,6 @@
NotifyCategoryDecl(collide, EXPCL_PANDA, EXPTP_PANDA);
extern const bool auto_clear_velocity;
extern EXPCL_PANDA void init_libcollide();
#endif

View File

@ -76,6 +76,7 @@ collect(PandaNode *node, int attrib_types) {
nassertv(_transform != (TransformState *)NULL);
_transform = _transform->compose(node->get_transform());
node->set_transform(TransformState::make_identity());
node->reset_prev_transform();
}
if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
@ -141,6 +142,7 @@ void AccumulatedAttribs::
apply_to_node(PandaNode *node, int attrib_types) {
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
node->set_transform(_transform->compose(node->get_transform()));
node->reset_prev_transform();
_transform = TransformState::make_identity();
}

View File

@ -417,7 +417,7 @@ get_state() const {
// Description: Changes the complete state object on this node.
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
set_state(const RenderState *state) const {
set_state(const RenderState *state) {
nassertv_always(!is_empty());
node()->set_state(state);
}
@ -450,7 +450,7 @@ get_transform() const {
// Description: Changes the complete transform object on this node.
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
set_transform(const TransformState *transform) const {
set_transform(const TransformState *transform) {
nassertv_always(!is_empty());
node()->set_transform(transform);
}
@ -466,17 +466,73 @@ get_net_transform() const {
return r_get_net_transform(_head);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_prev_transform
// Access: Published
// Description: Returns the transform that has been set as this
// node's "previous" position. See
// set_prev_transform().
////////////////////////////////////////////////////////////////////
INLINE const TransformState *NodePath::
get_prev_transform() const {
nassertr_always(!is_empty(), TransformState::make_identity());
return node()->get_prev_transform();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_prev_transform
// Access: Published
// Description: Sets the transform that represents this node's
// "previous" position, one frame ago, for the purposes
// of detecting motion for accurate collision
// calculations.
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
set_prev_transform(const TransformState *transform) {
nassertv_always(!is_empty());
node()->set_prev_transform(transform);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_net_prev_transform
// Access: Published
// Description: Returns the net "previous" transform on this node
// from the root. See set_prev_transform().
////////////////////////////////////////////////////////////////////
INLINE CPT(TransformState) NodePath::
get_net_prev_transform() const {
uncollapse_head();
return r_get_net_prev_transform(_head);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_pos
// Access: Published
// Description: Sets the translation component of the transform,
// leaving rotation and scale untouched.
// leaving rotation and scale untouched. This also
// resets the node's "previous" position, so that the
// collision system will see the node as having suddenly
// appeared in the new position, without passing any
// points in between.
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
set_pos(float x, float y, float z) {
set_pos(LPoint3f(x, y, z));
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_fluid_pos
// Access: Published
// Description: Sets the translation component, without changing the
// "previous" position, so that the collision system
// will see the node as moving fluidly from its previous
// position to its new position.
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
set_fluid_pos(float x, float y, float z) {
set_fluid_pos(LPoint3f(x, y, z));
}
INLINE float NodePath::
get_x() const {
return get_pos()[0];
@ -870,59 +926,6 @@ get_distance(const NodePath &other) const {
return length(LVector3f(pos));
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_velocity
// Access: Published
// Description: Sets the velocity of this node. This is a delta from
// the position of this node in the previous frame,
// relative to the node's parent. The value should not
// be transformed by the node's transformation (it is in
// the coordinate system of the node's parent). This
// has meaning only to the collision subsystem.
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
set_velocity(const LVector3f &velocity) {
nassertv_always(!is_empty());
node()->set_velocity(velocity);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::clear_velocity
// Access: Published
// Description: Resets the velocity of this node to zero. See
// set_velocity().
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
clear_velocity() {
nassertv_always(!is_empty());
node()->clear_velocity();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::has_velocity
// Access: Published
// Description: Returns true if a nonzero velocity has been set on
// this node, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool NodePath::
has_velocity() const {
nassertr_always(!is_empty(), false);
return node()->has_velocity();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_velocity
// Access: Published
// Description: Returns the velocity previously set on this node via
// set_velocity(), or LVector3f::zero() if no velocity
// has been set.
////////////////////////////////////////////////////////////////////
INLINE const LVector3f &NodePath::
get_velocity() const {
nassertr_always(!is_empty(), LVector3f::zero());
return node()->get_velocity();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_color_scale
// Access: Published

View File

@ -291,6 +291,9 @@ reparent_to(const NodePath &other, int sort) {
uncollapse_head();
other.uncollapse_head();
PandaNode::reparent(other._head, _head, sort);
// Reparenting implicitly resents the delta vector.
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -309,7 +312,14 @@ wrt_reparent_to(const NodePath &other, int sort) {
nassertv_always(!is_empty());
nassertv_always(!other.is_empty());
set_transform(get_transform(other));
if (get_transform() == get_prev_transform()) {
set_transform(get_transform(other));
node()->reset_prev_transform();
} else {
set_transform(get_transform(other));
set_prev_transform(get_prev_transform(other));
}
reparent_to(other, sort);
}
@ -343,6 +353,11 @@ instance_to(const NodePath &other, int sort) const {
NodePath new_instance;
new_instance._head = PandaNode::attach(other._head, node(), sort);
// instance_to() doesn't reset the velocity delta, unlike most of
// the other reparenting operations. The reasoning is that
// instance_to() is not necessarily a reparenting operation, since
// it doesn't change the original instance.
return new_instance;
}
@ -369,7 +384,7 @@ instance_under_node(const NodePath &other, const string &name, int sort) const {
////////////////////////////////////////////////////////////////////
// Function: NodePath::copy_to
// Access: Published
// Description: Functions exactly like instance_to(), except a deep
// Description: Functions like instance_to(), except a deep
// copy is made of the referenced node and all of its
// descendents, which is then parented to the indicated
// node. A NodePath to the newly created copy is
@ -386,6 +401,8 @@ copy_to(const NodePath &other, int sort) const {
PT(PandaNode) copy_node = source_node->copy_subgraph();
nassertr(copy_node != (PandaNode *)NULL, fail());
copy_node->reset_prev_transform();
return other.attach_new_node(copy_node, sort);
}
@ -444,6 +461,7 @@ remove_node() {
// In either case, quietly do nothing except to ensure the
// NodePath is clear.
if (!is_empty() && !is_singleton()) {
node()->reset_prev_transform();
uncollapse_head();
PandaNode::detach(_head);
}
@ -474,6 +492,7 @@ void NodePath::
detach_node() {
nassertv(_error_type != ET_not_found);
if (!is_empty() && !is_singleton()) {
node()->reset_prev_transform();
uncollapse_head();
PandaNode::detach(_head);
}
@ -546,7 +565,7 @@ get_state(const NodePath &other) const {
// the other node.
////////////////////////////////////////////////////////////////////
void NodePath::
set_state(const NodePath &other, const RenderState *state) const {
set_state(const NodePath &other, const RenderState *state) {
nassertv(_error_type == ET_ok && other._error_type == ET_ok);
nassertv_always(!is_empty());
@ -594,7 +613,7 @@ get_transform(const NodePath &other) const {
// other node.
////////////////////////////////////////////////////////////////////
void NodePath::
set_transform(const NodePath &other, const TransformState *transform) const {
set_transform(const NodePath &other, const TransformState *transform) {
nassertv(_error_type == ET_ok && other._error_type == ET_ok);
nassertv_always(!is_empty());
@ -610,16 +629,74 @@ set_transform(const NodePath &other, const TransformState *transform) const {
set_transform(new_trans);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_prev_transform
// Access: Published
// Description: Returns the relative "previous" transform to this
// node from the other node; i.e. the position of this
// node in the previous frame, as seen by the other node
// in the previous frame.
////////////////////////////////////////////////////////////////////
CPT(TransformState) NodePath::
get_prev_transform(const NodePath &other) const {
if (other.is_empty()) {
return get_net_prev_transform();
}
if (is_empty()) {
return other.get_net_prev_transform()->invert_compose(TransformState::make_identity());
}
nassertr(verify_complete(), TransformState::make_identity());
nassertr(other.verify_complete(), TransformState::make_identity());
int a_count, b_count;
find_common_ancestor(*this, other, a_count, b_count);
CPT(TransformState) a_prev_transform = r_get_partial_prev_transform(_head, a_count);
CPT(TransformState) b_prev_transform = r_get_partial_prev_transform(other._head, b_count);
return b_prev_transform->invert_compose(a_prev_transform);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_prev_transform
// Access: Published
// Description: Sets the "previous" transform object on this node,
// relative to the other node. This computes a new
// transform object that will have the indicated value
// when seen from the other node.
////////////////////////////////////////////////////////////////////
void NodePath::
set_prev_transform(const NodePath &other, const TransformState *transform) {
nassertv(_error_type == ET_ok && other._error_type == ET_ok);
nassertv_always(!is_empty());
// First, we perform a wrt to the parent, to get the conversion.
CPT(TransformState) rel_trans;
if (has_parent()) {
rel_trans = other.get_prev_transform(get_parent());
} else {
rel_trans = other.get_prev_transform(NodePath());
}
CPT(TransformState) new_trans = rel_trans->compose(transform);
set_prev_transform(new_trans);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_pos
// Access: Published
// Description: Sets the translation component of the transform,
// leaving rotation and scale untouched.
// leaving rotation and scale untouched. This also
// resets the node's "previous" position, so that the
// collision system will see the node as having suddenly
// appeared in the new position, without passing any
// points in between.
////////////////////////////////////////////////////////////////////
void NodePath::
set_pos(const LVecBase3f &pos) {
nassertv_always(!is_empty());
set_transform(get_transform()->set_pos(pos));
node()->reset_prev_transform();
}
void NodePath::
@ -646,6 +723,44 @@ set_z(float z) {
set_pos(pos);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_fluid_pos
// Access: Published
// Description: Sets the translation component, without changing the
// "previous" position, so that the collision system
// will see the node as moving fluidly from its previous
// position to its new position.
////////////////////////////////////////////////////////////////////
void NodePath::
set_fluid_pos(const LVecBase3f &pos) {
nassertv_always(!is_empty());
set_transform(get_transform()->set_pos(pos));
}
void NodePath::
set_fluid_x(float x) {
nassertv_always(!is_empty());
LPoint3f pos = get_pos();
pos[0] = x;
set_fluid_pos(pos);
}
void NodePath::
set_fluid_y(float y) {
nassertv_always(!is_empty());
LPoint3f pos = get_pos();
pos[1] = y;
set_fluid_pos(pos);
}
void NodePath::
set_fluid_z(float z) {
nassertv_always(!is_empty());
LPoint3f pos = get_pos();
pos[2] = z;
set_fluid_pos(pos);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_pos
// Access: Published
@ -657,6 +772,26 @@ get_pos() const {
return get_transform()->get_pos();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_pos_delta
// Access: Published
// Description: Returns the delta vector from this node's position in
// the previous frame (according to
// set_prev_transform(), typically set via the use of
// set_fluid_pos()) and its position in the current
// frame. This is the vector used to determine
// collisions. Generally, if the node was last
// repositioned via set_pos(), the delta will be zero;
// if it was adjusted via set_fluid_pos(), the delta
// will represent the change from the previous frame's
// position.
////////////////////////////////////////////////////////////////////
LVector3f NodePath::
get_pos_delta() const {
nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
return get_transform()->get_pos() - get_prev_transform()->get_pos();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_hpr
// Access: Published
@ -856,6 +991,7 @@ set_pos_hpr(const LVecBase3f &pos, const LVecBase3f &hpr) {
transform = TransformState::make_pos_hpr_scale_shear
(pos, hpr, transform->get_scale(), transform->get_shear());
set_transform(transform);
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -885,6 +1021,7 @@ set_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr,
nassertv_always(!is_empty());
set_transform(TransformState::make_pos_hpr_scale
(pos, hpr, scale));
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -899,6 +1036,7 @@ set_pos_quat_scale(const LVecBase3f &pos, const LQuaternionf &quat,
nassertv_always(!is_empty());
set_transform(TransformState::make_pos_quat_scale
(pos, quat, scale));
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -913,6 +1051,7 @@ set_pos_hpr_scale_shear(const LVecBase3f &pos, const LVecBase3f &hpr,
nassertv_always(!is_empty());
set_transform(TransformState::make_pos_hpr_scale_shear
(pos, hpr, scale, shear));
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -927,6 +1066,7 @@ set_pos_quat_scale_shear(const LVecBase3f &pos, const LQuaternionf &quat,
nassertv_always(!is_empty());
set_transform(TransformState::make_pos_quat_scale_shear
(pos, quat, scale, shear));
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -938,6 +1078,7 @@ void NodePath::
set_mat(const LMatrix4f &mat) {
nassertv_always(!is_empty());
set_transform(TransformState::make_mat(mat));
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -1003,6 +1144,7 @@ set_pos(const NodePath &other, const LVecBase3f &pos) {
// If we didn't have a componentwise transform already, never
// mind.
set_transform(other, rel_transform->set_pos(pos));
node()->reset_prev_transform();
}
}
@ -1042,6 +1184,27 @@ get_pos(const NodePath &other) const {
return get_transform(other)->get_pos();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_pos_delta
// Access: Published
// Description: Returns the delta vector from this node's position in
// the previous frame (according to
// set_prev_transform(), typically set via the use of
// set_fluid_pos()) and its position in the current
// frame, as seen in the indicated node's coordinate
// space. This is the vector used to determine
// collisions. Generally, if the node was last
// repositioned via set_pos(), the delta will be zero;
// if it was adjusted via set_fluid_pos(), the delta
// will represent the change from the previous frame's
// position.
////////////////////////////////////////////////////////////////////
LVector3f NodePath::
get_pos_delta(const NodePath &other) const {
nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
return get_transform(other)->get_pos() - get_prev_transform(other)->get_pos();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_hpr
// Access: Published
@ -1067,7 +1230,8 @@ set_hpr(const NodePath &other, const LVecBase3f &hpr) {
set_transform(other, rel_transform->set_hpr(hpr));
const TransformState *new_transform = get_transform();
if (new_transform->has_components()) {
set_pos_hpr_scale_shear(orig_pos, new_transform->get_hpr(), orig_scale, orig_shear);
set_transform(TransformState::make_pos_hpr_scale_shear
(orig_pos, new_transform->get_hpr(), orig_scale, orig_shear));
}
} else {
@ -1139,7 +1303,8 @@ set_quat(const NodePath &other, const LQuaternionf &quat) {
set_transform(other, rel_transform->set_quat(quat));
const TransformState *new_transform = get_transform();
if (new_transform->has_components()) {
set_pos_quat_scale_shear(orig_pos, new_transform->get_quat(), orig_scale, orig_shear);
set_transform(TransformState::make_pos_quat_scale_shear
(orig_pos, new_transform->get_quat(), orig_scale, orig_shear));
}
} else {
@ -1186,7 +1351,8 @@ set_scale(const NodePath &other, const LVecBase3f &scale) {
set_transform(other, rel_transform->set_scale(scale));
const TransformState *new_transform = get_transform();
if (new_transform->has_components()) {
set_pos_hpr_scale_shear(orig_pos, orig_hpr, new_transform->get_scale(), orig_shear);
set_transform(TransformState::make_pos_hpr_scale_shear
(orig_pos, orig_hpr, new_transform->get_scale(), orig_shear));
}
} else {
@ -1257,7 +1423,8 @@ set_shear(const NodePath &other, const LVecBase3f &shear) {
set_transform(other, rel_transform->set_shear(shear));
const TransformState *new_transform = get_transform();
if (new_transform->has_components()) {
set_pos_hpr_scale_shear(orig_pos, orig_hpr, orig_scale, new_transform->get_shear());
set_transform(TransformState::make_pos_hpr_scale_shear
(orig_pos, orig_hpr, orig_scale, new_transform->get_shear()));
}
} else {
@ -1338,6 +1505,7 @@ set_pos_hpr(const NodePath &other, const LVecBase3f &pos,
// mind.
set_transform(other, TransformState::make_pos_hpr_scale_shear
(pos, hpr, rel_transform->get_scale(), rel_transform->get_shear()));
node()->reset_prev_transform();
}
}
@ -1376,6 +1544,7 @@ set_pos_hpr_scale(const NodePath &other,
nassertv_always(!is_empty());
set_transform(other, TransformState::make_pos_hpr_scale
(pos, hpr, scale));
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -1392,6 +1561,7 @@ set_pos_quat_scale(const NodePath &other,
nassertv_always(!is_empty());
set_transform(other, TransformState::make_pos_quat_scale
(pos, quat, scale));
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -1408,6 +1578,7 @@ set_pos_hpr_scale_shear(const NodePath &other,
nassertv_always(!is_empty());
set_transform(other, TransformState::make_pos_hpr_scale_shear
(pos, hpr, scale, shear));
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -1424,6 +1595,7 @@ set_pos_quat_scale_shear(const NodePath &other,
nassertv_always(!is_empty());
set_transform(other, TransformState::make_pos_quat_scale_shear
(pos, quat, scale, shear));
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -1455,6 +1627,7 @@ void NodePath::
set_mat(const NodePath &other, const LMatrix4f &mat) {
nassertv_always(!is_empty());
set_transform(other, TransformState::make_mat(mat));
node()->reset_prev_transform();
}
////////////////////////////////////////////////////////////////////
@ -1525,106 +1698,6 @@ heads_up(const NodePath &other, const LPoint3f &point, const LVector3f &up) {
set_quat(quat);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_velocity
// Access: Published
// Description: Returns the relative velocity to this node from the
// other node; i.e. the velocity of this node as seen
// from the other node.
////////////////////////////////////////////////////////////////////
LVector3f NodePath::
get_velocity(const NodePath &other) const {
if (other.is_empty()) {
return get_net_velocity();
}
if (is_empty()) {
other.uncollapse_head();
CPT(TransformState) net_transform = TransformState::make_identity();
CPT(TransformState) parent_transform = net_transform;
LVector3f net_velocity = LVector3f::zero();
r_get_net_velocity(other._head, net_velocity, net_transform, parent_transform);
return -net_velocity;
}
nassertr(verify_complete(), LVector3f::zero());
nassertr(other.verify_complete(), LVector3f::zero());
int a_count, b_count;
find_common_ancestor(*this, other, a_count, b_count);
// Now compute the net velocity of each node, by working down from
// the common ancestor.
CPT(TransformState) a_transform = TransformState::make_identity();
CPT(TransformState) a_parent_transform = a_transform;
LVector3f a_velocity = LVector3f::zero();
r_get_partial_velocity(_head, a_count, a_velocity, a_transform,
a_parent_transform);
CPT(TransformState) b_transform = TransformState::make_identity();
CPT(TransformState) b_parent_transform = b_transform;
LVector3f b_velocity = LVector3f::zero();
r_get_partial_velocity(other._head, b_count, b_velocity, b_transform,
b_parent_transform);
LVector3f net_velocity = a_velocity - b_velocity;
// Finally, convert the net velocity back into the parent's
// coordinate space.
CPT(TransformState) a_parent_inverse =
a_parent_transform->invert_compose(TransformState::make_identity());
return net_velocity * a_parent_inverse->get_mat();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_velocity
// Access: Published
// Description: Sets the velocity of this node, relative to the other
// node. This computes a new velocity that will have
// the indicated value when seen from the other node.
////////////////////////////////////////////////////////////////////
void NodePath::
set_velocity(const NodePath &other, const LVector3f &velocity) {
nassertv(_error_type == ET_ok && other._error_type == ET_ok);
nassertv_always(!is_empty());
// First, we perform a wrt to the parent, to get the conversion.
LVector3f rel_velocity;
if (has_parent()) {
rel_velocity = other.get_velocity(get_parent());
} else {
rel_velocity = other.get_velocity(NodePath());
}
LVector3f new_velocity = velocity + rel_velocity;
set_velocity(new_velocity);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::get_net_velocity
// Access: Published
// Description: Returns the relative "velocity" of this node (as
// reported by get_velocity()) from the root of the
// scene graph, accumulating all velocity values set on
// ancestor nodes. The result is returned in the
// coordinate space of the node's parent (the same
// coordinate space in which get_velocity() is
// returned).
////////////////////////////////////////////////////////////////////
LVector3f NodePath::
get_net_velocity() const {
uncollapse_head();
CPT(TransformState) net_transform = TransformState::make_identity();
CPT(TransformState) parent_transform = net_transform;
LVector3f net_velocity = LVector3f::zero();
r_get_net_velocity(_head, net_velocity, net_transform, parent_transform);
// Convert the net velocity back from global coordinates into the
// parent's coordinate space.
CPT(TransformState) parent_inverse =
parent_transform->invert_compose(TransformState::make_identity());
return net_velocity * parent_inverse->get_mat();
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::set_color
@ -3442,58 +3515,38 @@ r_get_partial_transform(NodePathComponent *comp, int n) const {
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::r_get_net_velocity
// Function: NodePath::r_get_net_prev_transform
// Access: Private
// Description: Recursively determines the net velocity of the
// indicated node; the result is returned in the global
// coordinate space.
// Description: Recursively determines the net "previous" transform
// to the indicated component node from the root of the
// graph.
////////////////////////////////////////////////////////////////////
void NodePath::
r_get_net_velocity(NodePathComponent *comp, LVector3f &net_vel,
CPT(TransformState) &net_transform,
CPT(TransformState) &parent_net_transform) const {
if (comp != (NodePathComponent *)NULL) {
r_get_net_velocity(comp->get_next(), net_vel, net_transform,
parent_net_transform);
PandaNode *node = comp->get_node();
if (node->has_velocity()) {
LVector3f vel = node->get_velocity();
net_vel += vel * net_transform->get_mat();
}
CPT(TransformState) transform = node->get_transform();
parent_net_transform = net_transform;
net_transform = net_transform->compose(transform);
CPT(TransformState) NodePath::
r_get_net_prev_transform(NodePathComponent *comp) const {
if (comp == (NodePathComponent *)NULL) {
return TransformState::make_identity();
} else {
CPT(TransformState) transform = comp->get_node()->get_prev_transform();
return r_get_net_prev_transform(comp->get_next())->compose(transform);
}
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::r_get_partial_velocity
// Function: NodePath::r_get_partial_prev_transform
// Access: Private
// Description: Recursively determines the net velocity of the
// indicated component node from the nth node above it.
// If n exceeds the length of the path, this returns the
// net velocity from the root of the graph.
// Description: Recursively determines the net "previous" transform
// to the indicated component node from the nth node
// above it. If n exceeds the length of the path, this
// returns the net previous transform from the root of
// the graph.
////////////////////////////////////////////////////////////////////
void NodePath::
r_get_partial_velocity(NodePathComponent *comp, int n,
LVector3f &net_vel,
CPT(TransformState) &net_transform,
CPT(TransformState) &parent_net_transform) const {
if (n != 0 && comp != (NodePathComponent *)NULL) {
r_get_partial_velocity(comp->get_next(), n - 1, net_vel, net_transform,
parent_net_transform);
PandaNode *node = comp->get_node();
if (node->has_velocity()) {
LVector3f vel = node->get_velocity();
net_vel += vel * net_transform->get_mat();
}
CPT(TransformState) transform = node->get_transform();
parent_net_transform = net_transform;
net_transform = net_transform->compose(transform);
CPT(TransformState) NodePath::
r_get_partial_prev_transform(NodePathComponent *comp, int n) const {
if (n == 0 || comp == (NodePathComponent *)NULL) {
return TransformState::make_identity();
} else {
CPT(TransformState) transform = comp->get_node()->get_prev_transform();
return r_get_partial_prev_transform(comp->get_next(), n - 1)->compose(transform);
}
}

View File

@ -225,17 +225,23 @@ PUBLISHED:
// Aggregate transform and state information.
INLINE const RenderState *get_state() const;
INLINE void set_state(const RenderState *state) const;
INLINE void set_state(const RenderState *state);
CPT(RenderState) get_state(const NodePath &other) const;
void set_state(const NodePath &other, const RenderState *state) const;
void set_state(const NodePath &other, const RenderState *state);
INLINE CPT(RenderState) get_net_state() const;
INLINE const TransformState *get_transform() const;
INLINE void set_transform(const TransformState *transform) const;
INLINE void set_transform(const TransformState *transform);
CPT(TransformState) get_transform(const NodePath &other) const;
void set_transform(const NodePath &other, const TransformState *transform) const;
void set_transform(const NodePath &other, const TransformState *transform);
INLINE CPT(TransformState) get_net_transform() const;
INLINE const TransformState *get_prev_transform() const;
INLINE void set_prev_transform(const TransformState *transform);
CPT(TransformState) get_prev_transform(const NodePath &other) const;
void set_prev_transform(const NodePath &other, const TransformState *transform);
INLINE CPT(TransformState) get_net_prev_transform() const;
// Methods that get and set the matrix transform: pos, hpr, scale,
// in the local coordinate system.
@ -245,11 +251,18 @@ PUBLISHED:
void set_x(float x);
void set_y(float y);
void set_z(float z);
INLINE void set_fluid_pos(float x, float y, float z);
void set_fluid_pos(const LVecBase3f &pos);
void set_fluid_x(float x);
void set_fluid_y(float y);
void set_fluid_z(float z);
LPoint3f get_pos() const;
INLINE float get_x() const;
INLINE float get_y() const;
INLINE float get_z() const;
LVector3f get_pos_delta() const;
INLINE void set_hpr(float h, float p, float r);
void set_hpr(const LVecBase3f &hpr);
void set_h(float h);
@ -334,6 +347,8 @@ PUBLISHED:
INLINE float get_y(const NodePath &other) const;
INLINE float get_z(const NodePath &other) const;
LVector3f get_pos_delta(const NodePath &other) const;
INLINE void set_hpr(const NodePath &other, float h, float p, float r);
void set_hpr(const NodePath &other, const LVecBase3f &hpr);
void set_h(const NodePath &other, float h);
@ -421,17 +436,6 @@ PUBLISHED:
INLINE float get_distance(const NodePath &other) const;
INLINE void set_velocity(const LVector3f &velocity);
INLINE void clear_velocity();
INLINE bool has_velocity() const;
INLINE const LVector3f &get_velocity() const;
LVector3f get_velocity(const NodePath &other) const;
void set_velocity(const NodePath &other, const LVector3f &velocity);
LVector3f get_net_velocity() const;
// Methods that affect appearance of geometry: color, texture, etc.
// These affect the state at the bottom level only.
@ -595,14 +599,8 @@ private:
CPT(RenderState) r_get_partial_state(NodePathComponent *comp, int n) const;
CPT(TransformState) r_get_net_transform(NodePathComponent *comp) const;
CPT(TransformState) r_get_partial_transform(NodePathComponent *comp, int n) const;
void r_get_net_velocity(NodePathComponent *comp, LVector3f &net_vel,
CPT(TransformState) &net_transform,
CPT(TransformState) &parent_net_transform) const;
void r_get_partial_velocity(NodePathComponent *comp, int n,
LVector3f &net_vel,
CPT(TransformState) &net_transform,
CPT(TransformState) &parent_net_transform) const;
CPT(TransformState) r_get_net_prev_transform(NodePathComponent *comp) const;
CPT(TransformState) r_get_partial_prev_transform(NodePathComponent *comp, int n) const;
void find_matches(NodePathCollection &result,
const string &approx_path_str,

View File

@ -118,9 +118,8 @@ CData() {
_state = RenderState::make_empty();
_effects = RenderEffects::make_empty();
_transform = TransformState::make_identity();
_prev_transform = TransformState::make_identity();
_draw_mask = DrawMask::all_on();
_velocity = LVector3f::zero();
_has_velocity = false;
_net_collide_mask = CollideMask::all_off();
_fixed_internal_bound = false;
}
@ -139,10 +138,9 @@ CData(const PandaNode::CData &copy) :
_state(copy._state),
_effects(copy._effects),
_transform(copy._transform),
_prev_transform(copy._prev_transform),
_tag_data(copy._tag_data),
_draw_mask(copy._draw_mask),
_velocity(copy._velocity),
_has_velocity(copy._has_velocity),
_fixed_internal_bound(copy._fixed_internal_bound)
{
_net_collide_mask = CollideMask::all_off();
@ -662,6 +660,46 @@ clear_transform() {
transform_changed();
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::set_prev_transform
// Access: Published
// Description: Sets the transform that represents this node's
// "previous" position, one frame ago, for the purposes
// of detecting motion for accurate collision
// calculations.
////////////////////////////////////////////////////////////////////
INLINE void PandaNode::
set_prev_transform(const TransformState *transform) {
CDWriter cdata(_cycler);
cdata->_prev_transform = transform;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_prev_transform
// Access: Published
// Description: Returns the transform that has been set as this
// node's "previous" position. See
// set_prev_transform().
////////////////////////////////////////////////////////////////////
INLINE const TransformState *PandaNode::
get_prev_transform() const {
CDReader cdata(_cycler);
return cdata->_prev_transform;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::reset_prev_transform
// Access: Published
// Description: Resets the "previous" transform on this node to be
// the same as the current transform. This is not the
// same as clearing it to identity.
////////////////////////////////////////////////////////////////////
INLINE void PandaNode::
reset_prev_transform() {
CDWriter cdata(_cycler);
cdata->_prev_transform = cdata->_transform;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::set_tag
// Access: Published
@ -784,61 +822,6 @@ get_net_collide_mask() const {
return cdata->_net_collide_mask;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::set_velocity
// Access: Published
// Description: Sets the velocity of this node. This is a delta from
// the position of this node in the previous frame,
// relative to the node's parent. The value should not
// be transformed by the node's transformation (it is in
// the coordinate system of the node's parent). This
// has meaning only to the collision subsystem.
////////////////////////////////////////////////////////////////////
INLINE void PandaNode::
set_velocity(const LVector3f &velocity) {
CDWriter cdata(_cycler);
cdata->_velocity = velocity;
cdata->_has_velocity = (!velocity.almost_equal(LVector3f::zero()));
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::clear_velocity
// Access: Published
// Description: Resets the velocity of this node to zero. See
// set_velocity().
////////////////////////////////////////////////////////////////////
INLINE void PandaNode::
clear_velocity() {
CDWriter cdata(_cycler);
cdata->_velocity = LVector3f::zero();
cdata->_has_velocity = false;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::has_velocity
// Access: Published
// Description: Returns true if a nonzero velocity has been set on
// this node, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool PandaNode::
has_velocity() const {
CDReader cdata(_cycler);
return cdata->_has_velocity;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_velocity
// Access: Published
// Description: Returns the velocity previously set on this node via
// set_velocity(), or LVector3f::zero() if no velocity
// has been set.
////////////////////////////////////////////////////////////////////
INLINE const LVector3f &PandaNode::
get_velocity() const {
CDReader cdata(_cycler);
return cdata->_velocity;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::set_bound
// Access: Published

View File

@ -150,6 +150,10 @@ PUBLISHED:
INLINE const TransformState *get_transform() const;
INLINE void clear_transform();
INLINE void set_prev_transform(const TransformState *transform);
INLINE const TransformState *get_prev_transform() const;
INLINE void reset_prev_transform();
INLINE void set_tag(const string &key, const string &value);
INLINE string get_tag(const string &key) const;
INLINE bool has_tag(const string &key) const;
@ -162,11 +166,6 @@ PUBLISHED:
INLINE CollideMask get_net_collide_mask() const;
INLINE void set_velocity(const LVector3f &velocity);
INLINE void clear_velocity();
INLINE bool has_velocity() const;
INLINE const LVector3f &get_velocity() const;
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level) const;
@ -314,15 +313,13 @@ private:
CPT(RenderState) _state;
CPT(RenderEffects) _effects;
CPT(TransformState) _transform;
CPT(TransformState) _prev_transform;
TagData _tag_data;
// This is the draw_mask of this particular node.
DrawMask _draw_mask;
LVector3f _velocity;
bool _has_velocity;
// This is the union of all into_collide_mask bits for any
// CollisionNodes at and below this level. It's conceptually
// similar to a bounding volume--it represents the bounding volume

View File

@ -32,10 +32,8 @@ Transform2SG(const string &name) :
DataNode(name)
{
_transform_input = define_input("transform", EventStoreTransform::get_class_type());
_velocity_input = define_input("velocity", EventStoreVec3::get_class_type());
_node = NULL;
_velocity_node = NULL;
}
////////////////////////////////////////////////////////////////////
@ -59,33 +57,6 @@ get_node() const {
return _node;
}
////////////////////////////////////////////////////////////////////
// Function: Transform2SG::set_velocity_node
// Access: Public
// Description: Sets the node that this object will assign the
// computed velocity to. Normally this is a
// CollisionNode parented below the node indicated by
// set_node(). Setting this node allows the collision
// system to track the velocity imparted to the
// CollisionNode by the data graph object that set its
// transform, if that data is available.
////////////////////////////////////////////////////////////////////
void Transform2SG::
set_velocity_node(PandaNode *node) {
_velocity_node = node;
}
////////////////////////////////////////////////////////////////////
// Function: Transform2SG::get_velocity_node
// Access: Public
// Description: Returns the node that this object will assign the
// computed velocity to. See set_velocity_node().
////////////////////////////////////////////////////////////////////
PandaNode *Transform2SG::
get_velocity_node() const {
return _velocity_node;
}
////////////////////////////////////////////////////////////////////
// Function: Transform2SG::do_transmit_data
@ -110,13 +81,4 @@ do_transmit_data(const DataNodeTransmit &input, DataNodeTransmit &) {
_node->set_transform(ts);
}
}
if (input.has_data(_velocity_input)) {
const EventStoreVec3 *velocity;
DCAST_INTO_V(velocity, input.get_data(_velocity_input).get_ptr());
LVector3f vel = velocity->get_value();
if (_velocity_node != (PandaNode *)NULL) {
_velocity_node->set_velocity(vel);
}
}
}

View File

@ -38,12 +38,8 @@ PUBLISHED:
void set_node(PandaNode *node);
PandaNode *get_node() const;
void set_velocity_node(PandaNode *node);
PandaNode *get_velocity_node() const;
private:
PandaNode *_node;
PandaNode *_velocity_node;
protected:
// Inherited from DataNode
@ -53,7 +49,6 @@ protected:
private:
// inputs
int _transform_input;
int _velocity_input;
public:
static TypeHandle get_class_type() {