From 0065c64b3143401de537fb83b9553c43d4a59c74 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Mon, 7 Sep 2015 09:57:05 -0700 Subject: [PATCH] Snapshot of no-judder, before cleanup. --- interface/src/Application.cpp | 7 ++- interface/src/Application.h | 2 +- interface/src/avatar/Avatar.cpp | 6 +-- interface/src/avatar/Avatar.h | 1 + interface/src/avatar/AvatarManager.cpp | 8 ++-- interface/src/avatar/AvatarUpdate.cpp | 17 ++++--- interface/src/avatar/AvatarUpdate.h | 2 +- interface/src/avatar/MyAvatar.cpp | 6 ++- interface/src/avatar/SkeletonModel.cpp | 14 ++++-- interface/src/avatar/SkeletonModel.h | 1 + libraries/avatars/src/AvatarData.cpp | 48 +++++++++++++++++++ libraries/avatars/src/AvatarData.h | 13 +++++ .../src/DynamicCharacterController.cpp | 5 +- libraries/render-utils/src/Model.cpp | 10 ++-- 14 files changed, 108 insertions(+), 32 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc286dafae..92f64303c7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1019,6 +1019,8 @@ void Application::paintGL() { return; } _inPaint = true; + _myAvatar->captureAttitude(); + _myAvatar->startRender(); //FIXME Finally clearFlagLambda([this] { _inPaint = false; }); auto displayPlugin = getActiveDisplayPlugin(); @@ -1236,6 +1238,7 @@ void Application::paintGL() { gpu::Batch batch; batch.resetStages(); renderArgs._context->render(batch); + _myAvatar->endRender(); } void Application::runTests() { @@ -2152,7 +2155,7 @@ void Application::setAvatarSimrateSample(float sample) { } float Application::getAvatarSimrate() { uint64_t now = usecTimestampNow(); - + if (now - _lastAvatarSimsPerSecondUpdate > USECS_PER_SECOND) { _avatarSimsPerSecondReport = _avatarSimsPerSecond.getAverage(); _lastAvatarSimsPerSecondUpdate = now; @@ -2444,7 +2447,7 @@ void Application::init() { // Make sure any new sounds are loaded as soon as know about them. connect(tree, &EntityTree::newCollisionSoundURL, DependencyManager::get().data(), &SoundCache::getSound); connect(_myAvatar, &MyAvatar::newCollisionSoundURL, DependencyManager::get().data(), &SoundCache::getSound); - + setAvatarUpdateThreading(Menu::getInstance()->isOptionChecked(MenuOption::EnableAvatarUpdateThreading)); } diff --git a/interface/src/Application.h b/interface/src/Application.h index b6f807dec3..317832d9f5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -335,7 +335,7 @@ public: gpu::ContextPointer getGPUContext() const { return _gpuContext; } const QRect& getMirrorViewRect() const { return _mirrorViewRect; } - + void updateMyAvatarLookAtPosition(); AvatarUpdate* getAvatarUpdater() { return _avatarUpdate; } MyAvatar* getMyAvatar() { return _myAvatar; } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 67d60073fe..fbc940078e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -316,7 +316,7 @@ void Avatar::removeFromScene(AvatarSharedPointer self, std::shared_ptrupdate(); } @@ -391,7 +391,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } if (frustum->sphereInFrustum(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) { - avatarLock.unlock(); + //FIXME endRender(); return; } @@ -542,7 +542,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { if (!isMyAvatar() || cameraMode != CAMERA_MODE_FIRST_PERSON) { renderDisplayName(batch, *renderArgs->_viewFrustum, renderArgs->_viewport); } - avatarLock.unlock(); + //FIXME endRender(); } glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index a7cece2b45..6cfbf939a2 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -156,6 +156,7 @@ public: void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const; void slamPosition(const glm::vec3& position); + virtual void updateAttitude() { _skeletonModel.updateAttitude(); } // Call this when updating Avatar position with a delta. This will allow us to // _accurately_ measure position changes and compute the resulting velocity diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index d4885d651e..67668a549d 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -129,9 +129,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { _avatarFades.push_back(avatarIterator.value()); avatarIterator = _avatarHash.erase(avatarIterator); } else { - avatar->avatarLock.lockForWrite(); + avatar->startUpdate(); avatar->simulate(deltaTime); - avatar->avatarLock.unlock(); + avatar->endUpdate(); ++avatarIterator; } } @@ -150,7 +150,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { render::PendingChanges pendingChanges; while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); - avatar->avatarLock.lockForWrite(); + avatar->startUpdate(); avatar->setTargetScale(avatar->getScale() * SHRINK_RATE, true); if (avatar->getTargetScale() < MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); @@ -159,7 +159,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { avatar->simulate(deltaTime); ++fadingIterator; } - avatar->avatarLock.unlock(); + avatar->endUpdate(); } scene->enqueuePendingChanges(pendingChanges); } diff --git a/interface/src/avatar/AvatarUpdate.cpp b/interface/src/avatar/AvatarUpdate.cpp index 4121b95c82..c2240ef123 100644 --- a/interface/src/avatar/AvatarUpdate.cpp +++ b/interface/src/avatar/AvatarUpdate.cpp @@ -56,17 +56,20 @@ bool AvatarUpdate::process() { _lastAvatarUpdate = start; float deltaSeconds = deltaMicroseconds / (float) USECS_PER_SECOND; Application::getInstance()->setAvatarSimrateSample(1.0f / deltaSeconds); - + + QSharedPointer manager = DependencyManager::get(); + MyAvatar* myAvatar = manager->getMyAvatar(); + //loop through all the other avatars and simulate them... //gets current lookat data, removes missing avatars, etc. - DependencyManager::get()->updateOtherAvatars(deltaSeconds); - - Application::getInstance()->getMyAvatar()->avatarLock.lockForWrite(); + manager->updateOtherAvatars(deltaSeconds); + + myAvatar->startUpdate(); Application::getInstance()->updateMyAvatarLookAtPosition(); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes - DependencyManager::get()->updateMyAvatar(deltaSeconds); - Application::getInstance()->getMyAvatar()->avatarLock.unlock(); - + manager->updateMyAvatar(deltaSeconds); + myAvatar->endUpdate(); + if (!isThreaded()) { return true; } diff --git a/interface/src/avatar/AvatarUpdate.h b/interface/src/avatar/AvatarUpdate.h index 08c90c0701..27c88b6617 100644 --- a/interface/src/avatar/AvatarUpdate.h +++ b/interface/src/avatar/AvatarUpdate.h @@ -29,7 +29,7 @@ private: quint64 _lastAvatarUpdate; // microsoeconds quint64 _targetInterval; // microseconds bool _updateBillboard; - + // Goes away if Application::getActiveDisplayPlugin() and friends are made thread safe: public: bool isHMDMode() { return _isHMDMode; } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f75aa5cba4..4e4043b28b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -192,6 +192,9 @@ void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("transform"); updateOrientation(deltaTime); updatePosition(deltaTime); + // The 2 updates set position, orientation, and all manner of physics stuff. + // Here we record the results. + nextAttitude(getPosition(), getOrientation()); } { @@ -266,8 +269,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { if (getStandingHMDSensorMode()) { // set the body position/orientation to reflect motion due to the head. auto worldMat = _sensorToWorldMatrix * _bodySensorMatrix; - setPosition(extractTranslation(worldMat)); - setOrientation(glm::quat_cast(worldMat)); + nextAttitude(extractTranslation(worldMat), glm::quat_cast(worldMat)); } } diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 9bd6d35075..69aea5bb9d 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -40,10 +40,10 @@ SkeletonModel::~SkeletonModel() { } void SkeletonModel::avatarLockForWriteIfApplicable() { - _owningAvatar->avatarLock.lockForWrite(); + //FIXME _owningAvatar->avatarLock.lockForWrite(); } void SkeletonModel::avatarLockReleaseIfApplicable() { - _owningAvatar->avatarLock.unlock(); + //FIXME _owningAvatar->avatarLock.unlock(); } void SkeletonModel::initJointStates(QVector states) { @@ -154,13 +154,17 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { } } -// Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed), -// but just before head has been simulated. -void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { +void SkeletonModel::updateAttitude() { setTranslation(_owningAvatar->getSkeletonPosition()); static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); setRotation(_owningAvatar->getOrientation() * refOrientation); setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale()); +} + +// Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed), +// but just before head has been simulated. +void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { + updateAttitude(); setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients()); Model::simulate(deltaTime, fullUpdate); diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index d3bf850c53..1481619a04 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -31,6 +31,7 @@ public: virtual void simulate(float deltaTime, bool fullUpdate = true); virtual void updateRig(float deltaTime, glm::mat4 parentTransform); + void updateAttitude(); void renderIKConstraints(gpu::Batch& batch); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 46a323733a..9d7f974a68 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -110,6 +110,54 @@ void AvatarData::setOrientation(const glm::quat& orientation, bool overideRefere } } +// There are a number of possible strategies, some more optimal than others in terms of using the latest info +// The current one does not update anything until captureAttitude, and then keeps that value until rendered. +void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { + setPosition(position, true); setOrientation(orientation, true); + _nextPending = 1; // FIXME type bool +} +void AvatarData::captureAttitude() { + if (!_nextAllowed) { // We haven't finished rendering the last one + return; + } + avatarLock.lockForWrite(); + if (_nextPending) { + _nextAllowed = false; + _nextPosition = getPosition(); + _nextOrientation = getOrientation(); + } else { + qCDebug(avatars) << "FIXME capture with nothing pending"; + } + avatarLock.unlock(); +} +void AvatarData::startUpdate() { + avatarLock.lockForWrite(); +} +void AvatarData::endUpdate() { + avatarLock.unlock(); +} +void AvatarData::startRender() { + avatarLock.lockForRead(); + if (!_nextPending) { + return; + } + glm::vec3 pos = getPosition(); + glm::quat rot = getOrientation(); + setPosition(_nextPosition, true); + //setOrientation(_nextOrientation, true); + updateAttitude(); + _nextPosition = pos; + _nextOrientation = rot; +} +void AvatarData::endRender() { + setPosition(_nextPosition, true); + //setOrientation(_nextOrientation, true); + updateAttitude(); + _nextPending = 0; + _nextAllowed = true; + avatarLock.unlock(); +} + float AvatarData::getTargetScale() const { if (_referential) { _referential->update(); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index d4da9487f7..41d8cba997 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -198,6 +198,14 @@ public: glm::quat getOrientation() const; virtual void setOrientation(const glm::quat& orientation, bool overideReferential = false); + void nextAttitude(glm::vec3 position, glm::quat orientation); // Can be safely called at any time. + void captureAttitude(); // Indicates that the latest values are about to be captured for camera, etc. + void startUpdate(); // start/end of update iteration + void endUpdate(); + void startRender(); // start/end of rendering + void endRender(); + virtual void updateAttitude() {} // Tell skeleton mesh about changes + glm::quat getHeadOrientation() const { return _headData->getOrientation(); } void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); } @@ -358,6 +366,11 @@ protected: float _bodyPitch; // degrees float _bodyRoll; // degrees + glm::vec3 _nextPosition {}; + glm::quat _nextOrientation {}; + int _nextPending = 0; + bool _nextAllowed = true; + // Body scale float _targetScale; diff --git a/libraries/physics/src/DynamicCharacterController.cpp b/libraries/physics/src/DynamicCharacterController.cpp index 7c1455c69e..163cba6aae 100644 --- a/libraries/physics/src/DynamicCharacterController.cpp +++ b/libraries/physics/src/DynamicCharacterController.cpp @@ -405,14 +405,11 @@ void DynamicCharacterController::preSimulation(btScalar timeStep) { void DynamicCharacterController::postSimulation() { if (_enabled && _rigidBody) { - _avatarData->avatarLock.lockForWrite(); const btTransform& avatarTransform = _rigidBody->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); glm::vec3 position = bulletToGLM(avatarTransform.getOrigin()); - _avatarData->setOrientation(rotation); - _avatarData->setPosition(position - rotation * _shapeLocalOffset); + _avatarData->nextAttitude(position - rotation * _shapeLocalOffset, rotation); _avatarData->setVelocity(bulletToGLM(_rigidBody->getLinearVelocity())); - _avatarData->avatarLock.unlock(); } } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0a785dfa3c..99a0c81d4b 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1310,7 +1310,7 @@ void Model::updateClusterMatrices() { if (_showTrueJointTransforms) { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - auto jointMatrix =_rig->getJointTransform(cluster.jointIndex); + auto jointMatrix = _rig->getJointTransform(cluster.jointIndex); state.clusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix; // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. @@ -1324,7 +1324,7 @@ void Model::updateClusterMatrices() { } else { for (int j = 0; j < mesh.clusters.size(); j++) { const FBXCluster& cluster = mesh.clusters.at(j); - auto jointMatrix = _rig->getJointVisibleTransform(cluster.jointIndex); + auto jointMatrix = _rig->getJointVisibleTransform(cluster.jointIndex); // differs from above only in using get...VisibleTransform state.clusterMatrices[j] = modelToWorld * jointMatrix * cluster.inverseBindMatrix; // as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty. @@ -1472,6 +1472,10 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran return; // bail asap } + avatarLockForWriteIfApplicable(); + if (!_calculatedMeshPartOffsetValid) + qCDebug(renderutils) << "FIXME surprise!"; + _calculatedMeshPartOffsetValid = false; // FIXME // We need to make sure we have valid offsets calculated before we can render if (!_calculatedMeshPartOffsetValid) { _mutex.lock(); @@ -1496,10 +1500,10 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran // guard against partially loaded meshes if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size() ) { + avatarLockReleaseIfApplicable(); return; } - avatarLockForWriteIfApplicable(); updateClusterMatrices(); const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());