From 97ba5250a5d920fc93770c50ee372a948c279954 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 2 Apr 2014 12:01:18 -0700 Subject: [PATCH] Only simulate() Avatar Models when necessary Also: rebuild collision shapes when Model scale changes --- interface/src/avatar/Avatar.cpp | 33 ++++++++++++++-------- interface/src/avatar/FaceModel.cpp | 5 ++-- interface/src/avatar/MyAvatar.cpp | 2 ++ interface/src/avatar/SkeletonModel.cpp | 3 ++ interface/src/renderer/Model.cpp | 38 ++++++++++++++++---------- interface/src/renderer/Model.h | 9 +++--- libraries/avatars/src/AvatarData.cpp | 2 ++ libraries/avatars/src/AvatarData.h | 2 ++ 8 files changed, 59 insertions(+), 35 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 5e12282f53..ec8539954a 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -117,20 +117,29 @@ void Avatar::simulate(float deltaTime) { getHand()->simulate(deltaTime, false); _skeletonModel.setLODDistance(getLODDistance()); - // copy joint data to skeleton - for (int i = 0; i < _jointData.size(); i++) { - const JointData& data = _jointData.at(i); - _skeletonModel.setJointState(i, data.valid, data.rotation); - } - glm::vec3 headPosition = _position; if (!_shouldRenderBillboard && inViewFrustum) { - _skeletonModel.simulate(deltaTime); - _skeletonModel.getHeadPosition(headPosition); + glm::vec3 headPosition = _position; + + _skeletonModel.updateGeometry(); + if (_skeletonModel.isActive()) { + // copy joint data to skeleton + if (_hasNewJointRotations) { + for (int i = 0; i < _jointData.size(); i++) { + const JointData& data = _jointData.at(i); + _skeletonModel.setJointState(i, data.valid, data.rotation); + } + _skeletonModel.simulate(deltaTime); + _hasNewJointRotations = false; + } + _skeletonModel.getHeadPosition(headPosition); + } + + Head* head = getHead(); + head->setPosition(headPosition); + head->setScale(_scale); + head->getFaceModel().updateGeometry(); + head->simulate(deltaTime, false, _shouldRenderBillboard); } - Head* head = getHead(); - head->setPosition(headPosition); - head->setScale(_scale); - head->simulate(deltaTime, false, _shouldRenderBillboard); // use speed and angular velocity to determine walking vs. standing if (_speed + fabs(_bodyYawDelta) > 0.2) { diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index c483642d15..5d9b71f11d 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -19,8 +19,7 @@ FaceModel::FaceModel(Head* owningHead) : } void FaceModel::simulate(float deltaTime) { - bool geometryIsUpToDate = updateGeometry(); - if (!geometryIsUpToDate) { + if (!isActive()) { return; } Avatar* owningAvatar = static_cast(_owningHead->_owningAvatar); @@ -42,7 +41,7 @@ void FaceModel::simulate(float deltaTime) { setPupilDilation(_owningHead->getPupilDilation()); setBlendshapeCoefficients(_owningHead->getBlendshapeCoefficients()); - Model::simulateInternal(deltaTime); + Model::simulate(deltaTime); } void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBXJoint& joint, JointState& state) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9dcfaa09ba..0b220a532c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -289,6 +289,7 @@ void MyAvatar::simulate(float deltaTime) { getHand()->collideAgainstOurself(); getHand()->simulate(deltaTime, true); + _skeletonModel.updateGeometry(); _skeletonModel.simulate(deltaTime); // copy out the skeleton joints from the model @@ -305,6 +306,7 @@ void MyAvatar::simulate(float deltaTime) { } head->setPosition(headPosition); head->setScale(_scale); + head->getFaceModel().updateGeometry(); head->simulate(deltaTime, true); // Zero thrust out now that we've added it to velocity in this frame diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index e6318e2003..0ce97f4ef9 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -19,6 +19,9 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar) : } void SkeletonModel::simulate(float deltaTime) { + if (!isActive()) { + return; + } setTranslation(_owningAvatar->getPosition()); setRotation(_owningAvatar->getOrientation() * glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f))); const float MODEL_SCALE = 0.0006f; diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 1e609afe33..000a41b7d5 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -56,6 +56,14 @@ Model::SkinLocations Model::_skinLocations; Model::SkinLocations Model::_skinNormalMapLocations; Model::SkinLocations Model::_skinShadowLocations; +void Model::setScale(const glm::vec3& scale) { + glm::vec3 deltaScale = _scale - scale; + if (glm::length2(deltaScale) > EPSILON) { + _scale = scale; + rebuildShapes(); + } +} + void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations) { program.bind(); locations.clusterMatrices = program.uniformLocation("clusterMatrices"); @@ -182,10 +190,14 @@ void Model::reset() { } } -// return 'true' if geometry is up to date -bool Model::updateGeometry() { - bool needToRebuild = false; +void Model::updateGeometry() { + // NOTE: this is a recursive call that walks all attachments, and their attachments + for (int i = 0; i < _attachments.size(); i++) { + Model* model = _attachments.at(i); + model->updateGeometry(); + } + bool needToRebuild = false; if (_nextGeometry) { _nextGeometry = _nextGeometry->getLODOrFallback(_lodDistance, _nextLODHysteresis); _nextGeometry->setLoadPriority(this, -_lodDistance); @@ -197,7 +209,7 @@ bool Model::updateGeometry() { } if (!_geometry) { // geometry is not ready - return false; + return; } QSharedPointer geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); @@ -260,9 +272,9 @@ bool Model::updateGeometry() { model->setURL(attachment.url); _attachments.append(model); } - createShapes(); + rebuildShapes(); } - return true; + return; } bool Model::render(float alpha, bool forShadowMap) { @@ -440,7 +452,7 @@ void Model::clearShapes() { _jointShapes.clear(); } -void Model::createShapes() { +void Model::rebuildShapes() { clearShapes(); if (_jointStates.isEmpty()) { @@ -670,20 +682,16 @@ void Blender::run() { Q_ARG(const QVector&, vertices), Q_ARG(const QVector&, normals)); } - void Model::simulate(float deltaTime) { - bool geometryIsUpToDate = updateGeometry(); - if (!geometryIsUpToDate) { + // NOTE: this is a recursive call that walks all attachments, and their attachments + if (!isActive()) { return; } - simulateInternal(deltaTime); -} - -void Model::simulateInternal(float deltaTime) { // update the world space transforms for all joints for (int i = 0; i < _jointStates.size(); i++) { updateJointState(i); } + _shapesAreDirty = true; const FBXGeometry& geometry = _geometry->getFBXGeometry(); @@ -720,7 +728,6 @@ void Model::simulateInternal(float deltaTime) { } void Model::updateJointState(int index) { - _shapesAreDirty = true; JointState& state = _jointStates[index]; const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXJoint& joint = geometry.joints.at(index); @@ -838,6 +845,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last for (int j = freeLineage.size() - 1; j >= 0; j--) { updateJointState(freeLineage.at(j)); } + _shapesAreDirty = true; return true; } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index e7c94deb43..0c05b18429 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -36,7 +36,7 @@ public: void setRotation(const glm::quat& rotation) { _rotation = rotation; } const glm::quat& getRotation() const { return _rotation; } - void setScale(const glm::vec3& scale) { _scale = scale; } + void setScale(const glm::vec3& scale); const glm::vec3& getScale() const { return _scale; } void setOffset(const glm::vec3& offset) { _offset = offset; } @@ -156,7 +156,7 @@ public: float getRightArmLength() const; void clearShapes(); - void createShapes(); + void rebuildShapes(); void updateShapePositions(); void renderJointCollisionShapes(float alpha); void renderBoundingCollisionShapes(float alpha); @@ -185,6 +185,8 @@ public: /// Sets blended vertices computed in a separate thread. void setBlendedVertices(const QVector& vertices, const QVector& normals); + void updateGeometry(); + protected: QSharedPointer _geometry; @@ -217,9 +219,6 @@ protected: QVector _meshStates; - bool updateGeometry(); - void simulateInternal(float deltaTime); - /// Updates the state of the joint at the specified index. virtual void updateJointState(int index); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 31639b6836..930e3f7350 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -40,6 +40,7 @@ AvatarData::AvatarData() : _handState(0), _keyState(NO_KEY_DOWN), _isChatCirclingEnabled(false), + _hasNewJointRotations(true), _headData(NULL), _handData(NULL), _displayNameBoundingRect(), @@ -483,6 +484,7 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { } } } // numJoints * 8 bytes + _hasNewJointRotations = true; return sourceBuffer - startPosition; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 2ea20c1041..221bbd0428 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -242,6 +242,8 @@ protected: bool _isChatCirclingEnabled; + bool _hasNewJointRotations; // set in AvatarData, cleared in Avatar + HeadData* _headData; HandData* _handData;