From 83c6ba97c01a9a335ecde520db3f830cee0c1023 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 29 Apr 2015 23:48:08 +0200 Subject: [PATCH] Disable skinning updates for actors beyond the AI processing distance --- apps/openmw/mwmechanics/actors.cpp | 9 ++++++--- apps/openmw/mwmechanics/character.cpp | 5 +++++ apps/openmw/mwmechanics/character.hpp | 3 +++ apps/openmw/mwrender/animation.cpp | 8 ++++++++ apps/openmw/mwrender/animation.hpp | 4 ++++ components/sceneutil/riggeometry.cpp | 12 ++++++++++++ components/sceneutil/riggeometry.hpp | 3 +++ components/sceneutil/skeleton.cpp | 14 ++++++++++++-- components/sceneutil/skeleton.hpp | 8 ++++++++ 9 files changed, 61 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/actors.cpp b/apps/openmw/mwmechanics/actors.cpp index bb59d46c0..3333511d3 100644 --- a/apps/openmw/mwmechanics/actors.cpp +++ b/apps/openmw/mwmechanics/actors.cpp @@ -1085,12 +1085,15 @@ namespace MWMechanics // AI and magic effects update for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter) { + bool inProcessingRange = Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) + <= sqrProcessingDistance; + + iter->second->getCharacterController()->setActive(inProcessingRange); + if (!iter->first.getClass().getCreatureStats(iter->first).isDead()) { updateActor(iter->first, duration); - if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && - Ogre::Vector3(player.getRefData().getPosition().pos).squaredDistance(Ogre::Vector3(iter->first.getRefData().getPosition().pos)) - <= sqrProcessingDistance) + if (MWBase::Environment::get().getMechanicsManager()->isAIActive() && inProcessingRange) { if (timerUpdateAITargets == 0) { diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 98a420ba6..adcfb57a4 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -1898,6 +1898,11 @@ bool CharacterController::isKnockedOut() const return mHitState == CharState_KnockOut; } +void CharacterController::setActive(bool active) +{ + mAnimation->setActive(active); +} + void CharacterController::setHeadTrackTarget(const MWWorld::Ptr &target) { mHeadTrackTarget = target; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index da74b2a33..987a0d29a 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -228,6 +228,9 @@ public: bool isReadyToBlock() const; bool isKnockedOut() const; + /// @see Animation::setActive + void setActive(bool active); + /// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr. void setHeadTrackTarget(const MWWorld::Ptr& target); }; diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index c5479e3f7..245095492 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -214,6 +214,14 @@ namespace MWRender mInsert->removeChild(mObjectRoot); } + void Animation::setActive(bool active) + { + if (SceneUtil::Skeleton* skel = dynamic_cast(mObjectRoot.get())) + { + skel->setActive(active); + } + } + void Animation::updatePtr(const MWWorld::Ptr &ptr) { mPtr = ptr; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 9aa15520f..c85f87403 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -242,6 +242,10 @@ public: Animation(const MWWorld::Ptr &ptr, osg::ref_ptr parentNode, Resource::ResourceSystem* resourceSystem); virtual ~Animation(); + /// Set active flag on the object skeleton, if one exists. + /// @see SceneUtil::Skeleton::setActive + void setActive(bool active); + osg::Group* getOrCreateObjectRoot(); osg::Group* getObjectRoot(); diff --git a/components/sceneutil/riggeometry.cpp b/components/sceneutil/riggeometry.cpp index 19e5b0ae6..7f30aff74 100644 --- a/components/sceneutil/riggeometry.cpp +++ b/components/sceneutil/riggeometry.cpp @@ -58,6 +58,8 @@ public: }; RigGeometry::RigGeometry() + : mFirstFrame(true) + , mBoundsFirstFrame(true) { setCullCallback(new UpdateRigGeometry); setUpdateCallback(new UpdateRigBounds); @@ -67,6 +69,8 @@ RigGeometry::RigGeometry() RigGeometry::RigGeometry(const RigGeometry ©, const osg::CopyOp ©op) : osg::Geometry(copy, copyop) , mInfluenceMap(copy.mInfluenceMap) + , mFirstFrame(copy.mFirstFrame) + , mBoundsFirstFrame(copy.mBoundsFirstFrame) { setSourceGeometry(copy.mSourceGeometry); } @@ -199,6 +203,10 @@ void RigGeometry::update(osg::NodeVisitor* nv) return; } + if (!mSkeleton->getActive() && !mFirstFrame) + return; + mFirstFrame = false; + mSkeleton->updateBoneMatrices(nv); osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); @@ -247,6 +255,10 @@ void RigGeometry::updateBounds(osg::NodeVisitor *nv) return; } + if (!mSkeleton->getActive() && !mBoundsFirstFrame) + return; + mBoundsFirstFrame = false; + mSkeleton->updateBoneMatrices(nv); osg::Matrixf geomToSkel = getGeomToSkelMatrix(nv); diff --git a/components/sceneutil/riggeometry.hpp b/components/sceneutil/riggeometry.hpp index e82f6254a..ea4245aa8 100644 --- a/components/sceneutil/riggeometry.hpp +++ b/components/sceneutil/riggeometry.hpp @@ -64,6 +64,9 @@ namespace SceneUtil BoneSphereMap mBoneSphereMap; + bool mFirstFrame; + bool mBoundsFirstFrame; + bool initFromParentSkeleton(osg::NodeVisitor* nv); osg::Matrixf getGeomToSkelMatrix(osg::NodeVisitor* nv); diff --git a/components/sceneutil/skeleton.cpp b/components/sceneutil/skeleton.cpp index c1ab36136..f105977ba 100644 --- a/components/sceneutil/skeleton.cpp +++ b/components/sceneutil/skeleton.cpp @@ -35,6 +35,7 @@ Skeleton::Skeleton() : mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) , mLastFrameNumber(0) + , mActive(true) { } @@ -44,12 +45,11 @@ Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op) , mBoneCacheInit(false) , mNeedToUpdateBoneMatrices(true) , mLastFrameNumber(0) + , mActive(copy.mActive) { } - - Bone* Skeleton::getBone(const std::string &name) { if (!mBoneCacheInit) @@ -123,6 +123,16 @@ void Skeleton::updateBoneMatrices(osg::NodeVisitor* nv) } } +void Skeleton::setActive(bool active) +{ + mActive = active; +} + +bool Skeleton::getActive() const +{ + return mActive; +} + Bone::Bone() : mNode(NULL) { diff --git a/components/sceneutil/skeleton.hpp b/components/sceneutil/skeleton.hpp index d710ac61b..1987fd4e8 100644 --- a/components/sceneutil/skeleton.hpp +++ b/components/sceneutil/skeleton.hpp @@ -47,6 +47,12 @@ namespace SceneUtil /// Request an update of bone matrices. May be a no-op if already updated in this frame. void updateBoneMatrices(osg::NodeVisitor* nv); + /// Set the skinning active flag. Inactive skeletons will not have their child rigs updated. + /// You should set this flag to false if you know that bones are not currently moving. + void setActive(bool active); + + bool getActive() const; + private: // The root bone is not a "real" bone, it has no corresponding node in the scene graph. // As far as the scene graph goes we support multiple root bones. @@ -58,6 +64,8 @@ namespace SceneUtil bool mNeedToUpdateBoneMatrices; + bool mActive; + unsigned int mLastFrameNumber; };