From e9f52b12116ea4e67c2c083dae73cb6002e6fdd5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Dec 2015 14:40:30 -0800 Subject: [PATCH 1/8] properly scale avatar collision shape --- interface/src/Application.cpp | 5 +- interface/src/avatar/Avatar.cpp | 76 +++++++++++-------- interface/src/avatar/Avatar.h | 12 +-- interface/src/avatar/AvatarManager.cpp | 26 +++---- interface/src/avatar/AvatarMotionState.h | 2 +- interface/src/avatar/Hand.cpp | 6 +- interface/src/avatar/MyAvatar.cpp | 46 +++++++---- interface/src/avatar/MyAvatar.h | 5 +- .../src/avatar/MyCharacterController.cpp | 2 +- interface/src/avatar/SkeletonModel.cpp | 2 +- interface/src/ui/ApplicationCompositor.cpp | 2 +- interface/src/ui/PreferencesDialog.cpp | 2 +- interface/src/ui/overlays/OverlaysPayload.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 2 +- 14 files changed, 108 insertions(+), 82 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 930d3b0b8f..c34d2ce649 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1260,15 +1260,14 @@ void Application::paintGL() { hmdOffset.x = -hmdOffset.x; _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0) + mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + mirrorBodyOrientation * hmdOffset); - } else { _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0) + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 7a234f2b47..8231d1ebdd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -99,7 +99,8 @@ Avatar::Avatar(RigPointer rig) : // we may have been created in the network thread, but we live in the main thread moveToThread(qApp->thread()); - setAvatarScale(1.0f); + setScale(glm::vec3(1.0f)); // avatar scale is uniform + // give the pointer to our head to inherited _headData variable from AvatarData _headData = static_cast(new Head(this)); _handData = static_cast(new Hand(this)); @@ -143,15 +144,28 @@ AABox Avatar::getBounds() const { float Avatar::getLODDistance() const { return DependencyManager::get()->getAvatarLODDistanceMultiplier() * - glm::distance(qApp->getCamera()->getPosition(), getPosition()) / getAvatarScale(); + glm::distance(qApp->getCamera()->getPosition(), getPosition()) / getUniformScale(); +} + +void Avatar::animateScaleChanges(float deltaTime) { + float currentScale = getUniformScale(); + if (currentScale != _targetScale) { + const float SCALE_ANIMATION_TIMESCALE = 1.0f; + float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; + float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; + const float CLOSE_ENOUGH = 0.05f; + if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { + animatedScale = _targetScale; + } + setScale(glm::vec3(animatedScale)); // avatar scale is uniform + rebuildCollisionShape(); + } } void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); - if (getAvatarScale() != _targetScale) { - setAvatarScale(_targetScale); - } + animateScaleChanges(deltaTime); // update the billboard render flag const float BILLBOARD_HYSTERESIS_PROPORTION = 0.1f; @@ -164,7 +178,7 @@ void Avatar::simulate(float deltaTime) { _shouldRenderBillboard = true; qCDebug(interfaceapp) << "Billboarding" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for LOD" << getLODDistance(); } - + const bool isControllerLogging = DependencyManager::get()->getRenderDistanceControllerIsLogging(); float renderDistance = DependencyManager::get()->getRenderDistance(); const float SKIP_HYSTERESIS_PROPORTION = isControllerLogging ? 0.0f : BILLBOARD_HYSTERESIS_PROPORTION; @@ -210,7 +224,7 @@ void Avatar::simulate(float deltaTime) { _skeletonModel.getHeadPosition(headPosition); Head* head = getHead(); head->setPosition(headPosition); - head->setScale(getAvatarScale()); + head->setScale(getUniformScale()); head->simulate(deltaTime, false, _shouldRenderBillboard); } } @@ -238,12 +252,12 @@ void Avatar::simulate(float deltaTime) { measureMotionDerivatives(deltaTime); } -bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) { +bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { const float HEAD_SPHERE_RADIUS = 0.1f; glm::vec3 theirLookAt = dynamic_pointer_cast(avatar)->getHead()->getLookAtPosition(); glm::vec3 myEyePosition = getHead()->getEyePosition(); - return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getAvatarScale()); + return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getUniformScale()); } void Avatar::slamPosition(const glm::vec3& newPosition) { @@ -423,7 +437,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { const float BASE_LIGHT_DISTANCE = 2.0f; const float LIGHT_EXPONENT = 1.0f; const float LIGHT_CUTOFF = glm::radians(80.0f); - float distance = BASE_LIGHT_DISTANCE * getAvatarScale(); + float distance = BASE_LIGHT_DISTANCE * getUniformScale(); glm::vec3 position = glm::mix(_skeletonModel.getTranslation(), getHead()->getFaceModel().getTranslation(), 0.9f); glm::quat orientation = getOrientation(); foreach (const AvatarManager::LocalLight& light, DependencyManager::get()->getLocalLights()) { @@ -479,7 +493,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } DependencyManager::get()->renderSolidSphereInstance(batch, - Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT), + Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); position = getHead()->getRightEyePosition(); @@ -489,7 +503,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { eyeDiameter = DEFAULT_EYE_DIAMETER; } DependencyManager::get()->renderSolidSphereInstance(batch, - Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT), + Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); } @@ -590,9 +604,9 @@ void Avatar::simulateAttachments(float deltaTime) { glm::quat jointRotation; if (_skeletonModel.getJointPositionInWorldFrame(jointIndex, jointPosition) && _skeletonModel.getJointRotationInWorldFrame(jointIndex, jointRotation)) { - model->setTranslation(jointPosition + jointRotation * attachment.translation * getAvatarScale()); + model->setTranslation(jointPosition + jointRotation * attachment.translation * getUniformScale()); model->setRotation(jointRotation * attachment.rotation); - model->setScaleToFit(true, getAvatarScale() * attachment.scale, true); // hack to force rescale + model->setScaleToFit(true, getUniformScale() * attachment.scale, true); // hack to force rescale model->setSnapModelToCenter(false); // hack to force resnap model->setSnapModelToCenter(true); model->simulate(deltaTime); @@ -647,7 +661,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) { } float Avatar::getBillboardSize() const { - return getAvatarScale() * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); + return getUniformScale() * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); } #ifdef DEBUG @@ -796,7 +810,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co } void Avatar::setSkeletonOffset(const glm::vec3& offset) { - const float MAX_OFFSET_LENGTH = getAvatarScale() * 0.5f; + const float MAX_OFFSET_LENGTH = getUniformScale() * 0.5f; float offsetLength = glm::length(offset); if (offsetLength > MAX_OFFSET_LENGTH) { _skeletonOffset = (MAX_OFFSET_LENGTH / offsetLength) * offset; @@ -905,7 +919,7 @@ glm::vec3 Avatar::getJointPosition(const QString& name) const { void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const { //Scale a world space vector as if it was relative to the position - positionToScale = getPosition() + getAvatarScale() * (positionToScale - getPosition()); + positionToScale = getPosition() + getUniformScale() * (positionToScale - getPosition()); } void Avatar::setFaceModelURL(const QUrl& faceModelURL) { @@ -945,7 +959,7 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { for (int i = 0; i < attachmentData.size(); i++) { _attachmentModels[i]->setURL(attachmentData.at(i).modelURL); _attachmentModels[i]->setSnapModelToCenter(true); - _attachmentModels[i]->setScaleToFit(true, getAvatarScale() * _attachmentData.at(i).scale); + _attachmentModels[i]->setScaleToFit(true, getUniformScale() * _attachmentData.at(i).scale); } } @@ -1033,15 +1047,6 @@ void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, g } } -void Avatar::setAvatarScale(float scale) { - if (_targetScale * (1.0f - RESCALING_TOLERANCE) < scale && - scale < _targetScale * (1.0f + RESCALING_TOLERANCE)) { - setScale(glm::vec3(_targetScale)); - } else { - setScale(glm::vec3(scale)); - } -} - float Avatar::getSkeletonHeight() const { Extents extents = _skeletonModel.getBindExtents(); return extents.maximum.y - extents.minimum.y; @@ -1053,7 +1058,7 @@ float Avatar::getHeadHeight() const { // HACK: We have a really odd case when fading out for some models where this value explodes float result = extents.maximum.y - extents.minimum.y; - if (result >= 0.0f && result < 100.0f * getAvatarScale() ) { + if (result >= 0.0f && result < 100.0f * getUniformScale() ) { return result; } } @@ -1096,13 +1101,20 @@ void Avatar::setShowDisplayName(bool showDisplayName) { // virtual void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) { - shapeInfo.setCapsuleY(_skeletonModel.getBoundingCapsuleRadius(), 0.5f * _skeletonModel.getBoundingCapsuleHeight()); - shapeInfo.setOffset(_skeletonModel.getBoundingCapsuleOffset()); + float uniformScale = getUniformScale(); + shapeInfo.setCapsuleY(uniformScale * _skeletonModel.getBoundingCapsuleRadius(), + 0.5f * uniformScale * _skeletonModel.getBoundingCapsuleHeight()); + shapeInfo.setOffset(uniformScale * _skeletonModel.getBoundingCapsuleOffset()); } // virtual -void Avatar::rebuildSkeletonBody() { - DependencyManager::get()->updateAvatarPhysicsShape(this); +void Avatar::rebuildCollisionShape() { + if (_motionState) { + _motionState->addDirtyFlags(Simulation::DIRTY_SHAPE); + } else { + // adebug TODO: move most of updateAvatarPhysicsShape() to here + DependencyManager::get()->updateAvatarPhysicsShape(this); + } } glm::vec3 Avatar::getLeftPalmPosition() { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index cdb995efea..379ab8b627 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -36,7 +36,6 @@ namespace render { static const float SCALING_RATIO = .05f; static const float SMOOTHING_RATIO = .05f; // 0 < ratio < 1 -static const float RESCALING_TOLERANCE = .02f; static const float BILLBOARD_FIELD_OF_VIEW = 30.0f; // degrees static const float BILLBOARD_DISTANCE = 5.56f; // meters @@ -89,7 +88,7 @@ public: SkeletonModel& getSkeletonModel() { return _skeletonModel; } const SkeletonModel& getSkeletonModel() const { return _skeletonModel; } glm::vec3 getChestPosition() const; - float getAvatarScale() const { return getScale().y; } + float getUniformScale() const { return getScale().y; } const Head* getHead() const { return static_cast(_headData); } Head* getHead() { return static_cast(_headData); } Hand* getHand() { return static_cast(_handData); } @@ -154,7 +153,7 @@ public: // (otherwise floating point error will cause problems at large positions). void applyPositionDelta(const glm::vec3& delta); - virtual void rebuildSkeletonBody(); + virtual void rebuildCollisionShape(); virtual void computeShapeInfo(ShapeInfo& shapeInfo); @@ -199,14 +198,15 @@ protected: float _stringLength; bool _moving; ///< set when position is changing - bool isLookingAtMe(AvatarSharedPointer avatar); - // protected methods... + bool isLookingAtMe(AvatarSharedPointer avatar) const; + + virtual void animateScaleChanges(float deltaTime); + glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; - void setAvatarScale(float scale); void measureMotionDerivatives(float deltaTime); float getSkeletonHeight() const; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 7c1a52f1b3..562bea3542 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -203,7 +203,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); avatar->startUpdate(); - avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE); + avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); fadingIterator = _avatarFades.erase(fadingIterator); @@ -375,19 +375,17 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } void AvatarManager::updateAvatarPhysicsShape(Avatar* avatar) { - AvatarMotionState* motionState = avatar->getMotionState(); - if (motionState) { - motionState->addDirtyFlags(Simulation::DIRTY_SHAPE); - } else { - ShapeInfo shapeInfo; - avatar->computeShapeInfo(shapeInfo); - btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); - if (shape) { - AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); - avatar->setMotionState(motionState); - _motionStatesToAdd.insert(motionState); - _avatarMotionStates.insert(motionState); - } + // adebug TODO: move most of this logic to MyAvatar class + assert(!avatar->getMotionState()); + + ShapeInfo shapeInfo; + avatar->computeShapeInfo(shapeInfo); + btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); + if (shape) { + AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); + avatar->setMotionState(motionState); + _motionStatesToAdd.insert(motionState); + _avatarMotionStates.insert(motionState); } } diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 1c49705f23..b5101d2c70 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -46,7 +46,7 @@ public: virtual float getObjectFriction() const; virtual float getObjectLinearDamping() const; virtual float getObjectAngularDamping() const; - + virtual glm::vec3 getObjectPosition() const; virtual glm::quat getObjectRotation() const; virtual glm::vec3 getObjectLinearVelocity() const; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 4f16449aa2..fe03d22f0b 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -37,7 +37,7 @@ void Hand::simulate(float deltaTime, bool isMine) { void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { float avatarScale = 1.0f; if (_owningAvatar) { - avatarScale = _owningAvatar->getAvatarScale(); + avatarScale = _owningAvatar->getUniformScale(); } const float alpha = 1.0f; @@ -62,7 +62,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { transform.setRotation(palm.getRotation()); transform.postScale(SPHERE_RADIUS); DependencyManager::get()->renderSolidSphereInstance(batch, transform, grayColor); - + // draw a green sphere at the old "finger tip" transform = Transform(); position = palm.getTipPosition(); @@ -72,7 +72,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { DependencyManager::get()->renderSolidSphereInstance(batch, transform, greenColor); } } - + const float AXIS_RADIUS = 0.1f * SPHERE_RADIUS; const float AXIS_LENGTH = 10.0f * SPHERE_RADIUS; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9331682714..926d41f1ca 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -284,13 +284,26 @@ void MyAvatar::update(float deltaTime) { extern QByteArray avatarStateToFrame(const AvatarData* _avatar); extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); +void MyAvatar::animateScaleChanges(float deltaTime) { + // HACK: override Avatar::animateScaleChanges() until MyAvatar has a MotionState + float currentScale = getUniformScale(); + if (currentScale != _targetScale) { + const float SCALE_ANIMATION_TIMESCALE = 1.0f; + float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; + float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; + const float CLOSE_ENOUGH = 0.05f; + if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { + animatedScale = _targetScale; + } + setScale(glm::vec3(animatedScale)); + rebuildCollisionShape(); + } +} + void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); - if (getAvatarScale() != _targetScale) { - float scale = (1.0f - SMOOTHING_RATIO) * getAvatarScale() + SMOOTHING_RATIO * _targetScale; - setAvatarScale(scale); - } + animateScaleChanges(deltaTime); { PerformanceTimer perfTimer("transform"); @@ -337,7 +350,7 @@ void MyAvatar::simulate(float deltaTime) { headPosition = getPosition(); } head->setPosition(headPosition); - head->setScale(getAvatarScale()); + head->setScale(getUniformScale()); head->simulate(deltaTime, true); } @@ -681,7 +694,7 @@ void MyAvatar::loadData() { _leanScale = loadSetting(settings, "leanScale", 0.05f); _targetScale = loadSetting(settings, "scale", 1.0f); - setAvatarScale(getAvatarScale()); + setScale(glm::vec3(getUniformScale())); _animGraphUrl = settings.value("animGraphURL", "").toString(); _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl(); @@ -809,7 +822,7 @@ void MyAvatar::updateLookAtTargetAvatar() { float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition); avatar->setIsLookAtTarget(false); if (!avatar->isMyAvatar() && avatar->isInitialized() && - (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getAvatarScale())) { + (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getUniformScale())) { float angleTo = glm::angle(lookForward, glm::normalize(avatar->getHead()->getEyePosition() - cameraPosition)); if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) { _lookAtTargetAvatar = avatarPointer; @@ -1036,14 +1049,15 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { return Avatar::getPosition(); } -void MyAvatar::rebuildSkeletonBody() { +void MyAvatar::rebuildCollisionShape() { // compute localAABox - float radius = _skeletonModel.getBoundingCapsuleRadius(); - float height = _skeletonModel.getBoundingCapsuleHeight() + 2.0f * radius; + float scale = getUniformScale(); + float radius = scale * _skeletonModel.getBoundingCapsuleRadius(); + float height = scale * _skeletonModel.getBoundingCapsuleHeight() + 2.0f * radius; glm::vec3 corner(-radius, -0.5f * height, -radius); - corner += _skeletonModel.getBoundingCapsuleOffset(); - glm::vec3 scale(2.0f * radius, height, 2.0f * radius); - _characterController.setLocalBoundingBox(corner, scale); + corner += scale * _skeletonModel.getBoundingCapsuleOffset(); + glm::vec3 diagonal(2.0f * radius, height, 2.0f * radius); + _characterController.setLocalBoundingBox(corner, diagonal); } void MyAvatar::prepareForPhysicsSimulation() { @@ -1331,7 +1345,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; bool MyAvatar::cameraInsideHead() const { const Head* head = getHead(); const glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getAvatarScale()); + return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); } bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { @@ -1455,11 +1469,11 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe if (isHovering) { // we're flying --> complex acceleration curve with high max speed float motorSpeed = glm::length(_keyboardMotorVelocity); - float finalMaxMotorSpeed = getAvatarScale() * MAX_KEYBOARD_MOTOR_SPEED; + float finalMaxMotorSpeed = getUniformScale() * MAX_KEYBOARD_MOTOR_SPEED; float speedGrowthTimescale = 2.0f; float speedIncreaseFactor = 1.8f; motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor; - const float maxBoostSpeed = getAvatarScale() * MAX_BOOST_SPEED; + const float maxBoostSpeed = getUniformScale() * MAX_BOOST_SPEED; if (motorSpeed < maxBoostSpeed) { // an active keyboard motor should never be slower than this float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 514261bf16..bce6521c07 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -249,7 +249,7 @@ public slots: Q_INVOKABLE void updateMotionBehaviorFromMenu(); - virtual void rebuildSkeletonBody() override; + virtual void rebuildCollisionShape() override; Q_INVOKABLE QUrl getAnimGraphUrl() const { return _animGraphUrl; } @@ -263,6 +263,9 @@ public slots: glm::vec3 getPositionForAudio(); glm::quat getOrientationForAudio(); +protected: + void animateScaleChanges(float deltaTime); + signals: void audioListenerModeChanged(); void transformChanged(); diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index 23d601e58e..c7f2945757 100644 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -32,7 +32,7 @@ MyCharacterController::~MyCharacterController() { void MyCharacterController::updateShapeIfNecessary() { if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { - _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE; + _pendingFlags &= ~PENDING_FLAG_UPDATE_SHAPE; // compute new dimensions from avatar's bounding box float x = _boxScale.x; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 342f8315e1..47c22e9f08 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -69,7 +69,7 @@ void SkeletonModel::initJointStates() { _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); _headClipDistance = std::max(_headClipDistance, DEFAULT_NEAR_CLIP); - _owningAvatar->rebuildSkeletonBody(); + _owningAvatar->rebuildCollisionShape(); emit skeletonLoaded(); } diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 99285c6558..e5ecdfe217 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -386,7 +386,7 @@ bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& positi glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction); float t; - if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getAvatarScale(), &t)){ + if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getUniformScale(), &t)){ result = position + direction * t; return true; } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 9a995263cd..f7ef0c9d56 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -199,7 +199,7 @@ void PreferencesDialog::loadPreferences() { ui.leanScaleSpin->setValue(myAvatar->getLeanScale()); - ui.avatarScaleSpin->setValue(myAvatar->getAvatarScale()); + ui.avatarScaleSpin->setValue(myAvatar->getUniformScale()); ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl().toString()); ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond()); diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 1b1c48c3ca..753106fa0a 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -68,7 +68,7 @@ namespace render { glm::vec3 myAvatarPosition = avatar->getPosition(); float angle = glm::degrees(glm::angle(myAvatarRotation)); glm::vec3 axis = glm::axis(myAvatarRotation); - float myAvatarScale = avatar->getAvatarScale(); + float myAvatarScale = avatar->getUniformScale(); Transform transform = Transform(); transform.setTranslation(myAvatarPosition); transform.setRotation(glm::angleAxis(angle, axis)); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index d241df7e0e..dce973fb33 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -90,7 +90,7 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { avatarLock.lock(); - Transform trans; + Transform trans = getTransform(); trans.setTranslation(position); trans.setRotation(orientation); SpatiallyNestable::setTransform(trans); From 33634cdaa16e8faec4fb375f5efcb6ae9e0d27ef Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Dec 2015 18:09:58 -0800 Subject: [PATCH 2/8] properly delete departing avatars --- interface/src/avatar/Avatar.cpp | 21 +++++++++++++-------- interface/src/avatar/Avatar.h | 5 ++++- interface/src/avatar/AvatarManager.cpp | 16 ++++++++-------- interface/src/avatar/AvatarManager.h | 14 +++++++------- libraries/avatars/src/AvatarData.h | 5 +++++ 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 8231d1ebdd..a0fa822512 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -150,11 +150,12 @@ float Avatar::getLODDistance() const { void Avatar::animateScaleChanges(float deltaTime) { float currentScale = getUniformScale(); if (currentScale != _targetScale) { - const float SCALE_ANIMATION_TIMESCALE = 1.0f; - float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; - float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; - const float CLOSE_ENOUGH = 0.05f; - if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { + const float SCALE_ANIMATION_TIMESCALE = 0.5f; + float scaleVelocity = (_targetScale - currentScale) / SCALE_ANIMATION_TIMESCALE; + float animatedScale = currentScale + deltaTime * scaleVelocity; + const float MIN_SCALE_SPEED = 0.3f; + if (fabsf(scaleVelocity) < MIN_SCALE_SPEED) { + // close enough animatedScale = _targetScale; } setScale(glm::vec3(animatedScale)); // avatar scale is uniform @@ -165,6 +166,9 @@ void Avatar::animateScaleChanges(float deltaTime) { void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); + if (!isDead() && !_motionState) { + DependencyManager::get()->updateAvatarPhysicsShape(this); + } animateScaleChanges(deltaTime); // update the billboard render flag @@ -1107,13 +1111,14 @@ void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) { shapeInfo.setOffset(uniformScale * _skeletonModel.getBoundingCapsuleOffset()); } +void Avatar::setMotionState(AvatarMotionState* motionState) { + _motionState = motionState; +} + // virtual void Avatar::rebuildCollisionShape() { if (_motionState) { _motionState->addDirtyFlags(Simulation::DIRTY_SHAPE); - } else { - // adebug TODO: move most of updateAvatarPhysicsShape() to here - DependencyManager::get()->updateAvatarPhysicsShape(this); } } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 379ab8b627..4926212b4d 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -157,7 +157,6 @@ public: virtual void computeShapeInfo(ShapeInfo& shapeInfo); - void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } AvatarMotionState* getMotionState() { return _motionState; } virtual void setPosition(const glm::vec3& position) override; @@ -172,6 +171,10 @@ public slots: glm::quat getRightPalmRotation(); protected: + friend class AvatarManager; + + void setMotionState(AvatarMotionState* motionState); + SkeletonModel _skeletonModel; glm::vec3 _skeletonOffset; QVector _attachmentModels; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 562bea3542..38f191872e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -223,14 +223,14 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() { AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { auto newAvatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer); auto rawRenderableAvatar = std::static_pointer_cast(newAvatar); - + render::ScenePointer scene = qApp->getMain3DScene(); render::PendingChanges pendingChanges; if (DependencyManager::get()->shouldRenderAvatars()) { rawRenderableAvatar->addToScene(rawRenderableAvatar, scene, pendingChanges); } scene->enqueuePendingChanges(pendingChanges); - + return newAvatar; } @@ -251,7 +251,7 @@ void AvatarManager::removeAvatarMotionState(AvatarSharedPointer avatar) { // virtual void AvatarManager::removeAvatar(const QUuid& sessionUUID) { QWriteLocker locker(&_hashLock); - + auto removedAvatar = _avatarHash.take(sessionUUID); if (removedAvatar) { handleRemovedAvatar(removedAvatar); @@ -260,7 +260,8 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) { void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar) { AvatarHashMap::handleRemovedAvatar(removedAvatar); - + + removedAvatar->die(); removeAvatarMotionState(removedAvatar); _avatarFades.push_back(removedAvatar); } @@ -268,7 +269,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar void AvatarManager::clearOtherAvatars() { // clear any avatars that came from an avatar-mixer QWriteLocker locker(&_hashLock); - + AvatarHash::iterator avatarIterator = _avatarHash.begin(); while (avatarIterator != _avatarHash.end()) { auto avatar = std::static_pointer_cast(avatarIterator.value()); @@ -278,7 +279,7 @@ void AvatarManager::clearOtherAvatars() { } else { auto removedAvatar = avatarIterator.value(); avatarIterator = _avatarHash.erase(avatarIterator); - + handleRemovedAvatar(removedAvatar); } } @@ -375,7 +376,6 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } void AvatarManager::updateAvatarPhysicsShape(Avatar* avatar) { - // adebug TODO: move most of this logic to MyAvatar class assert(!avatar->getMotionState()); ShapeInfo shapeInfo; @@ -414,6 +414,6 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) if (sessionID == _myAvatar->getSessionUUID()) { return _myAvatar; } - + return findAvatar(sessionID); } diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 84a4bc44b8..d63df9fb76 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -52,7 +52,7 @@ public: glm::vec3 color; glm::vec3 direction; }; - + Q_INVOKABLE void setLocalLights(const QVector& localLights); Q_INVOKABLE QVector getLocalLights() const; // Currently, your own avatar will be included as the null avatar id. @@ -67,7 +67,7 @@ public: void handleCollisionEvents(const CollisionEvents& collisionEvents); void updateAvatarPhysicsShape(Avatar* avatar); - + // Expose results and parameter-tuning operations to other systems, such as stats and javascript. Q_INVOKABLE float getRenderDistance() { return _renderDistance; } Q_INVOKABLE float getRenderDistanceInverseLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); } @@ -80,7 +80,7 @@ public: Q_INVOKABLE void setRenderDistanceKD(float newValue) { _renderDistanceController.setKD(newValue); } Q_INVOKABLE void setRenderDistanceInverseLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); } Q_INVOKABLE void setRenderDistanceInverseHighLimit(float newValue); - + public slots: void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } void updateAvatarRenderStatus(bool shouldRenderAvatars); @@ -90,19 +90,19 @@ private: AvatarManager(const AvatarManager& other); void simulateAvatarFades(float deltaTime); - + // virtual overrides virtual AvatarSharedPointer newSharedAvatar(); virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer); void removeAvatarMotionState(AvatarSharedPointer avatar); - + virtual void removeAvatar(const QUuid& sessionUUID); virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar); - + QVector _avatarFades; std::shared_ptr _myAvatar; quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate. - + QVector _localLights; bool _shouldShowReceiveStats = false; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 1fa33ff606..cbd15f2ce1 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -342,6 +342,9 @@ public: glm::vec3 getClientGlobalPosition() { return _globalPosition; } + void die() { _isDead = true; } + bool isDead() const { return _isDead; } + public slots: void sendAvatarDataPacket(); void sendIdentityPacket(); @@ -413,6 +416,8 @@ protected: // updates about one avatar to another. glm::vec3 _globalPosition; + bool _isDead { false }; + private: friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); static QUrl _defaultFullAvatarModelUrl; From bab07516f032db80e2475b42d90cc94283276a7f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Dec 2015 12:06:11 -0800 Subject: [PATCH 3/8] fix size of rendered bounding capsule --- interface/src/avatar/Avatar.cpp | 3 ++- interface/src/avatar/SkeletonModel.cpp | 23 +++++++++++++---------- interface/src/avatar/SkeletonModel.h | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a0fa822512..9e881f49ea 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -454,7 +454,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); if (renderBounding && shouldRenderHead(renderArgs) && _skeletonModel.isRenderable()) { PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes"); - _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f); + const float BOUNDING_SHAPE_ALPHA = 0.7f; + _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA); } // If this is the avatar being looked at, render a little ball above their head diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 47c22e9f08..e8d952973b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -338,35 +338,38 @@ void SkeletonModel::computeBoundingShape() { return; } - _rig->computeAvatarBoundingCapsule(geometry, - _boundingCapsuleRadius, - _boundingCapsuleHeight, - _boundingCapsuleLocalOffset); + float radius, height; + glm::vec3 offset; + _rig->computeAvatarBoundingCapsule(geometry, radius, height, offset); + float invScale = 1.0f / _owningAvatar->getUniformScale(); + _boundingCapsuleRadius = invScale * radius; + _boundingCapsuleHeight = invScale * height; + _boundingCapsuleLocalOffset = invScale * offset; } -void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { +void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float scale, float alpha) { auto geometryCache = DependencyManager::get(); auto deferredLighting = DependencyManager::get(); // draw a blue sphere at the capsule top point - glm::vec3 topPoint = _translation + getRotation() * (_boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * glm::vec3(0.0f, 1.0f, 0.0f)); + glm::vec3 topPoint = _translation + getRotation() * (scale * (_boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * Vectors::UNIT_Y)); deferredLighting->renderSolidSphereInstance(batch, - Transform().setTranslation(topPoint).postScale(_boundingCapsuleRadius), + Transform().setTranslation(topPoint).postScale(scale * _boundingCapsuleRadius), glm::vec4(0.6f, 0.6f, 0.8f, alpha)); // draw a yellow sphere at the capsule bottom point - glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, _boundingCapsuleHeight, 0.0f); + glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, scale * _boundingCapsuleHeight, 0.0f); glm::vec3 axis = topPoint - bottomPoint; deferredLighting->renderSolidSphereInstance(batch, - Transform().setTranslation(bottomPoint).postScale(_boundingCapsuleRadius), + Transform().setTranslation(bottomPoint).postScale(scale * _boundingCapsuleRadius), glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points glm::vec3 origin(0.0f); batch.setModelTransform(Transform().setTranslation(bottomPoint)); deferredLighting->bindSimpleProgram(batch); - Avatar::renderJointConnectingCone(batch, origin, axis, _boundingCapsuleRadius, _boundingCapsuleRadius, + Avatar::renderJointConnectingCone(batch, origin, axis, scale * _boundingCapsuleRadius, scale * _boundingCapsuleRadius, glm::vec4(0.6f, 0.8f, 0.6f, alpha)); } diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 9b73119238..7541a002dc 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -89,7 +89,7 @@ public: /// \return whether or not the head was found. glm::vec3 getDefaultEyeModelPosition() const; - void renderBoundingCollisionShapes(gpu::Batch& batch, float alpha); + void renderBoundingCollisionShapes(gpu::Batch& batch, float scale, float alpha); float getBoundingCapsuleRadius() const { return _boundingCapsuleRadius; } float getBoundingCapsuleHeight() const { return _boundingCapsuleHeight; } const glm::vec3 getBoundingCapsuleOffset() const { return _boundingCapsuleLocalOffset; } From cd1e3810ca43c7d3822c7581096f79dd2bd5ac18 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Dec 2015 12:06:31 -0800 Subject: [PATCH 4/8] set the scale of avatar on login, don't animate --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 926d41f1ca..73ff332a37 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -694,7 +694,7 @@ void MyAvatar::loadData() { _leanScale = loadSetting(settings, "leanScale", 0.05f); _targetScale = loadSetting(settings, "scale", 1.0f); - setScale(glm::vec3(getUniformScale())); + setScale(glm::vec3(_targetScale)); _animGraphUrl = settings.value("animGraphURL", "").toString(); _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl(); From c3823de353ea40d96501fce20b84c778759991d3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Dec 2015 12:07:03 -0800 Subject: [PATCH 5/8] setClampedTargetScale()-->setTargetScaleVerbose() --- interface/src/ui/PreferencesDialog.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 5 +---- libraries/avatars/src/AvatarData.h | 6 +++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index f7ef0c9d56..a38cc13100 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -256,7 +256,7 @@ void PreferencesDialog::savePreferences() { myAvatar->getHead()->setPupilDilation(ui.pupilDilationSlider->value() / (float)ui.pupilDilationSlider->maximum()); myAvatar->setLeanScale(ui.leanScaleSpin->value()); - myAvatar->setClampedTargetScale(ui.avatarScaleSpin->value()); + myAvatar->setTargetScaleVerbose(ui.avatarScaleSpin->value()); if (myAvatar->getAnimGraphUrl() != ui.avatarAnimationEdit->text()) { // If changed, destroy the old and start with the new myAvatar->setAnimGraphUrl(ui.avatarAnimationEdit->text()); } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index dce973fb33..645e0ad7fc 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -132,10 +132,7 @@ void AvatarData::setTargetScale(float targetScale) { _targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, targetScale)); } -void AvatarData::setClampedTargetScale(float targetScale) { - - targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); - +void AvatarData::setTargetScaleVerbose(float targetScale) { setTargetScale(targetScale); qCDebug(avatars) << "Changed scale to " << _targetScale; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index cbd15f2ce1..64c215cee7 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -172,7 +172,7 @@ public: AvatarData(); virtual ~AvatarData(); - + static const QUrl& defaultFullAvatarModelUrl(); virtual bool isMyAvatar() const { return false; } @@ -237,7 +237,7 @@ public: // Scale float getTargetScale() const; void setTargetScale(float targetScale); - void setClampedTargetScale(float targetScale); + void setTargetScaleVerbose(float targetScale); // Hand State Q_INVOKABLE void setHandState(char s) { _handState = s; } @@ -261,7 +261,7 @@ public: Q_INVOKABLE bool isJointDataValid(const QString& name) const; Q_INVOKABLE glm::quat getJointRotation(const QString& name) const; Q_INVOKABLE glm::vec3 getJointTranslation(const QString& name) const; - + Q_INVOKABLE virtual QVector getJointRotations() const; Q_INVOKABLE virtual void setJointRotations(QVector jointRotations); Q_INVOKABLE virtual void setJointTranslations(QVector jointTranslations); From 9b0c199ed75752d71556adcc27244aacee49aa72 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 15 Dec 2015 15:30:56 -0800 Subject: [PATCH 6/8] updateAvatarPhysicsShape-->addAvatarToSimulation --- interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/AvatarManager.cpp | 3 ++- interface/src/avatar/AvatarManager.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 9e881f49ea..504124c4a7 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -167,7 +167,7 @@ void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); if (!isDead() && !_motionState) { - DependencyManager::get()->updateAvatarPhysicsShape(this); + DependencyManager::get()->addAvatarToSimulation(this); } animateScaleChanges(deltaTime); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 38f191872e..312742e778 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -375,13 +375,14 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } } -void AvatarManager::updateAvatarPhysicsShape(Avatar* avatar) { +void AvatarManager::addAvatarToSimulation(Avatar* avatar) { assert(!avatar->getMotionState()); ShapeInfo shapeInfo; avatar->computeShapeInfo(shapeInfo); btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); if (shape) { + // we don't add to the simulation now, we put it on a list to be added later AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); avatar->setMotionState(motionState); _motionStatesToAdd.insert(motionState); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index d63df9fb76..1b165495c3 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -66,7 +66,7 @@ public: void handleOutgoingChanges(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); - void updateAvatarPhysicsShape(Avatar* avatar); + void addAvatarToSimulation(Avatar* avatar); // Expose results and parameter-tuning operations to other systems, such as stats and javascript. Q_INVOKABLE float getRenderDistance() { return _renderDistance; } From 7baee8c39138e80c05238dd0e93f2671a7cb90dc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 15 Dec 2015 15:34:16 -0800 Subject: [PATCH 7/8] use glm::clamp() instead of std::min() and max() --- libraries/avatars/src/AvatarData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 645e0ad7fc..2ed9a47e02 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -129,7 +129,7 @@ float AvatarData::getTargetScale() const { } void AvatarData::setTargetScale(float targetScale) { - _targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, targetScale)); + _targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); } void AvatarData::setTargetScaleVerbose(float targetScale) { From 0e1e5db7eb808a71f209e7c219e74a87b29ddf58 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 15 Dec 2015 16:29:39 -0800 Subject: [PATCH 8/8] only need one animateScaleChanges() implementation --- interface/src/avatar/Avatar.cpp | 13 ++++++++----- interface/src/avatar/MyAvatar.cpp | 16 ---------------- interface/src/avatar/MyAvatar.h | 3 --- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 504124c4a7..f8040754d7 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -150,14 +150,17 @@ float Avatar::getLODDistance() const { void Avatar::animateScaleChanges(float deltaTime) { float currentScale = getUniformScale(); if (currentScale != _targetScale) { + // use exponential decay toward _targetScale const float SCALE_ANIMATION_TIMESCALE = 0.5f; - float scaleVelocity = (_targetScale - currentScale) / SCALE_ANIMATION_TIMESCALE; - float animatedScale = currentScale + deltaTime * scaleVelocity; - const float MIN_SCALE_SPEED = 0.3f; - if (fabsf(scaleVelocity) < MIN_SCALE_SPEED) { - // close enough + float blendFactor = glm::clamp(deltaTime / SCALE_ANIMATION_TIMESCALE, 0.0f, 1.0f); + float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; + + // snap to the end when we get close enough + const float MIN_RELATIVE_SCALE_ERROR = 0.03f; + if (fabsf(_targetScale - currentScale) / _targetScale < 0.03f) { animatedScale = _targetScale; } + setScale(glm::vec3(animatedScale)); // avatar scale is uniform rebuildCollisionShape(); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 73ff332a37..5c8230bd88 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -284,22 +284,6 @@ void MyAvatar::update(float deltaTime) { extern QByteArray avatarStateToFrame(const AvatarData* _avatar); extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); -void MyAvatar::animateScaleChanges(float deltaTime) { - // HACK: override Avatar::animateScaleChanges() until MyAvatar has a MotionState - float currentScale = getUniformScale(); - if (currentScale != _targetScale) { - const float SCALE_ANIMATION_TIMESCALE = 1.0f; - float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; - float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; - const float CLOSE_ENOUGH = 0.05f; - if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { - animatedScale = _targetScale; - } - setScale(glm::vec3(animatedScale)); - rebuildCollisionShape(); - } -} - void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index bce6521c07..019ba0f992 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -263,9 +263,6 @@ public slots: glm::vec3 getPositionForAudio(); glm::quat getOrientationForAudio(); -protected: - void animateScaleChanges(float deltaTime); - signals: void audioListenerModeChanged(); void transformChanged();