mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-11 00:26:35 +02:00
Merge pull request #14187 from luiscuenca/transitAddAnimation
Add animations to Avatar Transit
This commit is contained in:
commit
fac9188dfb
12 changed files with 422 additions and 111 deletions
140
interface/resources/avatar/network-animation.json
Normal file
140
interface/resources/avatar/network-animation.json
Normal file
|
@ -0,0 +1,140 @@
|
|||
{
|
||||
"version": "1.1",
|
||||
"root": {
|
||||
"id": "userAnimStateMachine",
|
||||
"type": "stateMachine",
|
||||
"data": {
|
||||
"currentState": "idleAnim",
|
||||
"states": [
|
||||
{
|
||||
"id": "idleAnim",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "postTransitAnim", "state": "postTransitAnim" },
|
||||
{ "var": "preTransitAnim", "state": "preTransitAnim" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "preTransitAnim",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "idleAnim", "state": "idleAnim" },
|
||||
{ "var": "transitAnim", "state": "transitAnim" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "transitAnim",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "preTransitAnim", "state": "preTransitAnim" },
|
||||
{ "var": "postTransitAnim", "state": "postTransitAnim" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "postTransitAnim",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "transitAnim", "state": "transitAnim" },
|
||||
{ "var": "idleAnim", "state": "idleAnim" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "userAnimA",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "idleAnim", "state": "idleAnim" },
|
||||
{ "var": "userAnimB", "state": "userAnimB" }
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "userAnimB",
|
||||
"interpTarget": 6,
|
||||
"interpDuration": 6,
|
||||
"transitions": [
|
||||
{ "var": "idleAnim", "state": "idleAnim" },
|
||||
{ "var": "userAnimA", "state": "userAnimA" }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"id": "idleAnim",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/idle.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 90.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "preTransitAnim",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-content.s3.amazonaws.com/luis/test_scripts/transitApp/animations/teleport01_warp.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 10.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "transitAnim",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-content.s3.amazonaws.com/luis/test_scripts/transitApp/animations/teleport01_warp.fbx",
|
||||
"startFrame": 11.0,
|
||||
"endFrame": 11.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "postTransitAnim",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "https://hifi-content.s3.amazonaws.com/luis/test_scripts/transitApp/animations/teleport01_warp.fbx",
|
||||
"startFrame": 22.0,
|
||||
"endFrame": 49.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": false
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "userAnimA",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/idle.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 90.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"id": "userAnimB",
|
||||
"type": "clip",
|
||||
"data": {
|
||||
"url": "qrc:///avatar/animations/idle.fbx",
|
||||
"startFrame": 0.0,
|
||||
"endFrame": 90.0,
|
||||
"timeScale": 1.0,
|
||||
"loopFlag": true
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -135,7 +135,7 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
|
|||
glm::vec3 palmPosition;
|
||||
glm::quat palmRotation;
|
||||
|
||||
bool isTransitingWithAvatar = holdingAvatar->getTransit()->isTransiting();
|
||||
bool isTransitingWithAvatar = holdingAvatar->getTransit()->isActive();
|
||||
if (isTransitingWithAvatar != _isTransitingWithAvatar) {
|
||||
_isTransitingWithAvatar = isTransitingWithAvatar;
|
||||
auto ownerEntity = _ownerEntity.lock();
|
||||
|
@ -424,7 +424,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
|||
if (ownerEntity) {
|
||||
ownerEntity->setDynamicDataDirty(true);
|
||||
ownerEntity->setDynamicDataNeedsTransmit(true);
|
||||
ownerEntity->setTransitingWithAvatar(myAvatar->getTransit()->isTransiting());
|
||||
ownerEntity->setTransitingWithAvatar(myAvatar->getTransit()->isActive());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -71,14 +71,12 @@ AvatarManager::AvatarManager(QObject* parent) :
|
|||
}
|
||||
});
|
||||
|
||||
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 = 1; // Based on testing
|
||||
|
||||
_transitConfig._totalFrames = AVATAR_TRANSIT_FRAME_COUNT;
|
||||
_transitConfig._triggerDistance = AVATAR_TRANSIT_TRIGGER_DISTANCE;
|
||||
_transitConfig._minTriggerDistance = AVATAR_TRANSIT_MIN_TRIGGER_DISTANCE;
|
||||
_transitConfig._maxTriggerDistance = AVATAR_TRANSIT_MAX_TRIGGER_DISTANCE;
|
||||
_transitConfig._framesPerMeter = AVATAR_TRANSIT_FRAMES_PER_METER;
|
||||
_transitConfig._isDistanceBased = true;
|
||||
_transitConfig._isDistanceBased = AVATAR_TRANSIT_DISTANCE_BASED;
|
||||
_transitConfig._abortDistance = AVATAR_TRANSIT_ABORT_DISTANCE;
|
||||
}
|
||||
|
||||
AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer<Node>& mixerWeakPointer) {
|
||||
|
@ -126,13 +124,39 @@ void AvatarManager::setSpace(workload::SpacePointer& space ) {
|
|||
_space = space;
|
||||
}
|
||||
|
||||
void AvatarManager::handleTransitAnimations(AvatarTransit::Status status) {
|
||||
switch (status) {
|
||||
case AvatarTransit::Status::STARTED:
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("preTransitAnim");
|
||||
break;
|
||||
case AvatarTransit::Status::START_TRANSIT:
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("transitAnim");
|
||||
break;
|
||||
case AvatarTransit::Status::END_TRANSIT:
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("postTransitAnim");
|
||||
break;
|
||||
case AvatarTransit::Status::ENDED:
|
||||
_myAvatar->getSkeletonModel()->getRig().triggerNetworkAnimation("idleAnim");
|
||||
break;
|
||||
case AvatarTransit::Status::PRE_TRANSIT:
|
||||
break;
|
||||
case AvatarTransit::Status::POST_TRANSIT:
|
||||
break;
|
||||
case AvatarTransit::Status::IDLE:
|
||||
break;
|
||||
case AvatarTransit::Status::TRANSITING:
|
||||
break;
|
||||
case AvatarTransit::Status::ABORT_TRANSIT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarManager::updateMyAvatar(float deltaTime) {
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
|
||||
|
||||
AvatarTransit::Status status = _myAvatar->updateTransit(deltaTime, _myAvatar->getNextPosition(), _transitConfig);
|
||||
bool sendFirstTransitPackage = (status == AvatarTransit::Status::START_TRANSIT);
|
||||
bool blockTransitData = (status == AvatarTransit::Status::TRANSITING);
|
||||
AvatarTransit::Status status = _myAvatar->updateTransit(deltaTime, _myAvatar->getNextPosition(), _myAvatar->getSensorToWorldScale(), _transitConfig);
|
||||
handleTransitAnimations(status);
|
||||
|
||||
_myAvatar->update(deltaTime);
|
||||
render::Transaction transaction;
|
||||
|
@ -142,18 +166,13 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
|
|||
quint64 now = usecTimestampNow();
|
||||
quint64 dt = now - _lastSendAvatarDataTime;
|
||||
|
||||
|
||||
if (sendFirstTransitPackage || (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS && !_myAvatarDataPacketsPaused && !blockTransitData)) {
|
||||
if (dt > MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS && !_myAvatarDataPacketsPaused) {
|
||||
// send head/hand data to the avatar mixer and voxel server
|
||||
PerformanceTimer perfTimer("send");
|
||||
if (sendFirstTransitPackage) {
|
||||
_myAvatar->overrideNextPackagePositionData(_myAvatar->getTransit()->getEndPosition());
|
||||
}
|
||||
PerformanceTimer perfTimer("send");
|
||||
_myAvatar->sendAvatarDataPacket();
|
||||
_lastSendAvatarDataTime = now;
|
||||
_myAvatarSendRate.increment();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -267,7 +286,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
if (inView && avatar->hasNewJointData()) {
|
||||
numAvatarsUpdated++;
|
||||
}
|
||||
auto transitStatus = avatar->_transit.update(deltaTime, avatar->_globalPosition, _transitConfig);
|
||||
auto transitStatus = avatar->_transit.update(deltaTime, avatar->_serverPosition, _transitConfig);
|
||||
if (avatar->getIsNewAvatar() && (transitStatus == AvatarTransit::Status::START_TRANSIT || transitStatus == AvatarTransit::Status::ABORT_TRANSIT)) {
|
||||
avatar->_transit.reset();
|
||||
avatar->setIsNewAvatar(false);
|
||||
|
|
|
@ -221,6 +221,7 @@ private:
|
|||
// frequently grabs a read lock on the hash to get a given avatar by ID
|
||||
void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar,
|
||||
KillAvatarReason removalReason = KillAvatarReason::NoReason) override;
|
||||
void handleTransitAnimations(AvatarTransit::Status status);
|
||||
|
||||
QVector<AvatarSharedPointer> _avatarsToFade;
|
||||
|
||||
|
|
|
@ -1058,7 +1058,6 @@ void MyAvatar::updateSensorToWorldMatrix() {
|
|||
updateJointFromController(controller::Action::RIGHT_HAND, _controllerRightHandMatrixCache);
|
||||
|
||||
if (hasSensorToWorldScaleChanged) {
|
||||
setTransitScale(sensorToWorldScale);
|
||||
emit sensorToWorldScaleChanged(sensorToWorldScale);
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,8 @@ public:
|
|||
bool getMirrorFlag() const { return _mirrorFlag; }
|
||||
void setMirrorFlag(bool mirrorFlag) { _mirrorFlag = mirrorFlag; }
|
||||
|
||||
float getFrame() const { return _frame; }
|
||||
|
||||
void loadURL(const QString& url);
|
||||
protected:
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "AnimSkeleton.h"
|
||||
#include "AnimUtil.h"
|
||||
#include "IKTarget.h"
|
||||
#include "PathUtils.h"
|
||||
|
||||
|
||||
static int nextRigId = 1;
|
||||
|
@ -133,6 +134,30 @@ void Rig::overrideAnimation(const QString& url, float fps, bool loop, float firs
|
|||
_animVars.set("userAnimB", clipNodeEnum == UserAnimState::B);
|
||||
}
|
||||
|
||||
void Rig::triggerNetworkAnimation(const QString& animName) {
|
||||
_networkVars.set("idleAnim", false);
|
||||
_networkVars.set("preTransitAnim", false);
|
||||
_networkVars.set("transitAnim", false);
|
||||
_networkVars.set("postTransitAnim", false);
|
||||
_sendNetworkNode = true;
|
||||
|
||||
if (animName == "idleAnim") {
|
||||
_networkVars.set("idleAnim", true);
|
||||
_networkAnimState.clipNodeEnum = NetworkAnimState::Idle;
|
||||
_sendNetworkNode = false;
|
||||
} else if (animName == "preTransitAnim") {
|
||||
_networkVars.set("preTransitAnim", true);
|
||||
_networkAnimState.clipNodeEnum = NetworkAnimState::PreTransit;
|
||||
} else if (animName == "transitAnim") {
|
||||
_networkVars.set("transitAnim", true);
|
||||
_networkAnimState.clipNodeEnum = NetworkAnimState::Transit;
|
||||
} else if (animName == "postTransitAnim") {
|
||||
_networkVars.set("postTransitAnim", true);
|
||||
_networkAnimState.clipNodeEnum = NetworkAnimState::PostTransit;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Rig::restoreAnimation() {
|
||||
if (_userAnimState.clipNodeEnum != UserAnimState::None) {
|
||||
_userAnimState.clipNodeEnum = UserAnimState::None;
|
||||
|
@ -144,6 +169,16 @@ void Rig::restoreAnimation() {
|
|||
}
|
||||
}
|
||||
|
||||
void Rig::restoreNetworkAnimation() {
|
||||
if (_networkAnimState.clipNodeEnum != NetworkAnimState::Idle) {
|
||||
_networkAnimState.clipNodeEnum = NetworkAnimState::Idle;
|
||||
_networkVars.set("idleAnim", true);
|
||||
_networkVars.set("preTransitAnim", false);
|
||||
_networkVars.set("transitAnim", false);
|
||||
_networkVars.set("postTransitAnim", false);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList Rig::getAnimationRoles() const {
|
||||
if (_animNode) {
|
||||
QStringList list;
|
||||
|
@ -208,11 +243,17 @@ void Rig::restoreRoleAnimation(const QString& role) {
|
|||
void Rig::destroyAnimGraph() {
|
||||
_animSkeleton.reset();
|
||||
_animLoader.reset();
|
||||
_networkLoader.reset();
|
||||
_animNode.reset();
|
||||
_internalPoseSet._relativePoses.clear();
|
||||
_internalPoseSet._absolutePoses.clear();
|
||||
_internalPoseSet._overridePoses.clear();
|
||||
_internalPoseSet._overrideFlags.clear();
|
||||
_networkNode.reset();
|
||||
_networkPoseSet._relativePoses.clear();
|
||||
_networkPoseSet._absolutePoses.clear();
|
||||
_networkPoseSet._overridePoses.clear();
|
||||
_networkPoseSet._overrideFlags.clear();
|
||||
_numOverrides = 0;
|
||||
_leftEyeJointChildren.clear();
|
||||
_rightEyeJointChildren.clear();
|
||||
|
@ -229,14 +270,24 @@ void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOff
|
|||
|
||||
_internalPoseSet._relativePoses.clear();
|
||||
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
_networkPoseSet._relativePoses.clear();
|
||||
_networkPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
||||
buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
|
||||
buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses);
|
||||
|
||||
_internalPoseSet._overridePoses.clear();
|
||||
_internalPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
||||
_internalPoseSet._overrideFlags.clear();
|
||||
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||
|
||||
_networkPoseSet._overridePoses.clear();
|
||||
_networkPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
||||
_networkPoseSet._overrideFlags.clear();
|
||||
_networkPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||
|
||||
_numOverrides = 0;
|
||||
|
||||
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
|
||||
|
@ -270,6 +321,18 @@ void Rig::reset(const FBXGeometry& geometry) {
|
|||
|
||||
_internalPoseSet._overrideFlags.clear();
|
||||
_internalPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||
|
||||
_networkPoseSet._relativePoses.clear();
|
||||
_networkPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
||||
buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses);
|
||||
|
||||
_networkPoseSet._overridePoses.clear();
|
||||
_networkPoseSet._overridePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
|
||||
_networkPoseSet._overrideFlags.clear();
|
||||
_networkPoseSet._overrideFlags.resize(_animSkeleton->getNumJoints(), false);
|
||||
|
||||
_numOverrides = 0;
|
||||
|
||||
buildAbsoluteRigPoses(_animSkeleton->getRelativeDefaultPoses(), _absoluteDefaultPoses);
|
||||
|
@ -1049,26 +1112,56 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons
|
|||
|
||||
updateAnimationStateHandlers();
|
||||
_animVars.setRigToGeometryTransform(_rigToGeometryTransform);
|
||||
|
||||
if (_networkNode) {
|
||||
_networkVars.setRigToGeometryTransform(_rigToGeometryTransform);
|
||||
}
|
||||
AnimContext context(_enableDebugDrawIKTargets, _enableDebugDrawIKConstraints, _enableDebugDrawIKChains,
|
||||
getGeometryToRigTransform(), rigToWorldTransform);
|
||||
|
||||
// evaluate the animation
|
||||
AnimVariantMap triggersOut;
|
||||
|
||||
AnimVariantMap networkTriggersOut;
|
||||
_internalPoseSet._relativePoses = _animNode->evaluate(_animVars, context, deltaTime, triggersOut);
|
||||
if (_networkNode) {
|
||||
_networkPoseSet._relativePoses = _networkNode->evaluate(_networkVars, context, deltaTime, networkTriggersOut);
|
||||
const float NETWORK_ANIMATION_BLEND_FRAMES = 6.0f;
|
||||
float alpha = 1.0f;
|
||||
std::shared_ptr<AnimClip> clip;
|
||||
if (_networkAnimState.clipNodeEnum == NetworkAnimState::PreTransit) {
|
||||
clip = std::dynamic_pointer_cast<AnimClip>(_networkNode->findByName("preTransitAnim"));
|
||||
if (clip) {
|
||||
alpha = (clip->getFrame() - clip->getStartFrame()) / NETWORK_ANIMATION_BLEND_FRAMES;
|
||||
}
|
||||
} else if (_networkAnimState.clipNodeEnum == NetworkAnimState::PostTransit) {
|
||||
clip = std::dynamic_pointer_cast<AnimClip>(_networkNode->findByName("postTransitAnim"));
|
||||
if (clip) {
|
||||
alpha = (clip->getEndFrame() - clip->getFrame()) / NETWORK_ANIMATION_BLEND_FRAMES;
|
||||
}
|
||||
}
|
||||
if (_sendNetworkNode) {
|
||||
for (size_t i = 0; i < _networkPoseSet._relativePoses.size(); i++) {
|
||||
_networkPoseSet._relativePoses[i].blend(_internalPoseSet._relativePoses[i], (alpha > 1.0f ? 1.0f : alpha));
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((int)_internalPoseSet._relativePoses.size() != _animSkeleton->getNumJoints()) {
|
||||
// animations haven't fully loaded yet.
|
||||
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
}
|
||||
if ((int)_networkPoseSet._relativePoses.size() != _animSkeleton->getNumJoints()) {
|
||||
// animations haven't fully loaded yet.
|
||||
_networkPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
|
||||
}
|
||||
_lastAnimVars = _animVars;
|
||||
_animVars.clearTriggers();
|
||||
_animVars = triggersOut;
|
||||
_networkVars.clearTriggers();
|
||||
_networkVars = networkTriggersOut;
|
||||
_lastContext = context;
|
||||
}
|
||||
applyOverridePoses();
|
||||
buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
|
||||
|
||||
buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses);
|
||||
// copy internal poses to external poses
|
||||
{
|
||||
QWriteLocker writeLock(&_externalPoseSetLock);
|
||||
|
@ -1672,11 +1765,14 @@ void Rig::initAnimGraph(const QUrl& url) {
|
|||
_animGraphURL = url;
|
||||
|
||||
_animNode.reset();
|
||||
_networkNode.reset();
|
||||
|
||||
// load the anim graph
|
||||
_animLoader.reset(new AnimNodeLoader(url));
|
||||
auto networkUrl = PathUtils::resourcesUrl("avatar/network-animation.json");
|
||||
_networkLoader.reset(new AnimNodeLoader(networkUrl));
|
||||
std::weak_ptr<AnimSkeleton> weakSkeletonPtr = _animSkeleton;
|
||||
connect(_animLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr](AnimNode::Pointer nodeIn) {
|
||||
connect(_animLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr, url](AnimNode::Pointer nodeIn) {
|
||||
_animNode = nodeIn;
|
||||
|
||||
// abort load if the previous skeleton was deleted.
|
||||
|
@ -1703,7 +1799,33 @@ void Rig::initAnimGraph(const QUrl& url) {
|
|||
emit onLoadComplete();
|
||||
});
|
||||
connect(_animLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) {
|
||||
qCCritical(animation) << "Error loading" << url.toDisplayString() << "code = " << error << "str =" << str;
|
||||
qCritical(animation) << "Error loading" << url.toDisplayString() << "code = " << error << "str =" << str;
|
||||
});
|
||||
|
||||
connect(_networkLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr, networkUrl](AnimNode::Pointer nodeIn) {
|
||||
_networkNode = nodeIn;
|
||||
// abort load if the previous skeleton was deleted.
|
||||
auto sharedSkeletonPtr = weakSkeletonPtr.lock();
|
||||
if (!sharedSkeletonPtr) {
|
||||
return;
|
||||
}
|
||||
_networkNode->setSkeleton(sharedSkeletonPtr);
|
||||
if (_networkAnimState.clipNodeEnum != NetworkAnimState::Idle) {
|
||||
// restore the user animation we had before reset.
|
||||
NetworkAnimState origState = _networkAnimState;
|
||||
_networkAnimState = { NetworkAnimState::Idle, "", 30.0f, false, 0.0f, 0.0f };
|
||||
if (_networkAnimState.clipNodeEnum == NetworkAnimState::PreTransit) {
|
||||
triggerNetworkAnimation("preTransitAnim");
|
||||
} else if (_networkAnimState.clipNodeEnum == NetworkAnimState::Transit) {
|
||||
triggerNetworkAnimation("transitAnim");
|
||||
} else if (_networkAnimState.clipNodeEnum == NetworkAnimState::PostTransit) {
|
||||
triggerNetworkAnimation("postTransitAnim");
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
connect(_networkLoader.get(), &AnimNodeLoader::error, [networkUrl](int error, QString str) {
|
||||
qCritical(animation) << "Error loading" << networkUrl.toDisplayString() << "code = " << error << "str =" << str;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1782,13 +1904,13 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
|
|||
if (isIndexValid(i)) {
|
||||
// rotations are in absolute rig frame.
|
||||
glm::quat defaultAbsRot = geometryToRigPose.rot() * _animSkeleton->getAbsoluteDefaultPose(i).rot();
|
||||
data.rotation = _internalPoseSet._absolutePoses[i].rot();
|
||||
data.rotation = !_sendNetworkNode ? _internalPoseSet._absolutePoses[i].rot() : _networkPoseSet._absolutePoses[i].rot();
|
||||
data.rotationIsDefaultPose = isEqual(data.rotation, defaultAbsRot);
|
||||
|
||||
// translations are in relative frame but scaled so that they are in meters,
|
||||
// instead of geometry units.
|
||||
glm::vec3 defaultRelTrans = _geometryOffset.scale() * _animSkeleton->getRelativeDefaultPose(i).trans();
|
||||
data.translation = _geometryOffset.scale() * _internalPoseSet._relativePoses[i].trans();
|
||||
data.translation = _geometryOffset.scale() * (!_sendNetworkNode ? _internalPoseSet._relativePoses[i].trans() : _networkPoseSet._relativePoses[i].trans());
|
||||
data.translationIsDefaultPose = isEqual(data.translation, defaultRelTrans);
|
||||
} else {
|
||||
data.translationIsDefaultPose = true;
|
||||
|
|
|
@ -113,7 +113,10 @@ public:
|
|||
void destroyAnimGraph();
|
||||
|
||||
void overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
void triggerNetworkAnimation(const QString& animName);
|
||||
void restoreAnimation();
|
||||
void restoreNetworkAnimation();
|
||||
|
||||
QStringList getAnimationRoles() const;
|
||||
void overrideRoleAnimation(const QString& role, const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
void restoreRoleAnimation(const QString& role);
|
||||
|
@ -269,6 +272,7 @@ protected:
|
|||
|
||||
// Only accessed by the main thread
|
||||
PoseSet _internalPoseSet;
|
||||
PoseSet _networkPoseSet;
|
||||
|
||||
// Copy of the _poseSet for external threads.
|
||||
PoseSet _externalPoseSet;
|
||||
|
@ -300,9 +304,12 @@ protected:
|
|||
|
||||
QUrl _animGraphURL;
|
||||
std::shared_ptr<AnimNode> _animNode;
|
||||
std::shared_ptr<AnimNode> _networkNode;
|
||||
std::shared_ptr<AnimSkeleton> _animSkeleton;
|
||||
std::unique_ptr<AnimNodeLoader> _animLoader;
|
||||
std::unique_ptr<AnimNodeLoader> _networkLoader;
|
||||
AnimVariantMap _animVars;
|
||||
AnimVariantMap _networkVars;
|
||||
|
||||
enum class RigRole {
|
||||
Idle = 0,
|
||||
|
@ -315,6 +322,25 @@ protected:
|
|||
RigRole _state { RigRole::Idle };
|
||||
RigRole _desiredState { RigRole::Idle };
|
||||
float _desiredStateAge { 0.0f };
|
||||
|
||||
struct NetworkAnimState {
|
||||
enum ClipNodeEnum {
|
||||
Idle = 0,
|
||||
PreTransit,
|
||||
Transit,
|
||||
PostTransit
|
||||
};
|
||||
NetworkAnimState() : clipNodeEnum(NetworkAnimState::Idle) {}
|
||||
NetworkAnimState(ClipNodeEnum clipNodeEnumIn, const QString& urlIn, float fpsIn, bool loopIn, float firstFrameIn, float lastFrameIn) :
|
||||
clipNodeEnum(clipNodeEnumIn), url(urlIn), fps(fpsIn), loop(loopIn), firstFrame(firstFrameIn), lastFrame(lastFrameIn) {}
|
||||
|
||||
ClipNodeEnum clipNodeEnum;
|
||||
QString url;
|
||||
float fps;
|
||||
bool loop;
|
||||
float firstFrame;
|
||||
float lastFrame;
|
||||
};
|
||||
|
||||
struct UserAnimState {
|
||||
enum ClipNodeEnum {
|
||||
|
@ -349,6 +375,7 @@ protected:
|
|||
};
|
||||
|
||||
UserAnimState _userAnimState;
|
||||
NetworkAnimState _networkAnimState;
|
||||
std::map<QString, RoleAnimState> _roleAnimStates;
|
||||
|
||||
float _leftHandOverlayAlpha { 0.0f };
|
||||
|
@ -382,6 +409,7 @@ protected:
|
|||
|
||||
int _rigId;
|
||||
bool _headEnabled { false };
|
||||
bool _sendNetworkNode { false };
|
||||
|
||||
AnimContext _lastContext;
|
||||
AnimVariantMap _lastAnimVars;
|
||||
|
|
|
@ -114,27 +114,29 @@ void Avatar::setShowNamesAboveHeads(bool show) {
|
|||
}
|
||||
|
||||
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);
|
||||
const float MAX_TRANSIT_DISTANCE = 30.0f;
|
||||
float scaledMaxTransitDistance = MAX_TRANSIT_DISTANCE * _scale;
|
||||
if (oneFrameDistance > config._triggerDistance && !_isTransiting) {
|
||||
if (oneFrameDistance < scaledMaxTransitDistance) {
|
||||
start(deltaTime, _lastPosition, currentPosition, config);
|
||||
float oneFrameDistance = _isActive ? glm::length(avatarPosition - _endPosition) : glm::length(avatarPosition - _lastPosition);
|
||||
if (oneFrameDistance > (config._minTriggerDistance * _scale)) {
|
||||
if (oneFrameDistance < (config._maxTriggerDistance * _scale)) {
|
||||
start(deltaTime, _lastPosition, avatarPosition, config);
|
||||
} else {
|
||||
_lastPosition = currentPosition;
|
||||
return Status::ABORT_TRANSIT;
|
||||
_lastPosition = avatarPosition;
|
||||
_status = Status::ABORT_TRANSIT;
|
||||
}
|
||||
}
|
||||
_lastPosition = currentPosition;
|
||||
_lastPosition = avatarPosition;
|
||||
_status = updatePosition(deltaTime);
|
||||
|
||||
if (_isActive && oneFrameDistance > (config._abortDistance * _scale) && _status == Status::POST_TRANSIT) {
|
||||
reset();
|
||||
_status = Status::ENDED;
|
||||
}
|
||||
return _status;
|
||||
}
|
||||
|
||||
void AvatarTransit::reset() {
|
||||
_lastPosition = _endPosition;
|
||||
_currentPosition = _endPosition;
|
||||
_isTransiting = false;
|
||||
_isActive = false;
|
||||
}
|
||||
void AvatarTransit::start(float deltaTime, const glm::vec3& startPosition, const glm::vec3& endPosition, const AvatarTransit::TransitConfig& config) {
|
||||
_startPosition = startPosition;
|
||||
|
@ -143,12 +145,14 @@ void AvatarTransit::start(float deltaTime, const glm::vec3& startPosition, const
|
|||
_transitLine = endPosition - startPosition;
|
||||
_totalDistance = glm::length(_transitLine);
|
||||
_easeType = config._easeType;
|
||||
const float REFERENCE_FRAMES_PER_SECOND = 30.0f;
|
||||
|
||||
|
||||
_preTransitTime = AVATAR_PRE_TRANSIT_FRAME_COUNT / AVATAR_TRANSIT_FRAMES_PER_SECOND;
|
||||
_postTransitTime = AVATAR_POST_TRANSIT_FRAME_COUNT / AVATAR_TRANSIT_FRAMES_PER_SECOND;
|
||||
int transitFrames = (!config._isDistanceBased) ? config._totalFrames : config._framesPerMeter * _totalDistance;
|
||||
_totalTime = (float)transitFrames / REFERENCE_FRAMES_PER_SECOND;
|
||||
_currentTime = 0.0f;
|
||||
_isTransiting = true;
|
||||
_transitTime = (float)transitFrames / AVATAR_TRANSIT_FRAMES_PER_SECOND;
|
||||
_totalTime = _transitTime + _preTransitTime + _postTransitTime;
|
||||
_currentTime = _isActive ? _preTransitTime : 0.0f;
|
||||
_isActive = true;
|
||||
}
|
||||
|
||||
float AvatarTransit::getEaseValue(AvatarTransit::EaseType type, float value) {
|
||||
|
@ -171,31 +175,37 @@ float AvatarTransit::getEaseValue(AvatarTransit::EaseType type, float value) {
|
|||
|
||||
AvatarTransit::Status AvatarTransit::updatePosition(float deltaTime) {
|
||||
Status status = Status::IDLE;
|
||||
if (_isTransiting) {
|
||||
if (_isActive) {
|
||||
float nextTime = _currentTime + deltaTime;
|
||||
if (nextTime >= _totalTime) {
|
||||
_currentPosition = _endPosition;
|
||||
_isTransiting = false;
|
||||
status = Status::END_TRANSIT;
|
||||
} else {
|
||||
if (nextTime < _preTransitTime) {
|
||||
_currentPosition = _startPosition;
|
||||
status = Status::PRE_TRANSIT;
|
||||
if (_currentTime == 0) {
|
||||
status = Status::STARTED;
|
||||
}
|
||||
} else if (nextTime < _totalTime - _postTransitTime){
|
||||
status = Status::TRANSITING;
|
||||
if (_currentTime <= _preTransitTime) {
|
||||
status = Status::START_TRANSIT;
|
||||
} else {
|
||||
status = Status::TRANSITING;
|
||||
float percentageIntoTransit = (nextTime - _preTransitTime) / _transitTime;
|
||||
_currentPosition = _startPosition + getEaseValue(_easeType, percentageIntoTransit) * _transitLine;
|
||||
}
|
||||
} else {
|
||||
status = Status::POST_TRANSIT;
|
||||
_currentPosition = _endPosition;
|
||||
if (nextTime >= _totalTime) {
|
||||
_isActive = false;
|
||||
status = Status::ENDED;
|
||||
} else if (_currentTime < _totalTime - _postTransitTime) {
|
||||
status = Status::END_TRANSIT;
|
||||
}
|
||||
float percentageIntoTransit = nextTime / _totalTime;
|
||||
_currentPosition = _startPosition + getEaseValue(_easeType, percentageIntoTransit) * _transitLine;
|
||||
}
|
||||
_currentTime = nextTime;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
bool AvatarTransit::getNextPosition(glm::vec3& nextPosition) {
|
||||
nextPosition = _currentPosition;
|
||||
return _isTransiting;
|
||||
}
|
||||
|
||||
Avatar::Avatar(QThread* thread) :
|
||||
_voiceSphereID(GeometryCache::UNKNOWN_ID)
|
||||
{
|
||||
|
@ -536,16 +546,10 @@ void Avatar::relayJointDataToChildren() {
|
|||
|
||||
void Avatar::simulate(float deltaTime, bool inView) {
|
||||
PROFILE_RANGE(simulation, "simulate");
|
||||
|
||||
if (_transit.isTransiting()) {
|
||||
glm::vec3 nextPosition;
|
||||
if (_transit.getNextPosition(nextPosition)) {
|
||||
_globalPosition = nextPosition;
|
||||
_globalPositionChanged = usecTimestampNow();
|
||||
if (!hasParent()) {
|
||||
setLocalPosition(nextPosition);
|
||||
}
|
||||
}
|
||||
|
||||
_globalPosition = _transit.isActive() ? _transit.getCurrentPosition() : _serverPosition;
|
||||
if (!hasParent()) {
|
||||
setLocalPosition(_globalPosition);
|
||||
}
|
||||
|
||||
_simulationRate.increment();
|
||||
|
@ -558,7 +562,7 @@ void Avatar::simulate(float deltaTime, bool inView) {
|
|||
PROFILE_RANGE(simulation, "updateJoints");
|
||||
if (inView) {
|
||||
Head* head = getHead();
|
||||
if (_hasNewJointData || _transit.isTransiting()) {
|
||||
if (_hasNewJointData || _transit.isActive()) {
|
||||
_skeletonModel->getRig().copyJointsFromJointData(_jointData);
|
||||
glm::mat4 rootTransform = glm::scale(_skeletonModel->getScale()) * glm::translate(_skeletonModel->getOffset());
|
||||
_skeletonModel->getRig().computeExternalPoses(rootTransform);
|
||||
|
@ -1995,22 +1999,12 @@ float Avatar::getUnscaledEyeHeightFromSkeleton() const {
|
|||
}
|
||||
}
|
||||
|
||||
AvatarTransit::Status Avatar::updateTransit(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config) {
|
||||
AvatarTransit::Status Avatar::updateTransit(float deltaTime, const glm::vec3& avatarPosition, float avatarScale, const AvatarTransit::TransitConfig& config) {
|
||||
std::lock_guard<std::mutex> lock(_transitLock);
|
||||
_transit.setScale(avatarScale);
|
||||
return _transit.update(deltaTime, avatarPosition, config);
|
||||
}
|
||||
|
||||
void Avatar::setTransitScale(float scale) {
|
||||
std::lock_guard<std::mutex> lock(_transitLock);
|
||||
return _transit.setScale(scale);
|
||||
}
|
||||
|
||||
void Avatar::overrideNextPackagePositionData(const glm::vec3& position) {
|
||||
std::lock_guard<std::mutex> lock(_transitLock);
|
||||
_overrideGlobalPosition = true;
|
||||
_globalPositionOverride = position;
|
||||
}
|
||||
|
||||
void Avatar::addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) {
|
||||
std::lock_guard<std::mutex> lock(_materialsLock);
|
||||
_materials[parentMaterialName].push(material);
|
||||
|
|
|
@ -56,9 +56,13 @@ class AvatarTransit {
|
|||
public:
|
||||
enum Status {
|
||||
IDLE = 0,
|
||||
STARTED,
|
||||
PRE_TRANSIT,
|
||||
START_TRANSIT,
|
||||
TRANSITING,
|
||||
END_TRANSIT,
|
||||
POST_TRANSIT,
|
||||
ENDED,
|
||||
ABORT_TRANSIT
|
||||
};
|
||||
|
||||
|
@ -72,20 +76,20 @@ public:
|
|||
struct TransitConfig {
|
||||
TransitConfig() {};
|
||||
int _totalFrames { 0 };
|
||||
int _framesPerMeter { 0 };
|
||||
float _framesPerMeter { 0.0f };
|
||||
bool _isDistanceBased { false };
|
||||
float _triggerDistance { 0 };
|
||||
float _minTriggerDistance { 0.0f };
|
||||
float _maxTriggerDistance { 0.0f };
|
||||
float _abortDistance{ 0.0f };
|
||||
EaseType _easeType { EaseType::EASE_OUT };
|
||||
};
|
||||
|
||||
AvatarTransit() {};
|
||||
Status update(float deltaTime, const glm::vec3& avatarPosition, const TransitConfig& config);
|
||||
Status getStatus() { return _status; }
|
||||
bool isTransiting() { return _isTransiting; }
|
||||
bool isActive() { return _isActive; }
|
||||
glm::vec3 getCurrentPosition() { return _currentPosition; }
|
||||
bool getNextPosition(glm::vec3& nextPosition);
|
||||
glm::vec3 getEndPosition() { return _endPosition; }
|
||||
float getTransitTime() { return _totalTime; }
|
||||
void setScale(float scale) { _scale = scale; }
|
||||
void reset();
|
||||
|
||||
|
@ -93,7 +97,7 @@ private:
|
|||
Status updatePosition(float deltaTime);
|
||||
void start(float deltaTime, const glm::vec3& startPosition, const glm::vec3& endPosition, const TransitConfig& config);
|
||||
float getEaseValue(AvatarTransit::EaseType type, float value);
|
||||
bool _isTransiting { false };
|
||||
bool _isActive { false };
|
||||
|
||||
glm::vec3 _startPosition;
|
||||
glm::vec3 _endPosition;
|
||||
|
@ -103,7 +107,10 @@ private:
|
|||
|
||||
glm::vec3 _transitLine;
|
||||
float _totalDistance { 0.0f };
|
||||
float _preTransitTime { 0.0f };
|
||||
float _totalTime { 0.0f };
|
||||
float _transitTime { 0.0f };
|
||||
float _postTransitTime { 0.0f };
|
||||
float _currentTime { 0.0f };
|
||||
EaseType _easeType { EaseType::EASE_OUT };
|
||||
Status _status { Status::IDLE };
|
||||
|
@ -431,11 +438,7 @@ public:
|
|||
virtual scriptable::ScriptableModelBase getScriptableModel() override;
|
||||
|
||||
std::shared_ptr<AvatarTransit> getTransit() { return std::make_shared<AvatarTransit>(_transit); };
|
||||
|
||||
AvatarTransit::Status updateTransit(float deltaTime, const glm::vec3& avatarPosition, const AvatarTransit::TransitConfig& config);
|
||||
void setTransitScale(float scale);
|
||||
|
||||
void overrideNextPackagePositionData(const glm::vec3& position);
|
||||
AvatarTransit::Status updateTransit(float deltaTime, const glm::vec3& avatarPosition, float avatarScale, const AvatarTransit::TransitConfig& config);
|
||||
|
||||
signals:
|
||||
void targetScaleChanged(float targetScale);
|
||||
|
|
|
@ -375,12 +375,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent
|
|||
|
||||
if (hasAvatarGlobalPosition) {
|
||||
auto startSection = destinationBuffer;
|
||||
if (_overrideGlobalPosition) {
|
||||
AVATAR_MEMCPY(_globalPositionOverride);
|
||||
} else {
|
||||
AVATAR_MEMCPY(_globalPosition);
|
||||
}
|
||||
|
||||
AVATAR_MEMCPY(_globalPosition);
|
||||
|
||||
int numBytes = destinationBuffer - startSection;
|
||||
|
||||
|
@ -887,20 +882,22 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
|||
offset = glm::vec3(row * SPACE_BETWEEN_AVATARS, 0.0f, col * SPACE_BETWEEN_AVATARS);
|
||||
}
|
||||
|
||||
auto newValue = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]) + offset;
|
||||
if (_globalPosition != newValue) {
|
||||
_globalPosition = newValue;
|
||||
_serverPosition = glm::vec3(data->globalPosition[0], data->globalPosition[1], data->globalPosition[2]) + offset;
|
||||
auto oneStepDistance = glm::length(_globalPosition - _serverPosition);
|
||||
if (oneStepDistance <= AVATAR_TRANSIT_MIN_TRIGGER_DISTANCE || oneStepDistance >= AVATAR_TRANSIT_MAX_TRIGGER_DISTANCE) {
|
||||
_globalPosition = _serverPosition;
|
||||
// if we don't have a parent, make sure to also set our local position
|
||||
if (!hasParent()) {
|
||||
setLocalPosition(_serverPosition);
|
||||
}
|
||||
}
|
||||
if (_globalPosition != _serverPosition) {
|
||||
_globalPositionChanged = now;
|
||||
}
|
||||
sourceBuffer += sizeof(AvatarDataPacket::AvatarGlobalPosition);
|
||||
int numBytesRead = sourceBuffer - startSection;
|
||||
_globalPositionRate.increment(numBytesRead);
|
||||
_globalPositionUpdateRate.increment();
|
||||
|
||||
// if we don't have a parent, make sure to also set our local position
|
||||
if (!hasParent()) {
|
||||
setLocalPosition(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasAvatarBoundingBox) {
|
||||
|
@ -2115,10 +2112,6 @@ void AvatarData::sendAvatarDataPacket(bool sendAll) {
|
|||
}
|
||||
}
|
||||
|
||||
if (_overrideGlobalPosition) {
|
||||
_overrideGlobalPosition = false;
|
||||
}
|
||||
|
||||
doneEncoding(cullSmallData);
|
||||
|
||||
static AvatarDataSequenceNumber sequenceNumber = 0;
|
||||
|
|
|
@ -327,6 +327,17 @@ const float AVATAR_DISTANCE_LEVEL_5 = 200.0f; // meters
|
|||
// This is the start location in the Sandbox (xyz: 6270, 211, 6000).
|
||||
const glm::vec3 START_LOCATION(6270, 211, 6000);
|
||||
|
||||
// Avatar Transit Constants
|
||||
const float AVATAR_TRANSIT_MIN_TRIGGER_DISTANCE = 1.0f;
|
||||
const float AVATAR_TRANSIT_MAX_TRIGGER_DISTANCE = 30.0f;
|
||||
const int AVATAR_TRANSIT_FRAME_COUNT = 11;
|
||||
const float AVATAR_TRANSIT_FRAMES_PER_METER = 0.5f;
|
||||
const float AVATAR_TRANSIT_ABORT_DISTANCE = 0.1f;
|
||||
const bool AVATAR_TRANSIT_DISTANCE_BASED = true;
|
||||
const float AVATAR_TRANSIT_FRAMES_PER_SECOND = 30.0f;
|
||||
const float AVATAR_PRE_TRANSIT_FRAME_COUNT = 10.0f;
|
||||
const float AVATAR_POST_TRANSIT_FRAME_COUNT = 27.0f;
|
||||
|
||||
enum KeyState {
|
||||
NO_KEY_DOWN = 0,
|
||||
INSERT_KEY_DOWN,
|
||||
|
@ -1378,8 +1389,7 @@ protected:
|
|||
// where Entities are located. This is currently only used by the mixer to decide how often to send
|
||||
// updates about one avatar to another.
|
||||
glm::vec3 _globalPosition { 0, 0, 0 };
|
||||
glm::vec3 _globalPositionOverride { 0, 0, 0 };
|
||||
bool _overrideGlobalPosition { false };
|
||||
glm::vec3 _serverPosition { 0, 0, 0 };
|
||||
|
||||
quint64 _globalPositionChanged { 0 };
|
||||
quint64 _avatarBoundingBoxChanged { 0 };
|
||||
|
|
Loading…
Reference in a new issue