mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 11:45:36 +02:00
Merge branch 'master' into HEAD
Conflicts: interface/src/avatar/SkeletonModel.cpp
This commit is contained in:
commit
ccbae81dad
26 changed files with 245 additions and 183 deletions
|
@ -226,7 +226,7 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
|||
// if the allowed editors list is empty then everyone can adjust locks
|
||||
bool canAdjustLocks = allowedEditors.empty();
|
||||
|
||||
if (allowedEditors.contains(username)) {
|
||||
if (allowedEditors.contains(username, Qt::CaseInsensitive)) {
|
||||
// we have a non-empty allowed editors list - check if this user is verified to be in it
|
||||
if (!verifiedUsername) {
|
||||
if (!verifyUserSignature(username, usernameSignature, HifiSockAddr())) {
|
||||
|
|
|
@ -74,8 +74,8 @@ var MSEC_PER_SEC = 1000.0;
|
|||
|
||||
// these control how long an abandoned pointer line will hang around
|
||||
var LIFETIME = 10;
|
||||
var ACTION_LIFETIME = 15; // seconds
|
||||
var ACTION_LIFETIME_REFRESH = 5;
|
||||
var ACTION_TTL = 15; // seconds
|
||||
var ACTION_TTL_REFRESH = 5;
|
||||
var PICKS_PER_SECOND_PER_HAND = 5;
|
||||
var MSECS_PER_SEC = 1000.0;
|
||||
|
||||
|
@ -429,12 +429,12 @@ function MyController(hand, triggerAction) {
|
|||
targetRotation: this.currentObjectRotation,
|
||||
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
||||
tag: getTag(),
|
||||
lifetime: ACTION_LIFETIME
|
||||
ttl: ACTION_TTL
|
||||
});
|
||||
if (this.actionID === NULL_ACTION_ID) {
|
||||
this.actionID = null;
|
||||
}
|
||||
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC);
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
|
||||
if (this.actionID !== null) {
|
||||
this.setState(STATE_CONTINUE_DISTANCE_HOLDING);
|
||||
|
@ -532,9 +532,9 @@ function MyController(hand, triggerAction) {
|
|||
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
||||
targetRotation: this.currentObjectRotation,
|
||||
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
||||
lifetime: ACTION_LIFETIME
|
||||
ttl: ACTION_TTL
|
||||
});
|
||||
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC);
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
};
|
||||
|
||||
this.nearGrabbing = function() {
|
||||
|
@ -587,12 +587,12 @@ function MyController(hand, triggerAction) {
|
|||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: this.offsetPosition,
|
||||
relativeRotation: this.offsetRotation,
|
||||
lifetime: ACTION_LIFETIME
|
||||
ttl: ACTION_TTL
|
||||
});
|
||||
if (this.actionID === NULL_ACTION_ID) {
|
||||
this.actionID = null;
|
||||
} else {
|
||||
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC);
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
this.setState(STATE_CONTINUE_NEAR_GRABBING);
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
|
||||
|
@ -632,16 +632,16 @@ function MyController(hand, triggerAction) {
|
|||
this.currentObjectTime = now;
|
||||
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrab");
|
||||
|
||||
if (this.actionTimeout - now < ACTION_LIFETIME_REFRESH * MSEC_PER_SEC) {
|
||||
// if less than a 5 seconds left, refresh the actions lifetime
|
||||
if (this.actionTimeout - now < ACTION_TTL_REFRESH * MSEC_PER_SEC) {
|
||||
// if less than a 5 seconds left, refresh the actions ttl
|
||||
Entities.updateAction(this.grabbedEntity, this.actionID, {
|
||||
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
||||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: this.offsetPosition,
|
||||
relativeRotation: this.offsetRotation,
|
||||
lifetime: ACTION_LIFETIME
|
||||
ttl: ACTION_TTL
|
||||
});
|
||||
this.actionTimeout = now + (ACTION_LIFETIME * MSEC_PER_SEC);
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ var IDENTITY_QUAT = {
|
|||
z: 0,
|
||||
w: 0
|
||||
};
|
||||
var ACTION_LIFETIME = 10; // seconds
|
||||
var ACTION_TTL = 10; // seconds
|
||||
|
||||
function getTag() {
|
||||
return "grab-" + MyAvatar.sessionUUID;
|
||||
|
@ -403,7 +403,7 @@ Grabber.prototype.moveEvent = function(event) {
|
|||
|
||||
var actionArgs = {
|
||||
tag: getTag(),
|
||||
lifetime: ACTION_LIFETIME
|
||||
ttl: ACTION_TTL
|
||||
};
|
||||
|
||||
if (this.mode === "rotate") {
|
||||
|
@ -424,7 +424,7 @@ Grabber.prototype.moveEvent = function(event) {
|
|||
targetRotation: this.lastRotation,
|
||||
angularTimeScale: 0.1,
|
||||
tag: getTag(),
|
||||
lifetime: ACTION_LIFETIME
|
||||
ttl: ACTION_TTL
|
||||
};
|
||||
|
||||
} else {
|
||||
|
@ -459,7 +459,7 @@ Grabber.prototype.moveEvent = function(event) {
|
|||
targetPosition: this.targetPosition,
|
||||
linearTimeScale: 0.1,
|
||||
tag: getTag(),
|
||||
lifetime: ACTION_LIFETIME
|
||||
ttl: ACTION_TTL
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -66,7 +66,8 @@ EntityActionPointer InterfaceActionFactory::factoryBA(EntityItemPointer ownerEnt
|
|||
if (action) {
|
||||
action->deserialize(data);
|
||||
if (action->lifetimeIsOver()) {
|
||||
qDebug() << "InterfaceActionFactory::factoryBA lifetimeIsOver during action creation";
|
||||
qDebug() << "InterfaceActionFactory::factoryBA lifetimeIsOver during action creation --"
|
||||
<< action->getExpires() << "<" << usecTimestampNow();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -454,7 +454,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
|||
*/
|
||||
|
||||
bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes);
|
||||
if (renderBounding && shouldRenderHead(renderArgs)) {
|
||||
if (renderBounding && shouldRenderHead(renderArgs) && _skeletonModel.isRenderable()) {
|
||||
_skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f);
|
||||
}
|
||||
|
||||
|
|
|
@ -243,7 +243,7 @@ QByteArray AvatarActionHold::serialize() const {
|
|||
dataStream << _linearTimeScale;
|
||||
dataStream << _hand;
|
||||
|
||||
dataStream << _expires + getEntityServerClockSkew();
|
||||
dataStream << localTimeToServerTime(_expires);
|
||||
dataStream << _tag;
|
||||
dataStream << _kinematic;
|
||||
dataStream << _kinematicSetVelocity;
|
||||
|
@ -277,8 +277,10 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) {
|
|||
_angularTimeScale = _linearTimeScale;
|
||||
dataStream >> _hand;
|
||||
|
||||
dataStream >> _expires;
|
||||
_expires -= getEntityServerClockSkew();
|
||||
quint64 serverExpires;
|
||||
dataStream >> serverExpires;
|
||||
_expires = serverTimeToLocalTime(serverExpires);
|
||||
|
||||
dataStream >> _tag;
|
||||
dataStream >> _kinematic;
|
||||
dataStream >> _kinematicSetVelocity;
|
||||
|
|
|
@ -77,7 +77,10 @@ AvatarManager::AvatarManager(QObject* parent) :
|
|||
|
||||
void AvatarManager::init() {
|
||||
_myAvatar->init();
|
||||
_avatarHash.insert(MY_AVATAR_KEY, _myAvatar);
|
||||
{
|
||||
QWriteLocker locker(&_hashLock);
|
||||
_avatarHash.insert(MY_AVATAR_KEY, _myAvatar);
|
||||
}
|
||||
|
||||
connect(DependencyManager::get<SceneScriptingInterface>().data(), &SceneScriptingInterface::shouldRenderAvatarsChanged, this, &AvatarManager::updateAvatarRenderStatus, Qt::QueuedConnection);
|
||||
|
||||
|
@ -127,6 +130,7 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
} else if (avatar->shouldDie()) {
|
||||
removeAvatarMotionState(avatar);
|
||||
_avatarFades.push_back(avatarIterator.value());
|
||||
QWriteLocker locker(&_hashLock);
|
||||
avatarIterator = _avatarHash.erase(avatarIterator);
|
||||
} else {
|
||||
avatar->startUpdate();
|
||||
|
@ -202,6 +206,7 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) {
|
|||
if (avatar != _myAvatar && avatar->isInitialized()) {
|
||||
removeAvatarMotionState(avatar);
|
||||
_avatarFades.push_back(avatarIterator.value());
|
||||
QWriteLocker locker(&_hashLock);
|
||||
_avatarHash.erase(avatarIterator);
|
||||
}
|
||||
}
|
||||
|
@ -218,6 +223,7 @@ void AvatarManager::clearOtherAvatars() {
|
|||
} else {
|
||||
removeAvatarMotionState(avatar);
|
||||
_avatarFades.push_back(avatarIterator.value());
|
||||
QWriteLocker locker(&_hashLock);
|
||||
avatarIterator = _avatarHash.erase(avatarIterator);
|
||||
}
|
||||
}
|
||||
|
@ -349,5 +355,6 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID)
|
|||
if (sessionID == _myAvatar->getSessionUUID()) {
|
||||
return std::static_pointer_cast<Avatar>(_myAvatar);
|
||||
}
|
||||
return getAvatarHash()[sessionID];
|
||||
QReadLocker locker(&_hashLock);
|
||||
return _avatarHash[sessionID];
|
||||
}
|
||||
|
|
|
@ -209,6 +209,11 @@ void MyAvatar::update(float deltaTime) {
|
|||
setPosition(_goToPosition);
|
||||
setOrientation(_goToOrientation);
|
||||
_goToPending = false;
|
||||
// updateFromHMDSensorMatrix (called from paintGL) expects that the sensorToWorldMatrix is updated for any position changes
|
||||
// that happen between render and Application::update (which calls updateSensorToWorldMatrix to do so).
|
||||
// However, render/MyAvatar::update/Application::update don't always match (e.g., when using the separate avatar update thread),
|
||||
// so we update now. It's ok if it updates again in the normal way.
|
||||
updateSensorToWorldMatrix();
|
||||
}
|
||||
|
||||
if (_referential) {
|
||||
|
@ -1088,7 +1093,11 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
|||
const float KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR = 1.3f;
|
||||
const float GREATEST_LOOKING_AT_DISTANCE = 10.0f;
|
||||
|
||||
foreach (const AvatarSharedPointer& avatarPointer, DependencyManager::get<AvatarManager>()->getAvatarHash()) {
|
||||
AvatarHash hash;
|
||||
DependencyManager::get<AvatarManager>()->withAvatarHash([&] (const AvatarHash& locked) {
|
||||
hash = locked; // make a shallow copy and operate on that, to minimize lock time
|
||||
});
|
||||
foreach (const AvatarSharedPointer& avatarPointer, hash) {
|
||||
auto avatar = static_pointer_cast<Avatar>(avatarPointer);
|
||||
bool isCurrentTarget = avatar->getIsLookAtTarget();
|
||||
float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition);
|
||||
|
@ -1120,7 +1129,6 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
|||
glm::vec3 humanLeftEye = humanSystem->getPosition() + (humanSystem->getOrientation() * leftEyeHeadLocal);
|
||||
glm::vec3 humanRightEye = humanSystem->getPosition() + (humanSystem->getOrientation() * rightEyeHeadLocal);
|
||||
|
||||
|
||||
// First find out where (in world space) the person is looking relative to that bridge-of-the-avatar point.
|
||||
// (We will be adding that offset to the camera position, after making some other adjustments.)
|
||||
glm::vec3 gazeOffset = lookAtPosition - getHead()->getEyePosition();
|
||||
|
@ -1132,14 +1140,14 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
|||
|
||||
// If the camera is also not oriented with the head, adjust by getting the offset in head-space...
|
||||
/* Not needed (i.e., code is a no-op), but I'm leaving the example code here in case something like this is needed someday.
|
||||
glm::quat avatarHeadOrientation = getHead()->getOrientation();
|
||||
glm::vec3 gazeOffsetLocalToHead = glm::inverse(avatarHeadOrientation) * gazeOffset;
|
||||
// ... and treat that as though it were in camera space, bringing it back to world space.
|
||||
// But camera is fudged to make the picture feel like the avatar's orientation.
|
||||
glm::quat humanOrientation = humanSystem->getOrientation(); // or just avatar getOrienation() ?
|
||||
gazeOffset = humanOrientation * gazeOffsetLocalToHead;
|
||||
glm::vec3 corrected = humanSystem->getPosition() + gazeOffset;
|
||||
*/
|
||||
glm::quat avatarHeadOrientation = getHead()->getOrientation();
|
||||
glm::vec3 gazeOffsetLocalToHead = glm::inverse(avatarHeadOrientation) * gazeOffset;
|
||||
// ... and treat that as though it were in camera space, bringing it back to world space.
|
||||
// But camera is fudged to make the picture feel like the avatar's orientation.
|
||||
glm::quat humanOrientation = humanSystem->getOrientation(); // or just avatar getOrienation() ?
|
||||
gazeOffset = humanOrientation * gazeOffsetLocalToHead;
|
||||
glm::vec3 corrected = humanSystem->getPosition() + gazeOffset;
|
||||
*/
|
||||
|
||||
// And now we can finally add that offset to the camera.
|
||||
glm::vec3 corrected = qApp->getViewFrustum()->getPosition() + gazeOffset;
|
||||
|
|
|
@ -103,15 +103,12 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
if (_owningAvatar->isMyAvatar()) {
|
||||
_rig->computeMotionAnimationState(deltaTime, _owningAvatar->getPosition(), _owningAvatar->getVelocity(), _owningAvatar->getOrientation());
|
||||
}
|
||||
Model::updateRig(deltaTime, parentTransform);
|
||||
Head* head = _owningAvatar->getHead();
|
||||
if (_owningAvatar->isMyAvatar()) {
|
||||
MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar);
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
|
||||
Rig::HeadParameters headParams;
|
||||
headParams.modelRotation = getRotation();
|
||||
headParams.modelTranslation = getTranslation();
|
||||
headParams.enableLean = qApp->getAvatarUpdater()->isHMDMode();
|
||||
headParams.leanSideways = head->getFinalLeanSideways();
|
||||
headParams.leanForward = head->getFinalLeanForward();
|
||||
|
@ -145,13 +142,8 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
headParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame();
|
||||
}
|
||||
|
||||
headParams.eyeLookAt = head->getLookAtPosition();
|
||||
headParams.eyeSaccade = head->getSaccade();
|
||||
headParams.leanJointIndex = geometry.leanJointIndex;
|
||||
headParams.neckJointIndex = geometry.neckJointIndex;
|
||||
headParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
|
||||
headParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
|
||||
|
||||
headParams.isTalking = head->getTimeWithoutTalking() <= 1.5f;
|
||||
|
||||
_rig->updateFromHeadParameters(headParams, deltaTime);
|
||||
|
@ -180,7 +172,28 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
|
||||
_rig->updateFromHandParameters(handParams, deltaTime);
|
||||
|
||||
// evaluate AnimGraph animation and update jointStates.
|
||||
Model::updateRig(deltaTime, parentTransform);
|
||||
|
||||
Rig::EyeParameters eyeParams;
|
||||
eyeParams.worldHeadOrientation = headParams.worldHeadOrientation;
|
||||
eyeParams.eyeLookAt = head->getLookAtPosition();
|
||||
eyeParams.eyeSaccade = head->getSaccade();
|
||||
eyeParams.modelRotation = getRotation();
|
||||
eyeParams.modelTranslation = getTranslation();
|
||||
eyeParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
|
||||
eyeParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
|
||||
|
||||
_rig->updateFromEyeParameters(eyeParams);
|
||||
|
||||
// rebuild the jointState transform for the eyes only
|
||||
_rig->updateJointState(eyeParams.leftEyeJointIndex, parentTransform);
|
||||
_rig->updateJointState(eyeParams.rightEyeJointIndex, parentTransform);
|
||||
|
||||
} else {
|
||||
|
||||
Model::updateRig(deltaTime, parentTransform);
|
||||
|
||||
// This is a little more work than we really want.
|
||||
//
|
||||
// Other avatars joint, including their eyes, should already be set just like any other joints
|
||||
|
@ -197,9 +210,16 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
head->setBasePitch(glm::degrees(-eulers.x));
|
||||
head->setBaseYaw(glm::degrees(eulers.y));
|
||||
head->setBaseRoll(glm::degrees(-eulers.z));
|
||||
_rig->updateEyeJoints(geometry.leftEyeJointIndex, geometry.rightEyeJointIndex,
|
||||
getTranslation(), getRotation(),
|
||||
head->getFinalOrientationInWorldFrame(), head->getCorrectedLookAtPosition());
|
||||
|
||||
Rig::EyeParameters eyeParams;
|
||||
eyeParams.worldHeadOrientation = head->getFinalOrientationInWorldFrame();
|
||||
eyeParams.eyeLookAt = head->getCorrectedLookAtPosition();
|
||||
eyeParams.eyeSaccade = glm::vec3();
|
||||
eyeParams.modelRotation = getRotation();
|
||||
eyeParams.modelTranslation = getTranslation();
|
||||
eyeParams.leftEyeJointIndex = geometry.leftEyeJointIndex;
|
||||
eyeParams.rightEyeJointIndex = geometry.rightEyeJointIndex;
|
||||
_rig->updateFromEyeParameters(eyeParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,11 +65,12 @@ AudioStatsDialog::AudioStatsDialog(QWidget* parent) :
|
|||
// Get statistics from the Audio Client
|
||||
_stats = &DependencyManager::get<AudioClient>()->getStats();
|
||||
|
||||
// Create layouter
|
||||
// Create layout
|
||||
_form = new QFormLayout();
|
||||
_form->setSizeConstraint(QLayout::SetFixedSize);
|
||||
QDialog::setLayout(_form);
|
||||
|
||||
// Load and initilize all channels
|
||||
// Load and initialize all channels
|
||||
renderStats();
|
||||
|
||||
_audioDisplayChannels = QVector<QVector<AudioStatsDisplay*>>(1);
|
||||
|
@ -80,10 +81,8 @@ AudioStatsDialog::AudioStatsDialog(QWidget* parent) :
|
|||
_downstreamID = addChannel(_form, _downstreamStats, COLOR3);
|
||||
_upstreamInjectedID = addChannel(_form, _upstreamInjectedStats, COLOR0);
|
||||
|
||||
|
||||
connect(averageUpdateTimer, SIGNAL(timeout()), this, SLOT(updateTimerTimeout()));
|
||||
averageUpdateTimer->start(1000);
|
||||
|
||||
}
|
||||
|
||||
int AudioStatsDialog::addChannel(QFormLayout* form, QVector<QString>& stats, const unsigned color) {
|
||||
|
@ -243,7 +242,6 @@ void AudioStatsDialog::paintEvent(QPaintEvent* event) {
|
|||
}
|
||||
|
||||
QDialog::paintEvent(event);
|
||||
setFixedSize(width(), height());
|
||||
}
|
||||
|
||||
void AudioStatsDialog::reject() {
|
||||
|
|
|
@ -72,8 +72,9 @@ BandwidthDialog::BandwidthDialog(QWidget* parent) :
|
|||
|
||||
this->setWindowTitle("Bandwidth Details");
|
||||
|
||||
// Create layouter
|
||||
// Create layout
|
||||
QFormLayout* form = new QFormLayout();
|
||||
form->setSizeConstraint(QLayout::SetFixedSize);
|
||||
this->QDialog::setLayout(form);
|
||||
|
||||
QSharedPointer<BandwidthRecorder> bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||
|
@ -118,7 +119,6 @@ void BandwidthDialog::paintEvent(QPaintEvent* event) {
|
|||
for (unsigned int i=0; i<_CHANNELCOUNT; i++)
|
||||
_allChannelDisplays[i]->paint();
|
||||
this->QDialog::paintEvent(event);
|
||||
this->setFixedSize(this->width(), this->height());
|
||||
}
|
||||
|
||||
void BandwidthDialog::reject() {
|
||||
|
|
|
@ -22,34 +22,6 @@
|
|||
#include "AnimSkeleton.h"
|
||||
#include "IKTarget.h"
|
||||
|
||||
|
||||
void Rig::HeadParameters::dump() const {
|
||||
qCDebug(animation, "HeadParameters =");
|
||||
qCDebug(animation, " leanSideways = %0.5f", (double)leanSideways);
|
||||
qCDebug(animation, " leanForward = %0.5f", (double)leanForward);
|
||||
qCDebug(animation, " torsoTwist = %0.5f", (double)torsoTwist);
|
||||
glm::vec3 axis = glm::axis(localHeadOrientation);
|
||||
float theta = glm::angle(localHeadOrientation);
|
||||
qCDebug(animation, " localHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta);
|
||||
axis = glm::axis(worldHeadOrientation);
|
||||
theta = glm::angle(worldHeadOrientation);
|
||||
qCDebug(animation, " localHead pitch = %.5f, yaw = %.5f, roll = %.5f", (double)localHeadPitch, (double)localHeadYaw, (double)localHeadRoll);
|
||||
qCDebug(animation, " localHeadPosition = (%.5f, %.5f, %.5f)", (double)localHeadPosition.x, (double)localHeadPosition.y, (double)localHeadPosition.z);
|
||||
qCDebug(animation, " isInHMD = %s", isInHMD ? "true" : "false");
|
||||
qCDebug(animation, " worldHeadOrientation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta);
|
||||
axis = glm::axis(modelRotation);
|
||||
theta = glm::angle(modelRotation);
|
||||
qCDebug(animation, " modelRotation axis = (%.5f, %.5f, %.5f), theta = %0.5f", (double)axis.x, (double)axis.y, (double)axis.z, (double)theta);
|
||||
qCDebug(animation, " modelTranslation = (%.5f, %.5f, %.5f)", (double)modelTranslation.x, (double)modelTranslation.y, (double)modelTranslation.z);
|
||||
qCDebug(animation, " eyeLookAt = (%.5f, %.5f, %.5f)", (double)eyeLookAt.x, (double)eyeLookAt.y, (double)eyeLookAt.z);
|
||||
qCDebug(animation, " eyeSaccade = (%.5f, %.5f, %.5f)", (double)eyeSaccade.x, (double)eyeSaccade.y, (double)eyeSaccade.z);
|
||||
qCDebug(animation, " leanJointIndex = %.d", leanJointIndex);
|
||||
qCDebug(animation, " neckJointIndex = %.d", neckJointIndex);
|
||||
qCDebug(animation, " leftEyeJointIndex = %.d", leftEyeJointIndex);
|
||||
qCDebug(animation, " rightEyeJointIndex = %.d", rightEyeJointIndex);
|
||||
qCDebug(animation, " isTalking = %s", isTalking ? "true" : "false");
|
||||
}
|
||||
|
||||
void insertSorted(QList<AnimationHandlePointer>& handles, const AnimationHandlePointer& handle) {
|
||||
for (QList<AnimationHandlePointer>::iterator it = handles.begin(); it != handles.end(); it++) {
|
||||
if (handle->getPriority() > (*it)->getPriority()) {
|
||||
|
@ -981,8 +953,6 @@ void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
|
|||
_animVars.unset("lean");
|
||||
}
|
||||
updateNeckJoint(params.neckJointIndex, params);
|
||||
updateEyeJoints(params.leftEyeJointIndex, params.rightEyeJointIndex, params.modelTranslation, params.modelRotation,
|
||||
params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade);
|
||||
|
||||
if (_enableAnimGraph) {
|
||||
_animVars.set("isTalking", params.isTalking);
|
||||
|
@ -990,6 +960,13 @@ void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
|
|||
}
|
||||
}
|
||||
|
||||
void Rig::updateFromEyeParameters(const EyeParameters& params) {
|
||||
updateEyeJoint(params.leftEyeJointIndex, params.modelTranslation, params.modelRotation,
|
||||
params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade);
|
||||
updateEyeJoint(params.rightEyeJointIndex, params.modelTranslation, params.modelRotation,
|
||||
params.worldHeadOrientation, params.eyeLookAt, params.eyeSaccade);
|
||||
}
|
||||
|
||||
static const glm::vec3 X_AXIS(1.0f, 0.0f, 0.0f);
|
||||
static const glm::vec3 Y_AXIS(0.0f, 1.0f, 0.0f);
|
||||
static const glm::vec3 Z_AXIS(0.0f, 0.0f, 1.0f);
|
||||
|
@ -1145,12 +1122,6 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
|
|||
}
|
||||
}
|
||||
|
||||
void Rig::updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation,
|
||||
const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) {
|
||||
updateEyeJoint(leftEyeIndex, modelTranslation, modelRotation, worldHeadOrientation, lookAtSpot, saccade);
|
||||
updateEyeJoint(rightEyeIndex, modelTranslation, modelRotation, worldHeadOrientation, lookAtSpot, saccade);
|
||||
}
|
||||
|
||||
void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) {
|
||||
if (index >= 0 && _jointStates[index].getParentIndex() >= 0) {
|
||||
auto& state = _jointStates[index];
|
||||
|
|
|
@ -57,24 +57,26 @@ public:
|
|||
float leanForward = 0.0f; // degrees
|
||||
float torsoTwist = 0.0f; // degrees
|
||||
bool enableLean = false;
|
||||
glm::quat modelRotation = glm::quat();
|
||||
glm::quat worldHeadOrientation = glm::quat();
|
||||
glm::quat localHeadOrientation = glm::quat();
|
||||
float localHeadPitch = 0.0f; // degrees
|
||||
float localHeadYaw = 0.0f; // degrees
|
||||
float localHeadRoll = 0.0f; // degrees
|
||||
glm::vec3 localHeadPosition = glm::vec3();
|
||||
bool isInHMD = false;
|
||||
int leanJointIndex = -1;
|
||||
int neckJointIndex = -1;
|
||||
bool isTalking = false;
|
||||
};
|
||||
|
||||
struct EyeParameters {
|
||||
glm::quat worldHeadOrientation = glm::quat();
|
||||
glm::vec3 eyeLookAt = glm::vec3(); // world space
|
||||
glm::vec3 eyeSaccade = glm::vec3(); // world space
|
||||
glm::vec3 modelTranslation = glm::vec3();
|
||||
int leanJointIndex = -1;
|
||||
int neckJointIndex = -1;
|
||||
glm::quat modelRotation = glm::quat();
|
||||
int leftEyeJointIndex = -1;
|
||||
int rightEyeJointIndex = -1;
|
||||
bool isTalking = false;
|
||||
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
struct HandParameters {
|
||||
|
@ -185,9 +187,7 @@ public:
|
|||
bool getEnableAnimGraph() const { return _enableAnimGraph; }
|
||||
|
||||
void updateFromHeadParameters(const HeadParameters& params, float dt);
|
||||
void updateEyeJoints(int leftEyeIndex, int rightEyeIndex, const glm::vec3& modelTranslation, const glm::quat& modelRotation,
|
||||
const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade = glm::vec3(0.0f));
|
||||
|
||||
void updateFromEyeParameters(const EyeParameters& params);
|
||||
void updateFromHandParameters(const HandParameters& params, float dt);
|
||||
|
||||
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
|
||||
|
|
|
@ -22,7 +22,12 @@ AvatarHashMap::AvatarHashMap() {
|
|||
connect(DependencyManager::get<NodeList>().data(), &NodeList::uuidChanged, this, &AvatarHashMap::sessionUUIDChanged);
|
||||
}
|
||||
|
||||
void AvatarHashMap::withAvatarHash(std::function<void(const AvatarHash& hash)> callback) {
|
||||
QReadLocker locker(&_hashLock);
|
||||
callback(_avatarHash);
|
||||
}
|
||||
bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range) {
|
||||
QReadLocker locker(&_hashLock);
|
||||
foreach(const AvatarSharedPointer& sharedAvatar, _avatarHash) {
|
||||
glm::vec3 avatarPosition = sharedAvatar->getPosition();
|
||||
float distance = glm::distance(avatarPosition, position);
|
||||
|
@ -43,6 +48,7 @@ AvatarSharedPointer AvatarHashMap::addAvatar(const QUuid& sessionUUID, const QWe
|
|||
AvatarSharedPointer avatar = newSharedAvatar();
|
||||
avatar->setSessionUUID(sessionUUID);
|
||||
avatar->setOwningAvatarMixer(mixerWeakPointer);
|
||||
QWriteLocker locker(&_hashLock);
|
||||
_avatarHash.insert(sessionUUID, avatar);
|
||||
|
||||
return avatar;
|
||||
|
@ -134,6 +140,7 @@ void AvatarHashMap::processKillAvatar(QSharedPointer<NLPacket> packet, SharedNod
|
|||
}
|
||||
|
||||
void AvatarHashMap::removeAvatar(const QUuid& sessionUUID) {
|
||||
QWriteLocker locker(&_hashLock);
|
||||
_avatarHash.remove(sessionUUID);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <QtCore/QSharedPointer>
|
||||
#include <QtCore/QUuid>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
@ -30,7 +31,7 @@ class AvatarHashMap : public QObject, public Dependency {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
const AvatarHash& getAvatarHash() { return _avatarHash; }
|
||||
void withAvatarHash(std::function<void(const AvatarHash& hash)>);
|
||||
int size() { return _avatarHash.size(); }
|
||||
|
||||
public slots:
|
||||
|
@ -52,6 +53,9 @@ protected:
|
|||
virtual void removeAvatar(const QUuid& sessionUUID);
|
||||
|
||||
AvatarHash _avatarHash;
|
||||
// "Case-based safety": Most access to the _avatarHash is on the same thread. Write access is protected by a write-lock.
|
||||
// If you read from a different thread, you must read-lock the _hashLock. (Scripted write access is not supported).
|
||||
QReadWriteLock _hashLock;
|
||||
|
||||
private:
|
||||
QUuid _lastOwnerSessionUUID;
|
||||
|
|
|
@ -47,6 +47,7 @@ public:
|
|||
static QString actionTypeToString(EntityActionType actionType);
|
||||
|
||||
virtual bool lifetimeIsOver() { return false; }
|
||||
virtual quint64 getExpires() { return 0; }
|
||||
|
||||
bool locallyAddedButNotYetReceived = false;
|
||||
|
||||
|
|
|
@ -1790,9 +1790,17 @@ const QByteArray EntityItem::getActionDataInternal() const {
|
|||
const QByteArray EntityItem::getActionData() const {
|
||||
QByteArray result;
|
||||
assertUnlocked();
|
||||
withReadLock([&] {
|
||||
result = getActionDataInternal();
|
||||
});
|
||||
|
||||
if (_actionDataDirty) {
|
||||
withWriteLock([&] {
|
||||
getActionDataInternal();
|
||||
result = _allActionsDataCache;
|
||||
});
|
||||
} else {
|
||||
withReadLock([&] {
|
||||
result = _allActionsDataCache;
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ Extents FBXGeometry::getUnscaledMeshExtents() const {
|
|||
glm::vec3 minimum = glm::vec3(offset * glm::vec4(extents.minimum, 1.0f));
|
||||
glm::vec3 maximum = glm::vec3(offset * glm::vec4(extents.maximum, 1.0f));
|
||||
Extents scaledExtents = { minimum, maximum };
|
||||
|
||||
|
||||
return scaledExtents;
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,7 @@ bool FBXGeometry::convexHullContains(const glm::vec3& point) const {
|
|||
if (!getUnscaledMeshExtents().containsPoint(point)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
auto checkEachPrimitive = [=](FBXMesh& mesh, QVector<int> indices, int primitiveSize) -> bool {
|
||||
// Check whether the point is "behind" all the primitives.
|
||||
for (int j = 0; j < indices.size(); j += primitiveSize) {
|
||||
|
@ -87,11 +87,11 @@ bool FBXGeometry::convexHullContains(const glm::vec3& point) const {
|
|||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
// Check that the point is contained in at least one convex mesh.
|
||||
for (auto mesh : meshes) {
|
||||
bool insideMesh = true;
|
||||
|
||||
|
||||
// To be considered inside a convex mesh,
|
||||
// the point needs to be "behind" all the primitives respective planes.
|
||||
for (auto part : mesh.parts) {
|
||||
|
@ -108,7 +108,7 @@ bool FBXGeometry::convexHullContains(const glm::vec3& point) const {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// It wasn't in any mesh, return false.
|
||||
return false;
|
||||
}
|
||||
|
@ -194,7 +194,7 @@ public:
|
|||
glm::vec3 rotationMax; // radians
|
||||
};
|
||||
|
||||
glm::mat4 getGlobalTransform(const QMultiHash<QString, QString>& _connectionParentMap,
|
||||
glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParentMap,
|
||||
const QHash<QString, FBXModel>& models, QString nodeID, bool mixamoHack) {
|
||||
glm::mat4 globalTransform;
|
||||
while (!nodeID.isNull()) {
|
||||
|
@ -228,12 +228,12 @@ void printNode(const FBXNode& node, int indentLevel) {
|
|||
int indentLength = 2;
|
||||
QByteArray spaces(indentLevel * indentLength, ' ');
|
||||
QDebug nodeDebug = qDebug(modelformat);
|
||||
|
||||
|
||||
nodeDebug.nospace() << spaces.data() << node.name.data() << ": ";
|
||||
foreach (const QVariant& property, node.properties) {
|
||||
nodeDebug << property;
|
||||
}
|
||||
|
||||
|
||||
foreach (const FBXNode& child, node.children) {
|
||||
printNode(child, indentLevel + 1);
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ public:
|
|||
glm::mat4 transformLink;
|
||||
};
|
||||
|
||||
void appendModelIDs(const QString& parentID, const QMultiHash<QString, QString>& connectionChildMap,
|
||||
void appendModelIDs(const QString& parentID, const QMultiMap<QString, QString>& connectionChildMap,
|
||||
QHash<QString, FBXModel>& models, QSet<QString>& remainingModels, QVector<QString>& modelIDs) {
|
||||
if (remainingModels.contains(parentID)) {
|
||||
modelIDs.append(parentID);
|
||||
|
@ -331,7 +331,7 @@ void addBlendshapes(const ExtractedBlendshape& extracted, const QList<WeightedIn
|
|||
}
|
||||
}
|
||||
|
||||
QString getTopModelID(const QMultiHash<QString, QString>& connectionParentMap,
|
||||
QString getTopModelID(const QMultiMap<QString, QString>& connectionParentMap,
|
||||
const QHash<QString, FBXModel>& models, const QString& modelID) {
|
||||
QString topID = modelID;
|
||||
forever {
|
||||
|
@ -342,7 +342,7 @@ QString getTopModelID(const QMultiHash<QString, QString>& connectionParentMap,
|
|||
}
|
||||
}
|
||||
return topID;
|
||||
|
||||
|
||||
outerContinue: ;
|
||||
}
|
||||
}
|
||||
|
@ -361,7 +361,7 @@ public:
|
|||
};
|
||||
|
||||
bool checkMaterialsHaveTextures(const QHash<QString, FBXMaterial>& materials,
|
||||
const QHash<QString, QByteArray>& textureFilenames, const QMultiHash<QString, QString>& _connectionChildMap) {
|
||||
const QHash<QString, QByteArray>& textureFilenames, const QMultiMap<QString, QString>& _connectionChildMap) {
|
||||
foreach (const QString& materialID, materials.keys()) {
|
||||
foreach (const QString& childID, _connectionChildMap.values(materialID)) {
|
||||
if (textureFilenames.contains(childID)) {
|
||||
|
@ -443,8 +443,8 @@ QByteArray fileOnUrl(const QByteArray& filenameString, const QString& url) {
|
|||
}
|
||||
|
||||
FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QString& url) {
|
||||
const FBXNode& node = _fbxNode;
|
||||
QHash<QString, ExtractedMesh> meshes;
|
||||
const FBXNode& node = _fbxNode;
|
||||
QMap<QString, ExtractedMesh> meshes;
|
||||
QHash<QString, QString> modelIDsToNames;
|
||||
QHash<QString, int> meshIDsToMeshIndices;
|
||||
QHash<QString, QString> ooChildToParent;
|
||||
|
@ -497,7 +497,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
QVector<QString> humanIKJointIDs(humanIKJointNames.size());
|
||||
|
||||
QVariantHash blendshapeMappings = mapping.value("bs").toHash();
|
||||
|
||||
|
||||
QMultiHash<QByteArray, WeightedIndex> blendshapeIndices;
|
||||
for (int i = 0;; i++) {
|
||||
QByteArray blendshapeName = FACESHIFT_BLENDSHAPES[i];
|
||||
|
@ -527,7 +527,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
QString hifiGlobalNodeID;
|
||||
unsigned int meshIndex = 0;
|
||||
foreach (const FBXNode& child, node.children) {
|
||||
|
||||
|
||||
if (child.name == "FBXHeaderExtension") {
|
||||
foreach (const FBXNode& object, child.children) {
|
||||
if (object.name == "SceneInfo") {
|
||||
|
@ -537,7 +537,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
if (subsubobject.name == "Author") {
|
||||
geometry.author = subsubobject.properties.at(0).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (subobject.name == "Properties70") {
|
||||
foreach (const FBXNode& subsubobject, subobject.children) {
|
||||
if (subsubobject.name == "P" && subsubobject.properties.size() >= 5 &&
|
||||
|
@ -620,7 +620,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
if (humanIKJointIndex != -1) {
|
||||
humanIKJointIDs[humanIKJointIndex] = getID(object.properties);
|
||||
}
|
||||
|
||||
|
||||
glm::vec3 translation;
|
||||
// NOTE: the euler angles as supplied by the FBX file are in degrees
|
||||
glm::vec3 rotationOffset;
|
||||
|
@ -709,7 +709,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
// it's a mesh as well as a model
|
||||
mesh = &meshes[getID(object.properties)];
|
||||
*mesh = extractMesh(object, meshIndex);
|
||||
|
||||
|
||||
} else if (subobject.name == "Shape") {
|
||||
ExtractedBlendshape blendshape = { subobject.properties.at(0).toString(),
|
||||
extractBlendshape(subobject) };
|
||||
|
@ -720,7 +720,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
QString attributetype = subobject.properties.at(0).toString();
|
||||
if (!attributetype.empty()) {
|
||||
if (attributetype == "Light") {
|
||||
QString lightprop;
|
||||
QString lightprop;
|
||||
foreach (const QVariant& vprop, subobject.properties) {
|
||||
lightprop = vprop.toString();
|
||||
}
|
||||
|
@ -731,23 +731,23 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
} else {
|
||||
QString whatisthat = subobject.name;
|
||||
if (whatisthat == "Shape") {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// add the blendshapes included in the model, if any
|
||||
if (mesh) {
|
||||
foreach (const ExtractedBlendshape& extracted, blendshapes) {
|
||||
addBlendshapes(extracted, blendshapeIndices.values(extracted.id.toLatin1()), *mesh);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// see FBX documentation, http://download.autodesk.com/us/fbx/20112/FBX_SDK_HELP/index.html
|
||||
model.translation = translation;
|
||||
|
||||
model.preTransform = glm::translate(rotationOffset) * glm::translate(rotationPivot);
|
||||
model.preRotation = glm::quat(glm::radians(preRotation));
|
||||
model.preTransform = glm::translate(rotationOffset) * glm::translate(rotationPivot);
|
||||
model.preRotation = glm::quat(glm::radians(preRotation));
|
||||
model.rotation = glm::quat(glm::radians(rotation));
|
||||
model.postRotation = glm::quat(glm::radians(postRotation));
|
||||
|
||||
|
@ -862,7 +862,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
if (subobject.name == "RelativeFilename") {
|
||||
filename = subobject.properties.at(0).toByteArray();
|
||||
filename = fileOnUrl(filename, url);
|
||||
|
||||
|
||||
} else if (subobject.name == "Content" && !subobject.properties.isEmpty()) {
|
||||
content = subobject.properties.at(0).toByteArray();
|
||||
}
|
||||
|
@ -905,10 +905,10 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
|
||||
} else if (property.properties.at(0) == "Emissive") {
|
||||
material.emissiveColor = getVec3(property.properties, index);
|
||||
|
||||
|
||||
} else if (property.properties.at(0) == "Shininess") {
|
||||
material.shininess = property.properties.at(index).value<double>();
|
||||
|
||||
|
||||
} else if (property.properties.at(0) == "Opacity") {
|
||||
material.opacity = property.properties.at(index).value<double>();
|
||||
}
|
||||
|
@ -1001,7 +1001,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
}
|
||||
animationCurves.insert(getID(object.properties), curve);
|
||||
|
||||
|
||||
}
|
||||
#if defined(DEBUG_FBXREADER)
|
||||
else {
|
||||
|
@ -1013,7 +1013,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
} else {
|
||||
unknown++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
} else if (child.name == "Connections") {
|
||||
|
@ -1041,14 +1041,14 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
|
||||
} else if (type.contains("transparentcolor")) { // it should be TransparentColor...
|
||||
// THis is how Maya assign a texture that affect diffuse color AND transparency ?
|
||||
// THis is how Maya assign a texture that affect diffuse color AND transparency ?
|
||||
diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
} else if (type.contains("bump")) {
|
||||
bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
} else if (type.contains("normal")) {
|
||||
normalTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
} else if (type.contains("specular") || type.contains("reflection")) {
|
||||
specularTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
specularTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
|
||||
} else if (type == "lcl rotation") {
|
||||
localRotations.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
|
@ -1097,7 +1097,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
} else {
|
||||
unknown++;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1142,7 +1142,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
}
|
||||
outerBreak:
|
||||
|
||||
|
||||
// make sure the parent is in the child map
|
||||
QString parent = _connectionParentMap.value(model.key());
|
||||
if (!_connectionChildMap.contains(parent, model.key())) {
|
||||
|
@ -1172,7 +1172,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
frame.translations.resize(modelIDs.size());
|
||||
geometry.animationFrames.append(frame);
|
||||
}
|
||||
|
||||
|
||||
// convert the models to joints
|
||||
QVariantList freeJoints = mapping.values("freeJoint");
|
||||
geometry.hasSkeletonJoints = false;
|
||||
|
@ -1181,7 +1181,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
FBXJoint joint;
|
||||
joint.isFree = freeJoints.contains(model.name);
|
||||
joint.parentIndex = model.parentIndex;
|
||||
|
||||
|
||||
// get the indices of all ancestors starting with the first free one (if any)
|
||||
int jointIndex = geometry.joints.size();
|
||||
joint.freeLineage.append(jointIndex);
|
||||
|
@ -1203,7 +1203,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
joint.rotationMax = model.rotationMax;
|
||||
glm::quat combinedRotation = joint.preRotation * joint.rotation * joint.postRotation;
|
||||
if (joint.parentIndex == -1) {
|
||||
joint.transform = geometry.offset * glm::translate(joint.translation) * joint.preTransform *
|
||||
joint.transform = geometry.offset * glm::translate(joint.translation) * joint.preTransform *
|
||||
glm::mat4_cast(combinedRotation) * joint.postTransform;
|
||||
joint.inverseDefaultRotation = glm::inverse(combinedRotation);
|
||||
joint.distanceToParent = 0.0f;
|
||||
|
@ -1272,11 +1272,11 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
geometry.rightHandJointIndex = modelIDs.indexOf(jointRightHandID);
|
||||
geometry.leftToeJointIndex = modelIDs.indexOf(jointLeftToeID);
|
||||
geometry.rightToeJointIndex = modelIDs.indexOf(jointRightToeID);
|
||||
|
||||
|
||||
foreach (const QString& id, humanIKJointIDs) {
|
||||
geometry.humanIKJointIndices.append(modelIDs.indexOf(id));
|
||||
}
|
||||
|
||||
|
||||
// extract the translation component of the neck transform
|
||||
if (geometry.neckJointIndex != -1) {
|
||||
const glm::mat4& transform = geometry.joints.at(geometry.neckJointIndex).transform;
|
||||
|
@ -1285,7 +1285,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
|
||||
geometry.bindExtents.reset();
|
||||
geometry.meshExtents.reset();
|
||||
|
||||
|
||||
// Create the Material Library
|
||||
consolidateFBXMaterials();
|
||||
geometry.materials = _fbxMaterials;
|
||||
|
@ -1293,9 +1293,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
// see if any materials have texture children
|
||||
bool materialsHaveTextures = checkMaterialsHaveTextures(_fbxMaterials, _textureFilenames, _connectionChildMap);
|
||||
|
||||
for (QHash<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
|
||||
for (QMap<QString, ExtractedMesh>::iterator it = meshes.begin(); it != meshes.end(); it++) {
|
||||
ExtractedMesh& extracted = it.value();
|
||||
|
||||
|
||||
extracted.mesh.meshExtents.reset();
|
||||
|
||||
// accumulate local transforms
|
||||
|
@ -1335,7 +1335,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
|
||||
materialIndex++;
|
||||
|
||||
|
||||
} else if (_textureFilenames.contains(childID)) {
|
||||
FBXTexture texture = getTexture(childID);
|
||||
for (int j = 0; j < extracted.partMaterialTextures.size(); j++) {
|
||||
|
@ -1360,7 +1360,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
setTangents(extracted.mesh, part.quadIndices.at(i + 2), part.quadIndices.at(i + 3));
|
||||
setTangents(extracted.mesh, part.quadIndices.at(i + 3), part.quadIndices.at(i));
|
||||
}
|
||||
// <= size - 3 in order to prevent overflowing triangleIndices when (i % 3) != 0
|
||||
// <= size - 3 in order to prevent overflowing triangleIndices when (i % 3) != 0
|
||||
// This is most likely evidence of a further problem in extractMesh()
|
||||
for (int i = 0; i <= part.triangleIndices.size() - 3; i += 3) {
|
||||
setTangents(extracted.mesh, part.triangleIndices.at(i), part.triangleIndices.at(i + 1));
|
||||
|
@ -1500,7 +1500,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
glm::vec4& weights = extracted.mesh.clusterWeights[i];
|
||||
float total = weights.x + weights.y + weights.z + weights.w;
|
||||
if (total != 1.0f && total != 0.0f) {
|
||||
weights /= total;
|
||||
weights /= total;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1573,7 +1573,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
avgRadius += glm::length(offset - projection * axis);
|
||||
}
|
||||
avgRadius /= (float)points.size();
|
||||
|
||||
|
||||
// compute endpoints of capsule in joint-frame
|
||||
glm::vec3 capsuleBegin = avgPoint;
|
||||
glm::vec3 capsuleEnd = avgPoint;
|
||||
|
@ -1594,27 +1594,27 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
joint.shapeInfo.radius = avgRadius;
|
||||
}
|
||||
geometry.palmDirection = parseVec3(mapping.value("palmDirection", "0, -1, 0").toString());
|
||||
|
||||
|
||||
// Add sitting points
|
||||
QVariantHash sittingPoints = mapping.value("sit").toHash();
|
||||
for (QVariantHash::const_iterator it = sittingPoints.constBegin(); it != sittingPoints.constEnd(); it++) {
|
||||
SittingPoint sittingPoint;
|
||||
sittingPoint.name = it.key();
|
||||
|
||||
|
||||
QVariantList properties = it->toList();
|
||||
sittingPoint.position = parseVec3(properties.at(0).toString());
|
||||
sittingPoint.rotation = glm::quat(glm::radians(parseVec3(properties.at(1).toString())));
|
||||
|
||||
|
||||
geometry.sittingPoints.append(sittingPoint);
|
||||
}
|
||||
|
||||
|
||||
// attempt to map any meshes to a named model
|
||||
for (QHash<QString, int>::const_iterator m = meshIDsToMeshIndices.constBegin();
|
||||
for (QHash<QString, int>::const_iterator m = meshIDsToMeshIndices.constBegin();
|
||||
m != meshIDsToMeshIndices.constEnd(); m++) {
|
||||
|
||||
|
||||
const QString& meshID = m.key();
|
||||
int meshIndex = m.value();
|
||||
|
||||
|
||||
if (ooChildToParent.contains(meshID)) {
|
||||
const QString& modelID = ooChildToParent.value(meshID);
|
||||
if (modelIDsToNames.contains(modelID)) {
|
||||
|
@ -1623,7 +1623,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return geometryPtr;
|
||||
}
|
||||
|
||||
|
@ -1641,5 +1641,3 @@ FBXGeometry* readFBX(QIODevice* device, const QVariantHash& mapping, const QStri
|
|||
|
||||
return reader.extractFBXGeometry(mapping, url);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -413,8 +413,8 @@ public:
|
|||
float _lightmapOffset = 0.0f;
|
||||
float _lightmapLevel;
|
||||
|
||||
QMultiHash<QString, QString> _connectionParentMap;
|
||||
QMultiHash<QString, QString> _connectionChildMap;
|
||||
QMultiMap<QString, QString> _connectionParentMap;
|
||||
QMultiMap<QString, QString> _connectionChildMap;
|
||||
|
||||
static glm::vec3 getVec3(const QVariantList& properties, int index);
|
||||
static QVector<glm::vec4> createVec4Vector(const QVector<double>& doubleVector);
|
||||
|
|
|
@ -85,11 +85,11 @@ bool ObjectAction::updateArguments(QVariantMap arguments) {
|
|||
quint64 previousExpires = _expires;
|
||||
QString previousTag = _tag;
|
||||
|
||||
bool lifetimeSet = true;
|
||||
float lifetime = EntityActionInterface::extractFloatArgument("action", arguments, "lifetime", lifetimeSet, false);
|
||||
if (lifetimeSet) {
|
||||
bool ttlSet = true;
|
||||
float ttl = EntityActionInterface::extractFloatArgument("action", arguments, "ttl", ttlSet, false);
|
||||
if (ttlSet) {
|
||||
quint64 now = usecTimestampNow();
|
||||
_expires = now + (quint64)(lifetime * USECS_PER_SECOND);
|
||||
_expires = now + (quint64)(ttl * USECS_PER_SECOND);
|
||||
} else {
|
||||
_expires = 0;
|
||||
}
|
||||
|
@ -114,10 +114,10 @@ QVariantMap ObjectAction::getArguments() {
|
|||
QVariantMap arguments;
|
||||
withReadLock([&]{
|
||||
if (_expires == 0) {
|
||||
arguments["lifetime"] = 0.0f;
|
||||
arguments["ttl"] = 0.0f;
|
||||
} else {
|
||||
quint64 now = usecTimestampNow();
|
||||
arguments["lifetime"] = (float)(_expires - now) / (float)USECS_PER_SECOND;
|
||||
arguments["ttl"] = (float)(_expires - now) / (float)USECS_PER_SECOND;
|
||||
}
|
||||
arguments["tag"] = _tag;
|
||||
});
|
||||
|
@ -245,3 +245,31 @@ bool ObjectAction::lifetimeIsOver() {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
quint64 ObjectAction::localTimeToServerTime(quint64 timeValue) const {
|
||||
// 0 indicates no expiration
|
||||
if (timeValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serverClockSkew = getEntityServerClockSkew();
|
||||
if (serverClockSkew < 0 && timeValue <= (quint64)(-serverClockSkew)) {
|
||||
return 1; // non-zero but long-expired value to avoid negative roll-over
|
||||
}
|
||||
|
||||
return timeValue + serverClockSkew;
|
||||
}
|
||||
|
||||
quint64 ObjectAction::serverTimeToLocalTime(quint64 timeValue) const {
|
||||
// 0 indicates no expiration
|
||||
if (timeValue == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int serverClockSkew = getEntityServerClockSkew();
|
||||
if (serverClockSkew > 0 && timeValue <= (quint64)serverClockSkew) {
|
||||
return 1; // non-zero but long-expired value to avoid negative roll-over
|
||||
}
|
||||
|
||||
return timeValue - serverClockSkew;
|
||||
}
|
||||
|
|
|
@ -47,11 +47,10 @@ public:
|
|||
virtual void deserialize(QByteArray serializedArguments) = 0;
|
||||
|
||||
virtual bool lifetimeIsOver();
|
||||
virtual quint64 getExpires() { return _expires; }
|
||||
|
||||
protected:
|
||||
|
||||
int getEntityServerClockSkew() const;
|
||||
|
||||
virtual btRigidBody* getRigidBody();
|
||||
virtual glm::vec3 getPosition();
|
||||
virtual void setPosition(glm::vec3 position);
|
||||
|
@ -68,6 +67,12 @@ protected:
|
|||
|
||||
quint64 _expires; // in seconds since epoch
|
||||
QString _tag;
|
||||
|
||||
quint64 localTimeToServerTime(quint64 timeValue) const;
|
||||
quint64 serverTimeToLocalTime(quint64 timeValue) const;
|
||||
|
||||
private:
|
||||
int getEntityServerClockSkew() const;
|
||||
};
|
||||
|
||||
#endif // hifi_ObjectAction_h
|
||||
|
|
|
@ -160,7 +160,7 @@ QByteArray ObjectActionOffset::serialize() const {
|
|||
dataStream << _linearDistance;
|
||||
dataStream << _linearTimeScale;
|
||||
dataStream << _positionalTargetSet;
|
||||
dataStream << _expires + getEntityServerClockSkew();
|
||||
dataStream << localTimeToServerTime(_expires);
|
||||
dataStream << _tag;
|
||||
});
|
||||
|
||||
|
@ -189,8 +189,11 @@ void ObjectActionOffset::deserialize(QByteArray serializedArguments) {
|
|||
dataStream >> _linearDistance;
|
||||
dataStream >> _linearTimeScale;
|
||||
dataStream >> _positionalTargetSet;
|
||||
dataStream >> _expires;
|
||||
_expires -= getEntityServerClockSkew();
|
||||
|
||||
quint64 serverExpires;
|
||||
dataStream >> serverExpires;
|
||||
_expires = serverTimeToLocalTime(serverExpires);
|
||||
|
||||
dataStream >> _tag;
|
||||
_active = true;
|
||||
});
|
||||
|
|
|
@ -198,7 +198,7 @@ QByteArray ObjectActionSpring::serialize() const {
|
|||
dataStream << _rotationalTarget;
|
||||
dataStream << _angularTimeScale;
|
||||
dataStream << _rotationalTargetSet;
|
||||
dataStream << _expires + getEntityServerClockSkew();
|
||||
dataStream << localTimeToServerTime(_expires);
|
||||
dataStream << _tag;
|
||||
});
|
||||
|
||||
|
@ -232,8 +232,10 @@ void ObjectActionSpring::deserialize(QByteArray serializedArguments) {
|
|||
dataStream >> _angularTimeScale;
|
||||
dataStream >> _rotationalTargetSet;
|
||||
|
||||
dataStream >> _expires;
|
||||
_expires -= getEntityServerClockSkew();
|
||||
quint64 serverExpires;
|
||||
dataStream >> serverExpires;
|
||||
_expires = serverTimeToLocalTime(serverExpires);
|
||||
|
||||
dataStream >> _tag;
|
||||
|
||||
_active = true;
|
||||
|
|
|
@ -229,7 +229,7 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locati
|
|||
|
||||
void MeshPartPayload::render(RenderArgs* args) const {
|
||||
PerformanceTimer perfTimer("MeshPartPayload::render");
|
||||
if (!model->_readyWhenAdded) {
|
||||
if (!model->_readyWhenAdded || !model->_isVisible) {
|
||||
return; // bail asap
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ static bool hasCorrectSyntax(const QScriptProgram& program) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool hadUncauchtExceptions(QScriptEngine& engine, const QString& fileName) {
|
||||
static bool hadUncaughtExceptions(QScriptEngine& engine, const QString& fileName) {
|
||||
if (engine.hasUncaughtException()) {
|
||||
const auto backtrace = engine.uncaughtExceptionBacktrace();
|
||||
const auto exception = engine.uncaughtException().toString();
|
||||
|
@ -615,7 +615,7 @@ QScriptValue ScriptEngine::evaluate(const QString& sourceCode, const QString& fi
|
|||
const auto result = QScriptEngine::evaluate(program);
|
||||
--_evaluatesPending;
|
||||
|
||||
const auto hadUncaughtException = hadUncauchtExceptions(*this, program.fileName());
|
||||
const auto hadUncaughtException = hadUncaughtExceptions(*this, program.fileName());
|
||||
if (_wantSignals) {
|
||||
emit evaluationFinished(result, hadUncaughtException);
|
||||
}
|
||||
|
@ -684,9 +684,8 @@ void ScriptEngine::run() {
|
|||
}
|
||||
lastUpdate = now;
|
||||
|
||||
if (hadUncauchtExceptions(*this, _fileNameString)) {
|
||||
stop();
|
||||
}
|
||||
// Debug and clear exceptions
|
||||
hadUncaughtExceptions(*this, _fileNameString);
|
||||
}
|
||||
|
||||
stopAllTimers(); // make sure all our timers are stopped if the script is ending
|
||||
|
@ -1021,7 +1020,7 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
|||
|
||||
QScriptEngine sandbox;
|
||||
QScriptValue testConstructor = sandbox.evaluate(program);
|
||||
if (hadUncauchtExceptions(sandbox, program.fileName())) {
|
||||
if (hadUncaughtExceptions(sandbox, program.fileName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
class ReadWriteLockable {
|
||||
public:
|
||||
template <typename F>
|
||||
bool withWriteLock(F f, bool require = true) {
|
||||
bool withWriteLock(F f, bool require = true) const {
|
||||
if (!require) {
|
||||
bool result = _lock.tryLockForWrite();
|
||||
if (result) {
|
||||
|
@ -22,7 +22,7 @@ public:
|
|||
_lock.unlock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
QWriteLocker locker(&_lock);
|
||||
f();
|
||||
|
@ -30,7 +30,7 @@ public:
|
|||
}
|
||||
|
||||
template <typename F>
|
||||
bool withTryWriteLock(F f) {
|
||||
bool withTryWriteLock(F f) const {
|
||||
return withWriteLock(f, false);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue