prevent avatar from getting trapped in voxels

This commit is contained in:
Andrew Meadows 2014-05-07 15:21:12 -07:00
parent 8ec493e85b
commit b92bbafc26
2 changed files with 35 additions and 46 deletions

View file

@ -21,6 +21,7 @@
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <AccountManager.h> #include <AccountManager.h>
#include <GeometryUtil.h>
#include <NodeList.h> #include <NodeList.h>
#include <PacketHeaders.h> #include <PacketHeaders.h>
#include <SharedUtil.h> #include <SharedUtil.h>
@ -63,6 +64,7 @@ MyAvatar::MyAvatar() :
_distanceToNearestAvatar(std::numeric_limits<float>::max()), _distanceToNearestAvatar(std::numeric_limits<float>::max()),
_wasPushing(false), _wasPushing(false),
_isPushing(false), _isPushing(false),
_wasStuck(false),
_thrust(0.0f), _thrust(0.0f),
_motorVelocity(0.0f), _motorVelocity(0.0f),
_motorTimescale(DEFAULT_MOTOR_TIMESCALE), _motorTimescale(DEFAULT_MOTOR_TIMESCALE),
@ -212,6 +214,8 @@ void MyAvatar::simulate(float deltaTime) {
} }
if (_collisionGroups & COLLISION_GROUP_VOXELS) { if (_collisionGroups & COLLISION_GROUP_VOXELS) {
updateCollisionWithVoxels(deltaTime, radius); updateCollisionWithVoxels(deltaTime, radius);
} else {
_wasStuck = false;
} }
if (_collisionGroups & COLLISION_GROUP_AVATARS) { if (_collisionGroups & COLLISION_GROUP_AVATARS) {
updateCollisionWithAvatars(deltaTime); updateCollisionWithAvatars(deltaTime);
@ -958,65 +962,49 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) {
static CollisionList myCollisions(64); static CollisionList myCollisions(64);
void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) { void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) {
const float MIN_STUCK_SPEED = 100.0f;
float speed = glm::length(_velocity);
if (speed > MIN_STUCK_SPEED) {
// don't even bother to try to collide against voxles when moving very fast
return;
}
myCollisions.clear(); myCollisions.clear();
const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape();
if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions)) { if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions)) {
const float VOXEL_ELASTICITY = 0.0f; const float VOXEL_ELASTICITY = 0.0f;
const float VOXEL_DAMPING = 0.0f; const float VOXEL_DAMPING = 0.0f;
float capsuleRadius = boundingShape.getRadius();
if (glm::length2(_gravity) > EPSILON) { glm::vec3 totalPenetration(0.0f);
if (myCollisions.size() == 1) { bool isStuck = false;
// trivial case for (int i = 0; i < myCollisions.size(); ++i) {
CollisionInfo* collision = myCollisions[0]; CollisionInfo* collision = myCollisions[i];
applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); float depth = glm::length(collision->_penetration);
_lastFloorContactPoint = collision->_contactPoint - collision->_penetration; if (depth > capsuleRadius) {
} else { isStuck = true;
// This is special collision handling for when walking on a voxel field which if (_wasStuck) {
// prevents snagging at corners and seams. glm::vec3 cubeCenter = collision->_vecData;
float cubeSide = collision->_floatData;
// sift through the collisions looking for one against the "floor" float distance = glm::dot(boundingShape.getPosition() - cubeCenter, _worldUpDirection);
int floorIndex = 0; if (distance < 0.0f) {
float distanceToFloor = 0.0f; distance = fabsf(distance) + 0.5f * cubeSide;
float penetrationWithFloor = 0.0f;
for (int i = 0; i < myCollisions.size(); ++i) {
CollisionInfo* collision = myCollisions[i];
float distance = glm::dot(_gravity, collision->_contactPoint - _position);
if (distance > distanceToFloor) {
distanceToFloor = distance;
penetrationWithFloor = glm::dot(_gravity, collision->_penetration);
floorIndex = i;
}
}
// step through the collisions again and apply each that is not redundant
glm::vec3 oldPosition = _position;
for (int i = 0; i < myCollisions.size(); ++i) {
CollisionInfo* collision = myCollisions[i];
if (i == floorIndex) {
applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
_lastFloorContactPoint = collision->_contactPoint - collision->_penetration;
} else {
float distance = glm::dot(_gravity, collision->_contactPoint - oldPosition);
float penetration = glm::dot(_gravity, collision->_penetration);
if (fabsf(distance - distanceToFloor) > penetrationWithFloor || penetration > penetrationWithFloor) {
// resolution of the deepest penetration would not resolve this one
// so we apply the collision
applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
}
} }
distance += capsuleRadius + boundingShape.getHalfHeight();
totalPenetration = addPenetrations(totalPenetration, - distance * _worldUpDirection);
} else {
totalPenetration = addPenetrations(totalPenetration, collision->_penetration);
} }
} }
} else { totalPenetration = addPenetrations(totalPenetration, collision->_penetration);
// no gravity -- apply all collisions
for (int i = 0; i < myCollisions.size(); ++i) {
CollisionInfo* collision = myCollisions[i];
applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
}
} }
applyHardCollision(totalPenetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
_wasStuck = isStuck;
const float VOXEL_COLLISION_FREQUENCY = 0.5f; const float VOXEL_COLLISION_FREQUENCY = 0.5f;
updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY);
} } else {
_wasStuck = false;
}
} }
void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) { void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) {

View file

@ -125,6 +125,7 @@ private:
bool _wasPushing; bool _wasPushing;
bool _isPushing; bool _isPushing;
bool _wasStuck;
glm::vec3 _thrust; // final acceleration from outside sources for the current frame glm::vec3 _thrust; // final acceleration from outside sources for the current frame
glm::vec3 _motorVelocity; // intended velocity of avatar motion glm::vec3 _motorVelocity; // intended velocity of avatar motion