mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
almost-complete implementation
This commit is contained in:
parent
2c4f49004f
commit
6526d3a57a
18
panda/src/collide/collisionHandlerFluidPusher.I
Executable file
18
panda/src/collide/collisionHandlerFluidPusher.I
Executable file
@ -0,0 +1,18 @@
|
||||
// Filename: collisionHandlerFluidPusher.I
|
||||
// Created by: WDIG (15Aug07)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
245
panda/src/collide/collisionHandlerFluidPusher.cxx
Executable file
245
panda/src/collide/collisionHandlerFluidPusher.cxx
Executable file
@ -0,0 +1,245 @@
|
||||
// Filename: collisionHandlerFluidPusher.cxx
|
||||
// Created by: drose (16Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "collisionHandlerFluidPusher.h"
|
||||
#include "collisionNode.h"
|
||||
#include "collisionEntry.h"
|
||||
#include "collisionPolygon.h"
|
||||
#include "config_collide.h"
|
||||
#include "dcast.h"
|
||||
|
||||
TypeHandle CollisionHandlerFluidPusher::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionHandlerFluidPusher::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CollisionHandlerFluidPusher::
|
||||
CollisionHandlerFluidPusher() {
|
||||
_wants_all_potential_collidees = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionHandlerFluidPusher::add_entry
|
||||
// Access: Public, Virtual
|
||||
// Description: Called between a begin_group() .. end_group()
|
||||
// sequence for each collision that is detected.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CollisionHandlerFluidPusher::
|
||||
add_entry(CollisionEntry *entry) {
|
||||
nassertv(entry != (CollisionEntry *)NULL);
|
||||
// skip over CollisionHandlerPhysical::add_entry, since it filters
|
||||
// out collidees by orientation; our collider can change direction
|
||||
// mid-frame, so it may collide with something that would have been
|
||||
// filtered out
|
||||
CollisionHandlerEvent::add_entry(entry);
|
||||
|
||||
// filter out non-tangibles
|
||||
if (entry->get_from()->is_tangible() &&
|
||||
(!entry->has_into() || entry->get_into()->is_tangible())) {
|
||||
|
||||
_from_entries[entry->get_from_node_path()].push_back(entry);
|
||||
_has_contact = true;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionHandlerFluidPusher::handle_entries
|
||||
// Access: Protected, Virtual
|
||||
// Description: Calculates a reasonable final position for a
|
||||
// collider given a set of collidees
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool CollisionHandlerFluidPusher::
|
||||
handle_entries() {
|
||||
/*
|
||||
This pusher repeatedly calculates the first collision, calculates a new
|
||||
trajectory based on that collision, and repeats until the original motion is
|
||||
exhausted or the collider becomes "stuck". This solves the "acute collisions"
|
||||
problem where colliders could bounce their way through to the other side
|
||||
of a wall.
|
||||
|
||||
Pseudocode:
|
||||
|
||||
INPUTS
|
||||
PosA = collider's previous position
|
||||
PosB = collider's current position
|
||||
M = movement vector (PosB - PosA)
|
||||
BV = bounding sphere that includes collider at PosA and PosB
|
||||
CS = 'collision set', all 'collidables' within BV (collision polys, tubes, etc)
|
||||
|
||||
VARIABLES
|
||||
N = movement vector since most recent collision (or start of frame)
|
||||
SCS = 'sub collision set', all collidables that could still be collided with
|
||||
C = single collider currently being collided with
|
||||
PosX = new position given movement along N interrupted by collision with C
|
||||
|
||||
OUTPUTS
|
||||
final position is PosX
|
||||
|
||||
1. N = M, SCS = CS, PosX = PosB
|
||||
2. compute, using SCS and N, which collidable C is the first collision
|
||||
3. if no collision found, DONE
|
||||
4. if movement in direction M is now blocked, then
|
||||
PosX = initial point of contact with C along N, DONE
|
||||
5. calculate PosX (and new N) assuming that there will be no more collisions
|
||||
6. remove C from SCS (assumes that you can't collide against a solid more than once per frame)
|
||||
7. go to 2
|
||||
*/
|
||||
bool okflag = true;
|
||||
|
||||
if (!_horizontal) {
|
||||
collide_cat.error() << "collisionHandlerFluidPusher::handle_entries is only supported in "
|
||||
"horizontal mode" << endl;
|
||||
nassertr(false, false);
|
||||
}
|
||||
|
||||
// for every fluid mover being pushed...
|
||||
FromEntries::iterator fei;
|
||||
for (fei = _from_entries.begin(); fei != _from_entries.end(); ++fei) {
|
||||
NodePath from_node_path = fei->first;
|
||||
Entries *entries = &fei->second;
|
||||
|
||||
Colliders::iterator ci;
|
||||
ci = _colliders.find(from_node_path);
|
||||
if (ci == _colliders.end()) {
|
||||
// Hmm, someone added a CollisionNode to a traverser and gave
|
||||
// it this CollisionHandler pointer--but they didn't tell us
|
||||
// about the node.
|
||||
collide_cat.error()
|
||||
<< "CollisionHandlerFluidPusher doesn't know about "
|
||||
<< from_node_path << ", disabling.\n";
|
||||
okflag = false;
|
||||
} else {
|
||||
ColliderDef &def = (*ci).second;
|
||||
|
||||
// extract the collision entries into a vector that we can safely modify
|
||||
Entries SCS(*entries);
|
||||
|
||||
// currently we only support spheres as the collider
|
||||
const CollisionSphere *sphere;
|
||||
DCAST_INTO_R(sphere, (*SCS.front()).get_from(), 0);
|
||||
// use a slightly larger radius value so that when we move along
|
||||
// collision planes we don't re-collide
|
||||
float sphere_radius = sphere->get_radius() * 1.001;
|
||||
|
||||
LPoint3f N(from_node_path.get_pos_delta(*_root));
|
||||
const LPoint3f orig_pos(from_node_path.get_pos());
|
||||
// this will hold the final calculated position
|
||||
LPoint3f PosX(orig_pos);
|
||||
|
||||
// unit vector facing back into original direction of motion
|
||||
LVector3f reverse_vec(-N);
|
||||
if (_horizontal) {
|
||||
reverse_vec[2] = 0.0f;
|
||||
}
|
||||
reverse_vec.normalize();
|
||||
|
||||
// unit vector pointing out to the right relative to the direction of motion,
|
||||
// looking into the direction of motion
|
||||
const LVector3f right_unit(LVector3f::up().cross(reverse_vec));
|
||||
|
||||
// if both of these become true, we're stuck in a 'corner'
|
||||
bool left_halfspace_obstructed = false;
|
||||
bool right_halfspace_obstructed = false;
|
||||
LVector3f left_plane_normal;
|
||||
LVector3f right_plane_normal;
|
||||
float left_plane_dot = 200.0f;
|
||||
float right_plane_dot = 200.0f;
|
||||
|
||||
// iterate until the mover runs out of movement or gets stuck
|
||||
while (true) {
|
||||
CollisionEntry *C = 0;
|
||||
Entries::iterator ei;
|
||||
// find the first (earliest) collision
|
||||
for (ei = SCS.begin(); ei != SCS.end(); ++ei) {
|
||||
CollisionEntry *entry = (*ei);
|
||||
nassertr(entry != (CollisionEntry *)NULL, false);
|
||||
if (entry->get_t() < C->get_t()) {
|
||||
nassertr(from_node_path == entry->get_from_node_path(), false);
|
||||
C = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if no collisions, we're done
|
||||
if (C == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
// calculate point of collision, move back to it
|
||||
nassertr(C->has_surface_point(), true);
|
||||
nassertr(C->has_surface_normal(), true);
|
||||
nassertr(C->has_interior_point(), true);
|
||||
LVector3f surface_normal = C->get_surface_normal(from_node_path);
|
||||
if (_horizontal) {
|
||||
surface_normal[2] = 0.0f;
|
||||
}
|
||||
surface_normal.normalize();
|
||||
PosX = C->get_surface_point(from_node_path) + (sphere_radius * surface_normal);
|
||||
|
||||
// check to see if we're stuck, given this collision
|
||||
float dot = right_unit.dot(surface_normal);
|
||||
if (dot > 0.0f) {
|
||||
// positive dot means plane is coming from the left (looking along original
|
||||
// direction of motion)
|
||||
if (dot < left_plane_dot) {
|
||||
if (right_halfspace_obstructed) {
|
||||
// we have obstructions from both directions, we're stuck
|
||||
break;
|
||||
}
|
||||
left_halfspace_obstructed = true;
|
||||
left_plane_normal = surface_normal;
|
||||
}
|
||||
} else {
|
||||
// negative dot means plane is coming from the right (looking along original
|
||||
// direction of motion)
|
||||
dot = -dot;
|
||||
if (dot < right_plane_dot) {
|
||||
if (left_halfspace_obstructed) {
|
||||
// we have obstructions from both directions, we're stuck
|
||||
break;
|
||||
}
|
||||
right_halfspace_obstructed = true;
|
||||
right_plane_normal = surface_normal;
|
||||
}
|
||||
}
|
||||
|
||||
// set up new current/last positions, re-calculate collisions
|
||||
}
|
||||
|
||||
LVector3f net_shove(PosX - orig_pos);
|
||||
LVector3f force_normal(net_shove);
|
||||
force_normal.normalize();
|
||||
|
||||
// This is the part where the node actually gets moved:
|
||||
CPT(TransformState) trans = def._target.get_transform();
|
||||
LVecBase3f pos = trans->get_pos();
|
||||
pos += net_shove * trans->get_mat();
|
||||
def._target.set_transform(trans->set_pos(pos));
|
||||
def.updated_transform();
|
||||
|
||||
// We call this to allow derived classes to do other
|
||||
// fix-ups as they see fit:
|
||||
apply_net_shove(def, net_shove, force_normal);
|
||||
apply_linear_force(def, force_normal);
|
||||
}
|
||||
}
|
||||
|
||||
return okflag;
|
||||
}
|
65
panda/src/collide/collisionHandlerFluidPusher.h
Executable file
65
panda/src/collide/collisionHandlerFluidPusher.h
Executable file
@ -0,0 +1,65 @@
|
||||
// Filename: collisionHandlerFluidPusher.h
|
||||
// Created by: drose (16Mar02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef COLLISIONHANDLERFLUIDPUSHER_H
|
||||
#define COLLISIONHANDLERFLUIDPUSHER_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#include "collisionHandlerPusher.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : CollisionHandlerFluidPusher
|
||||
// Description : A CollisionHandlerPusher that makes use of timing
|
||||
// and spatial information from fluid collisions to improve
|
||||
// collision response
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA_COLLIDE CollisionHandlerFluidPusher : public CollisionHandlerPusher {
|
||||
PUBLISHED:
|
||||
CollisionHandlerFluidPusher();
|
||||
|
||||
public:
|
||||
virtual void add_entry(CollisionEntry *entry);
|
||||
|
||||
protected:
|
||||
virtual bool handle_entries();
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
CollisionHandlerPusher::init_type();
|
||||
register_type(_type_handle, "CollisionHandlerFluidPusher",
|
||||
CollisionHandlerPusher::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "collisionHandlerFluidPusher.I"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user