BGE: New hysteresis offset to improve LOD level transitions

This change introduces a new hysteresis parameter that it will be added
or subtracted to/from the LOD distance to avoid popping when a LOD
object moves close to the LOD transition continuously.

Then, we have the following:

- a new LOD Hysteresis setting per scene (default 10%) which is located
in Scene context --> Level of Detail panel. This scene parameter also
will active/deactive the scene hysteresis.
- and a new LOD Hysteresis setting per object (default 10%) which is
located in Object context --> Levels of Detail panel. The LOD hysteresis
setting per object (if active) will overwrite the hysteresis setting per
scene value.

For the new blends: the hysteresis setting per scene would be active by
default and the per object would be inactive by default.
For the old blends: both hysteresis settings (per scene and per object)
would be inactive by default. A quick way to take advantage of this
feature for old blends would be to activate the hysteresis parameter in
the scene context -> Level of Detail panel

Reviewers: campbellbarton, kupoman, moguri

Reviewed By: kupoman, moguri

Subscribers: nonamejuju, lordodin

Differential Revision: https://developer.blender.org/D957
This commit is contained in:
Jorge Bernal
2015-03-22 18:13:53 +01:00
parent 0b4a71b072
commit e7d051043d
14 changed files with 170 additions and 5 deletions

View File

@@ -92,6 +92,8 @@ KX_GameObject::KX_GameObject(
m_bDyna(false),
m_layer(0),
m_currentLodLevel(0),
m_previousLodLevel(0),
m_lodHysteresis(0),
m_pBlenderObject(NULL),
m_pBlenderGroupObject(NULL),
m_bSuspendDynamics(false),
@@ -784,6 +786,11 @@ void KX_GameObject::AddLodMesh(RAS_MeshObject* mesh)
m_lodmeshes.push_back(mesh);
}
void KX_GameObject::SetLodHysteresisValue(int hysteresis)
{
m_lodHysteresis = hysteresis;
}
void KX_GameObject::UpdateLod(MT_Vector3 &cam_pos)
{
// Handle dupligroups
@@ -804,14 +811,47 @@ void KX_GameObject::UpdateLod(MT_Vector3 &cam_pos)
int level = 0;
Object *bob = this->GetBlenderObject();
LodLevel *lod = (LodLevel*) bob->lodlevels.first;
KX_Scene *sce = this->GetScene();
for (; lod; lod = lod->next, level++) {
if (!lod->source || lod->source->type != OB_MESH) level--;
if (!lod->next || lod->next->distance * lod->next->distance > distance2) break;
if (!lod->next) break;
if (level == (this->m_previousLodLevel) || (level == (this->m_previousLodLevel + 1))) {
short hysteresis = 0;
if (sce->IsActivedLodHysteresis()) {
// if exists, LoD level hysteresis will override scene hysteresis
if (lod->next->flags & OB_LOD_USE_HYST) {
hysteresis = lod->next->obhysteresis;
}
else if (this->m_lodHysteresis != 0) {
hysteresis = m_lodHysteresis;
}
}
float hystvariance = MT_abs(lod->next->distance - lod->distance) * hysteresis / 100;
if ((lod->next->distance + hystvariance) * (lod->next->distance + hystvariance) > distance2)
break;
}
else if (level == (this->m_previousLodLevel - 1)) {
short hysteresis = 0;
if (sce->IsActivedLodHysteresis()) {
// if exists, LoD level hysteresis will override scene hysteresis
if (lod->next->flags & OB_LOD_USE_HYST) {
hysteresis = lod->next->obhysteresis;
}
else if (this->m_lodHysteresis != 0) {
hysteresis = m_lodHysteresis;
}
}
float hystvariance = MT_abs(lod->next->distance - lod->distance) * hysteresis / 100;
if ((lod->next->distance - hystvariance) * (lod->next->distance - hystvariance) > distance2)
break;
}
}
RAS_MeshObject *mesh = this->m_lodmeshes[level];
this->m_currentLodLevel = level;
if (mesh != this->m_meshes[0]) {
this->m_previousLodLevel = level;
this->GetScene()->ReplaceMesh(this, mesh, true, false);
}
}