Clean this up a bit

master
Ansariel 2020-04-16 10:34:52 +02:00
parent 084eb8c030
commit 29f8de325c
2 changed files with 130 additions and 99 deletions

View File

@ -24,14 +24,14 @@
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
* http://www.firestormviewer.org
*/
#include "llviewerprecompiledheaders.h" // regular Firestorm includes
#include "llviewercontrol.h"
#include "llmath.h" // normal build
#include "llviewerobject.h"
#include "llframetimer.h"
#include "llviewerprecompiledheaders.h"
#include "fsregioncross.h"
//
#include "llframetimer.h"
#include "llmath.h"
#include "llviewercontrol.h"
#include "llviewerobject.h"
// Improved region crossing time limit prediction.
//
// Applied when
@ -55,15 +55,14 @@
// Potential vehicle, but might be just a chair.
// We don't start the movement averaging until there's movement at least once.
//
RegionCrossExtrapolateImpl::RegionCrossExtrapolateImpl(const LLViewerObject& vo) : // constructor
mOwner(vo), // back ref to owner
mPreviousUpdateTime(0), // time of last update
mMoved(false) // has not moved yet
RegionCrossExtrapolateImpl::RegionCrossExtrapolateImpl(const LLViewerObject& vo) :
mOwner(vo),
mPreviousUpdateTime(0),
mMoved(false)
{
LL_INFOS() << "Object " << vo.getID().asString() << " has sitter." << LL_ENDL; // log sit event
LL_INFOS() << "Object " << vo.getID().asString() << " has sitter." << LL_ENDL;
}
//
// update -- called for each object update message to "vehicle" objects.
//
// This is called for any object with an avatar sitting on it.
@ -71,42 +70,49 @@ RegionCrossExtrapolateImpl::RegionCrossExtrapolateImpl(const LLViewerObject& vo)
// If it has moved, we treat it as a vehicle.
//
void RegionCrossExtrapolateImpl::update()
{
if (!mMoved) // if not seen to move
{ LLVector3 rawvel = mOwner.getVelocity(); // velocity in world coords
if (rawvel.mV[VX] != 0.0 || rawvel.mV[VY] != 0.0 || rawvel.mV[VZ] != 0) // check for nonzero velocity
{ mMoved = true; } // moved, has seated avatar, thus is vehicle
{
if (!mMoved)
{
LLVector3 rawvel = mOwner.getVelocity(); // velocity in world coords
if (rawvel.mV[VX] != 0.f || rawvel.mV[VY] != 0.f || rawvel.mV[VZ] != 0.f) // check for nonzero velocity
{
mMoved = true; // moved, has seated avatar, thus is vehicle
}
else
{ return; } // sitting on stationary object, skip this
{
return; // sitting on stationary object, skip this
}
}
// Moving seat - do the extrapolation calculations
F64 dt = 1.0/45.0; // dt used on first value - one physics frame on server
F64 now = LLFrameTimer::getElapsedSeconds(); // timestamp
F64 dt = 1.0 / 45.0; // dt used on first value - one physics frame on server
F64 now = LLFrameTimer::getElapsedSeconds();
if (mPreviousUpdateTime != 0.0)
{ dt = now - mPreviousUpdateTime; // change since last update
{
dt = now - mPreviousUpdateTime; // change since last update
// Could adjust here for ping time and time dilation, but the filter isn't that
// sensitive to minor variations dt and it would just complicate things.
}
mPreviousUpdateTime = now;
LLQuaternion rot = mOwner.getRotationRegion(); // transform in global coords
const LLQuaternion& inverserot = rot.conjugate(); // transform global to local
LLVector3 vel = mOwner.getVelocity()*inverserot; // velocity in object coords
LLVector3 angvel = mOwner.getAngularVelocity()*inverserot; // angular velocity in object coords
mFilteredVel.update(vel,dt); // accum into filter in object coords
mFilteredAngVel.update(angvel,dt); // accum into filter in object coords
LLQuaternion rot = mOwner.getRotationRegion(); // transform in global coords
const LLQuaternion& inverserot = rot.conjugate(); // transform global to local
LLVector3 vel = mOwner.getVelocity() * inverserot; // velocity in object coords
LLVector3 angvel = mOwner.getAngularVelocity() * inverserot; // angular velocity in object coords
mFilteredVel.update(vel, dt); // accum into filter in object coords
mFilteredAngVel.update(angvel, dt); // accum into filter in object coords
}
//
// dividesafe -- floating divide with divide by zero check
//
// Returns infinity for a divide by near zero.
//
static inline F32 dividesafe(F32 num, F32 denom)
{ return((denom > FP_MAG_THRESHOLD // avoid divide by zero
|| denom < -FP_MAG_THRESHOLD)
? (num / denom)
: std::numeric_limits<F32>::infinity()); // return infinity if zero divide
{
return ((denom > FP_MAG_THRESHOLD || denom < -FP_MAG_THRESHOLD) // avoid divide by zero
? (num / denom) : std::numeric_limits<F32>::infinity()); // return infinity if zero divide
}
//
// getextraptimelimit -- don't extrapolate further ahead than this during a region crossing.
//
// Returns seconds of extrapolation that will probably stay within set limits of error.
@ -117,36 +123,43 @@ F32 RegionCrossExtrapolateImpl::getextraptimelimit() const
// The limits can be adjusted as debug symbols or in settings.xml, but that should not be necessary.
static LLCachedControl<F32> fsRegionCrossingPositionErrorLimit(gSavedSettings, "FSRegionCrossingPositionErrorLimit");
static LLCachedControl<F32> fsRegionCrossingAngleErrorLimit(gSavedSettings, "FSRegionCrossingAngleErrorLimit");
// Time limit is max allowed error / error. Returns worst case (smallest) of vel and angular vel limits.
// Time limit is max allowed error / error. Returns worst case (smallest) of vel and angular vel limits.
LLQuaternion rot = mOwner.getRotationRegion(); // transform in global coords
const LLQuaternion& inverserot = rot.conjugate(); // transform global to local
// Calculate safe extrapolation time limit.
F32 extrapTimeLimit = llmin(dividesafe(fsRegionCrossingPositionErrorLimit, ((mOwner.getVelocity()*inverserot - mFilteredVel.get()).length())),
dividesafe(fsRegionCrossingAngleErrorLimit, ((mOwner.getAngularVelocity()*inverserot - mFilteredAngVel.get()).length())));
LL_INFOS() << "Region cross extrapolation safe limit " << extrapTimeLimit << " secs." << LL_ENDL;
return(extrapTimeLimit); // do not extrapolate more than this
}
//
// Calculate safe extrapolation time limit.
F32 extrapTimeLimit = llmin(dividesafe(fsRegionCrossingPositionErrorLimit, ((mOwner.getVelocity() * inverserot - mFilteredVel.get()).length())),
dividesafe(fsRegionCrossingAngleErrorLimit, ((mOwner.getAngularVelocity() * inverserot - mFilteredAngVel.get()).length())));
LL_INFOS() << "Region cross extrapolation safe limit " << extrapTimeLimit << " secs." << LL_ENDL;
return extrapTimeLimit; // do not extrapolate more than this
}
// ifsaton -- True if object is being sat upon.
//
// Potential vehicle.
//
BOOL RegionCrossExtrapolate::ifsaton(const LLViewerObject& vo) // true if root object and being sat on
{ if (!vo.isRoot()) { return(false); } // not root, cannot be sat upon
bool RegionCrossExtrapolate::ifsaton(const LLViewerObject& vo) // true if root object and being sat on
{
if (!vo.isRoot())
{
return false; // not root, cannot be sat upon
}
for (auto iter = vo.getChildren().begin(); // check for avatar as child of root
iter != vo.getChildren().end(); iter++)
{
LLViewerObject* child = *iter; // get child
if (child->isAvatar()) // avatar as child
{
return(true); // we have a sitter
}
}
return(false); // no avatar children, not sat on
iter != vo.getChildren().end(); iter++)
{
LLViewerObject* child = *iter;
if (child->isAvatar())
{
return true;
}
}
return false; // no avatar children, not sat on
}
//
// LowPassFilter -- the low pass filter for smoothing velocities.
//
// Works on vectors.
@ -167,17 +180,17 @@ BOOL RegionCrossExtrapolate::ifsaton(const LLViewerObject& vo) // true if root
void LowPassFilter::update(const LLVector3& val, F32 secs) // add new value into filter
{
static LLCachedControl<F32> fsRegionCrossingSmoothingTime(gSavedSettings, "FSRegionCrossingSmoothingTime");
if (!mInitialized) // if not initialized yet
{ mFiltered = val; // just use new value
if (!mInitialized)
{
mFiltered = val; // just use new value
mInitialized = true;
return;
}
F32 filtermult = 1.0; // no filtering if zero filter time
if (fsRegionCrossingSmoothingTime > 0.001) // avoid divide by zero
{ filtermult = 1.0 - 1.0/pow(1.0+1.0/fsRegionCrossingSmoothingTime,secs); } // filter scale factor
mFiltered = val * filtermult + mFiltered*(1.0-filtermult); // low pass filter
F32 filtermult = 1.0f; // no filtering if zero filter time
if (fsRegionCrossingSmoothingTime > F_ALMOST_ZERO) // avoid divide by zero
{
filtermult = 1.0f - 1.0f / pow(1.0f + 1.0f / fsRegionCrossingSmoothingTime, secs); // filter scale factor
}
mFiltered = val * filtermult + mFiltered * (1.0f - filtermult); // low pass filter
}

View File

@ -32,9 +32,8 @@
// Improved region crossing support.
//
class LLViewerObject; // forward declaration
class LLViewerObject;
//
// LowPassFilter -- a simple Kalman low-pass filter.
//
// Supports nonuniform time deltas between samples, since object update times are not consistent.
@ -43,26 +42,27 @@ class LowPassFilter
{
private:
LLVector3 mFiltered; // filtered value
BOOL mInitialized; // true if initialized
bool mInitialized;
public:
LowPassFilter() : // constructor
LowPassFilter() :
mInitialized(false),
mFiltered(0.0,0.0,0.0)
{}
mFiltered()
{ }
void update(const LLVector3& val, F32 dt); // add new value into filter
const LLVector3& get() const // get filtered output
{
return(mFiltered); // already stored
return mFiltered; // already stored
}
void clear()
void clear()
{
mInitialized = false; // not initialized yet
mInitialized = false;
}
};
//
// RegionCrossExtrapolateImpl -- the extrapolation limit calculator.
//
// One of these is created when an object is sat upon. If the
@ -79,16 +79,15 @@ private:
F64 mPreviousUpdateTime; // previous update time
LowPassFilter mFilteredVel; // filtered velocity
LowPassFilter mFilteredAngVel; // filtered angular velocity
BOOL mMoved; // seen to move at least once
bool mMoved; // seen to move at least once
public:
RegionCrossExtrapolateImpl(const LLViewerObject& vo); // constructor
RegionCrossExtrapolateImpl(const LLViewerObject& vo);
void update(); // update on object update message
F32 getextraptimelimit() const; // don't extrapolate more than this
BOOL hasmoved() const { return(mMoved); } // true if has been seen to move with sitter
bool hasmoved() const { return (mMoved); } // true if has been seen to move with sitter
};
//
// RegionCrossExtrapolate -- calculate safe limit on how long to extrapolate after a region crossing
//
// Member object of llViewerObject. For vehicles, a RegionCrossExtrapolateImpl is allocated to do the real work.
@ -96,38 +95,57 @@ public:
// Call "changedlink" for any object update which changes parenting.
// Get the extrapolation limit time with getextraptimelimit.
//
class LLViewerObject; // forward
class RegionCrossExtrapolate {
class RegionCrossExtrapolate
{
private:
std::unique_ptr<RegionCrossExtrapolateImpl> mImpl; // pointer to region cross extrapolator, if present
std::unique_ptr<RegionCrossExtrapolateImpl> mImpl;
protected:
BOOL ifsaton(const LLViewerObject& vo); // true if root object and being sat on
bool ifsaton(const LLViewerObject& vo); // true if root object and being sat on
public:
void update(const LLViewerObject& vo) // new object update message received
{ if (mImpl.get()) { mImpl->update(); } // update extrapolator if present
{
if (mImpl.get())
{
mImpl->update(); // update extrapolator if present
}
}
void changedlink(const LLViewerObject& vo) // parent or child changed, check if extrapolation object needed
{
if (ifsaton(vo)) // if this object is now the root of a linkset with an avatar
{ if (!mImpl.get()) // if no extrapolation implementor
{ mImpl.reset(new RegionCrossExtrapolateImpl(vo)); } // add an extrapolator
} else { // not a vehicle
{
if (!mImpl.get()) // if no extrapolation implementor
{
mImpl.reset(new RegionCrossExtrapolateImpl(vo)); // add an extrapolator
}
}
else // not a vehicle
{
if (mImpl.get())
{ mImpl.reset(); } // no longer needed
{
mImpl.reset(); // no longer needed
}
}
}
BOOL ismovingssaton(const LLViewerObject &vo)
{ if (!mImpl.get()) { return(false); } // not sat on
return(mImpl->hasmoved()); // sat on, check for moving
bool ismovingssaton(const LLViewerObject &vo)
{
if (!mImpl.get())
{
return (false); // not sat on
}
return mImpl->hasmoved(); // sat on, check for moving
}
F32 getextraptimelimit() const // get extrapolation time limit
{ if (mImpl.get()) { return(mImpl->getextraptimelimit()); } // get extrapolation time limit if vehicle
return(std::numeric_limits<F32>::infinity()); // no limit if not a vehicle
{
if (mImpl.get())
{
return mImpl->getextraptimelimit(); // get extrapolation time limit if vehicle
}
return std::numeric_limits<F32>::infinity(); // no limit if not a vehicle
}
};