Add some hysteresis on the LOD switching to prevent rapid switching back

and forth.
This commit is contained in:
Andrzej Kapolka 2014-02-13 16:20:43 -08:00
parent ff01470850
commit 078b15c02d
4 changed files with 28 additions and 6 deletions

View file

@ -328,16 +328,30 @@ NetworkGeometry::~NetworkGeometry() {
} }
} }
QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance) const { QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance, float& hysteresis) const {
if (_lodParent.data() != this) { if (_lodParent.data() != this) {
return _lodParent.data()->getLODOrFallback(distance); return _lodParent.data()->getLODOrFallback(distance, hysteresis);
} }
if (_failedToLoad && _fallback) { if (_failedToLoad && _fallback) {
return _fallback; return _fallback;
} }
QSharedPointer<NetworkGeometry> lod = _lodParent;
float lodDistance = 0.0f;
QMap<float, QSharedPointer<NetworkGeometry> >::const_iterator it = _lods.upperBound(distance); QMap<float, QSharedPointer<NetworkGeometry> >::const_iterator it = _lods.upperBound(distance);
QSharedPointer<NetworkGeometry> lod = (it == _lods.constBegin()) ? _lodParent.toStrongRef() : *(it - 1); if (it != _lods.constBegin()) {
it = it - 1;
lod = it.value();
lodDistance = it.key();
}
if (hysteresis != NO_HYSTERESIS && hysteresis != lodDistance) {
// if we previously selected a different distance, make sure we've moved far enough to justify switching
const float HYSTERESIS_PROPORTION = 0.1f;
if (glm::abs(distance - qMax(hysteresis, lodDistance)) / fabsf(hysteresis - lodDistance) < HYSTERESIS_PROPORTION) {
return getLODOrFallback(hysteresis, hysteresis);
}
}
if (lod->isLoaded()) { if (lod->isLoaded()) {
hysteresis = lodDistance;
return lod; return lod;
} }
// if the ideal LOD isn't loaded, we need to make sure it's started to load, and possibly return the closest loaded one // if the ideal LOD isn't loaded, we need to make sure it's started to load, and possibly return the closest loaded one
@ -356,6 +370,7 @@ QSharedPointer<NetworkGeometry> NetworkGeometry::getLODOrFallback(float distance
closestDistance = distanceToLOD; closestDistance = distanceToLOD;
} }
} }
hysteresis = NO_HYSTERESIS;
return lod; return lod;
} }

View file

@ -62,6 +62,9 @@ class NetworkGeometry : public QObject {
public: public:
/// A hysteresis value indicating that we have no state memory.
static const float NO_HYSTERESIS = -1.0f;
NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback, NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback,
const QVariantHash& mapping = QVariantHash(), const QUrl& textureBase = QUrl()); const QVariantHash& mapping = QVariantHash(), const QUrl& textureBase = QUrl());
~NetworkGeometry(); ~NetworkGeometry();
@ -70,7 +73,8 @@ public:
bool isLoaded() const { return !_geometry.joints.isEmpty(); } bool isLoaded() const { return !_geometry.joints.isEmpty(); }
/// Returns a pointer to the geometry appropriate for the specified distance. /// Returns a pointer to the geometry appropriate for the specified distance.
QSharedPointer<NetworkGeometry> getLODOrFallback(float distance) const; /// \param hysteresis a hysteresis parameter that prevents rapid model switching
QSharedPointer<NetworkGeometry> getLODOrFallback(float distance, float& hysteresis) const;
const FBXGeometry& getFBXGeometry() const { return _geometry; } const FBXGeometry& getFBXGeometry() const { return _geometry; }
const QVector<NetworkMesh>& getMeshes() const { return _meshes; } const QVector<NetworkMesh>& getMeshes() const { return _meshes; }

View file

@ -93,7 +93,7 @@ void Model::simulate(float deltaTime) {
// update our LOD // update our LOD
if (_geometry) { if (_geometry) {
QSharedPointer<NetworkGeometry> geometry = _geometry->getLODOrFallback(glm::distance(_translation, QSharedPointer<NetworkGeometry> geometry = _geometry->getLODOrFallback(glm::distance(_translation,
Application::getInstance()->getCamera()->getPosition())); glm::vec3() /* Application::getInstance()->getCamera()->getPosition() */), _lodHysteresis);
if (_geometry != geometry) { if (_geometry != geometry) {
deleteGeometry(); deleteGeometry();
_dilatedTextures.clear(); _dilatedTextures.clear();
@ -419,6 +419,7 @@ void Model::setURL(const QUrl& url, const QUrl& fallback) {
// delete our local geometry and custom textures // delete our local geometry and custom textures
deleteGeometry(); deleteGeometry();
_dilatedTextures.clear(); _dilatedTextures.clear();
_lodHysteresis = NetworkGeometry::NO_HYSTERESIS;
_baseGeometry = _geometry = Application::getInstance()->getGeometryCache()->getGeometry(url, fallback); _baseGeometry = _geometry = Application::getInstance()->getGeometryCache()->getGeometry(url, fallback);
} }

View file

@ -176,7 +176,6 @@ public:
protected: protected:
QSharedPointer<NetworkGeometry> _baseGeometry;
QSharedPointer<NetworkGeometry> _geometry; QSharedPointer<NetworkGeometry> _geometry;
glm::vec3 _translation; glm::vec3 _translation;
@ -237,6 +236,9 @@ private:
void deleteGeometry(); void deleteGeometry();
void renderMeshes(float alpha, bool translucent); void renderMeshes(float alpha, bool translucent);
QSharedPointer<NetworkGeometry> _baseGeometry;
float _lodHysteresis;
float _pupilDilation; float _pupilDilation;
std::vector<float> _blendshapeCoefficients; std::vector<float> _blendshapeCoefficients;