mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 04:57:23 +02:00
prevent avatar from getting trapped in voxels
This commit is contained in:
parent
8ec493e85b
commit
b92bbafc26
2 changed files with 35 additions and 46 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue