diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b4b0ad10bb..d92ba53f6e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4307,7 +4307,7 @@ void Application::update(float deltaTime) { // AvatarManager update { - PerformanceTimer perfTimer("AvatarManger"); + PerformanceTimer perfTimer("AvatarManager"); _avatarSimCounter.increment(); { diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 2f99ccfdc8..dc5b6233aa 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -275,13 +275,16 @@ void Avatar::updateAvatarEntities() { } AvatarEntityIDs recentlyDettachedAvatarEntities = getAndClearRecentlyDetachedIDs(); - _avatarEntitiesLock.withReadLock([&] { - foreach (auto entityID, recentlyDettachedAvatarEntities) { - if (!_avatarEntityData.contains(entityID)) { - entityTree->deleteEntity(entityID, true, true); + if (!recentlyDettachedAvatarEntities.empty()) { + // only lock this thread when absolutely necessary + _avatarEntitiesLock.withReadLock([&] { + foreach (auto entityID, recentlyDettachedAvatarEntities) { + if (!_avatarEntityData.contains(entityID)) { + entityTree->deleteEntity(entityID, true, true); + } } - } - }); + }); + } }); if (success) { @@ -299,18 +302,25 @@ void Avatar::simulate(float deltaTime) { } animateScaleChanges(deltaTime); - bool avatarPositionInView = false; - bool avatarMeshInView = false; + bool avatarInView = false; { // update the shouldAnimate flag to match whether or not we will render the avatar. PerformanceTimer perfTimer("cull"); - ViewFrustum viewFrustum; { - PerformanceTimer perfTimer("LOD"); + // simple frustum check + PerformanceTimer perfTimer("inView"); + ViewFrustum viewFrustum; + qApp->copyDisplayViewFrustum(viewFrustum); + avatarInView = viewFrustum.sphereIntersectsFrustum(getPosition(), getBoundingRadius()) + || viewFrustum.boxIntersectsFrustum(_skeletonModel->getRenderableMeshBound()); + } + PerformanceTimer lodPerfTimer("LOD"); + if (avatarInView) { const float MINIMUM_VISIBILITY_FOR_ON = 0.4f; const float MAXIMUM_VISIBILITY_FOR_OFF = 0.6f; + ViewFrustum viewFrustum; qApp->copyViewFrustum(viewFrustum); float visibility = calculateRenderAccuracy(viewFrustum.getPosition(), - getBounds(), DependencyManager::get()->getOctreeSizeScale()); + getBounds(), DependencyManager::get()->getOctreeSizeScale()); if (!_shouldAnimate) { if (visibility > MINIMUM_VISIBILITY_FOR_ON) { _shouldAnimate = true; @@ -321,19 +331,11 @@ void Avatar::simulate(float deltaTime) { qCDebug(interfaceapp) << "Optimizing" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for visibility" << visibility; } } - - { - PerformanceTimer perfTimer("inView"); - // simple frustum check - float boundingRadius = getBoundingRadius(); - qApp->copyDisplayViewFrustum(viewFrustum); - avatarPositionInView = viewFrustum.sphereIntersectsFrustum(getPosition(), boundingRadius); - avatarMeshInView = viewFrustum.boxIntersectsFrustum(_skeletonModel->getRenderableMeshBound()); - } } uint64_t start = usecTimestampNow(); - if (_shouldAnimate && !_shouldSkipRender && (avatarPositionInView || avatarMeshInView)) { + // CRUFT? _shouldSkipRender is never set 'true' + if (_shouldAnimate && avatarInView && !_shouldSkipRender) { { PerformanceTimer perfTimer("skeleton"); _skeletonModel->getRig()->copyJointsFromJointData(_jointData); @@ -725,7 +727,7 @@ glm::vec3 Avatar::getDisplayNamePosition() const { glm::vec3 bodyUpDirection = getBodyUpDirection(); DEBUG_VALUE("bodyUpDirection =", bodyUpDirection); - if (getSkeletonModel()->getNeckPosition(namePosition)) { + if (_skeletonModel->getNeckPosition(namePosition)) { float headHeight = getHeadHeight(); DEBUG_VALUE("namePosition =", namePosition); DEBUG_VALUE("headHeight =", headHeight); @@ -1244,8 +1246,8 @@ glm::vec3 Avatar::getUncachedLeftPalmPosition() const { return leftPalmPosition; } // avatar didn't have a LeftHandMiddle1 joint, fall back on this: - getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getLeftHandJointIndex(), leftPalmRotation); - getSkeletonModel()->getLeftHandPosition(leftPalmPosition); + _skeletonModel->getJointRotationInWorldFrame(_skeletonModel->getLeftHandJointIndex(), leftPalmRotation); + _skeletonModel->getLeftHandPosition(leftPalmPosition); leftPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(leftPalmRotation); return leftPalmPosition; } @@ -1253,7 +1255,7 @@ glm::vec3 Avatar::getUncachedLeftPalmPosition() const { glm::quat Avatar::getUncachedLeftPalmRotation() const { assert(QThread::currentThread() == thread()); // main thread access only glm::quat leftPalmRotation; - getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getLeftHandJointIndex(), leftPalmRotation); + _skeletonModel->getJointRotationInWorldFrame(_skeletonModel->getLeftHandJointIndex(), leftPalmRotation); return leftPalmRotation; } @@ -1265,8 +1267,8 @@ glm::vec3 Avatar::getUncachedRightPalmPosition() const { return rightPalmPosition; } // avatar didn't have a RightHandMiddle1 joint, fall back on this: - getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getRightHandJointIndex(), rightPalmRotation); - getSkeletonModel()->getRightHandPosition(rightPalmPosition); + _skeletonModel->getJointRotationInWorldFrame(_skeletonModel->getRightHandJointIndex(), rightPalmRotation); + _skeletonModel->getRightHandPosition(rightPalmPosition); rightPalmPosition += HAND_TO_PALM_OFFSET * glm::inverse(rightPalmRotation); return rightPalmPosition; } @@ -1274,7 +1276,7 @@ glm::vec3 Avatar::getUncachedRightPalmPosition() const { glm::quat Avatar::getUncachedRightPalmRotation() const { assert(QThread::currentThread() == thread()); // main thread access only glm::quat rightPalmRotation; - getSkeletonModel()->getJointRotationInWorldFrame(getSkeletonModel()->getRightHandJointIndex(), rightPalmRotation); + _skeletonModel->getJointRotationInWorldFrame(_skeletonModel->getRightHandJointIndex(), rightPalmRotation); return rightPalmRotation; } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 886eafffcf..6066905943 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -161,6 +161,7 @@ void Rig::destroyAnimGraph() { _internalPoseSet._absolutePoses.clear(); _internalPoseSet._overridePoses.clear(); _internalPoseSet._overrideFlags.clear(); + _numOverrides = 0; } void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset) { @@ -180,6 +181,7 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff _internalPoseSet._overrideFlags.clear(); _internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false); + _numOverrides = 0; buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); @@ -207,6 +209,7 @@ void Rig::reset(const FBXGeometry& geometry) { _internalPoseSet._overrideFlags.clear(); _internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false); + _numOverrides = 0; buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses); @@ -276,13 +279,17 @@ void Rig::setModelOffset(const glm::mat4& modelOffsetMat) { void Rig::clearJointState(int index) { if (isIndexValid(index)) { - _internalPoseSet._overrideFlags[index] = false; + if (_internalPoseSet._overrideFlags[index]) { + _internalPoseSet._overrideFlags[index] = false; + --_numOverrides; + } _internalPoseSet._overridePoses[index] = _animSkeleton->getRelativeDefaultPose(index); } } void Rig::clearJointStates() { _internalPoseSet._overrideFlags.clear(); + _numOverrides = 0; if (_animSkeleton) { _internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints()); _internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses(); @@ -291,7 +298,10 @@ void Rig::clearJointStates() { void Rig::clearJointAnimationPriority(int index) { if (isIndexValid(index)) { - _internalPoseSet._overrideFlags[index] = false; + if (_internalPoseSet._overrideFlags[index]) { + _internalPoseSet._overrideFlags[index] = false; + --_numOverrides; + } _internalPoseSet._overridePoses[index] = _animSkeleton->getRelativeDefaultPose(index); } } @@ -320,7 +330,10 @@ void Rig::setJointTranslation(int index, bool valid, const glm::vec3& translatio if (isIndexValid(index)) { if (valid) { assert(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size()); - _internalPoseSet._overrideFlags[index] = true; + if (!_internalPoseSet._overrideFlags[index]) { + _internalPoseSet._overrideFlags[index] = true; + ++_numOverrides; + } _internalPoseSet._overridePoses[index].trans = translation; } } @@ -329,7 +342,10 @@ void Rig::setJointTranslation(int index, bool valid, const glm::vec3& translatio void Rig::setJointState(int index, bool valid, const glm::quat& rotation, const glm::vec3& translation, float priority) { if (isIndexValid(index)) { assert(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size()); - _internalPoseSet._overrideFlags[index] = true; + if (!_internalPoseSet._overrideFlags[index]) { + _internalPoseSet._overrideFlags[index] = true; + ++_numOverrides; + } _internalPoseSet._overridePoses[index].rot = rotation; _internalPoseSet._overridePoses[index].trans = translation; } @@ -339,7 +355,10 @@ void Rig::setJointRotation(int index, bool valid, const glm::quat& rotation, flo if (isIndexValid(index)) { if (valid) { ASSERT(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size()); - _internalPoseSet._overrideFlags[index] = true; + if (!_internalPoseSet._overrideFlags[index]) { + _internalPoseSet._overrideFlags[index] = true; + ++_numOverrides; + } _internalPoseSet._overridePoses[index].rot = rotation; } } @@ -518,7 +537,7 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos // sine wave LFO var for testing. static float t = 0.0f; - _animVars.set("sine", 2.0f * static_cast(0.5 * sin(t) + 0.5)); + _animVars.set("sine", 2.0f * 0.5f * sinf(t) + 0.5f); float moveForwardAlpha = 0.0f; float moveBackwardAlpha = 0.0f; @@ -884,10 +903,12 @@ void Rig::updateAnimationStateHandlers() { // called on avatar update thread (wh void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) { PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xffff00ff, 0); + PerformanceTimer perfTimer("updateAnimations"); setModelOffset(rootTransform); if (_animNode) { + PerformanceTimer perfTimer("handleTriggers"); updateAnimationStateHandlers(); _animVars.setRigToGeometryTransform(_rigToGeometryTransform); @@ -903,9 +924,8 @@ void Rig::updateAnimations(float deltaTime, glm::mat4 rootTransform) { for (auto& trigger : triggersOut) { _animVars.setTrigger(trigger); } + applyOverridePoses(); } - - applyOverridePoses(); buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); // copy internal poses to external poses @@ -1176,7 +1196,8 @@ bool Rig::getModelRegistrationPoint(glm::vec3& modelRegistrationPointOut) const } void Rig::applyOverridePoses() { - if (!_animSkeleton) { + PerformanceTimer perfTimer("override"); + if (_numOverrides == 0 || !_animSkeleton) { return; } @@ -1192,28 +1213,24 @@ void Rig::applyOverridePoses() { } void Rig::buildAbsoluteRigPoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePosesOut) { + PerformanceTimer perfTimer("buildAbsolute"); if (!_animSkeleton) { return; } ASSERT(_animSkeleton->getNumJoints() == (int)relativePoses.size()); - // flatten all poses out so they are absolute not relative absolutePosesOut.resize(relativePoses.size()); + AnimPose geometryToRigTransform(_geometryToRigTransform); for (int i = 0; i < (int)relativePoses.size(); i++) { int parentIndex = _animSkeleton->getParentIndex(i); if (parentIndex == -1) { - absolutePosesOut[i] = relativePoses[i]; + // transform all root absolute poses into rig space + absolutePosesOut[i] = geometryToRigTransform * relativePoses[i]; } else { absolutePosesOut[i] = absolutePosesOut[parentIndex] * relativePoses[i]; } } - - // transform all absolute poses into rig space. - AnimPose geometryToRigTransform(_geometryToRigTransform); - for (int i = 0; i < (int)absolutePosesOut.size(); i++) { - absolutePosesOut[i] = geometryToRigTransform * absolutePosesOut[i]; - } } glm::mat4 Rig::getJointTransform(int jointIndex) const { @@ -1251,62 +1268,36 @@ void Rig::copyJointsIntoJointData(QVector& jointDataVec) const { void Rig::copyJointsFromJointData(const QVector& jointDataVec) { PerformanceTimer perfTimer("copyJoints"); - if (_animSkeleton && jointDataVec.size() == (int)_internalPoseSet._overrideFlags.size()) { - - // transform all the default poses into rig space. - const AnimPose geometryToRigPose(_geometryToRigTransform); - std::vector overrideFlags(_internalPoseSet._overridePoses.size(), false); - - // start with the default rotations in absolute rig frame + if (_animSkeleton && jointDataVec.size() == (int)_internalPoseSet._relativePoses.size()) { + // make a vector of rotations in absolute-geometry-frame + const AnimPoseVec& absoluteDefaultPoses = _animSkeleton->getAbsoluteDefaultPoses(); std::vector rotations; rotations.reserve(_animSkeleton->getAbsoluteDefaultPoses().size()); - for (auto& pose : _animSkeleton->getAbsoluteDefaultPoses()) { - rotations.push_back(geometryToRigPose.rot * pose.rot); - } - - // start translations in relative frame but scaled to meters. - std::vector translations; - translations.reserve(_animSkeleton->getRelativeDefaultPoses().size()); - for (auto& pose : _animSkeleton->getRelativeDefaultPoses()) { - translations.push_back(_geometryOffset.scale * pose.trans); - } - - ASSERT(overrideFlags.size() == rotations.size()); - - // copy over rotations from the jointDataVec, which is also in absolute rig frame + const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform)); for (int i = 0; i < jointDataVec.size(); i++) { - if (isIndexValid(i)) { - const JointData& data = jointDataVec.at(i); - if (data.rotationSet) { - overrideFlags[i] = true; - rotations[i] = data.rotation; - } - if (data.translationSet) { - overrideFlags[i] = true; - translations[i] = data.translation; - } + const JointData& data = jointDataVec.at(i); + if (data.rotationSet) { + // JointData rotations are in absolute rig-frame so we rotate them to absolute geometry-frame + rotations.push_back(rigToGeometryRot * data.rotation); + } else { + rotations.push_back(absoluteDefaultPoses[i].rot); } } - ASSERT(_internalPoseSet._overrideFlags.size() == _internalPoseSet._overridePoses.size()); - - // convert resulting rotations into geometry space. - const glm::quat rigToGeometryRot(glmExtractRotation(_rigToGeometryTransform)); - for (auto& rot : rotations) { - rot = rigToGeometryRot * rot; - } - - // convert all rotations from absolute to parent relative. + // convert rotations from absolute to parent relative. _animSkeleton->convertAbsoluteRotationsToRelative(rotations); - // copy the geometry space parent relative poses into _overridePoses + // store new relative poses + const AnimPoseVec& relativeDefaultPoses = _animSkeleton->getRelativeDefaultPoses(); for (int i = 0; i < jointDataVec.size(); i++) { - if (overrideFlags[i]) { - _internalPoseSet._overrideFlags[i] = true; - _internalPoseSet._overridePoses[i].scale = Vectors::ONE; - _internalPoseSet._overridePoses[i].rot = rotations[i]; - // scale translations from meters back into geometry units. - _internalPoseSet._overridePoses[i].trans = _invGeometryOffset.scale * translations[i]; + const JointData& data = jointDataVec.at(i); + _internalPoseSet._relativePoses[i].scale = Vectors::ONE; + _internalPoseSet._relativePoses[i].rot = rotations[i]; + if (data.translationSet) { + // JointData translations are in scaled relative-frame so we scale back to regular relative-frame + _internalPoseSet._relativePoses[i].trans = _invGeometryOffset.scale * data.translation; + } else { + _internalPoseSet._relativePoses[i].trans = relativeDefaultPoses[i].trans; } } } diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 151a7ae8e9..aa091fe10c 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -311,6 +311,7 @@ protected: std::map _origRoleAnimations; + int32_t _numOverrides { 0 }; bool _lastEnableInverseKinematics { true }; bool _enableInverseKinematics { true }; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 14c80faa96..436574a1ff 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -234,17 +234,19 @@ void Model::updateRenderItems() { render::PendingChanges pendingChanges; foreach (auto itemID, self->_modelMeshRenderItems.keys()) { pendingChanges.updateItem(itemID, [modelTransform, modelMeshOffset, deleteGeometryCounter](ModelMeshPartPayload& data) { - if (!data.hasStartedFade() && data._model && data._model->isLoaded() && data._model->getGeometry()->areTexturesLoaded()) { - data.startFade(); - } - // Ensure the model geometry was not reset between frames - if (data._model && data._model->isLoaded() && deleteGeometryCounter == data._model->_deleteGeometryCounter) { - // lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box. - data._model->updateClusterMatrices(modelTransform.getTranslation(), modelTransform.getRotation()); + if (data._model && data._model->isLoaded()) { + if (!data.hasStartedFade() && data._model->getGeometry()->areTexturesLoaded()) { + data.startFade(); + } + // Ensure the model geometry was not reset between frames + if (deleteGeometryCounter == data._model->_deleteGeometryCounter) { + // lazy update of cluster matrices used for rendering. We need to update them here, so we can correctly update the bounding box. + data._model->updateClusterMatrices(modelTransform.getTranslation(), modelTransform.getRotation()); - // update the model transform and bounding box for this render item. - const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); - data.updateTransformForSkinnedMesh(modelTransform, modelMeshOffset, state.clusterMatrices); + // update the model transform and bounding box for this render item. + const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex); + data.updateTransformForSkinnedMesh(modelTransform, modelMeshOffset, state.clusterMatrices); + } } }); }