From 662c34c266c230619c5272b11866d830dbc7bb0a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 6 Apr 2017 09:40:24 -0700 Subject: [PATCH] fix avatar scale animation and avatar render debug --- interface/src/avatar/Avatar.cpp | 9 +- interface/src/avatar/Avatar.h | 1 + interface/src/avatar/AvatarManager.cpp | 111 ++++++++++++++++-------- interface/src/avatar/AvatarManager.h | 10 +-- interface/src/avatar/MyAvatar.cpp | 3 +- libraries/avatars/src/AvatarData.cpp | 1 + libraries/avatars/src/AvatarHashMap.cpp | 41 +++++---- libraries/avatars/src/AvatarHashMap.h | 11 +-- 8 files changed, 117 insertions(+), 70 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a8fc4840fe..988d34e554 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -192,6 +192,7 @@ void Avatar::animateScaleChanges(float deltaTime) { _isAnimatingScale = false; } setScale(glm::vec3(animatedScale)); // avatar scale is uniform + _hasNewJointData = true; // TODO: rebuilding the shape constantly is somehwat expensive. // We should only rebuild after significant change. @@ -200,8 +201,12 @@ void Avatar::animateScaleChanges(float deltaTime) { } void Avatar::setTargetScale(float targetScale) { - AvatarData::setTargetScale(targetScale); - _isAnimatingScale = true; + float newValue = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); + if (_targetScale != newValue) { + _targetScale = newValue; + _scaleChanged = usecTimestampNow(); + _isAnimatingScale = true; + } } void Avatar::updateAvatarEntities() { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index ae98c525c8..c4084fce9a 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -285,6 +285,7 @@ protected: void addToScene(AvatarSharedPointer self); void ensureInScene(AvatarSharedPointer self); + bool isInScene() const { return render::Item::isValidID(_renderItemID); } // Some rate tracking support RateCounter<> _simulationRate; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 03d7dd1c6c..0d9cd13d24 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -100,15 +100,16 @@ void AvatarManager::init() { _avatarHash.insert(MY_AVATAR_KEY, _myAvatar); } + _shouldRender = DependencyManager::get()->shouldRenderAvatars(); connect(DependencyManager::get().data(), &SceneScriptingInterface::shouldRenderAvatarsChanged, this, &AvatarManager::updateAvatarRenderStatus, Qt::QueuedConnection); - render::ScenePointer scene = qApp->getMain3DScene(); - render::Transaction transaction; - if (DependencyManager::get()->shouldRenderAvatars()) { + if (_shouldRender) { + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; _myAvatar->addToScene(_myAvatar, scene, transaction); + scene->enqueueTransaction(transaction); } - scene->enqueueTransaction(transaction); } void AvatarManager::updateMyAvatar(float deltaTime) { @@ -181,30 +182,24 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { // DO NOT update or fade out uninitialized Avatars return true; // ignore it } - if (avatar->shouldDie()) { - removeAvatar(avatar->getID()); - return true; // ignore it - } - if (avatar->isDead()) { - return true; // ignore it - } - return false; }); - render::Transaction transaction; uint64_t startTime = usecTimestampNow(); const uint64_t UPDATE_BUDGET = 2000; // usec uint64_t updateExpiry = startTime + UPDATE_BUDGET; - int numAvatarsUpdated = 0; int numAVatarsNotUpdated = 0; + + render::Transaction transaction; while (!sortedAvatars.empty()) { const AvatarPriority& sortData = sortedAvatars.top(); const auto& avatar = std::static_pointer_cast(sortData.avatar); // for ALL avatars... - avatar->ensureInScene(avatar); + if (_shouldRender) { + avatar->ensureInScene(avatar); + } if (!avatar->getMotionState()) { ShapeInfo shapeInfo; avatar->computeShapeInfo(shapeInfo); @@ -218,6 +213,10 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } } avatar->animateScaleChanges(deltaTime); + if (avatar->shouldDie()) { + avatar->die(); + removeAvatar(avatar->getID()); + } const float OUT_OF_VIEW_THRESHOLD = 0.5f * AvatarData::OUT_OF_VIEW_PENALTY; uint64_t now = usecTimestampNow(); @@ -259,10 +258,21 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { sortedAvatars.pop(); } + if (_shouldRender) { + QVector::iterator itr = _avatarsToFade.begin(); + while (itr != _avatarsToFade.end() && usecTimestampNow() > updateExpiry) { + auto avatar = std::static_pointer_cast(*itr); + avatar->animateScaleChanges(deltaTime); + avatar->simulate(deltaTime, true); + avatar->updateRenderItem(transaction); + ++itr; + } + qApp->getMain3DScene()->enqueueTransaction(transaction); + } + _avatarSimulationTime = (float)(usecTimestampNow() - startTime) / (float)USECS_PER_MSEC; _numAvatarsUpdated = numAvatarsUpdated; _numAvatarsNotUpdated = numAVatarsNotUpdated; - qApp->getMain3DScene()->enqueueTransaction(transaction); simulateAvatarFades(deltaTime); } @@ -277,38 +287,68 @@ void AvatarManager::postUpdate(float deltaTime) { } void AvatarManager::simulateAvatarFades(float deltaTime) { - QVector::iterator fadingIterator = _avatarsToFade.begin(); + QVector::iterator itr = _avatarsToFade.begin(); const float SHRINK_RATE = 0.15f; const float MIN_FADE_SCALE = MIN_AVATAR_SCALE; - render::ScenePointer scene = qApp->getMain3DScene(); - render::Transaction transaction; - while (fadingIterator != _avatarsToFade.end()) { - auto avatar = std::static_pointer_cast(*fadingIterator); + while (itr != _avatarsToFade.end()) { + auto avatar = std::static_pointer_cast(*itr); avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); avatar->animateScaleChanges(deltaTime); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { - avatar->removeFromScene(*fadingIterator, scene, transaction); + // fading to zero is such a rare event we push unique transaction for each one + removeAvatar(avatar->getID()); + if (avatar->isInScene()) { + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; + avatar->removeFromScene(*itr, scene, transaction); + scene->enqueueTransaction(transaction); + } + // only remove from _avatarsToFade if we're sure its motionState has been removed from PhysicsEngine if (_motionStatesToRemoveFromPhysics.empty()) { - fadingIterator = _avatarsToFade.erase(fadingIterator); + itr = _avatarsToFade.erase(itr); } else { - ++fadingIterator; + ++itr; } } else { const bool inView = true; // HACK avatar->simulate(deltaTime, inView); - ++fadingIterator; + ++itr; } } - scene->enqueueTransaction(transaction); } AvatarSharedPointer AvatarManager::newSharedAvatar() { - std::shared_ptr avatar = std::make_shared(std::make_shared()); - avatar->addToScene(avatar); - return avatar; + return std::make_shared(std::make_shared()); +} + +void AvatarManager::processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode) { + PerformanceTimer perfTimer("receiveAvatar"); + // enumerate over all of the avatars in this packet + // only add them if mixerWeakPointer points to something (meaning that mixer is still around) + while (message->getBytesLeftToRead()) { + AvatarSharedPointer avatarData = parseAvatarData(message, sendingNode); + if (avatarData) { + auto avatar = std::static_pointer_cast(avatarData); + if (avatar->isInScene()) { + if (!_shouldRender) { + // rare transition so we process pending changes immediately + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; + avatar->removeFromScene(avatar, scene, transaction); + scene->enqueueTransaction(transaction); + } + } else if (_shouldRender) { + // very rare transition so we process pending changes immediately + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; + avatar->addToScene(avatar, scene, transaction); + scene->enqueueTransaction(transaction); + } + } + } } void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { @@ -458,26 +498,23 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } void AvatarManager::updateAvatarRenderStatus(bool shouldRenderAvatars) { - if (DependencyManager::get()->shouldRenderAvatars()) { + _shouldRender = shouldRenderAvatars; + render::ScenePointer scene = qApp->getMain3DScene(); + render::Transaction transaction; + if (_shouldRender) { for (auto avatarData : _avatarHash) { auto avatar = std::static_pointer_cast(avatarData); - render::ScenePointer scene = qApp->getMain3DScene(); - render::Transaction transaction; avatar->addToScene(avatar, scene, transaction); - scene->enqueueTransaction(transaction); } } else { for (auto avatarData : _avatarHash) { auto avatar = std::static_pointer_cast(avatarData); - render::ScenePointer scene = qApp->getMain3DScene(); - render::Transaction transaction; avatar->removeFromScene(avatar, scene, transaction); - scene->enqueueTransaction(transaction); } } + scene->enqueueTransaction(transaction); } - AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) const { if (sessionID == AVATAR_SELF_ID || sessionID == _myAvatar->getSessionUUID()) { return _myAvatar; diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 228fe7e92f..3f053f43a6 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -91,6 +91,9 @@ public slots: void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } void updateAvatarRenderStatus(bool shouldRenderAvatars); +protected slots: + void processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode) override; + private: explicit AvatarManager(QObject* parent = 0); explicit AvatarManager(const AvatarManager& other); @@ -100,12 +103,6 @@ private: AvatarSharedPointer newSharedAvatar() override; void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override; - /* TODO: maintain these lists - QVector _avatarsToRemoveFromScene; - QVector _avatarsToAddToScene; - QVector _avatarsToRemoveFromPhysicsEngine; - QVector _avatarsToAddToPhysicsEngine; - */ QVector _avatarsToFade; SetOfAvatarMotionStates _motionStatesThatMightUpdate; @@ -125,6 +122,7 @@ private: int _numAvatarsUpdated { 0 }; int _numAvatarsNotUpdated { 0 }; float _avatarSimulationTime { 0.0f }; + bool _shouldRender { true }; }; Q_DECLARE_METATYPE(AvatarManager::LocalLight) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d1edf9d44e..2a616a7a2a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -54,6 +54,7 @@ #include "DebugDraw.h" #include "EntityEditPacketSender.h" #include "MovingEntitiesOperator.h" +#include "SceneScriptingInterface.h" using namespace std; @@ -1634,7 +1635,7 @@ void MyAvatar::postUpdate(float deltaTime) { Avatar::postUpdate(deltaTime); render::ScenePointer scene = qApp->getMain3DScene(); - if (_skeletonModel->initWhenReady(scene)) { + if (DependencyManager::get()->shouldRenderAvatars() && _skeletonModel->initWhenReady(scene)) { initHeadBones(); _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a1ea103edb..23aa0cd811 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -123,6 +123,7 @@ void AvatarData::setTargetScale(float targetScale) { if (_targetScale != newValue) { _targetScale = newValue; _scaleChanged = usecTimestampNow(); + _avatarScaleChanged = _scaleChanged; } } diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 48e5d673c9..8708030190 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -80,13 +80,10 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe AvatarSharedPointer AvatarHashMap::newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { QWriteLocker locker(&_hashLock); - auto avatar = _avatarHash.value(sessionUUID); - if (!avatar) { avatar = addAvatar(sessionUUID, mixerWeakPointer); } - return avatar; } @@ -103,27 +100,33 @@ void AvatarHashMap::processAvatarDataPacket(QSharedPointer mess // enumerate over all of the avatars in this packet // only add them if mixerWeakPointer points to something (meaning that mixer is still around) while (message->getBytesLeftToRead()) { - QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); + parseAvatarData(message, sendingNode); + } +} - int positionBeforeRead = message->getPosition(); +AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointer message, SharedNodePointer sendingNode) { + QUuid sessionUUID = QUuid::fromRfc4122(message->readWithoutCopy(NUM_BYTES_RFC4122_UUID)); - QByteArray byteArray = message->readWithoutCopy(message->getBytesLeftToRead()); + int positionBeforeRead = message->getPosition(); - // make sure this isn't our own avatar data or for a previously ignored node - auto nodeList = DependencyManager::get(); + QByteArray byteArray = message->readWithoutCopy(message->getBytesLeftToRead()); - if (sessionUUID != _lastOwnerSessionUUID && (!nodeList->isIgnoringNode(sessionUUID) || nodeList->getRequestsDomainListData())) { - auto avatar = newOrExistingAvatar(sessionUUID, sendingNode); + // make sure this isn't our own avatar data or for a previously ignored node + auto nodeList = DependencyManager::get(); - // have the matching (or new) avatar parse the data from the packet - int bytesRead = avatar->parseDataFromBuffer(byteArray); - message->seek(positionBeforeRead + bytesRead); - } else { - // create a dummy AvatarData class to throw this data on the ground - AvatarData dummyData; - int bytesRead = dummyData.parseDataFromBuffer(byteArray); - message->seek(positionBeforeRead + bytesRead); - } + if (sessionUUID != _lastOwnerSessionUUID && (!nodeList->isIgnoringNode(sessionUUID) || nodeList->getRequestsDomainListData())) { + auto avatar = newOrExistingAvatar(sessionUUID, sendingNode); + + // have the matching (or new) avatar parse the data from the packet + int bytesRead = avatar->parseDataFromBuffer(byteArray); + message->seek(positionBeforeRead + bytesRead); + return avatar; + } else { + // create a dummy AvatarData class to throw this data on the ground + AvatarData dummyData; + int bytesRead = dummyData.parseDataFromBuffer(byteArray); + message->seek(positionBeforeRead + bytesRead); + return std::make_shared(); } } diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index 104ac83261..346cd36b60 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -49,11 +49,11 @@ signals: public slots: bool isAvatarInRange(const glm::vec3 & position, const float range); - -private slots: + +protected slots: void sessionUUIDChanged(const QUuid& sessionUUID, const QUuid& oldUUID); - - void processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode); + + virtual void processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode); void processAvatarIdentityPacket(QSharedPointer message, SharedNodePointer sendingNode); void processKillAvatar(QSharedPointer message, SharedNodePointer sendingNode); void processExitingSpaceBubble(QSharedPointer message, SharedNodePointer sendingNode); @@ -61,12 +61,13 @@ private slots: protected: AvatarHashMap(); + virtual AvatarSharedPointer parseAvatarData(QSharedPointer message, SharedNodePointer sendingNode); virtual AvatarSharedPointer newSharedAvatar(); virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer); AvatarSharedPointer newOrExistingAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer); virtual AvatarSharedPointer findAvatar(const QUuid& sessionUUID) const; // uses a QReadLocker on the hashLock virtual void removeAvatar(const QUuid& sessionUUID, KillAvatarReason removalReason = KillAvatarReason::NoReason); - + virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason); AvatarHash _avatarHash;