mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 16:18:05 +02:00
Merge pull request #3361 from AndrewMeadows/inertia
expose the _measured_ MyAvatar.getVelocity() to JS
This commit is contained in:
commit
b311017c9a
5 changed files with 151 additions and 267 deletions
|
@ -50,12 +50,13 @@ Avatar::Avatar() :
|
||||||
AvatarData(),
|
AvatarData(),
|
||||||
_skeletonModel(this),
|
_skeletonModel(this),
|
||||||
_bodyYawDelta(0.0f),
|
_bodyYawDelta(0.0f),
|
||||||
_velocity(0.0f, 0.0f, 0.0f),
|
_lastPosition(0.0f),
|
||||||
_lastVelocity(0.0f, 0.0f, 0.0f),
|
_velocity(0.0f),
|
||||||
_acceleration(0.0f, 0.0f, 0.0f),
|
_lastVelocity(0.0f),
|
||||||
_angularVelocity(0.0f, 0.0f, 0.0f),
|
_acceleration(0.0f),
|
||||||
_lastAngularVelocity(0.0f, 0.0f, 0.0f),
|
_angularVelocity(0.0f),
|
||||||
_angularAcceleration(0.0f, 0.0f, 0.0f),
|
_lastAngularVelocity(0.0f),
|
||||||
|
_angularAcceleration(0.0f),
|
||||||
_lastOrientation(),
|
_lastOrientation(),
|
||||||
_leanScale(0.5f),
|
_leanScale(0.5f),
|
||||||
_scale(1.0f),
|
_scale(1.0f),
|
||||||
|
@ -186,10 +187,6 @@ void Avatar::simulate(float deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update position by velocity, and subtract the change added earlier for gravity
|
|
||||||
_position += _velocity * deltaTime;
|
|
||||||
updateAcceleration(deltaTime);
|
|
||||||
|
|
||||||
// update animation for display name fade in/out
|
// update animation for display name fade in/out
|
||||||
if ( _displayNameTargetAlpha != _displayNameAlpha) {
|
if ( _displayNameTargetAlpha != _displayNameAlpha) {
|
||||||
// the alpha function is
|
// the alpha function is
|
||||||
|
@ -206,17 +203,23 @@ void Avatar::simulate(float deltaTime) {
|
||||||
}
|
}
|
||||||
_displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha;
|
_displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_position += _velocity * deltaTime;
|
||||||
|
measureMotionDerivatives(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::updateAcceleration(float deltaTime) {
|
void Avatar::measureMotionDerivatives(float deltaTime) {
|
||||||
// Linear Component of Acceleration
|
// linear
|
||||||
_acceleration = (_velocity - _lastVelocity) * (1.f / deltaTime);
|
float invDeltaTime = 1.0f / deltaTime;
|
||||||
|
_velocity = (_position - _lastPosition) * invDeltaTime;
|
||||||
|
_lastPosition = _position;
|
||||||
|
_acceleration = (_velocity - _lastVelocity) * invDeltaTime;
|
||||||
_lastVelocity = _velocity;
|
_lastVelocity = _velocity;
|
||||||
// Angular Component of Acceleration
|
// angular
|
||||||
glm::quat orientation = getOrientation();
|
glm::quat orientation = getOrientation();
|
||||||
glm::quat delta = glm::inverse(_lastOrientation) * orientation;
|
glm::quat delta = glm::inverse(_lastOrientation) * orientation;
|
||||||
_angularVelocity = safeEulerAngles(delta) * (1.f / deltaTime);
|
_angularVelocity = safeEulerAngles(delta) * invDeltaTime;
|
||||||
_angularAcceleration = (_angularVelocity - _lastAngularVelocity) * (1.f / deltaTime);
|
_angularAcceleration = (_angularVelocity - _lastAngularVelocity) * invDeltaTime;
|
||||||
_lastOrientation = getOrientation();
|
_lastOrientation = getOrientation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,6 @@ public:
|
||||||
const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; }
|
const QVector<Model*>& getAttachmentModels() const { return _attachmentModels; }
|
||||||
glm::vec3 getChestPosition() const;
|
glm::vec3 getChestPosition() const;
|
||||||
float getScale() const { return _scale; }
|
float getScale() const { return _scale; }
|
||||||
Q_INVOKABLE const glm::vec3& getVelocity() const { return _velocity; }
|
|
||||||
const Head* getHead() const { return static_cast<const Head*>(_headData); }
|
const Head* getHead() const { return static_cast<const Head*>(_headData); }
|
||||||
Head* getHead() { return static_cast<Head*>(_headData); }
|
Head* getHead() { return static_cast<Head*>(_headData); }
|
||||||
Hand* getHand() { return static_cast<Hand*>(_handData); }
|
Hand* getHand() { return static_cast<Hand*>(_handData); }
|
||||||
|
@ -152,6 +151,7 @@ public:
|
||||||
Q_INVOKABLE glm::quat getJointCombinedRotation(int index) const;
|
Q_INVOKABLE glm::quat getJointCombinedRotation(int index) const;
|
||||||
Q_INVOKABLE glm::quat getJointCombinedRotation(const QString& name) const;
|
Q_INVOKABLE glm::quat getJointCombinedRotation(const QString& name) const;
|
||||||
|
|
||||||
|
Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; }
|
||||||
Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; }
|
Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; }
|
||||||
Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; }
|
Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; }
|
||||||
Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; }
|
Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; }
|
||||||
|
@ -172,6 +172,12 @@ protected:
|
||||||
SkeletonModel _skeletonModel;
|
SkeletonModel _skeletonModel;
|
||||||
QVector<Model*> _attachmentModels;
|
QVector<Model*> _attachmentModels;
|
||||||
float _bodyYawDelta;
|
float _bodyYawDelta;
|
||||||
|
|
||||||
|
// These position histories and derivatives are in the world-frame.
|
||||||
|
// The derivatives are the MEASURED results of all external and internal forces
|
||||||
|
// and are therefor READ-ONLY --> motion control of the Avatar is NOT obtained
|
||||||
|
// by setting these values.
|
||||||
|
glm::vec3 _lastPosition;
|
||||||
glm::vec3 _velocity;
|
glm::vec3 _velocity;
|
||||||
glm::vec3 _lastVelocity;
|
glm::vec3 _lastVelocity;
|
||||||
glm::vec3 _acceleration;
|
glm::vec3 _acceleration;
|
||||||
|
@ -179,6 +185,7 @@ protected:
|
||||||
glm::vec3 _lastAngularVelocity;
|
glm::vec3 _lastAngularVelocity;
|
||||||
glm::vec3 _angularAcceleration;
|
glm::vec3 _angularAcceleration;
|
||||||
glm::quat _lastOrientation;
|
glm::quat _lastOrientation;
|
||||||
|
|
||||||
float _leanScale;
|
float _leanScale;
|
||||||
float _scale;
|
float _scale;
|
||||||
glm::vec3 _worldUpDirection;
|
glm::vec3 _worldUpDirection;
|
||||||
|
@ -195,7 +202,7 @@ protected:
|
||||||
glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }
|
glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }
|
||||||
glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const;
|
glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const;
|
||||||
void setScale(float scale);
|
void setScale(float scale);
|
||||||
void updateAcceleration(float deltaTime);
|
void measureMotionDerivatives(float deltaTime);
|
||||||
|
|
||||||
float getSkeletonHeight() const;
|
float getSkeletonHeight() const;
|
||||||
float getHeadHeight() const;
|
float getHeadHeight() const;
|
||||||
|
|
|
@ -62,9 +62,9 @@ MyAvatar::MyAvatar() :
|
||||||
_mousePressed(false),
|
_mousePressed(false),
|
||||||
_bodyPitchDelta(0.0f),
|
_bodyPitchDelta(0.0f),
|
||||||
_bodyRollDelta(0.0f),
|
_bodyRollDelta(0.0f),
|
||||||
_shouldJump(false),
|
|
||||||
_gravity(0.0f, 0.0f, 0.0f),
|
_gravity(0.0f, 0.0f, 0.0f),
|
||||||
_distanceToNearestAvatar(std::numeric_limits<float>::max()),
|
_distanceToNearestAvatar(std::numeric_limits<float>::max()),
|
||||||
|
_shouldJump(false),
|
||||||
_wasPushing(false),
|
_wasPushing(false),
|
||||||
_isPushing(false),
|
_isPushing(false),
|
||||||
_isBraking(false),
|
_isBraking(false),
|
||||||
|
@ -74,7 +74,6 @@ MyAvatar::MyAvatar() :
|
||||||
_motorTimescale(DEFAULT_MOTOR_TIMESCALE),
|
_motorTimescale(DEFAULT_MOTOR_TIMESCALE),
|
||||||
_maxMotorSpeed(MAX_MOTOR_SPEED),
|
_maxMotorSpeed(MAX_MOTOR_SPEED),
|
||||||
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
|
_motionBehaviors(AVATAR_MOTION_DEFAULTS),
|
||||||
_lastBodyPenetration(0.0f),
|
|
||||||
_lastFloorContactPoint(0.0f),
|
_lastFloorContactPoint(0.0f),
|
||||||
_lookAtTargetAvatar(),
|
_lookAtTargetAvatar(),
|
||||||
_shouldRender(true),
|
_shouldRender(true),
|
||||||
|
@ -103,7 +102,7 @@ void MyAvatar::reset() {
|
||||||
_skeletonModel.reset();
|
_skeletonModel.reset();
|
||||||
getHead()->reset();
|
getHead()->reset();
|
||||||
|
|
||||||
setVelocity(glm::vec3(0.0f));
|
_velocity = glm::vec3(0.0f);
|
||||||
setThrust(glm::vec3(0.0f));
|
setThrust(glm::vec3(0.0f));
|
||||||
// Reset the pitch and roll components of the avatar's orientation, preserve yaw direction
|
// Reset the pitch and roll components of the avatar's orientation, preserve yaw direction
|
||||||
glm::vec3 eulers = safeEulerAngles(getOrientation());
|
glm::vec3 eulers = safeEulerAngles(getOrientation());
|
||||||
|
@ -1159,6 +1158,11 @@ void MyAvatar::updatePosition(float deltaTime) {
|
||||||
boundingShape.getStartPoint(startCap);
|
boundingShape.getStartPoint(startCap);
|
||||||
glm::vec3 bottom = startCap - boundingShape.getRadius() * _worldUpDirection;
|
glm::vec3 bottom = startCap - boundingShape.getRadius() * _worldUpDirection;
|
||||||
|
|
||||||
|
// velocity is initialized to the measured _velocity but will be modified
|
||||||
|
// by friction, external thrust, etc
|
||||||
|
glm::vec3 velocity = _velocity;
|
||||||
|
|
||||||
|
// apply friction
|
||||||
if (gravityLength > EPSILON) {
|
if (gravityLength > EPSILON) {
|
||||||
float speedFromGravity = _scale * deltaTime * gravityLength;
|
float speedFromGravity = _scale * deltaTime * gravityLength;
|
||||||
float distanceToFall = glm::distance(bottom, _lastFloorContactPoint);
|
float distanceToFall = glm::distance(bottom, _lastFloorContactPoint);
|
||||||
|
@ -1167,26 +1171,26 @@ void MyAvatar::updatePosition(float deltaTime) {
|
||||||
if (walkingOnFloor) {
|
if (walkingOnFloor) {
|
||||||
// BEGIN HACK: to prevent the avatar from bouncing on a floor surface
|
// BEGIN HACK: to prevent the avatar from bouncing on a floor surface
|
||||||
if (distanceToFall < deltaTime * speedFromGravity) {
|
if (distanceToFall < deltaTime * speedFromGravity) {
|
||||||
float verticalSpeed = glm::dot(_velocity, _worldUpDirection);
|
float verticalSpeed = glm::dot(velocity, _worldUpDirection);
|
||||||
if (fabs(verticalSpeed) < speedFromGravity) {
|
if (fabs(verticalSpeed) < speedFromGravity) {
|
||||||
// we're standing on a floor, and nearly at rest so we zero the vertical velocity component
|
// we're standing on a floor, and nearly at rest so we zero the vertical velocity component
|
||||||
_velocity -= verticalSpeed * _worldUpDirection;
|
velocity -= verticalSpeed * _worldUpDirection;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// fall with gravity against floor
|
// fall with gravity against floor
|
||||||
_velocity -= speedFromGravity * _worldUpDirection;
|
velocity -= speedFromGravity * _worldUpDirection;
|
||||||
}
|
}
|
||||||
// END HACK
|
// END HACK
|
||||||
} else {
|
} else {
|
||||||
if (!_isBraking) {
|
if (!_isBraking) {
|
||||||
// fall with gravity toward floor
|
// fall with gravity toward floor
|
||||||
_velocity -= speedFromGravity * _worldUpDirection;
|
velocity -= speedFromGravity * _worldUpDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) {
|
if (_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) {
|
||||||
const float MAX_VERTICAL_FLOOR_DETECTION_SPEED = _scale * MAX_WALKING_SPEED;
|
const float MAX_VERTICAL_FLOOR_DETECTION_SPEED = _scale * MAX_WALKING_SPEED;
|
||||||
if (keyboardInput && glm::dot(_motorVelocity, _worldUpDirection) > 0.0f &&
|
if (keyboardInput && glm::dot(_motorVelocity, _worldUpDirection) > 0.0f &&
|
||||||
glm::dot(_velocity, _worldUpDirection) > MAX_VERTICAL_FLOOR_DETECTION_SPEED) {
|
glm::dot(velocity, _worldUpDirection) > MAX_VERTICAL_FLOOR_DETECTION_SPEED) {
|
||||||
// disable local gravity when flying up
|
// disable local gravity when flying up
|
||||||
setLocalGravity(glm::vec3(0.0f));
|
setLocalGravity(glm::vec3(0.0f));
|
||||||
} else {
|
} else {
|
||||||
|
@ -1198,93 +1202,123 @@ void MyAvatar::updatePosition(float deltaTime) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if ((_collisionGroups & COLLISION_GROUP_VOXELS) &&
|
||||||
if ((_collisionGroups & COLLISION_GROUP_VOXELS) &&
|
_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) {
|
||||||
_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) {
|
const float MIN_FLOOR_DETECTION_SPEED = _scale * 1.0f;
|
||||||
const float MIN_FLOOR_DETECTION_SPEED = _scale * 1.0f;
|
if (glm::length(_velocity) < MIN_FLOOR_DETECTION_SPEED ) {
|
||||||
if (glm::length(_velocity) < MIN_FLOOR_DETECTION_SPEED ) {
|
// scan for floor under avatar
|
||||||
// scan for floor under avatar
|
const float maxFloorDistance = _scale * NEARBY_FLOOR_THRESHOLD;
|
||||||
const float maxFloorDistance = _scale * NEARBY_FLOOR_THRESHOLD;
|
if (computeDistanceToFloor(bottom) < maxFloorDistance) {
|
||||||
if (computeDistanceToFloor(bottom) < maxFloorDistance) {
|
// enable local gravity
|
||||||
// enable local gravity
|
setLocalGravity(-_worldUpDirection);
|
||||||
setLocalGravity(-_worldUpDirection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyboardInput > 0.0f || glm::length2(_velocity) > 0.0f || glm::length2(_thrust) > 0.0f || ! walkingOnFloor) {
|
float speed = glm::length(velocity);
|
||||||
// update motor and thrust
|
if (keyboardInput > 0.0f || speed > 0.0f || glm::length2(_thrust) > 0.0f || ! walkingOnFloor) {
|
||||||
updateMotorFromKeyboard(deltaTime, walkingOnFloor);
|
// update motor
|
||||||
applyMotor(deltaTime);
|
if (_motionBehaviors & AVATAR_MOTION_MOTOR_KEYBOARD_ENABLED) {
|
||||||
applyThrust(deltaTime);
|
// Increase motor velocity until its length is equal to _maxMotorSpeed.
|
||||||
|
glm::vec3 localVelocity = velocity;
|
||||||
|
if (_motionBehaviors & AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME) {
|
||||||
|
glm::quat orientation = getHead()->getCameraOrientation();
|
||||||
|
localVelocity = glm::inverse(orientation) * velocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute keyboard input
|
||||||
|
glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT;
|
||||||
|
glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT;
|
||||||
|
glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP;
|
||||||
|
|
||||||
|
glm::vec3 direction = front + right + up;
|
||||||
|
float directionLength = glm::length(direction);
|
||||||
|
|
||||||
|
// Compute motor magnitude
|
||||||
|
if (directionLength > EPSILON) {
|
||||||
|
direction /= directionLength;
|
||||||
|
// the finalMotorSpeed depends on whether we are walking or not
|
||||||
|
float finalMaxMotorSpeed = walkingOnFloor ? _scale * MAX_WALKING_SPEED : _scale * _maxMotorSpeed;
|
||||||
|
|
||||||
|
float motorLength = glm::length(_motorVelocity);
|
||||||
|
if (motorLength < _scale * MIN_KEYBOARD_CONTROL_SPEED) {
|
||||||
|
// an active keyboard motor should never be slower than this
|
||||||
|
_motorVelocity = _scale * MIN_KEYBOARD_CONTROL_SPEED * direction;
|
||||||
|
} else {
|
||||||
|
float MOTOR_LENGTH_TIMESCALE = 1.5f;
|
||||||
|
float tau = glm::clamp(deltaTime / MOTOR_LENGTH_TIMESCALE, 0.0f, 1.0f);
|
||||||
|
float INCREASE_FACTOR = 2.0f;
|
||||||
|
//_motorVelocity *= 1.0f + tau * INCREASE_FACTOR;
|
||||||
|
motorLength *= 1.0f + tau * INCREASE_FACTOR;
|
||||||
|
if (motorLength > finalMaxMotorSpeed) {
|
||||||
|
motorLength = finalMaxMotorSpeed;
|
||||||
|
}
|
||||||
|
_motorVelocity = motorLength * direction;
|
||||||
|
}
|
||||||
|
_isPushing = true;
|
||||||
|
} else {
|
||||||
|
// motor opposes motion (wants to be at rest)
|
||||||
|
_motorVelocity = - localVelocity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply motor
|
||||||
|
if (_motionBehaviors & AVATAR_MOTION_MOTOR_ENABLED) {
|
||||||
|
glm::vec3 targetVelocity = _motorVelocity;
|
||||||
|
if (_motionBehaviors & AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME) {
|
||||||
|
// rotate _motorVelocity into world frame
|
||||||
|
glm::quat rotation = getHead()->getCameraOrientation();
|
||||||
|
targetVelocity = rotation * _motorVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::vec3 targetDirection(0.0f);
|
||||||
|
if (glm::length2(targetVelocity) > EPSILON) {
|
||||||
|
targetDirection = glm::normalize(targetVelocity);
|
||||||
|
}
|
||||||
|
glm::vec3 deltaVelocity = targetVelocity - velocity;
|
||||||
|
|
||||||
|
if (_motionBehaviors & AVATAR_MOTION_MOTOR_COLLISION_SURFACE_ONLY && glm::length2(_gravity) > EPSILON) {
|
||||||
|
// For now we subtract the component parallel to gravity but what we need to do is:
|
||||||
|
// TODO: subtract the component perp to the local surface normal (motor only pushes in surface plane).
|
||||||
|
glm::vec3 gravityDirection = glm::normalize(_gravity);
|
||||||
|
glm::vec3 parallelDelta = glm::dot(deltaVelocity, gravityDirection) * gravityDirection;
|
||||||
|
if (glm::dot(targetVelocity, velocity) > 0.0f) {
|
||||||
|
// remove parallel part from deltaVelocity
|
||||||
|
deltaVelocity -= parallelDelta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// simple critical damping
|
||||||
|
float timescale = computeMotorTimescale(velocity);
|
||||||
|
float tau = glm::clamp(deltaTime / timescale, 0.0f, 1.0f);
|
||||||
|
velocity += tau * deltaVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply thrust
|
||||||
|
velocity += _thrust * deltaTime;
|
||||||
|
speed = glm::length(velocity);
|
||||||
|
if (speed > MAX_AVATAR_SPEED) {
|
||||||
|
velocity *= MAX_AVATAR_SPEED / speed;
|
||||||
|
speed = MAX_AVATAR_SPEED;
|
||||||
|
}
|
||||||
|
_thrust = glm::vec3(0.0f);
|
||||||
|
|
||||||
// update position
|
// update position
|
||||||
if (glm::length2(_velocity) < EPSILON) {
|
const float MIN_AVATAR_SPEED = 0.075f;
|
||||||
_velocity = glm::vec3(0.0f);
|
if (speed > MIN_AVATAR_SPEED) {
|
||||||
} else {
|
_position += velocity * deltaTime;
|
||||||
_position += _velocity * deltaTime;
|
|
||||||
}
|
}
|
||||||
updateAcceleration(deltaTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update moving flag based on speed
|
// update moving flag based on speed
|
||||||
const float MOVING_SPEED_THRESHOLD = 0.01f;
|
const float MOVING_SPEED_THRESHOLD = 0.01f;
|
||||||
_moving = glm::length(_velocity) > MOVING_SPEED_THRESHOLD;
|
_moving = speed > MOVING_SPEED_THRESHOLD;
|
||||||
|
|
||||||
updateChatCircle(deltaTime);
|
updateChatCircle(deltaTime);
|
||||||
|
measureMotionDerivatives(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::updateMotorFromKeyboard(float deltaTime, bool walking) {
|
float MyAvatar::computeMotorTimescale(const glm::vec3& velocity) {
|
||||||
// Increase motor velocity until its length is equal to _maxMotorSpeed.
|
|
||||||
if (!(_motionBehaviors & AVATAR_MOTION_MOTOR_KEYBOARD_ENABLED)) {
|
|
||||||
// nothing to do
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 localVelocity = _velocity;
|
|
||||||
if (_motionBehaviors & AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME) {
|
|
||||||
glm::quat orientation = getHead()->getCameraOrientation();
|
|
||||||
localVelocity = glm::inverse(orientation) * _velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute keyboard input
|
|
||||||
glm::vec3 front = (_driveKeys[FWD] - _driveKeys[BACK]) * IDENTITY_FRONT;
|
|
||||||
glm::vec3 right = (_driveKeys[RIGHT] - _driveKeys[LEFT]) * IDENTITY_RIGHT;
|
|
||||||
glm::vec3 up = (_driveKeys[UP] - _driveKeys[DOWN]) * IDENTITY_UP;
|
|
||||||
|
|
||||||
glm::vec3 direction = front + right + up;
|
|
||||||
float directionLength = glm::length(direction);
|
|
||||||
|
|
||||||
// Compute motor magnitude
|
|
||||||
if (directionLength > EPSILON) {
|
|
||||||
direction /= directionLength;
|
|
||||||
// the finalMotorSpeed depends on whether we are walking or not
|
|
||||||
float finalMaxMotorSpeed = walking ? _scale * MAX_WALKING_SPEED : _scale * _maxMotorSpeed;
|
|
||||||
|
|
||||||
float motorLength = glm::length(_motorVelocity);
|
|
||||||
if (motorLength < _scale * MIN_KEYBOARD_CONTROL_SPEED) {
|
|
||||||
// an active keyboard motor should never be slower than this
|
|
||||||
_motorVelocity = _scale * MIN_KEYBOARD_CONTROL_SPEED * direction;
|
|
||||||
} else {
|
|
||||||
float MOTOR_LENGTH_TIMESCALE = 1.5f;
|
|
||||||
float tau = glm::clamp(deltaTime / MOTOR_LENGTH_TIMESCALE, 0.0f, 1.0f);
|
|
||||||
float INCREASE_FACTOR = 2.0f;
|
|
||||||
//_motorVelocity *= 1.0f + tau * INCREASE_FACTOR;
|
|
||||||
motorLength *= 1.0f + tau * INCREASE_FACTOR;
|
|
||||||
if (motorLength > finalMaxMotorSpeed) {
|
|
||||||
motorLength = finalMaxMotorSpeed;
|
|
||||||
}
|
|
||||||
_motorVelocity = motorLength * direction;
|
|
||||||
}
|
|
||||||
_isPushing = true;
|
|
||||||
} else {
|
|
||||||
// motor opposes motion (wants to be at rest)
|
|
||||||
_motorVelocity = - localVelocity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float MyAvatar::computeMotorTimescale() {
|
|
||||||
// The timescale of the motor is the approximate time it takes for the motor to
|
// The timescale of the motor is the approximate time it takes for the motor to
|
||||||
// accomplish its intended velocity. A short timescale makes the motor strong,
|
// accomplish its intended velocity. A short timescale makes the motor strong,
|
||||||
// and a long timescale makes it weak. The value of timescale to use depends
|
// and a long timescale makes it weak. The value of timescale to use depends
|
||||||
|
@ -1304,7 +1338,7 @@ float MyAvatar::computeMotorTimescale() {
|
||||||
timescale = _motorTimescale;
|
timescale = _motorTimescale;
|
||||||
_isBraking = false;
|
_isBraking = false;
|
||||||
} else {
|
} else {
|
||||||
float speed = glm::length(_velocity);
|
float speed = glm::length(velocity);
|
||||||
_isBraking = _wasPushing || (_isBraking && speed > MIN_BRAKE_SPEED);
|
_isBraking = _wasPushing || (_isBraking && speed > MIN_BRAKE_SPEED);
|
||||||
if (_isBraking) {
|
if (_isBraking) {
|
||||||
timescale = MIN_MOTOR_TIMESCALE;
|
timescale = MIN_MOTOR_TIMESCALE;
|
||||||
|
@ -1315,160 +1349,6 @@ float MyAvatar::computeMotorTimescale() {
|
||||||
return timescale;
|
return timescale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::applyMotor(float deltaTime) {
|
|
||||||
// TODO: recover extra braking behavior when flying close to nearest avatar
|
|
||||||
if (!( _motionBehaviors & AVATAR_MOTION_MOTOR_ENABLED)) {
|
|
||||||
// nothing to do --> early exit
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
glm::vec3 targetVelocity = _motorVelocity;
|
|
||||||
if (_motionBehaviors & AVATAR_MOTION_MOTOR_USE_LOCAL_FRAME) {
|
|
||||||
// rotate _motorVelocity into world frame
|
|
||||||
glm::quat rotation = getHead()->getCameraOrientation();
|
|
||||||
targetVelocity = rotation * _motorVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 targetDirection(0.0f);
|
|
||||||
if (glm::length2(targetVelocity) > EPSILON) {
|
|
||||||
targetDirection = glm::normalize(targetVelocity);
|
|
||||||
}
|
|
||||||
glm::vec3 deltaVelocity = targetVelocity - _velocity;
|
|
||||||
|
|
||||||
if (_motionBehaviors & AVATAR_MOTION_MOTOR_COLLISION_SURFACE_ONLY && glm::length2(_gravity) > EPSILON) {
|
|
||||||
// For now we subtract the component parallel to gravity but what we need to do is:
|
|
||||||
// TODO: subtract the component perp to the local surface normal (motor only pushes in surface plane).
|
|
||||||
glm::vec3 gravityDirection = glm::normalize(_gravity);
|
|
||||||
glm::vec3 parallelDelta = glm::dot(deltaVelocity, gravityDirection) * gravityDirection;
|
|
||||||
if (glm::dot(targetVelocity, _velocity) > 0.0f) {
|
|
||||||
// remove parallel part from deltaVelocity
|
|
||||||
deltaVelocity -= parallelDelta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// simple critical damping
|
|
||||||
float timescale = computeMotorTimescale();
|
|
||||||
float tau = glm::clamp(deltaTime / timescale, 0.0f, 1.0f);
|
|
||||||
_velocity += tau * deltaVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MyAvatar::applyThrust(float deltaTime) {
|
|
||||||
_velocity += _thrust * deltaTime;
|
|
||||||
float speed = glm::length(_velocity);
|
|
||||||
// cap the speed that thrust can achieve
|
|
||||||
if (speed > MAX_AVATAR_SPEED) {
|
|
||||||
_velocity *= MAX_AVATAR_SPEED / speed;
|
|
||||||
}
|
|
||||||
// zero thrust so we don't pile up thrust from other sources
|
|
||||||
_thrust = glm::vec3(0.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Keep this code for the short term as reference in case we need to further tune the new model
|
|
||||||
* to achieve legacy movement response.
|
|
||||||
void MyAvatar::updateThrust(float deltaTime) {
|
|
||||||
//
|
|
||||||
// Gather thrust information from keyboard and sensors to apply to avatar motion
|
|
||||||
//
|
|
||||||
glm::quat orientation = getHead()->getCameraOrientation();
|
|
||||||
glm::vec3 front = orientation * IDENTITY_FRONT;
|
|
||||||
glm::vec3 right = orientation * IDENTITY_RIGHT;
|
|
||||||
glm::vec3 up = orientation * IDENTITY_UP;
|
|
||||||
|
|
||||||
const float THRUST_MAG_UP = 800.0f;
|
|
||||||
const float THRUST_MAG_DOWN = 300.0f;
|
|
||||||
const float THRUST_MAG_FWD = 500.0f;
|
|
||||||
const float THRUST_MAG_BACK = 300.0f;
|
|
||||||
const float THRUST_MAG_LATERAL = 250.0f;
|
|
||||||
const float THRUST_JUMP = 120.0f;
|
|
||||||
|
|
||||||
// Add Thrusts from keyboard
|
|
||||||
_thrust += _driveKeys[FWD] * _scale * THRUST_MAG_FWD * _thrustMultiplier * deltaTime * front;
|
|
||||||
_thrust -= _driveKeys[BACK] * _scale * THRUST_MAG_BACK * _thrustMultiplier * deltaTime * front;
|
|
||||||
_thrust += _driveKeys[RIGHT] * _scale * THRUST_MAG_LATERAL * _thrustMultiplier * deltaTime * right;
|
|
||||||
_thrust -= _driveKeys[LEFT] * _scale * THRUST_MAG_LATERAL * _thrustMultiplier * deltaTime * right;
|
|
||||||
_thrust += _driveKeys[UP] * _scale * THRUST_MAG_UP * _thrustMultiplier * deltaTime * up;
|
|
||||||
_thrust -= _driveKeys[DOWN] * _scale * THRUST_MAG_DOWN * _thrustMultiplier * deltaTime * up;
|
|
||||||
|
|
||||||
// attenuate thrust when in penetration
|
|
||||||
if (glm::dot(_thrust, _lastBodyPenetration) > EPSILON) {
|
|
||||||
const float MAX_BODY_PENETRATION_DEPTH = 0.6f * _skeletonModel.getBoundingShapeRadius();
|
|
||||||
float penetrationFactor = glm::min(1.0f, glm::length(_lastBodyPenetration) / MAX_BODY_PENETRATION_DEPTH);
|
|
||||||
glm::vec3 penetrationDirection = glm::normalize(_lastBodyPenetration);
|
|
||||||
// attenuate parallel component
|
|
||||||
glm::vec3 parallelThrust = glm::dot(_thrust, penetrationDirection) * penetrationDirection;
|
|
||||||
// attenuate perpendicular component (friction)
|
|
||||||
glm::vec3 perpendicularThrust = _thrust - parallelThrust;
|
|
||||||
// recombine to get the final thrust
|
|
||||||
_thrust = (1.0f - penetrationFactor) * parallelThrust + (1.0f - penetrationFactor * penetrationFactor) * perpendicularThrust;
|
|
||||||
|
|
||||||
// attenuate the growth of _thrustMultiplier when in penetration
|
|
||||||
// otherwise the avatar will eventually be able to tunnel through the obstacle
|
|
||||||
_thrustMultiplier *= (1.0f - penetrationFactor * penetrationFactor);
|
|
||||||
} else if (_thrustMultiplier < 1.0f) {
|
|
||||||
// rapid healing of attenuated thrustMultiplier after penetration event
|
|
||||||
_thrustMultiplier = 1.0f;
|
|
||||||
}
|
|
||||||
_lastBodyPenetration = glm::vec3(0.0f);
|
|
||||||
|
|
||||||
// If thrust keys are being held down, slowly increase thrust to allow reaching great speeds
|
|
||||||
if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) {
|
|
||||||
const float THRUST_INCREASE_RATE = 1.05f;
|
|
||||||
const float MAX_THRUST_MULTIPLIER = 75.0f;
|
|
||||||
_thrustMultiplier *= 1.0f + deltaTime * THRUST_INCREASE_RATE;
|
|
||||||
if (_thrustMultiplier > MAX_THRUST_MULTIPLIER) {
|
|
||||||
_thrustMultiplier = MAX_THRUST_MULTIPLIER;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
_thrustMultiplier = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add one time jumping force if requested
|
|
||||||
if (_shouldJump) {
|
|
||||||
if (glm::length(_gravity) > EPSILON) {
|
|
||||||
_thrust += _scale * THRUST_JUMP * up;
|
|
||||||
}
|
|
||||||
_shouldJump = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update speed brake status
|
|
||||||
const float MIN_SPEED_BRAKE_VELOCITY = _scale * 0.4f;
|
|
||||||
if ((glm::length(_thrust) == 0.0f) && _isThrustOn && (glm::length(_velocity) > MIN_SPEED_BRAKE_VELOCITY)) {
|
|
||||||
_speedBrakes = true;
|
|
||||||
}
|
|
||||||
_isThrustOn = (glm::length(_thrust) > EPSILON);
|
|
||||||
|
|
||||||
if (_isThrustOn || (_speedBrakes && (glm::length(_velocity) < MIN_SPEED_BRAKE_VELOCITY))) {
|
|
||||||
_speedBrakes = false;
|
|
||||||
}
|
|
||||||
_velocity += _thrust * deltaTime;
|
|
||||||
|
|
||||||
// Zero thrust out now that we've added it to velocity in this frame
|
|
||||||
_thrust = glm::vec3(0.0f);
|
|
||||||
|
|
||||||
// apply linear damping
|
|
||||||
const float MAX_STATIC_FRICTION_SPEED = 0.5f;
|
|
||||||
const float STATIC_FRICTION_STRENGTH = _scale * 20.0f;
|
|
||||||
applyStaticFriction(deltaTime, _velocity, MAX_STATIC_FRICTION_SPEED, STATIC_FRICTION_STRENGTH);
|
|
||||||
|
|
||||||
const float LINEAR_DAMPING_STRENGTH = 0.5f;
|
|
||||||
const float SPEED_BRAKE_POWER = _scale * 10.0f;
|
|
||||||
const float SQUARED_DAMPING_STRENGTH = 0.007f;
|
|
||||||
|
|
||||||
const float SLOW_NEAR_RADIUS = 5.0f;
|
|
||||||
float linearDamping = LINEAR_DAMPING_STRENGTH;
|
|
||||||
const float NEAR_AVATAR_DAMPING_FACTOR = 50.0f;
|
|
||||||
if (_distanceToNearestAvatar < _scale * SLOW_NEAR_RADIUS) {
|
|
||||||
linearDamping *= 1.0f + NEAR_AVATAR_DAMPING_FACTOR *
|
|
||||||
((SLOW_NEAR_RADIUS - _distanceToNearestAvatar) / SLOW_NEAR_RADIUS);
|
|
||||||
}
|
|
||||||
if (_speedBrakes) {
|
|
||||||
applyDamping(deltaTime, _velocity, linearDamping * SPEED_BRAKE_POWER, SQUARED_DAMPING_STRENGTH * SPEED_BRAKE_POWER);
|
|
||||||
} else {
|
|
||||||
applyDamping(deltaTime, _velocity, linearDamping, SQUARED_DAMPING_STRENGTH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) {
|
void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) {
|
||||||
glm::vec3 up = getBodyUpDirection();
|
glm::vec3 up = getBodyUpDirection();
|
||||||
const float ENVIRONMENT_SURFACE_ELASTICITY = 0.0f;
|
const float ENVIRONMENT_SURFACE_ELASTICITY = 0.0f;
|
||||||
|
|
|
@ -54,7 +54,6 @@ public:
|
||||||
|
|
||||||
// setters
|
// setters
|
||||||
void setMousePressed(bool mousePressed) { _mousePressed = mousePressed; }
|
void setMousePressed(bool mousePressed) { _mousePressed = mousePressed; }
|
||||||
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
|
|
||||||
void setLeanScale(float scale) { _leanScale = scale; }
|
void setLeanScale(float scale) { _leanScale = scale; }
|
||||||
void setLocalGravity(glm::vec3 gravity);
|
void setLocalGravity(glm::vec3 gravity);
|
||||||
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; }
|
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; }
|
||||||
|
@ -189,23 +188,23 @@ private:
|
||||||
bool _mousePressed;
|
bool _mousePressed;
|
||||||
float _bodyPitchDelta; // degrees
|
float _bodyPitchDelta; // degrees
|
||||||
float _bodyRollDelta; // degrees
|
float _bodyRollDelta; // degrees
|
||||||
bool _shouldJump;
|
|
||||||
float _driveKeys[MAX_DRIVE_KEYS];
|
|
||||||
glm::vec3 _gravity;
|
glm::vec3 _gravity;
|
||||||
float _distanceToNearestAvatar; // How close is the nearest avatar?
|
float _distanceToNearestAvatar; // How close is the nearest avatar?
|
||||||
|
|
||||||
|
bool _shouldJump;
|
||||||
|
float _driveKeys[MAX_DRIVE_KEYS];
|
||||||
bool _wasPushing;
|
bool _wasPushing;
|
||||||
bool _isPushing;
|
bool _isPushing;
|
||||||
bool _isBraking;
|
bool _isBraking;
|
||||||
float _trapDuration; // seconds that avatar has been trapped by collisions
|
|
||||||
glm::vec3 _thrust; // final acceleration from outside sources for the current frame
|
|
||||||
|
|
||||||
glm::vec3 _motorVelocity; // intended velocity of avatar motion
|
float _trapDuration; // seconds that avatar has been trapped by collisions
|
||||||
|
glm::vec3 _thrust; // impulse accumulator for outside sources
|
||||||
|
|
||||||
|
glm::vec3 _motorVelocity; // intended velocity of avatar motion (relative to what it's standing on)
|
||||||
float _motorTimescale; // timescale for avatar motor to achieve its desired velocity
|
float _motorTimescale; // timescale for avatar motor to achieve its desired velocity
|
||||||
float _maxMotorSpeed;
|
float _maxMotorSpeed;
|
||||||
quint32 _motionBehaviors;
|
quint32 _motionBehaviors;
|
||||||
|
|
||||||
glm::vec3 _lastBodyPenetration;
|
|
||||||
glm::vec3 _lastFloorContactPoint;
|
glm::vec3 _lastFloorContactPoint;
|
||||||
QWeakPointer<AvatarData> _lookAtTargetAvatar;
|
QWeakPointer<AvatarData> _lookAtTargetAvatar;
|
||||||
glm::vec3 _targetAvatarPosition;
|
glm::vec3 _targetAvatarPosition;
|
||||||
|
@ -223,10 +222,7 @@ private:
|
||||||
float computeDistanceToFloor(const glm::vec3& startPoint);
|
float computeDistanceToFloor(const glm::vec3& startPoint);
|
||||||
void updateOrientation(float deltaTime);
|
void updateOrientation(float deltaTime);
|
||||||
void updatePosition(float deltaTime);
|
void updatePosition(float deltaTime);
|
||||||
void updateMotorFromKeyboard(float deltaTime, bool walking);
|
float computeMotorTimescale(const glm::vec3& velocity);
|
||||||
float computeMotorTimescale();
|
|
||||||
void applyMotor(float deltaTime);
|
|
||||||
void applyThrust(float deltaTime);
|
|
||||||
void updateCollisionWithAvatars(float deltaTime);
|
void updateCollisionWithAvatars(float deltaTime);
|
||||||
void updateCollisionWithEnvironment(float deltaTime, float radius);
|
void updateCollisionWithEnvironment(float deltaTime, float radius);
|
||||||
void updateCollisionWithVoxels(float deltaTime, float radius);
|
void updateCollisionWithVoxels(float deltaTime, float radius);
|
||||||
|
|
|
@ -240,8 +240,6 @@ public:
|
||||||
const HeadData* getHeadData() const { return _headData; }
|
const HeadData* getHeadData() const { return _headData; }
|
||||||
const HandData* getHandData() const { return _handData; }
|
const HandData* getHandData() const { return _handData; }
|
||||||
|
|
||||||
virtual const glm::vec3& getVelocity() const { return vec3Zero; }
|
|
||||||
|
|
||||||
virtual bool findSphereCollisions(const glm::vec3& particleCenter, float particleRadius, CollisionList& collisions) {
|
virtual bool findSphereCollisions(const glm::vec3& particleCenter, float particleRadius, CollisionList& collisions) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue