mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-16 18:19:55 +00:00
Don't update off-screen animations
Make flying creatures animate in-place when out of processing range
This commit is contained in:
parent
1522bda60b
commit
bba9a8dd91
7 changed files with 51 additions and 19 deletions
|
@ -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 ©, const osg::CopyOp ©op)
|
|||
, 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…
Reference in a new issue