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._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);
_transitConfig._startTransitAnimation = AvatarTransit::TransitAnimation(START_ANIMATION_URL, 0, 14);
_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) {
@ -145,28 +147,39 @@ void AvatarManager::playTransitAnimations(AvatarTransit::Status status) {
auto startAnimation = _transitConfig._startTransitAnimation;
auto middleAnimation = _transitConfig._middleTransitAnimation;
auto endAnimation = _transitConfig._endTransitAnimation;
const float REFERENCE_FPS = 30.0f;
switch (status) {
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;
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;
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;
case AvatarTransit::Status::END_FRAME:
qDebug() << "END_FRAME";
_myAvatar->restoreAnimation();
break;
case AvatarTransit::Status::IDLE:
break;
case AvatarTransit::Status::TRANSITING:
break;
}
}
void AvatarManager::updateMyAvatar(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
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) {
playTransitAnimations(status);
@ -295,7 +308,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
}
// smooth other avatars positions
{
avatar->_transit.update(avatar->_globalPosition, _transitConfig);
avatar->_transit.update(deltaTime, avatar->_globalPosition, _transitConfig);
}
avatar->simulate(deltaTime, inView);
@ -911,4 +924,37 @@ void AvatarManager::setAvatarSortCoefficient(const QString& name, const QScriptV
if (data.contains("playAnimation")) {
_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 void setAvatarTransitData(const QVariantMap& data);
Q_INVOKABLE void setAvatarTransitAnimationData(const QVariantMap& data);
float getMyAvatarSendRate() const { return _myAvatarSendRate.rate(); }
int getIdentityRequestsSent() const { return _identityRequestsSent; }
@ -208,6 +209,8 @@ private:
void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
void playTransitAnimations(AvatarTransit::Status status);
AvatarTransit::TransitAnimation getAnimationFromJsonObject(const QJsonObject& object);
QVector<AvatarSharedPointer> _avatarsToFade;
QVector<AvatarSharedPointer> _avatarsToCopy;

View file

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

View file

@ -63,12 +63,11 @@ public:
struct TransitAnimation {
TransitAnimation() {};
TransitAnimation(const QString& animationUrl, int fps, int firstFrame, int frameCount) :
_firstFrame(firstFrame), _frameCount(frameCount), _animationUrl(animationUrl), _fps(fps) {};
TransitAnimation(const QString& animationUrl, int firstFrame, int frameCount) :
_firstFrame(firstFrame), _frameCount(frameCount), _animationUrl(animationUrl) {};
int _firstFrame;
int _frameCount;
QString _animationUrl;
int _fps;
};
struct TransitConfig {
@ -83,27 +82,30 @@ public:
TransitAnimation _endTransitAnimation;
};
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; };
glm::vec3 getCurrentPosition() { return _currentPosition; };
bool getNextPosition(glm::vec3& nextPosition);
int getCurrentStep() { return _step; };
private:
void calculateSteps(int stepCount);
Status updatePosition(const glm::vec3& avatarPosition);
void start(const glm::vec3& startPosition, const glm::vec3& endPosition, const TransitConfig& config);
Status updatePosition(float deltaTime);
void start(float deltaTime, 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<glm::vec3> _transitSteps;
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 {
@ -419,7 +421,7 @@ public:
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:
void targetScaleChanged(float targetScale);