Time-based frames, max distance and setting animation from script

This commit is contained in:
luiscuenca 2018-09-19 16:43:45 -07:00
parent 96e8b060eb
commit cad8425c7b
4 changed files with 118 additions and 75 deletions

View file

@ -91,9 +91,11 @@ AvatarManager::AvatarManager(QObject* parent) :
_transitConfig._triggerDistance = AVATAR_TRANSIT_TRIGGER_DISTANCE; _transitConfig._triggerDistance = AVATAR_TRANSIT_TRIGGER_DISTANCE;
_transitConfig._framesPerMeter = AVATAR_TRANSIT_FRAMES_PER_METER; _transitConfig._framesPerMeter = AVATAR_TRANSIT_FRAMES_PER_METER;
_transitConfig._isDistanceBased = true; _transitConfig._isDistanceBased = true;
_transitConfig._startTransitAnimation = AvatarTransit::TransitAnimation(START_ANIMATION_URL, 30, 0, 10);
_transitConfig._middleTransitAnimation = AvatarTransit::TransitAnimation(MIDDLE_ANIMATION_URL, 30, 11, 0); _transitConfig._startTransitAnimation = AvatarTransit::TransitAnimation(START_ANIMATION_URL, 0, 14);
_transitConfig._endTransitAnimation = AvatarTransit::TransitAnimation(END_ANIMATION_URL, 30, 12, 38); _transitConfig._middleTransitAnimation = AvatarTransit::TransitAnimation(MIDDLE_ANIMATION_URL, 15, 0);
_transitConfig._endTransitAnimation = AvatarTransit::TransitAnimation(END_ANIMATION_URL, 16, 38);
} }
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) { AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
@ -146,27 +148,38 @@ void AvatarManager::playTransitAnimations(AvatarTransit::Status status) {
auto middleAnimation = _transitConfig._middleTransitAnimation; auto middleAnimation = _transitConfig._middleTransitAnimation;
auto endAnimation = _transitConfig._endTransitAnimation; auto endAnimation = _transitConfig._endTransitAnimation;
const float REFERENCE_FPS = 30.0f;
switch (status) { switch (status) {
case AvatarTransit::Status::START_FRAME: case AvatarTransit::Status::START_FRAME:
_myAvatar->overrideAnimation(startAnimation._animationUrl, startAnimation._fps, false, startAnimation._firstFrame, startAnimation._firstFrame + startAnimation._frameCount); qDebug() << "START_FRAME";
_myAvatar->overrideAnimation(startAnimation._animationUrl, REFERENCE_FPS, false, startAnimation._firstFrame, startAnimation._firstFrame + startAnimation._frameCount);
break; break;
case AvatarTransit::Status::START_TRANSIT: case AvatarTransit::Status::START_TRANSIT:
_myAvatar->overrideAnimation(middleAnimation._animationUrl, middleAnimation._fps, false, middleAnimation._firstFrame, middleAnimation._firstFrame + middleAnimation._frameCount); qDebug() << "START_TRANSIT";
_myAvatar->overrideAnimation(middleAnimation._animationUrl, REFERENCE_FPS, false, middleAnimation._firstFrame, middleAnimation._firstFrame + middleAnimation._frameCount);
break; break;
case AvatarTransit::Status::END_TRANSIT: case AvatarTransit::Status::END_TRANSIT:
_myAvatar->overrideAnimation(endAnimation._animationUrl, endAnimation._fps, false, endAnimation._firstFrame, endAnimation._firstFrame + endAnimation._frameCount); qDebug() << "END_TRANSIT";
_myAvatar->overrideAnimation(endAnimation._animationUrl, REFERENCE_FPS, false, endAnimation._firstFrame, endAnimation._firstFrame + endAnimation._frameCount);
break; break;
case AvatarTransit::Status::END_FRAME: case AvatarTransit::Status::END_FRAME:
qDebug() << "END_FRAME";
_myAvatar->restoreAnimation(); _myAvatar->restoreAnimation();
break; break;
case AvatarTransit::Status::IDLE:
break;
case AvatarTransit::Status::TRANSITING:
break;
} }
} }
void AvatarManager::updateMyAvatar(float deltaTime) { void AvatarManager::updateMyAvatar(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()"); PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
AvatarTransit::Status status = _myAvatar->updateTransit(_myAvatar->getWorldPosition(), _transitConfig); AvatarTransit::Status status = _myAvatar->updateTransit(deltaTime, _myAvatar->getWorldPosition(), _transitConfig);
if (_transitConfig._playAnimation) { if (_transitConfig._playAnimation) {
playTransitAnimations(status); playTransitAnimations(status);
@ -295,7 +308,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
} }
// smooth other avatars positions // smooth other avatars positions
{ {
avatar->_transit.update(avatar->_globalPosition, _transitConfig); avatar->_transit.update(deltaTime, avatar->_globalPosition, _transitConfig);
} }
avatar->simulate(deltaTime, inView); avatar->simulate(deltaTime, inView);
@ -912,3 +925,36 @@ void AvatarManager::setAvatarSortCoefficient(const QString& name, const QScriptV
_transitConfig._playAnimation = data["playAnimation"].toBool(); _transitConfig._playAnimation = data["playAnimation"].toBool();
} }
} }
AvatarTransit::TransitAnimation AvatarManager::getAnimationFromJsonObject(const QJsonObject& object) {
QString animationUrl;
int firstFrame = 0;
int frameCount = 0;
if (object.contains("animationUrl")) {
animationUrl = object["animationUrl"].toString();
}
if (object.contains("firstFrame")) {
firstFrame = object["firstFrame"].toInt();
}
if (object.contains("frameCount")) {
frameCount = object["frameCount"].toInt();
}
return AvatarTransit::TransitAnimation(animationUrl, firstFrame, frameCount);
}
void AvatarManager::setAvatarTransitAnimationData(const QVariantMap& data) {
AvatarTransit::TransitAnimation startAnimation, middleAnimation, endAnimation;
if (data.contains("startAnimation")) {
QJsonObject object = data["startAnimation"].toJsonObject();
_transitConfig._startTransitAnimation = getAnimationFromJsonObject(object);
}
if (data.contains("middleAnimation")) {
QJsonObject object = data["middleAnimation"].toJsonObject();
_transitConfig._middleTransitAnimation = getAnimationFromJsonObject(object);
}
if (data.contains("endAnimation")) {
QJsonObject object = data["endAnimation"].toJsonObject();
_transitConfig._endTransitAnimation = getAnimationFromJsonObject(object);
}
}

