Merge pull request #10136 from mittens/21217

Added quadratic ease-in-and-out smoothing to remote avatars
This commit is contained in:
Seth Alves 2017-04-18 10:05:48 -07:00 committed by GitHub
commit b2de5ebdaf
2 changed files with 79 additions and 4 deletions

View file

@ -96,6 +96,14 @@ Avatar::Avatar(RigPointer rig) :
_lastOrientation(), _lastOrientation(),
_worldUpDirection(DEFAULT_UP_DIRECTION), _worldUpDirection(DEFAULT_UP_DIRECTION),
_moving(false), _moving(false),
_smoothPositionTime(SMOOTH_TIME_POSITION),
_smoothPositionTimer(std::numeric_limits<float>::max()),
_smoothOrientationTime(SMOOTH_TIME_ORIENTATION),
_smoothOrientationTimer(std::numeric_limits<float>::max()),
_smoothPositionInitial(),
_smoothPositionTarget(),
_smoothOrientationInitial(),
_smoothOrientationTarget(),
_initialized(false), _initialized(false),
_voiceSphereID(GeometryCache::UNKNOWN_ID) _voiceSphereID(GeometryCache::UNKNOWN_ID)
{ {
@ -349,6 +357,33 @@ void Avatar::simulate(float deltaTime, bool inView) {
_simulationInViewRate.increment(); _simulationInViewRate.increment();
} }
if (!isMyAvatar()) {
if (_smoothPositionTimer < _smoothPositionTime) {
// Smooth the remote avatar movement.
_smoothPositionTimer += deltaTime;
if (_smoothPositionTimer < _smoothPositionTime) {
AvatarData::setPosition(
lerp(_smoothPositionInitial,
_smoothPositionTarget,
easeInOutQuad(glm::clamp(_smoothPositionTimer / _smoothPositionTime, 0.0f, 1.0f)))
);
updateAttitude();
}
}
if (_smoothOrientationTimer < _smoothOrientationTime) {
// Smooth the remote avatar movement.
_smoothOrientationTimer += deltaTime;
if (_smoothOrientationTimer < _smoothOrientationTime) {
AvatarData::setOrientation(
slerp(_smoothOrientationInitial,
_smoothOrientationTarget,
easeInOutQuad(glm::clamp(_smoothOrientationTimer / _smoothOrientationTime, 0.0f, 1.0f)))
);
updateAttitude();
}
}
}
PerformanceTimer perfTimer("simulate"); PerformanceTimer perfTimer("simulate");
{ {
@ -1361,13 +1396,31 @@ glm::quat Avatar::getUncachedRightPalmRotation() const {
} }
void Avatar::setPosition(const glm::vec3& position) { void Avatar::setPosition(const glm::vec3& position) {
AvatarData::setPosition(position); if (isMyAvatar()) {
updateAttitude(); // This is the local avatar, no need to handle any position smoothing.
AvatarData::setPosition(position);
updateAttitude();
return;
}
// Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position.
_smoothPositionInitial = getPosition();
_smoothPositionTarget = position;
_smoothPositionTimer = 0.0f;
} }
void Avatar::setOrientation(const glm::quat& orientation) { void Avatar::setOrientation(const glm::quat& orientation) {
AvatarData::setOrientation(orientation); if (isMyAvatar()) {
updateAttitude(); // This is the local avatar, no need to handle any position smoothing.
AvatarData::setOrientation(orientation);
updateAttitude();
return;
}
// Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position.
_smoothOrientationInitial = getOrientation();
_smoothOrientationTarget = orientation;
_smoothOrientationTimer = 0.0f;
} }
void Avatar::updatePalms() { void Avatar::updatePalms() {

View file

@ -230,6 +230,16 @@ public:
bool hasNewJointData() const { return _hasNewJointData; } bool hasNewJointData() const { return _hasNewJointData; }
inline float easeInOutQuad(float lerpValue) {
assert(!((lerpValue < 0.0f) || (lerpValue > 1.0f)));
if (lerpValue < 0.5f) {
return (2.0f * lerpValue * lerpValue);
}
return (lerpValue*(4.0f - 2.0f * lerpValue) - 1.0f);
}
public slots: public slots:
// FIXME - these should be migrated to use Pose data instead // FIXME - these should be migrated to use Pose data instead
@ -244,6 +254,9 @@ public slots:
protected: protected:
friend class AvatarManager; friend class AvatarManager;
const float SMOOTH_TIME_POSITION = 0.125f;
const float SMOOTH_TIME_ORIENTATION = 0.075f;
virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send. virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send.
QString _empty{}; QString _empty{};
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter! virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter!
@ -313,6 +326,15 @@ protected:
RateCounter<> _skeletonModelSimulationRate; RateCounter<> _skeletonModelSimulationRate;
RateCounter<> _jointDataSimulationRate; RateCounter<> _jointDataSimulationRate;
// Smoothing data for blending from one position/orientation to another on remote agents.
float _smoothPositionTime;
float _smoothPositionTimer;
float _smoothOrientationTime;
float _smoothOrientationTimer;
glm::vec3 _smoothPositionInitial;
glm::vec3 _smoothPositionTarget;
glm::quat _smoothOrientationInitial;
glm::quat _smoothOrientationTarget;
private: private:
class AvatarEntityDataHash { class AvatarEntityDataHash {