mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
prevent avatars from walking up walls
This commit is contained in:
parent
d29386c43f
commit
4fb6d5023b
3 changed files with 72 additions and 21 deletions
|
@ -128,6 +128,7 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
|||
_ghost.setMaxStepHeight(0.75f * (_radius + _halfHeight)); // HACK
|
||||
_ghost.setMinWallAngle(PI / 4.0f); // HACK
|
||||
_ghost.setUpDirection(_currentUp);
|
||||
_ghost.setMotorOnly(!_moveKinematically);
|
||||
_ghost.setWorldTransform(_rigidBody->getWorldTransform());
|
||||
}
|
||||
if (_dynamicsWorld) {
|
||||
|
@ -143,7 +144,24 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) {
|
|||
}
|
||||
|
||||
bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld, btScalar dt) {
|
||||
if (_moveKinematically) {
|
||||
// kinematic motion will move() the _ghost later
|
||||
return _ghost.hasSupport();
|
||||
}
|
||||
_stepHeight = _minStepHeight; // clears last step obstacle
|
||||
|
||||
btScalar targetSpeed = _targetVelocity.length();
|
||||
if (targetSpeed > FLT_EPSILON) {
|
||||
// move the _ghost forward to test for step
|
||||
btTransform transform = _rigidBody->getWorldTransform();
|
||||
transform.setOrigin(transform.getOrigin());
|
||||
_ghost.setWorldTransform(transform);
|
||||
_ghost.setMotorVelocity(_targetVelocity);
|
||||
float overshoot = _radius;
|
||||
_ghost.setHovering(_state == State::Hover);
|
||||
_ghost.move(dt, overshoot, _gravity);
|
||||
}
|
||||
|
||||
btDispatcher* dispatcher = collisionWorld->getDispatcher();
|
||||
int numManifolds = dispatcher->getNumManifolds();
|
||||
bool hasFloor = false;
|
||||
|
@ -165,17 +183,26 @@ bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld, btSc
|
|||
btVector3 pointOnCharacter = characterIsFirst ? contact.m_localPointA : contact.m_localPointB; // object-local-frame
|
||||
btVector3 normal = characterIsFirst ? contact.m_normalWorldOnB : -contact.m_normalWorldOnB; // points toward character
|
||||
btScalar hitHeight = _halfHeight + _radius + pointOnCharacter.dot(_currentUp);
|
||||
if (hitHeight < _radius && normal.dot(_currentUp) > COS_PI_OVER_THREE) {
|
||||
if (hitHeight < _maxStepHeight && normal.dot(_currentUp) > COS_PI_OVER_THREE) {
|
||||
hasFloor = true;
|
||||
if (!_ghost.isSteppingUp()) {
|
||||
// early exit since all we need to know is that we're on a floor
|
||||
break;
|
||||
}
|
||||
}
|
||||
// remember highest step obstacle
|
||||
if (hitHeight > _maxStepHeight) {
|
||||
// this manifold is invalidated by point that is too high
|
||||
stepContactIndex = -1;
|
||||
break;
|
||||
} else if (hitHeight > highestStep && normal.dot(_targetVelocity) < 0.0f ) {
|
||||
highestStep = hitHeight;
|
||||
stepContactIndex = j;
|
||||
// analysis of the step info using manifold data is unreliable, so we only proceed
|
||||
// when the _ghost has detected a steppable obstacle
|
||||
if (_ghost.isSteppingUp()) {
|
||||
// remember highest step obstacle
|
||||
if (hitHeight > _maxStepHeight) {
|
||||
// this manifold is invalidated by point that is too high
|
||||
stepContactIndex = -1;
|
||||
break;
|
||||
} else if (hitHeight > highestStep && normal.dot(_targetVelocity) < 0.0f ) {
|
||||
highestStep = hitHeight;
|
||||
stepContactIndex = j;
|
||||
hasFloor = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (stepContactIndex > -1 && highestStep > _stepHeight) {
|
||||
|
@ -187,6 +214,10 @@ bool CharacterController::checkForSupport(btCollisionWorld* collisionWorld, btSc
|
|||
_stepPoint = rotation * pointOnCharacter; // rotate into world-frame
|
||||
_stepNormal = normal;
|
||||
}
|
||||
if (hasFloor && !_ghost.isSteppingUp()) {
|
||||
// early exit since all we need to know is that we're on a floor
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hasFloor;
|
||||
|
@ -532,9 +563,13 @@ void CharacterController::applyMotor(int index, btScalar dt, btVector3& worldVel
|
|||
} else {
|
||||
// compute local UP
|
||||
btVector3 up = _currentUp.rotate(axis, -angle);
|
||||
|
||||
// add sky hook when encountering a step obstacle
|
||||
btVector3 motorVelocity = motor.velocity;
|
||||
|
||||
// save these non-adjusted components for later
|
||||
btVector3 vTargetVelocity = motorVelocity.dot(up) * up;
|
||||
btVector3 hTargetVelocity = motorVelocity - vTargetVelocity;
|
||||
|
||||
// adjust motorVelocity uphill when encountering a step obstacle
|
||||
btScalar vTimescale = motor.vTimescale;
|
||||
if (_stepHeight > _minStepHeight) {
|
||||
// there is a step
|
||||
|
@ -557,8 +592,8 @@ void CharacterController::applyMotor(int index, btScalar dt, btVector3& worldVel
|
|||
// split velocity into horizontal and vertical components
|
||||
btVector3 vVelocity = velocity.dot(up) * up;
|
||||
btVector3 hVelocity = velocity - vVelocity;
|
||||
btVector3 vTargetVelocity = motorVelocity.dot(up) * up;
|
||||
btVector3 hTargetVelocity = motorVelocity - vTargetVelocity;
|
||||
btVector3 vMotorVelocity = motorVelocity.dot(up) * up;
|
||||
btVector3 hMotorVelocity = motorVelocity - vMotorVelocity;
|
||||
|
||||
// modify each component separately
|
||||
btScalar maxTau = 0.0f;
|
||||
|
@ -568,7 +603,7 @@ void CharacterController::applyMotor(int index, btScalar dt, btVector3& worldVel
|
|||
tau = 1.0f;
|
||||
}
|
||||
maxTau = tau;
|
||||
hVelocity += (hTargetVelocity - hVelocity) * tau;
|
||||
hVelocity += (hMotorVelocity - hVelocity) * tau;
|
||||
}
|
||||
if (vTimescale < MAX_CHARACTER_MOTOR_TIMESCALE) {
|
||||
btScalar tau = dt / vTimescale;
|
||||
|
@ -578,7 +613,7 @@ void CharacterController::applyMotor(int index, btScalar dt, btVector3& worldVel
|
|||
if (tau > maxTau) {
|
||||
maxTau = tau;
|
||||
}
|
||||
vVelocity += (vTargetVelocity - vVelocity) * tau;
|
||||
vVelocity += (vMotorVelocity - vVelocity) * tau;
|
||||
}
|
||||
|
||||
// add components back together and rotate into world-frame
|
||||
|
@ -819,5 +854,6 @@ void CharacterController::setMoveKinematically(bool kinematic) {
|
|||
if (kinematic != _moveKinematically) {
|
||||
_moveKinematically = kinematic;
|
||||
_pendingFlags |= PENDING_FLAG_UPDATE_SHAPE;
|
||||
_ghost.setMotorOnly(!_moveKinematically);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,6 +54,13 @@ void CharacterGhostObject::setUpDirection(const btVector3& up) {
|
|||
}
|
||||
}
|
||||
|
||||
void CharacterGhostObject::setMotorVelocity(const btVector3& velocity) {
|
||||
_motorVelocity = velocity;
|
||||
if (_motorOnly) {
|
||||
_linearVelocity = _motorVelocity;
|
||||
}
|
||||
}
|
||||
|
||||
// override of btCollisionObject::setCollisionShape()
|
||||
void CharacterGhostObject::setCharacterCapsule(btCapsuleShape* capsule) {
|
||||
assert(capsule);
|
||||
|
@ -74,6 +81,7 @@ void CharacterGhostObject::setCollisionWorld(btCollisionWorld* world) {
|
|||
}
|
||||
|
||||
void CharacterGhostObject::move(btScalar dt, btScalar overshoot, btScalar gravity) {
|
||||
bool oldOnFloor = _onFloor;
|
||||
_onFloor = false;
|
||||
_steppingUp = false;
|
||||
assert(_world && _inWorld);
|
||||
|
@ -172,6 +180,7 @@ void CharacterGhostObject::move(btScalar dt, btScalar overshoot, btScalar gravit
|
|||
}
|
||||
nextTransform.setOrigin(startPosition + forwardTranslation);
|
||||
setWorldTransform(nextTransform);
|
||||
_onFloor = _onFloor || oldOnFloor;
|
||||
return;
|
||||
}
|
||||
// if we get here then we hit something that might be steppable
|
||||
|
@ -213,6 +222,7 @@ void CharacterGhostObject::move(btScalar dt, btScalar overshoot, btScalar gravit
|
|||
// either there is no future landing spot, or there is but we can't stand on it
|
||||
// in any case: we go forward as much as possible
|
||||
nextTransform.setOrigin(startPosition + forwardSweepHitFraction * (stepDistance / longSweepDistance) * forwardSweep);
|
||||
_onFloor = _onFloor || oldOnFloor;
|
||||
updateTraction(nextTransform.getOrigin());
|
||||
}
|
||||
setWorldTransform(nextTransform);
|
||||
|
@ -352,10 +362,12 @@ void CharacterGhostObject::refreshOverlappingPairCache() {
|
|||
}
|
||||
|
||||
void CharacterGhostObject::updateVelocity(btScalar dt, btScalar gravity) {
|
||||
if (_hovering) {
|
||||
_linearVelocity *= 0.999f; // HACK damping
|
||||
} else {
|
||||
_linearVelocity += (dt * gravity) * _upDirection;
|
||||
if (!_motorOnly) {
|
||||
if (_hovering) {
|
||||
_linearVelocity *= 0.999f; // HACK damping
|
||||
} else {
|
||||
_linearVelocity += (dt * gravity) * _upDirection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,7 +389,7 @@ void CharacterGhostObject::updateHoverState(const btVector3& position) {
|
|||
|
||||
void CharacterGhostObject::updateTraction(const btVector3& position) {
|
||||
updateHoverState(position);
|
||||
if (_hovering) {
|
||||
if (_hovering || _motorOnly) {
|
||||
_linearVelocity = _motorVelocity;
|
||||
} else if (_onFloor) {
|
||||
// compute a velocity that swings the capsule around the _floorContact
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
|
||||
void setRadiusAndHalfHeight(btScalar radius, btScalar halfHeight);
|
||||
void setUpDirection(const btVector3& up);
|
||||
void setMotorVelocity(const btVector3& velocity) { _motorVelocity = velocity; }
|
||||
void setMotorVelocity(const btVector3& velocity);
|
||||
void setMinWallAngle(btScalar angle) { _maxWallNormalUpComponent = cosf(angle); }
|
||||
void setMaxStepHeight(btScalar height) { _maxStepHeight = height; }
|
||||
|
||||
|
@ -53,9 +53,11 @@ public:
|
|||
|
||||
bool isHovering() const { return _hovering; }
|
||||
void setHovering(bool hovering) { _hovering = hovering; }
|
||||
void setMotorOnly(bool motorOnly) { _motorOnly = motorOnly; }
|
||||
|
||||
bool hasSupport() const { return _onFloor; }
|
||||
bool isSteppingUp() const { return _steppingUp; }
|
||||
const btVector3& getFloorNormal() const { return _floorNormal; }
|
||||
|
||||
protected:
|
||||
void removeFromWorld();
|
||||
|
@ -93,6 +95,7 @@ protected:
|
|||
bool _onFloor { false }; // output, is actually standing on floor
|
||||
bool _steppingUp { false }; // output, future sweep hit a steppable ledge
|
||||
bool _hasFloor { false }; // output, has floor underneath to fall on
|
||||
bool _motorOnly { false }; // input, _linearVelocity slaves to _motorVelocity
|
||||
};
|
||||
|
||||
#endif // hifi_CharacterGhostObject_h
|
||||
|
|
Loading…
Reference in a new issue