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
|
// AI and magic effects update
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
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
|
// 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)
|
// (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:
|
// 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)
|
// 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()
|
bool inProcessingRange = distSqr <= sqrAiProcessingDistance;
|
||||||
<= sqrAiProcessingDistance;
|
|
||||||
|
|
||||||
iter->second->getCharacterController()->setActive(inProcessingRange);
|
|
||||||
|
|
||||||
if (iter->first == player)
|
if (iter->first == player)
|
||||||
iter->second->getCharacterController()->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell());
|
iter->second->getCharacterController()->setAttackingOrSpell(MWBase::Environment::get().getWorld()->getPlayer().getAttackingOrSpell());
|
||||||
|
@ -1326,9 +1324,24 @@ namespace MWMechanics
|
||||||
CharacterController* playerCharacter = NULL;
|
CharacterController* playerCharacter = NULL;
|
||||||
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
for(PtrActorMap::iterator iter(mActors.begin()); iter != mActors.end(); ++iter)
|
||||||
{
|
{
|
||||||
if (iter->first != player &&
|
const float animationDistance = aiProcessingDistance + 400; // Slightly larger than AI distance so there is time to switch back to the idle animation.
|
||||||
(player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2()
|
const float distSqr = (player.getRefData().getPosition().asVec3() - iter->first.getRefData().getPosition().asVec3()).length2();
|
||||||
> sqrAiProcessingDistance)
|
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;
|
continue;
|
||||||
|
|
||||||
if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
|
if (iter->first.getClass().getCreatureStats(iter->first).isParalyzed())
|
||||||
|
|
|
@ -2392,7 +2392,7 @@ float CharacterController::getAttackStrength() const
|
||||||
return mAttackStrength;
|
return mAttackStrength;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::setActive(bool active)
|
void CharacterController::setActive(int active)
|
||||||
{
|
{
|
||||||
mAnimation->setActive(active);
|
mAnimation->setActive(active);
|
||||||
}
|
}
|
||||||
|
|
|
@ -292,7 +292,7 @@ public:
|
||||||
float getAttackStrength() const;
|
float getAttackStrength() const;
|
||||||
|
|
||||||
/// @see Animation::setActive
|
/// @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.
|
/// Make this character turn its head towards \a target. To turn off head tracking, pass an empty Ptr.
|
||||||
void setHeadTrackTarget(const MWWorld::ConstPtr& target);
|
void setHeadTrackTarget(const MWWorld::ConstPtr& target);
|
||||||
|
|
|
@ -486,10 +486,10 @@ namespace MWRender
|
||||||
return mPtr;
|
return mPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::setActive(bool active)
|
void Animation::setActive(int active)
|
||||||
{
|
{
|
||||||
if (mSkeleton)
|
if (mSkeleton)
|
||||||
mSkeleton->setActive(active);
|
mSkeleton->setActive(static_cast<SceneUtil::Skeleton::ActiveType>(active));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animation::updatePtr(const MWWorld::Ptr &ptr)
|
void Animation::updatePtr(const MWWorld::Ptr &ptr)
|
||||||
|
|
|
@ -347,7 +347,8 @@ public:
|
||||||
|
|
||||||
/// Set active flag on the object skeleton, if one exists.
|
/// Set active flag on the object skeleton, if one exists.
|
||||||
/// @see SceneUtil::Skeleton::setActive
|
/// @see SceneUtil::Skeleton::setActive
|
||||||
void setActive(bool active);
|
/// 0 = Inactive, 1 = Active in place, 2 = Active
|
||||||
|
void setActive(int active);
|
||||||
|
|
||||||
osg::Group* getOrCreateObjectRoot();
|
osg::Group* getOrCreateObjectRoot();
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,9 @@ private:
|
||||||
Skeleton::Skeleton()
|
Skeleton::Skeleton()
|
||||||
: mBoneCacheInit(false)
|
: mBoneCacheInit(false)
|
||||||
, mNeedToUpdateBoneMatrices(true)
|
, mNeedToUpdateBoneMatrices(true)
|
||||||
, mActive(true)
|
, mActive(Active)
|
||||||
, mLastFrameNumber(0)
|
, mLastFrameNumber(0)
|
||||||
|
, mLastCullFrameNumber(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,6 +49,7 @@ Skeleton::Skeleton(const Skeleton ©, const osg::CopyOp ©op)
|
||||||
, mNeedToUpdateBoneMatrices(true)
|
, mNeedToUpdateBoneMatrices(true)
|
||||||
, mActive(copy.mActive)
|
, mActive(copy.mActive)
|
||||||
, mLastFrameNumber(0)
|
, 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;
|
mActive = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Skeleton::getActive() const
|
bool Skeleton::getActive() const
|
||||||
{
|
{
|
||||||
return mActive;
|
return mActive != Inactive;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Skeleton::markDirty()
|
void Skeleton::markDirty()
|
||||||
|
@ -142,8 +144,16 @@ void Skeleton::markDirty()
|
||||||
|
|
||||||
void Skeleton::traverse(osg::NodeVisitor& nv)
|
void Skeleton::traverse(osg::NodeVisitor& nv)
|
||||||
{
|
{
|
||||||
if (!getActive() && nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR && mLastFrameNumber != 0)
|
if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
|
||||||
return;
|
{
|
||||||
|
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);
|
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.
|
/// Request an update of bone matrices. May be a no-op if already updated in this frame.
|
||||||
void updateBoneMatrices(unsigned int traversalNumber);
|
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.
|
/// 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.
|
/// 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;
|
bool getActive() const;
|
||||||
|
|
||||||
|
@ -71,9 +78,10 @@ namespace SceneUtil
|
||||||
|
|
||||||
bool mNeedToUpdateBoneMatrices;
|
bool mNeedToUpdateBoneMatrices;
|
||||||
|
|
||||||
bool mActive;
|
ActiveType mActive;
|
||||||
|
|
||||||
unsigned int mLastFrameNumber;
|
unsigned int mLastFrameNumber;
|
||||||
|
unsigned int mLastCullFrameNumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue