diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index cea0ff0f4d..edf9469670 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -79,13 +79,21 @@ AvatarManager::AvatarManager(QObject* parent) : } }); - const float AVATAR_TRANSIT_MAX_DISTANCE = 1.0f; + const float AVATAR_TRANSIT_TRIGGER_DISTANCE = 1.0f; const int AVATAR_TRANSIT_FRAME_COUNT = 11; // Based on testing const int AVATAR_TRANSIT_FRAMES_PER_METER = 3; // Based on testing - _avatarTransitMaxDistance = AVATAR_TRANSIT_MAX_DISTANCE; - _avatarTransitFrameCount = AVATAR_TRANSIT_FRAME_COUNT; - _avatarTransitFramesPerMeter = AVATAR_TRANSIT_FRAMES_PER_METER; + const QString START_ANIMATION_URL = "https://hifi-content.s3.amazonaws.com/luis/test_scripts/transitApp/animations/teleport01_warp.fbx"; + const QString MIDDLE_ANIMATION_URL = "https://hifi-content.s3.amazonaws.com/luis/test_scripts/transitApp/animations/teleport01_warp.fbx"; + const QString END_ANIMATION_URL = "https://hifi-content.s3.amazonaws.com/luis/test_scripts/transitApp/animations/teleport01_warp.fbx"; + + _transitConfig._totalFrames = AVATAR_TRANSIT_FRAME_COUNT; + _transitConfig._triggerDistance = AVATAR_TRANSIT_TRIGGER_DISTANCE; + _transitConfig._framesPerMeter = AVATAR_TRANSIT_FRAMES_PER_METER; + _transitConfig._isDistanceBased = true; + _transitConfig._startTransitAnimation = AvatarTransit::TransitAnimation(START_ANIMATION_URL, 30, 0, 10); + _transitConfig._middleTransitAnimation = AvatarTransit::TransitAnimation(MIDDLE_ANIMATION_URL, 30, 11, 0); + _transitConfig._endTransitAnimation = AvatarTransit::TransitAnimation(END_ANIMATION_URL, 30, 12, 38); } AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { @@ -133,26 +141,37 @@ void AvatarManager::setSpace(workload::SpacePointer& space ) { _space = space; } +void AvatarManager::playTransitAnimations(AvatarTransit::Status status) { + auto startAnimation = _transitConfig._startTransitAnimation; + auto middleAnimation = _transitConfig._middleTransitAnimation; + auto endAnimation = _transitConfig._endTransitAnimation; + + switch (status) { + case AvatarTransit::Status::START_FRAME: + _myAvatar->overrideAnimation(startAnimation._animationUrl, startAnimation._fps, false, startAnimation._firstFrame, startAnimation._firstFrame + startAnimation._frameCount); + break; + case AvatarTransit::Status::START_TRANSIT: + _myAvatar->overrideAnimation(middleAnimation._animationUrl, middleAnimation._fps, false, middleAnimation._firstFrame, middleAnimation._firstFrame + middleAnimation._frameCount); + break; + case AvatarTransit::Status::END_TRANSIT: + _myAvatar->overrideAnimation(endAnimation._animationUrl, endAnimation._fps, false, endAnimation._firstFrame, endAnimation._firstFrame + endAnimation._frameCount); + break; + case AvatarTransit::Status::END_FRAME: + _myAvatar->restoreAnimation(); + break; + } +} + void AvatarManager::updateMyAvatar(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()"); - /* - std::shared_ptr transit = _myAvatar->getTransit(); - bool initTransit = false; - if (!transit->isTransiting()) { - initTransit = transit->update(_myAvatar->getWorldPosition(), _avatarTransitFrameCount, _avatarTransitFramesPerMeter, _avatarTransitDistanceBased, _avatarTransitMaxDistance); - if (initTransit) { - _myAvatar->getSkeletonModel()->getRig().restoreAnimation(); - _myAvatar->getSkeletonModel()->getRig().overrideAnimation("https://hifi-content.s3.amazonaws.com/luis/test_scripts/transit_app/animations/teleport01_warp.fbx", 30, false, 0, 49); - } - } - if (transit->isTransiting()){ - glm::vec3 nextPosition; - if (!transit->getNextPosition(nextPosition)) { - _myAvatar->getSkeletonModel()->getRig().restoreAnimation(); - } + + AvatarTransit::Status status = _myAvatar->updateTransit(_myAvatar->getWorldPosition(), _transitConfig); + + if (_transitConfig._playAnimation) { + playTransitAnimations(status); } - */ + _myAvatar->update(deltaTime); render::Transaction transaction; _myAvatar->updateRenderItem(transaction); @@ -276,7 +295,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { } // smooth other avatars positions { - avatar->_transit.update(avatar->_globalPosition, _avatarTransitFrameCount, _avatarTransitFramesPerMeter, _avatarTransitDistanceBased, _avatarTransitMaxDistance); + avatar->_transit.update(avatar->_globalPosition, _transitConfig); } avatar->simulate(deltaTime, inView); @@ -866,3 +885,30 @@ void AvatarManager::setAvatarSortCoefficient(const QString& name, const QScriptV doc.insert("data", palData); return doc.toVariantMap(); } + + QVariantMap AvatarManager::getAvatarTransitData() { + QVariantMap result; + result["frameCount"] = _transitConfig._totalFrames; + result["framesPerMeter"] = _transitConfig._framesPerMeter; + result["isDistanceBased"] = _transitConfig._isDistanceBased; + result["triggerDistance"] = _transitConfig._triggerDistance; + result["playAnimation"] = _transitConfig._playAnimation; + return result; +} + void AvatarManager::setAvatarTransitData(const QVariantMap& data) { + if (data.contains("frameCount")) { + _transitConfig._totalFrames = data["frameCount"].toInt(); + } + if (data.contains("framesPerMeter")) { + _transitConfig._framesPerMeter = data["framesPerMeter"].toInt(); + } + if (data.contains("isDistanceBased")) { + _transitConfig._isDistanceBased = data["isDistanceBased"].toBool(); + } + if (data.contains("triggerDistance")) { + _transitConfig._triggerDistance = data["triggerDistance"].toDouble(); + } + if (data.contains("playAnimation")) { + _transitConfig._playAnimation = data["playAnimation"].toBool(); + } +} \ No newline at end of file diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 3fc675f9b8..e5936154a4 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -178,14 +178,8 @@ public: */ Q_INVOKABLE QVariantMap getPalData(const QList specificAvatarIdentifiers = QList()); - Q_INVOKABLE void setAvatarTransitDistanceBased(bool isDistanceBased) { _avatarTransitDistanceBased = isDistanceBased; } - Q_INVOKABLE void setAvatarTransitMaxDistance(float maxDistance) { _avatarTransitMaxDistance = maxDistance; } - Q_INVOKABLE void setAvatarTransitFrameCount(int frameCount) { _avatarTransitFrameCount = frameCount; } - Q_INVOKABLE void setAvatarTransitFramesPerMeter(int frameCount) { _avatarTransitFramesPerMeter = frameCount; } - Q_INVOKABLE bool getAvatarTransitDistanceBased() { return _avatarTransitDistanceBased; } - Q_INVOKABLE float getAvatarTransitMaxDistance() { return _avatarTransitMaxDistance; } - Q_INVOKABLE int getAvatarTransitFrameCount() { return _avatarTransitFrameCount; } - Q_INVOKABLE int getAvatarTransitFramesPerMeter() { return _avatarTransitFramesPerMeter; } + Q_INVOKABLE QVariantMap getAvatarTransitData(); + Q_INVOKABLE void setAvatarTransitData(const QVariantMap& data); float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); } int getIdentityRequestsSent() const { return _identityRequestsSent; } @@ -212,6 +206,7 @@ private: AvatarSharedPointer newSharedAvatar() override; void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override; + void playTransitAnimations(AvatarTransit::Status status); QVector _avatarsToFade; QVector _avatarsToCopy; @@ -237,11 +232,7 @@ private: // Other avatars smooth transit global configuration - bool _avatarTransitDistanceBased { true }; - float _avatarTransitMaxDistance; - int _avatarTransitFrameCount; - int _avatarTransitFramesPerMeter; - + AvatarTransit::TransitConfig _transitConfig; }; #endif // hifi_AvatarManager_h diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 05d49a9ec0..a3c3286793 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -113,29 +113,27 @@ void Avatar::setShowNamesAboveHeads(bool show) { showNamesAboveHeads = show; } -bool AvatarTransit::update(const glm::vec3& avatarPosition, int totalFrames, int framesPerMeter, bool isDistanceBased, float maxDistance) { - bool starting = false; +AvatarTransit::Status AvatarTransit::update(const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) { glm::vec3 currentPosition = _isTransiting ? _currentPosition : avatarPosition; float oneFrameDistance = glm::length(currentPosition - _lastPosition); - if (oneFrameDistance > maxDistance && !_isTransiting) { - start(_lastPosition, currentPosition, totalFrames, framesPerMeter, isDistanceBased); - starting = true; - } - updatePosition(avatarPosition); - return starting; + if (oneFrameDistance > config._triggerDistance && !_isTransiting) { + start(_lastPosition, currentPosition, config); + } + return updatePosition(avatarPosition); } -void AvatarTransit::start(const glm::vec3& startPosition, const glm::vec3& endPosition, int totalFrames, int framesPerMeter, bool isDistanceBased) { +void AvatarTransit::start(const glm::vec3& startPosition, const glm::vec3& endPosition, const AvatarTransit::TransitConfig& config) { _startPosition = startPosition; _endPosition = endPosition; + _framesBefore = config._startTransitAnimation._frameCount; + _framesAfter = config._endTransitAnimation._frameCount; _step = 0; - if (!isDistanceBased) { - calculateSteps(totalFrames); + if (!config._isDistanceBased) { + calculateSteps(config._totalFrames); } else { float distance = glm::length(_endPosition - _startPosition); - calculateSteps(framesPerMeter * distance); + calculateSteps(config._framesPerMeter * distance); } - _isTransiting = true; } @@ -145,22 +143,42 @@ void AvatarTransit::calculateSteps(int stepCount) { glm::vec3 transitLine = _endPosition - startPosition; glm::vec3 direction = glm::normalize(transitLine); glm::vec3 stepVector = (glm::length(transitLine) / stepCount) * direction; - for (auto i = 0; i < stepCount; i++) { - glm::vec3 localStep = _transitSteps.size() > 0 ? _transitSteps[i-1] + stepVector : _startPosition + stepVector; - _transitSteps.push_back(localStep); + int totalSteps = stepCount + _framesBefore + _framesAfter; + for (auto i = 0; i < totalSteps; i++) { + if (i < _framesBefore) { + _transitSteps.push_back(_startPosition); + } else if (i >= stepCount + _framesBefore) { + _transitSteps.push_back(_endPosition); + } else { + glm::vec3 localStep = _transitSteps.size() > _framesBefore ? _transitSteps[i - 1] + stepVector : _startPosition + stepVector; + _transitSteps.push_back(localStep); + } } } -void AvatarTransit::updatePosition(const glm::vec3& avatarPosition) { +AvatarTransit::Status AvatarTransit::updatePosition(const glm::vec3& avatarPosition) { + Status status = Status::IDLE; _lastPosition = _isTransiting ? _currentPosition : avatarPosition; if (_isTransiting) { int lastIdx = (int)_transitSteps.size() - 1; _isTransiting = _step < lastIdx; if (_isTransiting) { + if (_step == 0) { + status = Status::START_FRAME; + qDebug() << "Transit starting"; + } else if (_step == _framesBefore - 1) { + status = Status::START_TRANSIT; + } else if (_step == (int)_transitSteps.size() - _framesAfter) { + status = Status::END_TRANSIT; + } _step++; _currentPosition = _transitSteps[_step]; + } else { + status = Status::END_FRAME; + qDebug() << "Transit ending"; } } + return status; } bool AvatarTransit::getNextPosition(glm::vec3& nextPosition) { @@ -1936,6 +1954,11 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const { } } +AvatarTransit::Status Avatar::updateTransit(const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) { + std::lock_guard lock(_transitLock); + return _transit.update(avatarPosition, config); +} + void Avatar::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) { std::lock_guard lock(_materialsLock); _materials[parentMaterialName].push(material); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 22163635ff..b955706861 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -52,21 +52,55 @@ class Texture; class AvatarTransit { public: + enum Status { + IDLE = 0, + START_FRAME, + START_TRANSIT, + TRANSITING, + END_TRANSIT, + END_FRAME + }; + + struct TransitAnimation { + TransitAnimation() {}; + TransitAnimation(const QString& animationUrl, int fps, int firstFrame, int frameCount) : + _firstFrame(firstFrame), _frameCount(frameCount), _animationUrl(animationUrl), _fps(fps) {}; + int _firstFrame; + int _frameCount; + QString _animationUrl; + int _fps; + }; + + struct TransitConfig { + TransitConfig() {}; + int _totalFrames { 0 }; + int _framesPerMeter { 0 }; + bool _isDistanceBased { false }; + float _triggerDistance { 0 }; + bool _playAnimation { false }; + TransitAnimation _startTransitAnimation; + TransitAnimation _middleTransitAnimation; + TransitAnimation _endTransitAnimation; + }; + + AvatarTransit() {}; - bool update(const glm::vec3& avatarPosition, int totalFrames, int framesPerMeter, bool isDistanceBased, float maxDistance); - void start(const glm::vec3& startPosition, const glm::vec3& endPosition, int totalFrames, int framesPerMeter, bool isDistanceBased); - bool getNextPosition(glm::vec3& nextPosition); + Status update(const glm::vec3& avatarPosition, const TransitConfig& config); bool isTransiting() { return _isTransiting; }; glm::vec3 getCurrentPosition() { return _currentPosition; }; + bool getNextPosition(glm::vec3& nextPosition); int getCurrentStep() { return _step; }; private: void calculateSteps(int stepCount); - void updatePosition(const glm::vec3& avatarPosition); + Status updatePosition(const glm::vec3& avatarPosition); + void start(const glm::vec3& startPosition, const glm::vec3& endPosition, const TransitConfig& config); bool _isTransiting{ false }; glm::vec3 _startPosition; glm::vec3 _endPosition; glm::vec3 _currentPosition; + int _framesBefore { 0 }; + int _framesAfter { 0 }; std::vector _transitSteps; glm::vec3 _lastPosition; int _step { 0 }; @@ -385,6 +419,7 @@ public: std::shared_ptr getTransit() { return std::make_shared(_transit); }; + AvatarTransit::Status updateTransit(const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config); signals: void targetScaleChanged(float targetScale); @@ -520,6 +555,7 @@ protected: RateCounter<> _skeletonModelSimulationRate; RateCounter<> _jointDataSimulationRate; + protected: class AvatarEntityDataHash { public: @@ -544,7 +580,7 @@ protected: float _modelScale { 1.0f }; AvatarTransit _transit; - + std::mutex _transitLock; static int _jointConesID;