Don't update off-screen animations

Make flying creatures animate in-place when out of processing range
0.6.3
scrawl 7 years ago
parent 1522bda60b
commit bba9a8dd91
No known key found for this signature in database
GPG Key ID: 2E6CC3676024C402

@ -1213,14 +1213,12 @@ namespace MWMechanics
// AI and magic effects update
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{
float distSqr = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2();
// AI processing is only done within distance of 7168 units to the player. Note the "AI distance" slider doesn't affect this
// (it only does some throttling for targets beyond the "AI distance", so doesn't give any guarantees as to whether AI will be enabled or not)
// This distance could be made configurable later, but the setting must be marked with a big warning:
// using higher values will make a quest in Bloodmoon harder or impossible to complete (bug #1876)
bool inProcessingRange = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2()
<= sqrAiProcessingDistance;
iter->second->getCharacterController()->setActive(inProcessingRange);
bool inProcessingRange = distSqr <= sqrAiProcessingDistance;
if (iter->first == player)
iter->second->getCharacterController()->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell());
@ -1326,9 +1324,24 @@ namespace MWMechanics
CharacterController* playerCharacter = NULL;
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
{
if (iter->first != player &&
(player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2()
> sqrAiProcessingDistance)
const float animationDistance = aiProcessingDistance + 400; // Slightly larger than AI distance so there is time to switch back to the idle animation.
const float distSqr = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2();
bool isPlayer = iter->first == player;
bool inAnimationRange = isPlayer || (animationDistance == 0 || distSqr <= animationDistance*animationDistance);
int activeFlag = 1; // Can be changed back to '2' to keep updating bounding boxes off screen (more accurate, but slower)
if (isPlayer)
activeFlag = 2;
int active = inAnimationRange ? activeFlag : 0;
bool canFly = iter->first.getClass().canFly(iter->first);
if (canFly)
{
// Keep animating flying creatures so they don't just hover in-air
inAnimationRange = true;
active = std::max(1, active);
}
iter->second->getCharacterController()->setActive(active);
if (!inAnimationRange)
continue;
if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed())

@ -2392,7 +2392,7 @@ float CharacterController::getAttackStrength() const
return mAttackStrength;
}
void CharacterController::setActive(bool active)
void CharacterController::setActive(int active)
{
mAnimation->setActive(active);
}

@ -292,7 +292,7 @@ public:
float getAttackStrength() const;
/// @see Animation::setActive
void setActive(bool active);
void setActive(int active);
/// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr.
void setHeadTrackTarget(const MWWorld::ConstPtr& target);

@ -486,10 +486,10 @@ namespace MWRender
return mPtr;
}
void Animation::setActive(bool active)
void Animation::setActive(int active)
{
if (mSkeleton)
mSkeleton->setActive(active);
mSkeleton->setActive(static_cast<SceneUtil::Skeleton::ActiveType>(active));
}
void Animation::updatePtr(const MWWorld::Ptr &ptr)

@ -347,7 +347,8 @@ public:
/// Set active flag on the object skeleton, if one exists.
/// @see SceneUtil::Skeleton::setActive
void setActive(bool active);
/// 0 = Inactive, 1 = Active in place, 2 = Active
void setActive(int active);
osg::Group* getOrCreateObjectRoot();

@ -36,8 +36,9 @@ private:
Skeleton::Skeleton()
: mBoneCacheInit(false)
, mNeedToUpdateBoneMatrices(true)
, mActive(true)
, mActive(Active)
, mLastFrameNumber(0)
, mLastCullFrameNumber(0)
{
}
@ -48,6 +49,7 @@ Skeleton::Skeleton(const Skeleton &copy, const osg::CopyOp &copyop)
, mNeedToUpdateBoneMatrices(true)
, mActive(copy.mActive)
, mLastFrameNumber(0)
, mLastCullFrameNumber(0)
{
}
@ -123,14 +125,14 @@ void Skeleton::updateBoneMatrices(unsigned int traversalNumber)
}
}
void Skeleton::setActive(bool active)
void Skeleton::setActive(ActiveType active)
{
mActive = active;
}
bool Skeleton::getActive() const
{
return mActive;
return mActive != Inactive;
}
void Skeleton::markDirty()
@ -142,8 +144,16 @@ void Skeleton::markDirty()
void Skeleton::traverse(osg::NodeVisitor& nv)
{
if (!getActive() && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR && mLastFrameNumber != 0)
return;
if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
{
if (mActive == Inactive && mLastFrameNumber != 0)
return;
if (mActive == SemiActive && mLastFrameNumber != 0 && mLastCullFrameNumber+3 <= nv.getTraversalNumber())
return;
}
else if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
mLastCullFrameNumber = nv.getTraversalNumber();
osg::Group::traverse(nv);
}

@ -47,9 +47,16 @@ namespace SceneUtil
/// Request an update of bone matrices. May be a no-op if already updated in this frame.
void updateBoneMatrices(unsigned int traversalNumber);
enum ActiveType
{
Inactive=0,
SemiActive, /// Like Active, but don't bother with Update (including new bounding box) if we're off-screen
Active
};
/// 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);
void setActive(ActiveType active);
bool getActive() const;
@ -71,9 +78,10 @@ namespace SceneUtil
bool mNeedToUpdateBoneMatrices;
bool mActive;
ActiveType mActive;
unsigned int mLastFrameNumber;
unsigned int mLastCullFrameNumber;
};
}

Loading…
Cancel
Save