mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
Merge pull request #7048 from hyperlogic/tony/avatar-on-moving-platform
Better avatar animation when attached to a moving entity
This commit is contained in:
commit
43592fd699
16 changed files with 248 additions and 78 deletions
40
examples/moving-platform.js
Normal file
40
examples/moving-platform.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
var platform;
|
||||
|
||||
function init() {
|
||||
platform = Entities.addEntity({
|
||||
name: "platform",
|
||||
type: "Box",
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
dimensions: { x: 10, y: 2, z: 10 },
|
||||
color: { red: 0, green: 0, blue: 255 },
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
visible: true,
|
||||
locked: false,
|
||||
lifetime: 6000,
|
||||
velocity: { x: 1.0, y: 0, z: 0 },
|
||||
damping: 0,
|
||||
isDynamic: false
|
||||
});
|
||||
if (platform) {
|
||||
if (MyAvatar.getParentID() != platform) {
|
||||
MyAvatar.position = { x: 0, y: 3, z: 0 };
|
||||
MyAvatar.setParentID(platform);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function update(dt) {
|
||||
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
if (platform) {
|
||||
MyAvatar.setParentID(0);
|
||||
Entities.deleteEntity(platform);
|
||||
}
|
||||
}
|
||||
|
||||
Script.setTimeout(init, 3000);
|
||||
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(shutdown);
|
|
@ -86,9 +86,7 @@ Avatar::Avatar(RigPointer rig) :
|
|||
_positionDeltaAccumulator(0.0f),
|
||||
_lastVelocity(0.0f),
|
||||
_acceleration(0.0f),
|
||||
_angularVelocity(0.0f),
|
||||
_lastAngularVelocity(0.0f),
|
||||
_angularAcceleration(0.0f),
|
||||
_lastOrientation(),
|
||||
_leanScale(0.5f),
|
||||
_worldUpDirection(DEFAULT_UP_DIRECTION),
|
||||
|
@ -235,9 +233,6 @@ void Avatar::simulate(float deltaTime) {
|
|||
_displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha;
|
||||
}
|
||||
|
||||
// NOTE: we shouldn't extrapolate an Avatar instance forward in time...
|
||||
// until velocity is included in AvatarData update message.
|
||||
//_position += _velocity * deltaTime;
|
||||
measureMotionDerivatives(deltaTime);
|
||||
|
||||
simulateAttachments(deltaTime);
|
||||
|
@ -255,7 +250,7 @@ bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const {
|
|||
void Avatar::slamPosition(const glm::vec3& newPosition) {
|
||||
setPosition(newPosition);
|
||||
_positionDeltaAccumulator = glm::vec3(0.0f);
|
||||
_velocity = glm::vec3(0.0f);
|
||||
setVelocity(glm::vec3(0.0f));
|
||||
_lastVelocity = glm::vec3(0.0f);
|
||||
}
|
||||
|
||||
|
@ -269,15 +264,17 @@ void Avatar::measureMotionDerivatives(float deltaTime) {
|
|||
float invDeltaTime = 1.0f / deltaTime;
|
||||
// Floating point error prevents us from computing velocity in a naive way
|
||||
// (e.g. vel = (pos - oldPos) / dt) so instead we use _positionOffsetAccumulator.
|
||||
_velocity = _positionDeltaAccumulator * invDeltaTime;
|
||||
glm::vec3 velocity = _positionDeltaAccumulator * invDeltaTime;
|
||||
_positionDeltaAccumulator = glm::vec3(0.0f);
|
||||
_acceleration = (_velocity - _lastVelocity) * invDeltaTime;
|
||||
_lastVelocity = _velocity;
|
||||
_acceleration = (velocity - _lastVelocity) * invDeltaTime;
|
||||
_lastVelocity = velocity;
|
||||
setVelocity(velocity);
|
||||
|
||||
// angular
|
||||
glm::quat orientation = getOrientation();
|
||||
glm::quat delta = glm::inverse(_lastOrientation) * orientation;
|
||||
_angularVelocity = safeEulerAngles(delta) * invDeltaTime;
|
||||
_angularAcceleration = (_angularVelocity - _lastAngularVelocity) * invDeltaTime;
|
||||
glm::vec3 angularVelocity = glm::axis(delta) * glm::angle(delta) * invDeltaTime;
|
||||
setAngularVelocity(angularVelocity);
|
||||
_lastOrientation = getOrientation();
|
||||
}
|
||||
|
||||
|
|
|
@ -135,8 +135,6 @@ public:
|
|||
Q_INVOKABLE glm::vec3 getNeckPosition() const;
|
||||
|
||||
Q_INVOKABLE glm::vec3 getAcceleration() const { return _acceleration; }
|
||||
Q_INVOKABLE glm::vec3 getAngularVelocity() const { return _angularVelocity; }
|
||||
Q_INVOKABLE glm::vec3 getAngularAcceleration() const { return _angularAcceleration; }
|
||||
|
||||
Q_INVOKABLE bool getShouldRender() const { return !_shouldSkipRender; }
|
||||
|
||||
|
|
|
@ -1080,6 +1080,15 @@ void MyAvatar::rebuildCollisionShape() {
|
|||
|
||||
void MyAvatar::prepareForPhysicsSimulation() {
|
||||
relayDriveKeysToCharacterController();
|
||||
|
||||
bool success;
|
||||
glm::vec3 parentVelocity = getParentVelocity(success);
|
||||
if (!success) {
|
||||
qDebug() << "Warning: getParentVelocity failed" << getID();
|
||||
parentVelocity = glm::vec3();
|
||||
}
|
||||
_characterController.setParentVelocity(parentVelocity);
|
||||
|
||||
_characterController.setTargetVelocity(getTargetVelocity());
|
||||
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
|
||||
if (qApp->isHMDMode()) {
|
||||
|
|
|
@ -67,6 +67,7 @@ void MyCharacterController::updateShapeIfNecessary() {
|
|||
_rigidBody->setAngularFactor(0.0f);
|
||||
_rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()),
|
||||
glmToBullet(_avatar->getPosition())));
|
||||
_rigidBody->setDamping(0.0f, 0.0f);
|
||||
if (_state == State::Hover) {
|
||||
_rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f));
|
||||
} else {
|
||||
|
|
|
@ -148,7 +148,11 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
_rig->updateFromHandParameters(handParams, deltaTime);
|
||||
|
||||
Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState());
|
||||
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation(), ccState);
|
||||
|
||||
auto velocity = myAvatar->getLocalVelocity();
|
||||
auto position = myAvatar->getLocalPosition();
|
||||
auto orientation = myAvatar->getLocalOrientation();
|
||||
_rig->computeMotionAnimationState(deltaTime, position, velocity, orientation, ccState);
|
||||
|
||||
// evaluate AnimGraph animation and update jointStates.
|
||||
Model::updateRig(deltaTime, parentTransform);
|
||||
|
|
|
@ -507,32 +507,7 @@ static const std::vector<float> LATERAL_SPEEDS = { 0.2f, 0.65f }; // m/s
|
|||
void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, CharacterControllerState ccState) {
|
||||
|
||||
glm::vec3 front = worldRotation * IDENTITY_FRONT;
|
||||
|
||||
// It can be more accurate/smooth to use velocity rather than position,
|
||||
// but some modes (e.g., hmd standing) update position without updating velocity.
|
||||
// It's very hard to debug hmd standing. (Look down at yourself, or have a second person observe. HMD third person is a bit undefined...)
|
||||
// So, let's create our own workingVelocity from the worldPosition...
|
||||
glm::vec3 workingVelocity = _lastVelocity;
|
||||
glm::vec3 positionDelta = worldPosition - _lastPosition;
|
||||
|
||||
// Don't trust position delta if deltaTime is 'small'.
|
||||
// NOTE: This is mostly just a work around for an issue in oculus 0.7 runtime, where
|
||||
// Application::idle() is being called more frequently and with smaller dt's then expected.
|
||||
const float SMALL_DELTA_TIME = 0.006f; // 6 ms
|
||||
if (deltaTime > SMALL_DELTA_TIME) {
|
||||
workingVelocity = positionDelta / deltaTime;
|
||||
}
|
||||
|
||||
#if !WANT_DEBUG
|
||||
// But for smoothest (non-hmd standing) results, go ahead and use velocity:
|
||||
if (!positionDelta.x && !positionDelta.y && !positionDelta.z) {
|
||||
workingVelocity = worldVelocity;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (deltaTime > SMALL_DELTA_TIME) {
|
||||
_lastVelocity = workingVelocity;
|
||||
}
|
||||
glm::vec3 workingVelocity = worldVelocity;
|
||||
|
||||
{
|
||||
glm::vec3 localVel = glm::inverse(worldRotation) * workingVelocity;
|
||||
|
@ -809,7 +784,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
|
|||
|
||||
// compute blend based on velocity
|
||||
const float JUMP_SPEED = 3.5f;
|
||||
float alpha = glm::clamp(-_lastWorldVelocity.y / JUMP_SPEED, -1.0f, 1.0f) + 1.0f;
|
||||
float alpha = glm::clamp(-_lastVelocity.y / JUMP_SPEED, -1.0f, 1.0f) + 1.0f;
|
||||
_animVars.set("inAirAlpha", alpha);
|
||||
}
|
||||
|
||||
|
@ -827,7 +802,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
|
|||
|
||||
_lastFront = front;
|
||||
_lastPosition = worldPosition;
|
||||
_lastWorldVelocity = worldVelocity;
|
||||
_lastVelocity = workingVelocity;
|
||||
}
|
||||
|
||||
// Allow script to add/remove handlers and report results, from within their thread.
|
||||
|
|
|
@ -267,7 +267,6 @@ public:
|
|||
glm::vec3 _lastFront;
|
||||
glm::vec3 _lastPosition;
|
||||
glm::vec3 _lastVelocity;
|
||||
glm::vec3 _lastWorldVelocity;
|
||||
glm::vec3 _eyesInRootFrame { Vectors::ZERO };
|
||||
|
||||
QUrl _animGraphURL;
|
||||
|
|
|
@ -64,7 +64,6 @@ AvatarData::AvatarData() :
|
|||
_billboard(),
|
||||
_errorLogExpiry(0),
|
||||
_owningAvatarMixer(),
|
||||
_velocity(0.0f),
|
||||
_targetVelocity(0.0f),
|
||||
_localAABox(DEFAULT_LOCAL_AABOX_CORNER, DEFAULT_LOCAL_AABOX_SCALE)
|
||||
{
|
||||
|
|
|
@ -151,6 +151,9 @@ class AvatarData : public QObject, public SpatiallyNestable {
|
|||
Q_PROPERTY(float headYaw READ getHeadYaw WRITE setHeadYaw)
|
||||
Q_PROPERTY(float headRoll READ getHeadRoll WRITE setHeadRoll)
|
||||
|
||||
Q_PROPERTY(glm::vec3 velocity READ getVelocity WRITE setVelocity)
|
||||
Q_PROPERTY(glm::vec3 angularVelocity READ getAngularVelocity WRITE setAngularVelocity)
|
||||
|
||||
Q_PROPERTY(float audioLoudness READ getAudioLoudness WRITE setAudioLoudness)
|
||||
Q_PROPERTY(float audioAverageLoudness READ getAudioAverageLoudness WRITE setAudioAverageLoudness)
|
||||
|
||||
|
@ -334,8 +337,6 @@ public:
|
|||
int getAverageBytesReceivedPerSecond() const;
|
||||
int getReceiveRate() const;
|
||||
|
||||
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
|
||||
Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; }
|
||||
const glm::vec3& getTargetVelocity() const { return _targetVelocity; }
|
||||
|
||||
bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; }
|
||||
|
@ -406,7 +407,6 @@ protected:
|
|||
/// Loads the joint indices, names from the FST file (if any)
|
||||
virtual void updateJointMappings();
|
||||
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _targetVelocity;
|
||||
|
||||
AABox _localAABox;
|
||||
|
|
|
@ -49,7 +49,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
|||
_localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA),
|
||||
_density(ENTITY_ITEM_DEFAULT_DENSITY),
|
||||
_volumeMultiplier(1.0f),
|
||||
_velocity(ENTITY_ITEM_DEFAULT_VELOCITY),
|
||||
_gravity(ENTITY_ITEM_DEFAULT_GRAVITY),
|
||||
_acceleration(ENTITY_ITEM_DEFAULT_ACCELERATION),
|
||||
_damping(ENTITY_ITEM_DEFAULT_DAMPING),
|
||||
|
@ -60,7 +59,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
|||
_scriptTimestamp(ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP),
|
||||
_collisionSoundURL(ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
|
||||
_registrationPoint(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT),
|
||||
_angularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY),
|
||||
_angularDamping(ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING),
|
||||
_visible(ENTITY_ITEM_DEFAULT_VISIBLE),
|
||||
_collisionless(ENTITY_ITEM_DEFAULT_COLLISIONLESS),
|
||||
|
@ -78,6 +76,8 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
|||
_physicsInfo(nullptr),
|
||||
_simulated(false)
|
||||
{
|
||||
setVelocity(ENTITY_ITEM_DEFAULT_VELOCITY);
|
||||
setAngularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY);
|
||||
// explicitly set transform parts to set dirty flags used by batch rendering
|
||||
setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
|
||||
quint64 now = usecTimestampNow();
|
||||
|
@ -886,41 +886,45 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) {
|
|||
}
|
||||
|
||||
if (hasAngularVelocity()) {
|
||||
glm::vec3 angularVelocity = getAngularVelocity();
|
||||
|
||||
// angular damping
|
||||
if (_angularDamping > 0.0f) {
|
||||
_angularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
|
||||
angularVelocity *= powf(1.0f - _angularDamping, timeElapsed);
|
||||
#ifdef WANT_DEBUG
|
||||
qCDebug(entities) << " angularDamping :" << _angularDamping;
|
||||
qCDebug(entities) << " newAngularVelocity:" << _angularVelocity;
|
||||
qCDebug(entities) << " newAngularVelocity:" << angularVelocity;
|
||||
#endif
|
||||
}
|
||||
|
||||
float angularSpeed = glm::length(_angularVelocity);
|
||||
float angularSpeed = glm::length(angularVelocity);
|
||||
|
||||
const float EPSILON_ANGULAR_VELOCITY_LENGTH = 0.0017453f; // 0.0017453 rad/sec = 0.1f degrees/sec
|
||||
if (angularSpeed < EPSILON_ANGULAR_VELOCITY_LENGTH) {
|
||||
if (setFlags && angularSpeed > 0.0f) {
|
||||
_dirtyFlags |= Simulation::DIRTY_MOTION_TYPE;
|
||||
}
|
||||
_angularVelocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
angularVelocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
} else {
|
||||
// for improved agreement with the way Bullet integrates rotations we use an approximation
|
||||
// and break the integration into bullet-sized substeps
|
||||
glm::quat rotation = getRotation();
|
||||
float dt = timeElapsed;
|
||||
while (dt > PHYSICS_ENGINE_FIXED_SUBSTEP) {
|
||||
glm::quat dQ = computeBulletRotationStep(_angularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||
glm::quat dQ = computeBulletRotationStep(angularVelocity, PHYSICS_ENGINE_FIXED_SUBSTEP);
|
||||
rotation = glm::normalize(dQ * rotation);
|
||||
dt -= PHYSICS_ENGINE_FIXED_SUBSTEP;
|
||||
}
|
||||
// NOTE: this final partial substep can drift away from a real Bullet simulation however
|
||||
// it only becomes significant for rapidly rotating objects
|
||||
// (e.g. around PI/4 radians per substep, or 7.5 rotations/sec at 60 substeps/sec).
|
||||
glm::quat dQ = computeBulletRotationStep(_angularVelocity, dt);
|
||||
glm::quat dQ = computeBulletRotationStep(angularVelocity, dt);
|
||||
rotation = glm::normalize(dQ * rotation);
|
||||
|
||||
setRotation(rotation);
|
||||
}
|
||||
|
||||
setAngularVelocity(angularVelocity);
|
||||
}
|
||||
|
||||
if (hasVelocity()) {
|
||||
|
@ -1077,9 +1081,9 @@ EntityItemProperties EntityItem::getProperties(EntityPropertyFlags desiredProper
|
|||
void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) const {
|
||||
// a TerseUpdate includes the transform and its derivatives
|
||||
properties._position = getLocalPosition();
|
||||
properties._velocity = _velocity;
|
||||
properties._velocity = getLocalVelocity();
|
||||
properties._rotation = getLocalOrientation();
|
||||
properties._angularVelocity = _angularVelocity;
|
||||
properties._angularVelocity = getLocalAngularVelocity();
|
||||
properties._acceleration = _acceleration;
|
||||
|
||||
properties._positionChanged = true;
|
||||
|
@ -1406,13 +1410,15 @@ void EntityItem::updateVelocity(const glm::vec3& value) {
|
|||
if (shouldSuppressLocationEdits()) {
|
||||
return;
|
||||
}
|
||||
if (_velocity != value) {
|
||||
glm::vec3 velocity = getLocalVelocity();
|
||||
if (velocity != value) {
|
||||
const float MIN_LINEAR_SPEED = 0.001f;
|
||||
if (glm::length(value) < MIN_LINEAR_SPEED) {
|
||||
_velocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
velocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
} else {
|
||||
_velocity = value;
|
||||
velocity = value;
|
||||
}
|
||||
setLocalVelocity(velocity);
|
||||
_dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
|
||||
}
|
||||
}
|
||||
|
@ -1436,13 +1442,15 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) {
|
|||
if (shouldSuppressLocationEdits()) {
|
||||
return;
|
||||
}
|
||||
if (_angularVelocity != value) {
|
||||
glm::vec3 angularVelocity = getLocalAngularVelocity();
|
||||
if (angularVelocity != value) {
|
||||
const float MIN_ANGULAR_SPEED = 0.0002f;
|
||||
if (glm::length(value) < MIN_ANGULAR_SPEED) {
|
||||
_angularVelocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
angularVelocity = ENTITY_ITEM_ZERO_VEC3;
|
||||
} else {
|
||||
_angularVelocity = value;
|
||||
angularVelocity = value;
|
||||
}
|
||||
setLocalAngularVelocity(angularVelocity);
|
||||
_dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -193,9 +193,7 @@ public:
|
|||
|
||||
float getDensity() const { return _density; }
|
||||
|
||||
const glm::vec3& getVelocity() const { return _velocity; } /// get velocity in meters
|
||||
void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in meters
|
||||
bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; }
|
||||
bool hasVelocity() const { return getVelocity() != ENTITY_ITEM_ZERO_VEC3; }
|
||||
|
||||
const glm::vec3& getGravity() const { return _gravity; } /// get gravity in meters
|
||||
void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters
|
||||
|
@ -255,9 +253,7 @@ public:
|
|||
void setRegistrationPoint(const glm::vec3& value)
|
||||
{ _registrationPoint = glm::clamp(value, 0.0f, 1.0f); requiresRecalcBoxes(); }
|
||||
|
||||
const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
|
||||
void setAngularVelocity(const glm::vec3& value) { _angularVelocity = value; }
|
||||
bool hasAngularVelocity() const { return _angularVelocity != ENTITY_ITEM_ZERO_VEC3; }
|
||||
bool hasAngularVelocity() const { return getAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; }
|
||||
|
||||
float getAngularDamping() const { return _angularDamping; }
|
||||
void setAngularDamping(float value) { _angularDamping = value; }
|
||||
|
@ -435,7 +431,6 @@ protected:
|
|||
// rather than in all of the derived classes. If we ever collapse these classes to one we could do it a
|
||||
// different way.
|
||||
float _volumeMultiplier = 1.0f;
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _gravity;
|
||||
glm::vec3 _acceleration;
|
||||
float _damping;
|
||||
|
@ -446,7 +441,6 @@ protected:
|
|||
quint64 _scriptTimestamp;
|
||||
QString _collisionSoundURL;
|
||||
glm::vec3 _registrationPoint;
|
||||
glm::vec3 _angularVelocity;
|
||||
float _angularDamping;
|
||||
bool _visible;
|
||||
bool _collisionless;
|
||||
|
|
|
@ -54,7 +54,7 @@ CharacterController::CharacterController() {
|
|||
|
||||
_floorDistance = MAX_FALL_HEIGHT;
|
||||
|
||||
_walkVelocity.setValue(0.0f, 0.0f, 0.0f);
|
||||
_targetVelocity.setValue(0.0f, 0.0f, 0.0f);
|
||||
_followDesiredBodyTransform.setIdentity();
|
||||
_followTimeRemaining = 0.0f;
|
||||
_jumpSpeed = JUMP_SPEED;
|
||||
|
@ -166,12 +166,12 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
|
|||
|
||||
const btScalar MIN_SPEED = 0.001f;
|
||||
|
||||
btVector3 actualVelocity = _rigidBody->getLinearVelocity();
|
||||
btVector3 actualVelocity = _rigidBody->getLinearVelocity() - _parentVelocity;
|
||||
if (actualVelocity.length() < MIN_SPEED) {
|
||||
actualVelocity = btVector3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
btVector3 desiredVelocity = _walkVelocity;
|
||||
btVector3 desiredVelocity = _targetVelocity;
|
||||
if (desiredVelocity.length() < MIN_SPEED) {
|
||||
desiredVelocity = btVector3(0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ void CharacterController::playerStep(btCollisionWorld* dynaWorld, btScalar dt) {
|
|||
break;
|
||||
}
|
||||
|
||||
_rigidBody->setLinearVelocity(finalVelocity);
|
||||
_rigidBody->setLinearVelocity(finalVelocity + _parentVelocity);
|
||||
|
||||
// Dynamicaly compute a follow velocity to move this body toward the _followDesiredBodyTransform.
|
||||
// Rather then add this velocity to velocity the RigidBody, we explicitly teleport the RigidBody towards its goal.
|
||||
|
@ -383,8 +383,11 @@ void CharacterController::getPositionAndOrientation(glm::vec3& position, glm::qu
|
|||
}
|
||||
|
||||
void CharacterController::setTargetVelocity(const glm::vec3& velocity) {
|
||||
//_walkVelocity = glmToBullet(_avatarData->getTargetVelocity());
|
||||
_walkVelocity = glmToBullet(velocity);
|
||||
_targetVelocity = glmToBullet(velocity);
|
||||
}
|
||||
|
||||
void CharacterController::setParentVelocity(const glm::vec3& velocity) {
|
||||
_parentVelocity = glmToBullet(velocity);
|
||||
}
|
||||
|
||||
void CharacterController::setFollowParameters(const glm::mat4& desiredWorldBodyMatrix, float timeRemaining) {
|
||||
|
|
|
@ -69,6 +69,7 @@ public:
|
|||
void getPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const;
|
||||
|
||||
void setTargetVelocity(const glm::vec3& velocity);
|
||||
void setParentVelocity(const glm::vec3& parentVelocity);
|
||||
void setFollowParameters(const glm::mat4& desiredWorldMatrix, float timeRemaining);
|
||||
float getFollowTime() const { return _followTime; }
|
||||
glm::vec3 getFollowLinearDisplacement() const;
|
||||
|
@ -105,7 +106,8 @@ protected:
|
|||
|
||||
protected:
|
||||
btVector3 _currentUp;
|
||||
btVector3 _walkVelocity;
|
||||
btVector3 _targetVelocity;
|
||||
btVector3 _parentVelocity;
|
||||
btTransform _followDesiredBodyTransform;
|
||||
btScalar _followTimeRemaining;
|
||||
btTransform _characterBodyTransform;
|
||||
|
|
|
@ -391,6 +391,96 @@ void SpatiallyNestable::setOrientation(const glm::quat& orientation) {
|
|||
#endif
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getVelocity(bool& success) const {
|
||||
glm::vec3 parentVelocity = getParentVelocity(success);
|
||||
Transform parentTransform = getParentTransform(success);
|
||||
glm::vec3 result;
|
||||
_velocityLock.withReadLock([&] {
|
||||
// TODO: take parent angularVelocity into account.
|
||||
result = parentVelocity + parentTransform.getRotation() * _velocity;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getVelocity() const {
|
||||
bool success;
|
||||
glm::vec3 result = getVelocity(success);
|
||||
if (!success) {
|
||||
qDebug() << "Warning -- setVelocity failed" << getID();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setVelocity(const glm::vec3& velocity, bool& success) {
|
||||
glm::vec3 parentVelocity = getParentVelocity(success);
|
||||
Transform parentTransform = getParentTransform(success);
|
||||
_velocityLock.withWriteLock([&] {
|
||||
// TODO: take parent angularVelocity into account.
|
||||
_velocity = glm::inverse(parentTransform.getRotation()) * velocity - parentVelocity;
|
||||
});
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setVelocity(const glm::vec3& velocity) {
|
||||
bool success;
|
||||
setVelocity(velocity, success);
|
||||
if (!success) {
|
||||
qDebug() << "Warning -- setVelocity failed" << getID();
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getParentVelocity(bool& success) const {
|
||||
glm::vec3 result;
|
||||
SpatiallyNestablePointer parent = getParentPointer(success);
|
||||
if (success && parent) {
|
||||
result = parent->getVelocity(success);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getAngularVelocity(bool& success) const {
|
||||
glm::vec3 parentAngularVelocity = getParentAngularVelocity(success);
|
||||
Transform parentTransform = getParentTransform(success);
|
||||
glm::vec3 result;
|
||||
_angularVelocityLock.withReadLock([&] {
|
||||
result = parentAngularVelocity + parentTransform.getRotation() * _angularVelocity;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getAngularVelocity() const {
|
||||
bool success;
|
||||
glm::vec3 result = getAngularVelocity(success);
|
||||
if (!success) {
|
||||
qDebug() << "Warning -- getAngularVelocity failed" << getID();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setAngularVelocity(const glm::vec3& angularVelocity, bool& success) {
|
||||
glm::vec3 parentAngularVelocity = getParentAngularVelocity(success);
|
||||
Transform parentTransform = getParentTransform(success);
|
||||
_angularVelocityLock.withWriteLock([&] {
|
||||
_angularVelocity = glm::inverse(parentTransform.getRotation()) * angularVelocity - parentAngularVelocity;
|
||||
});
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setAngularVelocity(const glm::vec3& angularVelocity) {
|
||||
bool success;
|
||||
setAngularVelocity(angularVelocity, success);
|
||||
if (!success) {
|
||||
qDebug() << "Warning -- setAngularVelocity failed" << getID();
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getParentAngularVelocity(bool& success) const {
|
||||
glm::vec3 result;
|
||||
SpatiallyNestablePointer parent = getParentPointer(success);
|
||||
if (success && parent) {
|
||||
result = parent->getAngularVelocity(success);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const Transform SpatiallyNestable::getTransform(bool& success) const {
|
||||
// return a world-space transform for this object's location
|
||||
Transform parentTransform = getParentTransform(success);
|
||||
|
@ -519,6 +609,34 @@ void SpatiallyNestable::setLocalOrientation(const glm::quat& orientation) {
|
|||
locationChanged();
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getLocalVelocity() const {
|
||||
glm::vec3 result(glm::vec3::_null);
|
||||
_velocityLock.withReadLock([&] {
|
||||
result = _velocity;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setLocalVelocity(const glm::vec3& velocity) {
|
||||
_velocityLock.withWriteLock([&] {
|
||||
_velocity = velocity;
|
||||
});
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getLocalAngularVelocity() const {
|
||||
glm::vec3 result(glm::vec3::_null);
|
||||
_angularVelocityLock.withReadLock([&] {
|
||||
result = _angularVelocity;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setLocalAngularVelocity(const glm::vec3& angularVelocity) {
|
||||
_angularVelocityLock.withWriteLock([&] {
|
||||
_angularVelocity = angularVelocity;
|
||||
});
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getLocalScale() const {
|
||||
// TODO: scale
|
||||
glm::vec3 result;
|
||||
|
|
|
@ -68,6 +68,18 @@ public:
|
|||
virtual void setOrientation(const glm::quat& orientation, bool& success);
|
||||
virtual void setOrientation(const glm::quat& orientation);
|
||||
|
||||
virtual glm::vec3 getVelocity(bool& success) const;
|
||||
virtual glm::vec3 getVelocity() const;
|
||||
virtual void setVelocity(const glm::vec3& velocity, bool& success);
|
||||
virtual void setVelocity(const glm::vec3& velocity);
|
||||
virtual glm::vec3 getParentVelocity(bool& success) const;
|
||||
|
||||
virtual glm::vec3 getAngularVelocity(bool& success) const;
|
||||
virtual glm::vec3 getAngularVelocity() const;
|
||||
virtual void setAngularVelocity(const glm::vec3& angularVelocity, bool& success);
|
||||
virtual void setAngularVelocity(const glm::vec3& angularVelocity);
|
||||
virtual glm::vec3 getParentAngularVelocity(bool& success) const;
|
||||
|
||||
virtual AACube getMaximumAACube(bool& success) const;
|
||||
virtual bool computePuffedQueryAACube();
|
||||
|
||||
|
@ -94,6 +106,12 @@ public:
|
|||
virtual glm::quat getLocalOrientation() const;
|
||||
virtual void setLocalOrientation(const glm::quat& orientation);
|
||||
|
||||
virtual glm::vec3 getLocalVelocity() const;
|
||||
virtual void setLocalVelocity(const glm::vec3& velocity);
|
||||
|
||||
virtual glm::vec3 getLocalAngularVelocity() const;
|
||||
virtual void setLocalAngularVelocity(const glm::vec3& angularVelocity);
|
||||
|
||||
virtual glm::vec3 getLocalScale() const;
|
||||
virtual void setLocalScale(const glm::vec3& scale);
|
||||
|
||||
|
@ -126,6 +144,7 @@ protected:
|
|||
QUuid _parentID; // what is this thing's transform relative to?
|
||||
quint16 _parentJointIndex { 0 }; // which joint of the parent is this relative to?
|
||||
SpatiallyNestablePointer getParentPointer(bool& success) const;
|
||||
|
||||
mutable SpatiallyNestableWeakPointer _parent;
|
||||
|
||||
virtual void beParentOfChild(SpatiallyNestablePointer newChild) const;
|
||||
|
@ -146,7 +165,11 @@ protected:
|
|||
private:
|
||||
mutable ReadWriteLockable _transformLock;
|
||||
mutable ReadWriteLockable _idLock;
|
||||
mutable ReadWriteLockable _velocityLock;
|
||||
mutable ReadWriteLockable _angularVelocityLock;
|
||||
Transform _transform; // this is to be combined with parent's world-transform to produce this' world-transform.
|
||||
glm::vec3 _velocity;
|
||||
glm::vec3 _angularVelocity;
|
||||
mutable bool _parentKnowsMe { false };
|
||||
bool _isDead { false };
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue