mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
Merge pull request #4509 from AndrewMeadows/inertia
character transitions into "hover" when stepping over abyss
This commit is contained in:
commit
6550b4e311
5 changed files with 129 additions and 155 deletions
|
@ -174,11 +174,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
{
|
||||
PerformanceTimer perfTimer("transform");
|
||||
updateOrientation(deltaTime);
|
||||
if (isPhysicsEnabled()) {
|
||||
updatePositionWithPhysics(deltaTime);
|
||||
} else {
|
||||
updatePosition(deltaTime);
|
||||
}
|
||||
updatePosition(deltaTime);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -1258,128 +1254,38 @@ glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVe
|
|||
return localVelocity + motorEfficiency * deltaVelocity;
|
||||
}
|
||||
|
||||
const float NEARBY_FLOOR_THRESHOLD = 5.0f;
|
||||
|
||||
void MyAvatar::updatePosition(float deltaTime) {
|
||||
|
||||
// check for floor by casting a ray straight down from avatar's position
|
||||
float heightAboveFloor = FLT_MAX;
|
||||
bool hasFloor = false;
|
||||
const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape();
|
||||
const float maxFloorDistance = boundingShape.getBoundingRadius() * NEARBY_FLOOR_THRESHOLD;
|
||||
|
||||
RayIntersectionInfo intersection;
|
||||
// NOTE: avatar is center of PhysicsSimulation, so rayStart is the origin for the purposes of the raycast
|
||||
intersection._rayStart = glm::vec3(0.0f);
|
||||
intersection._rayDirection = - _worldUpDirection;
|
||||
intersection._rayLength = 4.0f * boundingShape.getBoundingRadius();
|
||||
|
||||
// velocity is initialized to the measured _velocity but will be modified by friction, external thrust, etc
|
||||
glm::vec3 velocity = _velocity;
|
||||
|
||||
bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f;
|
||||
if (_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) {
|
||||
const float MAX_SPEED_UNDER_GRAVITY = 2.0f * _scale * MAX_WALKING_SPEED;
|
||||
if (pushingUp || glm::length2(velocity) > MAX_SPEED_UNDER_GRAVITY * MAX_SPEED_UNDER_GRAVITY) {
|
||||
// we're pushing up or moving quickly, so disable gravity
|
||||
setLocalGravity(glm::vec3(0.0f));
|
||||
hasFloor = false;
|
||||
} else {
|
||||
if (heightAboveFloor > maxFloorDistance) {
|
||||
// disable local gravity when floor is too far away
|
||||
setLocalGravity(glm::vec3(0.0f));
|
||||
hasFloor = false;
|
||||
} else {
|
||||
// enable gravity
|
||||
setLocalGravity(-_worldUpDirection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool zeroDownwardVelocity = false;
|
||||
bool gravityEnabled = (glm::length2(_gravity) > EPSILON);
|
||||
if (gravityEnabled) {
|
||||
const float SLOP = 0.002f;
|
||||
if (heightAboveFloor < SLOP) {
|
||||
if (heightAboveFloor < 0.0) {
|
||||
// Gravity is in effect so we assume that the avatar is colliding against the world and we need
|
||||
// to lift avatar out of floor, but we don't want to do it too fast (keep it smooth).
|
||||
float distanceToLift = glm::min(-heightAboveFloor, MAX_WALKING_SPEED * deltaTime);
|
||||
|
||||
// We don't use applyPositionDelta() for this lift distance because we don't want the avatar
|
||||
// to come flying out of the floor. Instead we update position directly, and set a boolean
|
||||
// that will remind us later to zero any downward component of the velocity.
|
||||
_position += distanceToLift * _worldUpDirection;
|
||||
}
|
||||
zeroDownwardVelocity = true;
|
||||
}
|
||||
if (!zeroDownwardVelocity) {
|
||||
velocity += (deltaTime * GRAVITY_EARTH) * _gravity;
|
||||
}
|
||||
}
|
||||
|
||||
// rotate velocity into camera frame
|
||||
glm::quat rotation = getHead()->getCameraOrientation();
|
||||
glm::vec3 localVelocity = glm::inverse(rotation) * velocity;
|
||||
|
||||
// apply motors in camera frame
|
||||
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor);
|
||||
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
|
||||
|
||||
// rotate back into world-frame
|
||||
velocity = rotation * newLocalVelocity;
|
||||
|
||||
// apply thrust
|
||||
velocity += _thrust * deltaTime;
|
||||
_thrust = glm::vec3(0.0f);
|
||||
|
||||
// remove downward velocity so we don't push into floor
|
||||
if (zeroDownwardVelocity) {
|
||||
float verticalSpeed = glm::dot(velocity, _worldUpDirection);
|
||||
if (verticalSpeed < 0.0f || !pushingUp) {
|
||||
velocity -= verticalSpeed * _worldUpDirection;
|
||||
}
|
||||
}
|
||||
|
||||
// cap avatar speed
|
||||
float speed = glm::length(velocity);
|
||||
if (speed > MAX_AVATAR_SPEED) {
|
||||
velocity *= MAX_AVATAR_SPEED / speed;
|
||||
speed = MAX_AVATAR_SPEED;
|
||||
}
|
||||
|
||||
// update position
|
||||
if (speed > MIN_AVATAR_SPEED) {
|
||||
applyPositionDelta(deltaTime * velocity);
|
||||
}
|
||||
|
||||
// update _moving flag based on speed
|
||||
const float MOVING_SPEED_THRESHOLD = 0.01f;
|
||||
_moving = speed > MOVING_SPEED_THRESHOLD;
|
||||
|
||||
measureMotionDerivatives(deltaTime);
|
||||
}
|
||||
|
||||
void MyAvatar::updatePositionWithPhysics(float deltaTime) {
|
||||
// rotate velocity into camera frame
|
||||
glm::quat rotation = getHead()->getCameraOrientation();
|
||||
glm::vec3 localVelocity = glm::inverse(rotation) * _velocity;
|
||||
|
||||
bool hasFloor = false;
|
||||
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor);
|
||||
bool isOnGround = _characterController.onGround();
|
||||
glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isOnGround);
|
||||
newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity);
|
||||
|
||||
// cap avatar speed
|
||||
float speed = glm::length(newLocalVelocity);
|
||||
if (speed > MAX_WALKING_SPEED) {
|
||||
newLocalVelocity *= MAX_WALKING_SPEED / speed;
|
||||
}
|
||||
|
||||
// rotate back into world-frame
|
||||
_velocity = rotation * newLocalVelocity;
|
||||
|
||||
_velocity += _thrust * deltaTime;
|
||||
_thrust = glm::vec3(0.0f);
|
||||
|
||||
// cap avatar speed
|
||||
float speed = glm::length(_velocity);
|
||||
if (speed > MAX_AVATAR_SPEED) {
|
||||
_velocity *= MAX_AVATAR_SPEED / speed;
|
||||
speed = MAX_AVATAR_SPEED;
|
||||
}
|
||||
|
||||
if (speed > MIN_AVATAR_SPEED && !isPhysicsEnabled()) {
|
||||
// update position ourselves
|
||||
applyPositionDelta(deltaTime * _velocity);
|
||||
measureMotionDerivatives(deltaTime);
|
||||
} // else physics will move avatar later
|
||||
|
||||
// update _moving flag based on speed
|
||||
const float MOVING_SPEED_THRESHOLD = 0.01f;
|
||||
_moving = speed > MOVING_SPEED_THRESHOLD;
|
||||
|
||||
}
|
||||
|
||||
void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) {
|
||||
|
|
|
@ -234,7 +234,6 @@ private:
|
|||
glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor);
|
||||
glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity);
|
||||
void updatePosition(float deltaTime);
|
||||
void updatePositionWithPhysics(float deltaTime);
|
||||
void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency);
|
||||
void maybeUpdateBillboard();
|
||||
void setGravity(const glm::vec3& gravity);
|
||||
|
|
|
@ -282,7 +282,7 @@ void AccountManager::processReply() {
|
|||
} else {
|
||||
passErrorToCallback(requestReply);
|
||||
}
|
||||
delete requestReply;
|
||||
requestReply->deleteLater();
|
||||
}
|
||||
|
||||
void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) {
|
||||
|
|
|
@ -40,6 +40,24 @@ static btVector3 getNormalizedVector(const btVector3& v) {
|
|||
return n;
|
||||
}
|
||||
|
||||
class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback {
|
||||
public:
|
||||
btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) :
|
||||
btCollisionWorld::ClosestRayResultCallback(btVector3(0.0f, 0.0f, 0.0f), btVector3(0.0f, 0.0f, 0.0f)) {
|
||||
_me = me;
|
||||
}
|
||||
|
||||
virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) {
|
||||
if (rayResult.m_collisionObject == _me) {
|
||||
return 1.0f;
|
||||
}
|
||||
return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace);
|
||||
}
|
||||
protected:
|
||||
btCollisionObject* _me;
|
||||
};
|
||||
|
||||
|
||||
class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback {
|
||||
public:
|
||||
btKinematicClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot)
|
||||
|
@ -210,11 +228,12 @@ CharacterController::CharacterController(AvatarData* avatarData) {
|
|||
_velocityTimeInterval = 0.0f;
|
||||
_verticalVelocity = 0.0f;
|
||||
_verticalOffset = 0.0f;
|
||||
_gravity = 9.8f;
|
||||
_gravity = 5.0f; // slower than Earth's
|
||||
_maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s.
|
||||
_jumpSpeed = 7.0f;
|
||||
_wasOnGround = false;
|
||||
_wasJumping = false;
|
||||
_jumpSpeed = 5.0f;
|
||||
_isOnGround = false;
|
||||
_isJumping = false;
|
||||
_isHovering = true;
|
||||
setMaxSlope(btRadians(45.0f));
|
||||
_lastStepUp = 0.0f;
|
||||
_pendingFlags = 0;
|
||||
|
@ -325,6 +344,26 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl
|
|||
return penetration;
|
||||
}
|
||||
|
||||
void CharacterController::scanDown(btCollisionWorld* world) {
|
||||
// we test with downward raycast and if we don't find floor close enough then turn on "hover"
|
||||
btKinematicClosestNotMeRayResultCallback callback(_ghostObject);
|
||||
callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup;
|
||||
callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS);
|
||||
btVector3 start = _currentPosition;
|
||||
const btScalar MAX_SCAN_HEIGHT = 20.0f + _halfHeight + _radius; // closest possible floor for disabling hover
|
||||
const btScalar MIN_HOVER_HEIGHT = 3.0f + _halfHeight + _radius; // distance to floor for enabling hover
|
||||
btVector3 end = start - MAX_SCAN_HEIGHT * up;
|
||||
|
||||
world->rayTest(start, end, callback);
|
||||
if (!callback.hasHit()) {
|
||||
_isHovering = true;
|
||||
} else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) {
|
||||
_isHovering = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterController::stepUp(btCollisionWorld* world) {
|
||||
// phase 1: up
|
||||
|
||||
|
@ -334,7 +373,7 @@ void CharacterController::stepUp(btCollisionWorld* world) {
|
|||
btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS);
|
||||
start.setOrigin(_currentPosition + up * (_convexShape->getMargin() + _addedMargin));
|
||||
|
||||
_targetPosition = _currentPosition + up * _stepHeight;
|
||||
_targetPosition = _currentPosition + up * _stepUpHeight;
|
||||
end.setIdentity();
|
||||
end.setOrigin(_targetPosition);
|
||||
|
||||
|
@ -352,15 +391,15 @@ void CharacterController::stepUp(btCollisionWorld* world) {
|
|||
|
||||
// Only modify the position if the hit was a slope and not a wall or ceiling.
|
||||
if (callback.m_hitNormalWorld.dot(up) > 0.0f) {
|
||||
_lastStepUp = _stepHeight * callback.m_closestHitFraction;
|
||||
_lastStepUp = _stepUpHeight * callback.m_closestHitFraction;
|
||||
_currentPosition.setInterpolate3(_currentPosition, _targetPosition, callback.m_closestHitFraction);
|
||||
} else {
|
||||
_lastStepUp = _stepHeight;
|
||||
_lastStepUp = _stepUpHeight;
|
||||
_currentPosition = _targetPosition;
|
||||
}
|
||||
} else {
|
||||
_currentPosition = _targetPosition;
|
||||
_lastStepUp = _stepHeight;
|
||||
_lastStepUp = _stepUpHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -411,12 +450,12 @@ void CharacterController::stepForward(btCollisionWorld* collisionWorld, const bt
|
|||
btScalar margin = _convexShape->getMargin();
|
||||
_convexShape->setMargin(margin + _addedMargin);
|
||||
|
||||
const btScalar MIN_STEP_DISTANCE = 0.0001f;
|
||||
const btScalar MIN_STEP_DISTANCE_SQUARED = 1.0e-6f;
|
||||
btVector3 step = _targetPosition - _currentPosition;
|
||||
btScalar stepLength2 = step.length2();
|
||||
int maxIter = 10;
|
||||
|
||||
while (stepLength2 > MIN_STEP_DISTANCE && maxIter-- > 0) {
|
||||
while (stepLength2 > MIN_STEP_DISTANCE_SQUARED && maxIter-- > 0) {
|
||||
start.setOrigin(_currentPosition);
|
||||
end.setOrigin(_targetPosition);
|
||||
|
||||
|
@ -477,13 +516,16 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt
|
|||
end.setOrigin(_targetPosition);
|
||||
_ghostObject->convexSweepTest(_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration);
|
||||
|
||||
_isOnGround = false;
|
||||
if (callback.hasHit()) {
|
||||
_currentPosition += callback.m_closestHitFraction * step;
|
||||
_verticalVelocity = 0.0f;
|
||||
_verticalOffset = 0.0f;
|
||||
_wasJumping = false;
|
||||
} else if (!_wasJumping) {
|
||||
_isJumping = false;
|
||||
_isOnGround = true;
|
||||
} else if (!_isJumping) {
|
||||
// sweep again for floor within downStep threshold
|
||||
step = -_stepDownHeight * up;
|
||||
StepDownConvexResultCallback callback2 (_ghostObject,
|
||||
up,
|
||||
_currentPosition, step,
|
||||
|
@ -495,8 +537,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt
|
|||
callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask;
|
||||
|
||||
_currentPosition = _targetPosition;
|
||||
btVector3 oldPosition = _currentPosition;
|
||||
step = (- _stepHeight) * up;
|
||||
_targetPosition = _currentPosition + step;
|
||||
|
||||
start.setOrigin(_currentPosition);
|
||||
|
@ -507,10 +547,10 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt
|
|||
_currentPosition += callback2.m_closestHitFraction * step;
|
||||
_verticalVelocity = 0.0f;
|
||||
_verticalOffset = 0.0f;
|
||||
_wasJumping = false;
|
||||
_isJumping = false;
|
||||
_isOnGround = true;
|
||||
} else {
|
||||
// nothing to step down on, so remove the stepUp effect
|
||||
_currentPosition = oldPosition - _lastStepUp * up;
|
||||
// nothing to step down on
|
||||
_lastStepUp = 0.0f;
|
||||
}
|
||||
} else {
|
||||
|
@ -534,8 +574,8 @@ void CharacterController::setVelocityForTimeInterval(const btVector3& velocity,
|
|||
void CharacterController::reset(btCollisionWorld* collisionWorld) {
|
||||
_verticalVelocity = 0.0;
|
||||
_verticalOffset = 0.0;
|
||||
_wasOnGround = false;
|
||||
_wasJumping = false;
|
||||
_isOnGround = false;
|
||||
_isJumping = false;
|
||||
_walkDirection.setValue(0,0,0);
|
||||
_velocityTimeInterval = 0.0;
|
||||
|
||||
|
@ -581,14 +621,17 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar
|
|||
return; // no motion
|
||||
}
|
||||
|
||||
_wasOnGround = onGround();
|
||||
|
||||
// Update fall velocity.
|
||||
_verticalVelocity -= _gravity * dt;
|
||||
if (_verticalVelocity > _jumpSpeed) {
|
||||
_verticalVelocity = _jumpSpeed;
|
||||
} else if (_verticalVelocity < -_maxFallSpeed) {
|
||||
_verticalVelocity = -_maxFallSpeed;
|
||||
if (_isHovering) {
|
||||
const btScalar HOVER_RELAXATION_TIMESCALE = 1.0f;
|
||||
_verticalVelocity *= (1.0f - dt / HOVER_RELAXATION_TIMESCALE);
|
||||
} else {
|
||||
_verticalVelocity -= _gravity * dt;
|
||||
if (_verticalVelocity > _jumpSpeed) {
|
||||
_verticalVelocity = _jumpSpeed;
|
||||
} else if (_verticalVelocity < -_maxFallSpeed) {
|
||||
_verticalVelocity = -_maxFallSpeed;
|
||||
}
|
||||
}
|
||||
_verticalOffset = _verticalVelocity * dt;
|
||||
|
||||
|
@ -600,11 +643,14 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar
|
|||
// (2) step the character forward
|
||||
// (3) step the character down looking for new ledges, the original floor, or a floor one step below where we started
|
||||
|
||||
scanDown(collisionWorld);
|
||||
|
||||
stepUp(collisionWorld);
|
||||
|
||||
// compute substep and decrement total interval
|
||||
btScalar dtMoving = (dt < _velocityTimeInterval) ? dt : _velocityTimeInterval;
|
||||
_velocityTimeInterval -= dt;
|
||||
_stepDt += dt;
|
||||
|
||||
// stepForward substep
|
||||
btVector3 move = _walkDirection * dtMoving;
|
||||
|
@ -629,7 +675,7 @@ void CharacterController::setMaxJumpHeight(btScalar maxJumpHeight) {
|
|||
}
|
||||
|
||||
bool CharacterController::canJump() const {
|
||||
return onGround();
|
||||
return _isOnGround;
|
||||
}
|
||||
|
||||
void CharacterController::jump() {
|
||||
|
@ -654,7 +700,7 @@ btScalar CharacterController::getMaxSlope() const {
|
|||
}
|
||||
|
||||
bool CharacterController::onGround() const {
|
||||
return _enabled && _verticalVelocity == 0.0f && _verticalOffset == 0.0f;
|
||||
return _isOnGround;
|
||||
}
|
||||
|
||||
void CharacterController::debugDraw(btIDebugDraw* debugDrawer) {
|
||||
|
@ -711,11 +757,13 @@ void CharacterController::setEnabled(bool enabled) {
|
|||
// Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit.
|
||||
// Setting the ADD bit here works for all cases so we don't even bother checking other bits.
|
||||
_pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION;
|
||||
_isHovering = true;
|
||||
} else {
|
||||
// Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case
|
||||
// it was previously set by something else (e.g. an UPDATE_SHAPE event).
|
||||
_pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION;
|
||||
_pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION;
|
||||
_isOnGround = false;
|
||||
}
|
||||
_enabled = enabled;
|
||||
}
|
||||
|
@ -772,10 +820,8 @@ void CharacterController::updateShapeIfNecessary() {
|
|||
_ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()),
|
||||
glmToBullet(_avatarData->getPosition())));
|
||||
// stepHeight affects the heights of ledges that the character can ascend
|
||||
// however the actual ledge height is some function of _stepHeight
|
||||
// due to character shape and this CharacterController algorithm
|
||||
// (the function is approximately 2*_stepHeight)
|
||||
_stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f;
|
||||
_stepUpHeight = _radius + 0.25f * _halfHeight + 0.1f;
|
||||
_stepDownHeight = _radius;
|
||||
|
||||
// create new shape
|
||||
_convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight);
|
||||
|
@ -799,9 +845,12 @@ void CharacterController::preSimulation(btScalar timeStep) {
|
|||
_pendingFlags &= ~ PENDING_FLAG_JUMP;
|
||||
if (canJump()) {
|
||||
_verticalVelocity = _jumpSpeed;
|
||||
_wasJumping = true;
|
||||
_isJumping = true;
|
||||
}
|
||||
}
|
||||
// remember last position so we can throttle the total motion from the next step
|
||||
_lastPosition = position;
|
||||
_stepDt = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -809,9 +858,24 @@ void CharacterController::postSimulation() {
|
|||
if (_enabled) {
|
||||
const btTransform& avatarTransform = _ghostObject->getWorldTransform();
|
||||
glm::quat rotation = bulletToGLM(avatarTransform.getRotation());
|
||||
glm::vec3 offset = rotation * _shapeLocalOffset;
|
||||
glm::vec3 position = bulletToGLM(avatarTransform.getOrigin());
|
||||
|
||||
// cap the velocity of the step so that the character doesn't POP! so hard on steps
|
||||
glm::vec3 finalStep = position - _lastPosition;
|
||||
btVector3 finalVelocity = _walkDirection;
|
||||
btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS);
|
||||
finalVelocity += _verticalVelocity * up;
|
||||
const btScalar MAX_RESOLUTION_SPEED = 5.0f; // m/sec
|
||||
btScalar maxStepLength = glm::max(MAX_RESOLUTION_SPEED, 2.0f * finalVelocity.length()) * _stepDt;
|
||||
btScalar stepLength = glm::length(finalStep);
|
||||
if (stepLength > maxStepLength) {
|
||||
position = _lastPosition + (maxStepLength / stepLength) * finalStep;
|
||||
// NOTE: we don't need to move ghostObject to throttled position unless
|
||||
// we want to support do async ray-traces/collision-queries against character
|
||||
}
|
||||
|
||||
_avatarData->setOrientation(rotation);
|
||||
_avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset);
|
||||
_avatarData->setPosition(position - rotation * _shapeLocalOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,8 @@ protected:
|
|||
btScalar _maxSlopeCosine; // Cosine equivalent of _maxSlopeRadians (calculated once when set, for optimization)
|
||||
btScalar _gravity;
|
||||
|
||||
btScalar _stepHeight; // height of stepUp prior to stepForward
|
||||
btScalar _stepUpHeight; // height of stepUp prior to stepForward
|
||||
btScalar _stepDownHeight; // height of stepDown
|
||||
|
||||
btScalar _addedMargin;//@todo: remove this and fix the code
|
||||
|
||||
|
@ -71,6 +72,7 @@ protected:
|
|||
btVector3 _currentPosition;
|
||||
btQuaternion _currentRotation;
|
||||
btVector3 _targetPosition;
|
||||
glm::vec3 _lastPosition;
|
||||
btScalar _lastStepUp;
|
||||
|
||||
///keep track of the contact manifolds
|
||||
|
@ -80,9 +82,11 @@ protected:
|
|||
btVector3 _floorNormal; // points from object to character
|
||||
|
||||
bool _enabled;
|
||||
bool _wasOnGround;
|
||||
bool _wasJumping;
|
||||
bool _isOnGround;
|
||||
bool _isJumping;
|
||||
bool _isHovering;
|
||||
btScalar _velocityTimeInterval;
|
||||
btScalar _stepDt;
|
||||
uint32_t _pendingFlags;
|
||||
|
||||
glm::vec3 _shapeLocalOffset;
|
||||
|
@ -95,6 +99,7 @@ protected:
|
|||
btVector3 perpindicularComponent(const btVector3& direction, const btVector3& normal);
|
||||
|
||||
bool recoverFromPenetration(btCollisionWorld* collisionWorld);
|
||||
void scanDown(btCollisionWorld* collisionWorld);
|
||||
void stepUp(btCollisionWorld* collisionWorld);
|
||||
void updateTargetPositionBasedOnCollision(const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0));
|
||||
void stepForward(btCollisionWorld* collisionWorld, const btVector3& walkMove);
|
||||
|
|
Loading…
Reference in a new issue