mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 04:04:13 +02:00
Merge pull request #16106 from AndrewMeadows/less-MyAvatar-mesh-tuneling-2
BUGZ-1325 prevent MyAvatar from pushing through mesh barrier
This commit is contained in:
commit
e07e8abc0d
3 changed files with 53 additions and 20 deletions
|
@ -3586,6 +3586,8 @@ void MyAvatar::updateActionMotor(float deltaTime) {
|
|||
float speedGrowthTimescale = 2.0f;
|
||||
float speedIncreaseFactor = 1.8f * _walkSpeedScalar;
|
||||
motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale, 0.0f, 1.0f) * speedIncreaseFactor;
|
||||
// use feedback from CharacterController to prevent tunneling under high motorspeed
|
||||
motorSpeed *= _characterController.getCollisionBrakeAttenuationFactor();
|
||||
const float maxBoostSpeed = sensorToWorldScale * MAX_BOOST_SPEED;
|
||||
|
||||
if (_isPushing) {
|
||||
|
|
|
@ -189,7 +189,7 @@ void CharacterController::addToWorld() {
|
|||
_rigidBody->setCollisionFlags(btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
|
||||
|
||||
// enable CCD
|
||||
_rigidBody->setCcdSweptSphereRadius(2.0f * (_radius + _halfHeight));
|
||||
_rigidBody->setCcdSweptSphereRadius(_halfHeight);
|
||||
_rigidBody->setCcdMotionThreshold(_radius);
|
||||
|
||||
btCollisionShape* shape = _rigidBody->getCollisionShape();
|
||||
|
@ -556,7 +556,7 @@ void CharacterController::setLocalBoundingBox(const glm::vec3& minCorner, const
|
|||
|
||||
if (_rigidBody) {
|
||||
// update CCD with new _radius
|
||||
_rigidBody->setCcdSweptSphereRadius(2.0f * (_radius + _halfHeight));
|
||||
_rigidBody->setCcdSweptSphereRadius(_halfHeight);
|
||||
_rigidBody->setCcdMotionThreshold(_radius);
|
||||
}
|
||||
}
|
||||
|
@ -570,6 +570,12 @@ void CharacterController::setPhysicsEngine(const PhysicsEnginePointer& engine) {
|
|||
}
|
||||
}
|
||||
|
||||
float CharacterController::getCollisionBrakeAttenuationFactor() const {
|
||||
// _collisionBrake ranges from 0.0 (no brake) to 1.0 (max brake)
|
||||
// which we use to compute a corresponding attenutation factor from 1.0 to 0.5
|
||||
return 1.0f - 0.5f * _collisionBrake;
|
||||
}
|
||||
|
||||
void CharacterController::setCollisionless(bool collisionless) {
|
||||
if (collisionless != _collisionless) {
|
||||
_collisionless = collisionless;
|
||||
|
@ -784,40 +790,63 @@ void CharacterController::computeNewVelocity(btScalar dt, btVector3& velocity) {
|
|||
// but we want to avoid getting stuck and tunelling through geometry so we perform
|
||||
// further checks and modify/abandon our velocity calculations
|
||||
|
||||
if (_isStuck || _stuckTransitionCount == 0) {
|
||||
// we are either definitely stuck, or definitely not --> nothing to do
|
||||
const float SAFE_COLLISION_SPEED = glm::abs(STUCK_PENETRATION) * (float)NUM_SUBSTEPS_PER_SECOND;
|
||||
const float SAFE_COLLISION_SPEED_SQUARED = SAFE_COLLISION_SPEED * SAFE_COLLISION_SPEED;
|
||||
|
||||
// NOTE: the thresholds are negative which indicates the vectors oppose each other
|
||||
// and which means comparison operators against them may look wrong at first glance.
|
||||
// The magnitudes of the thresholds have been tuned manually.
|
||||
const float STRONG_OPPOSING_IMPACT_THRESHOLD = -1000.0f;
|
||||
const float VERY_STRONG_OPPOSING_IMPACT_THRESHOLD = -2000.0f;
|
||||
float velocityDotImpulse = velocity.dot(_netCollisionImpulse);
|
||||
|
||||
const float COLLISION_BRAKE_TIMESCALE = 0.20f; // must be > PHYSICS_ENGINE_FIXED_SUBSTEP for stability
|
||||
const float MIN_COLLISION_BRAKE = 0.05f;
|
||||
if ((velocityDotImpulse > VERY_STRONG_OPPOSING_IMPACT_THRESHOLD && _stuckTransitionCount == 0) || _isStuck) {
|
||||
// we are either definitely NOT stuck (in which case nothing to do)
|
||||
// or definitely are (in which case we'll be temporarily disabling collisions with the offending object
|
||||
// and we don't mind tunnelling as an escape route out of stuck)
|
||||
if (_collisionBrake > MIN_COLLISION_BRAKE) {
|
||||
_collisionBrake *= (1.0f - dt / COLLISION_BRAKE_TIMESCALE);
|
||||
if (_collisionBrake < MIN_COLLISION_BRAKE) {
|
||||
_collisionBrake = 0.0f;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const float SAFE_COLLISION_SPEED = glm::abs(STUCK_PENETRATION) * (float)NUM_SUBSTEPS_PER_SECOND;
|
||||
const float SAFE_COLLISION_SPEED_SQUARED = SAFE_COLLISION_SPEED * SAFE_COLLISION_SPEED;
|
||||
bool fast = velocity.length2() > SAFE_COLLISION_SPEED_SQUARED;
|
||||
if (velocityDotImpulse < VERY_STRONG_OPPOSING_IMPACT_THRESHOLD ||
|
||||
(velocityDotImpulse < STRONG_OPPOSING_IMPACT_THRESHOLD && velocity.length2() > SAFE_COLLISION_SPEED_SQUARED)) {
|
||||
if (_collisionBrake < 1.0f) {
|
||||
_collisionBrake += (1.0f - _collisionBrake) * (dt / COLLISION_BRAKE_TIMESCALE);
|
||||
const float MAX_COLLISION_BRAKE = 1.0f - MIN_COLLISION_BRAKE;
|
||||
if (_collisionBrake > MAX_COLLISION_BRAKE) {
|
||||
_collisionBrake = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
const float STRONG_IMPACT_IMPULSE_DOT = -1000.0f; // this tuned manually
|
||||
bool strongImpact = velocity.dot(_netCollisionImpulse) < STRONG_IMPACT_IMPULSE_DOT;
|
||||
// NOTE about REFLECTION_COEFFICIENT: a value of 2.0 provides full reflection
|
||||
// (zero attenuation) whereas a value of 1.0 zeros it (full attenuation).
|
||||
const float REFLECTION_COEFFICIENT = 1.1f;
|
||||
|
||||
if (fast && strongImpact) {
|
||||
const float REFLECTION_COEFFICIENT = 1.5f;
|
||||
if (velocity.dot(currentVelocity) > 0.0f) {
|
||||
// our new velocity points in the same direction as our currentVelocity
|
||||
// but strongImpact means new velocity points against netImpulse
|
||||
// but negative "impact" means new velocity points against netCollisionImpulse
|
||||
if (currentVelocity.dot(_netCollisionImpulse) > 0.0f) {
|
||||
// currentVelocity points positively with netImpulse
|
||||
// so we will assume collisions will save us and use it for our new velocity
|
||||
// currentVelocity points positively with netCollisionImpulse --> trust physics to save us
|
||||
velocity = currentVelocity;
|
||||
} else {
|
||||
// can't trust physical simulation --> reflect velocity against netImpulse
|
||||
// can't trust physics --> use new velocity but reflect it
|
||||
btVector3 impulseDirection = _netCollisionImpulse.normalized();
|
||||
velocity -= (REFLECTION_COEFFICIENT * velocity.dot(impulseDirection)) * impulseDirection;
|
||||
// also attenuate the velocity to help slow down the character before its penetration gets worse
|
||||
const float ATTENUATION_COEFFICIENT = 0.8f;
|
||||
velocity *= ATTENUATION_COEFFICIENT;
|
||||
}
|
||||
} else {
|
||||
// currentVelocity points against new velocity, which means it is probably better but...
|
||||
// this doesn't mean it points in a good direction yet, so we must check
|
||||
// when the physical simulation starts to fail (e.g. in deep penetration in mesh geometry)
|
||||
// the currentVelocity can point in unhelpful directions, so we check it and reflect any component
|
||||
// opposing netCollisionImpulse in hopes netCollisionImpulse points toward good exit
|
||||
if (currentVelocity.dot(_netCollisionImpulse) < 0.0f) {
|
||||
// currentVelocity points against netImpulse, so we reflect it
|
||||
// currentVelocity points against netCollisionImpulse --> reflect
|
||||
btVector3 impulseDirection = _netCollisionImpulse.normalized();
|
||||
currentVelocity -= (REFLECTION_COEFFICIENT * currentVelocity.dot(impulseDirection)) * impulseDirection;
|
||||
}
|
||||
|
|
|
@ -128,6 +128,7 @@ public:
|
|||
void setPhysicsEngine(const PhysicsEnginePointer& engine);
|
||||
bool isEnabledAndReady() const { return (bool)_physicsEngine; }
|
||||
bool isStuck() const { return _isStuck; }
|
||||
float getCollisionBrakeAttenuationFactor() const;
|
||||
|
||||
void setCollisionless(bool collisionless);
|
||||
|
||||
|
@ -221,6 +222,7 @@ protected:
|
|||
bool _isPushingUp;
|
||||
bool _isStuck { false };
|
||||
bool _isSeated { false };
|
||||
float _collisionBrake { 0.0f };
|
||||
|
||||
PhysicsEnginePointer _physicsEngine { nullptr };
|
||||
btRigidBody* _rigidBody { nullptr };
|
||||
|
|
Loading…
Reference in a new issue