View file

@ -180,6 +180,7 @@ public:
Q_INVOKABLE QVariantMap getAvatarTransitData(); Q_INVOKABLE QVariantMap getAvatarTransitData();
Q_INVOKABLE void setAvatarTransitData(const QVariantMap& data); Q_INVOKABLE void setAvatarTransitData(const QVariantMap& data);
Q_INVOKABLE void setAvatarTransitAnimationData(const QVariantMap& data);
float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); } float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); }
int getIdentityRequestsSent() const { return _identityRequestsSent; } int getIdentityRequestsSent() const { return _identityRequestsSent; }
@ -208,6 +209,8 @@ private:
void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override; void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
void playTransitAnimations(AvatarTransit::Status status); void playTransitAnimations(AvatarTransit::Status status);
AvatarTransit::TransitAnimation getAnimationFromJsonObject(const QJsonObject& object);
QVector<AvatarSharedPointer> _avatarsToFade; QVector<AvatarSharedPointer> _avatarsToFade;
QVector<AvatarSharedPointer> _avatarsToCopy; QVector<AvatarSharedPointer> _avatarsToCopy;

View file

@ -113,70 +113,63 @@ void Avatar::setShowNamesAboveHeads(bool show) {
showNamesAboveHeads = show; showNamesAboveHeads = show;
} }
AvatarTransit::Status AvatarTransit::update(const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) { AvatarTransit::Status AvatarTransit::update(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) {
glm::vec3 currentPosition = _isTransiting ? _currentPosition : avatarPosition; glm::vec3 currentPosition = _isTransiting ? _currentPosition : avatarPosition;
float oneFrameDistance = glm::length(currentPosition - _lastPosition); float oneFrameDistance = glm::length(currentPosition - _lastPosition);
if (oneFrameDistance > config._triggerDistance && !_isTransiting) { const float MAX_TRANSIT_DISTANCE = 20.0f;
start(_lastPosition, currentPosition, config); if (oneFrameDistance > config._triggerDistance && oneFrameDistance < MAX_TRANSIT_DISTANCE && !_isTransiting) {
start(deltaTime, _lastPosition, currentPosition, config);
} }
return updatePosition(avatarPosition); _lastPosition = currentPosition;
return updatePosition(deltaTime);
} }
void AvatarTransit::start(const glm::vec3& startPosition, const glm::vec3& endPosition, const AvatarTransit::TransitConfig& config) { void AvatarTransit::start(float deltaTime, const glm::vec3& startPosition, const glm::vec3& endPosition, const AvatarTransit::TransitConfig& config) {
_startPosition = startPosition; _startPosition = startPosition;
_endPosition = endPosition; _endPosition = endPosition;
_framesBefore = config._startTransitAnimation._frameCount;
_framesAfter = config._endTransitAnimation._frameCount; _transitLine = endPosition - startPosition;
_step = 0; _totalDistance = glm::length(_transitLine);
if (!config._isDistanceBased) { const float REFERENCE_FRAMES_PER_SECOND = 30.0f;
calculateSteps(config._totalFrames);
} else { int framesBefore = config._playAnimation ? config._startTransitAnimation._frameCount : 0;
float distance = glm::length(_endPosition - _startPosition); int framesAfter = config._playAnimation ? config._endTransitAnimation._frameCount : 0;
calculateSteps(config._framesPerMeter * distance); _timeBefore = (float)framesBefore / REFERENCE_FRAMES_PER_SECOND;
} _timeAfter = (float)framesAfter / REFERENCE_FRAMES_PER_SECOND;
int transitFrames = (!config._isDistanceBased) ? config._totalFrames : config._framesPerMeter * _totalDistance;
_transitTime = (float)transitFrames / REFERENCE_FRAMES_PER_SECOND;
_totalTime = _transitTime + _timeBefore + _timeAfter;
_currentTime = 0.0f;
_isTransiting = true; _isTransiting = true;
} }
void AvatarTransit::calculateSteps(int stepCount) { AvatarTransit::Status AvatarTransit::updatePosition(float deltaTime) {
glm::vec3 startPosition = _isTransiting ? _transitSteps[_step] : _startPosition;
_transitSteps.clear();
glm::vec3 transitLine = _endPosition - startPosition;
glm::vec3 direction = glm::normalize(transitLine);
glm::vec3 stepVector = (glm::length(transitLine) / stepCount) * direction;
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);
}
}
}
AvatarTransit::Status AvatarTransit::updatePosition(const glm::vec3& avatarPosition) {
Status status = Status::IDLE; Status status = Status::IDLE;
_lastPosition = _isTransiting ? _currentPosition : avatarPosition;
if (_isTransiting) { if (_isTransiting) {
int lastIdx = (int)_transitSteps.size() - 1; float nextTime = _currentTime + deltaTime;
_isTransiting = _step < lastIdx; glm::vec3 newPosition;
if (_isTransiting) { if (nextTime < _timeBefore) {
if (_step == 0) { _currentPosition = _startPosition;
if (_currentTime == 0) {
status = Status::START_FRAME; status = Status::START_FRAME;
qDebug() << "Transit starting"; }
} else if (_step == _framesBefore - 1) { } else if (nextTime >= _totalTime - _timeAfter) {
status = Status::START_TRANSIT; if (_currentTime < _totalTime - _timeAfter) {
} else if (_step == (int)_transitSteps.size() - _framesAfter) {
status = Status::END_TRANSIT; status = Status::END_TRANSIT;
} } else if (nextTime >= _totalTime) {
_step++;
_currentPosition = _transitSteps[_step];
} else {
status = Status::END_FRAME; status = Status::END_FRAME;
qDebug() << "Transit ending"; _isTransiting = false;
} }
_currentPosition = _endPosition;
} else {
if (_currentTime <= _timeBefore) {
status = Status::START_TRANSIT;
}
float percentageIntoTransit = (nextTime - _timeBefore) / _transitTime;
_currentPosition = _startPosition + percentageIntoTransit * _transitLine;
}
_currentTime = nextTime;
} }
return status; return status;
} }
@ -521,7 +514,6 @@ void Avatar::simulate(float deltaTime, bool inView) {
if (_transit.isTransiting()) { if (_transit.isTransiting()) {
glm::vec3 nextPosition; glm::vec3 nextPosition;
if (_transit.getNextPosition(nextPosition)) { if (_transit.getNextPosition(nextPosition)) {
// setWorldPosition(nextPosition);
_globalPosition = nextPosition; _globalPosition = nextPosition;
_globalPositionChanged = usecTimestampNow(); _globalPositionChanged = usecTimestampNow();
if (!hasParent()) { if (!hasParent()) {
@ -540,7 +532,7 @@ void Avatar::simulate(float deltaTime, bool inView) {
PROFILE_RANGE(simulation, "updateJoints"); PROFILE_RANGE(simulation, "updateJoints");
if (inView) { if (inView) {
Head* head = getHead(); Head* head = getHead();
if (true) { if (_hasNewJointData || _transit.isTransiting()) {
_skeletonModel->getRig().copyJointsFromJointData(_jointData); _skeletonModel->getRig().copyJointsFromJointData(_jointData);
glm::mat4 rootTransform = glm::scale(_skeletonModel->getScale()) * glm::translate(_skeletonModel->getOffset()); glm::mat4 rootTransform = glm::scale(_skeletonModel->getScale()) * glm::translate(_skeletonModel->getOffset());
_skeletonModel->getRig().computeExternalPoses(rootTransform); _skeletonModel->getRig().computeExternalPoses(rootTransform);
@ -1954,9 +1946,9 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const {
} }
} }
AvatarTransit::Status Avatar::updateTransit(const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) { AvatarTransit::Status Avatar::updateTransit(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) {
std::lock_guard<std::mutex> lock(_transitLock); std::lock_guard<std::mutex> lock(_transitLock);
return _transit.update(avatarPosition, config); return _transit.update(deltaTime, avatarPosition, config);
} }
void Avatar::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) { void Avatar::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {

View file

@ -63,12 +63,11 @@ public:
struct TransitAnimation { struct TransitAnimation {
TransitAnimation() {}; TransitAnimation() {};
TransitAnimation(const QString& animationUrl, int fps, int firstFrame, int frameCount) : TransitAnimation(const QString& animationUrl, int firstFrame, int frameCount) :
_firstFrame(firstFrame), _frameCount(frameCount), _animationUrl(animationUrl), _fps(fps) {}; _firstFrame(firstFrame), _frameCount(frameCount), _animationUrl(animationUrl) {};
int _firstFrame; int _firstFrame;
int _frameCount; int _frameCount;
QString _animationUrl; QString _animationUrl;
int _fps;
}; };
struct TransitConfig { struct TransitConfig {
@ -83,27 +82,30 @@ public:
TransitAnimation _endTransitAnimation; TransitAnimation _endTransitAnimation;
}; };
AvatarTransit() {}; AvatarTransit() {};
Status update(const glm::vec3& avatarPosition, const TransitConfig& config); Status update(float deltaTime, const glm::vec3& avatarPosition, const TransitConfig& config);
bool isTransiting() { return _isTransiting; }; bool isTransiting() { return _isTransiting; };
glm::vec3 getCurrentPosition() { return _currentPosition; }; glm::vec3 getCurrentPosition() { return _currentPosition; };
bool getNextPosition(glm::vec3& nextPosition); bool getNextPosition(glm::vec3& nextPosition);
int getCurrentStep() { return _step; };
private: private:
void calculateSteps(int stepCount); Status updatePosition(float deltaTime);
Status updatePosition(const glm::vec3& avatarPosition); void start(float deltaTime, const glm::vec3& startPosition, const glm::vec3& endPosition, const TransitConfig& config);
void start(const glm::vec3& startPosition, const glm::vec3& endPosition, const TransitConfig& config);
bool _isTransiting{ false }; bool _isTransiting{ false };
glm::vec3 _startPosition; glm::vec3 _startPosition;
glm::vec3 _endPosition; glm::vec3 _endPosition;
glm::vec3 _currentPosition; glm::vec3 _currentPosition;
int _framesBefore { 0 };
int _framesAfter { 0 };
std::vector<glm::vec3> _transitSteps;
glm::vec3 _lastPosition; glm::vec3 _lastPosition;
int _step { 0 };
glm::vec3 _transitLine;
float _totalDistance { 0.0f };
float _totalTime { 0.0f };
float _currentTime { 0.0f };
float _transitTime { 0.0f };
float _timeBefore { 0.0f };
float _timeAfter { 0.0f };
}; };
class Avatar : public AvatarData, public scriptable::ModelProvider { class Avatar : public AvatarData, public scriptable::ModelProvider {
@ -419,7 +421,7 @@ public:
std::shared_ptr<AvatarTransit> getTransit() { return std::make_shared<AvatarTransit>(_transit); }; std::shared_ptr<AvatarTransit> getTransit() { return std::make_shared<AvatarTransit>(_transit); };
AvatarTransit::Status updateTransit(const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config); AvatarTransit::Status updateTransit(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config);
signals: signals:
void targetScaleChanged(float targetScale); void targetScaleChanged(float targetScale);