Visually hidden instances still present in the "frozen" scene

Hi! I have an issue. When I create/remove objects sometimes my pooled(visually hidden) objects appear on the screen. And it only disappeared if I manually call scene.unfreezeActiveMeshes();.

There are bushes around the yellow arrow:

After scene.unfreezeActiveMeshes(); bushes disappeared:

But it appears again after some time…

My frozen Scene constructor:

this.performancePriority = BABYLON.ScenePerformancePriority.Aggressive;
this.skipFrustumClipping = true;
this.autoClearDepthAndStencil = false;

When I change object’s transform or create a new instance, I call this method:

forceModelToUpdate(model: BABYLON.AbstractMesh): void {
    scene.renderingManager.maintainStateBetweenFrames = false;
    model._unFreeze();
    if (model.isAnInstance) {
      (model as BABYLON.InstancedMesh).sourceMesh._unFreeze();
    }
}

This is how I put the object in my pool (to make it “visually” hidden):

pool.push(model);
model.unfreezeWorldMatrix();
model.position.y = 10000; // <--- this way
model.scaling.setAll(1);
model.freezeWorldMatrix();
scene.forceModelToUpdate(model);

This is how I create new instance:

modelInstance = (model as BABYLON.Mesh).createInstance(id);
modelInstance.setParent(model.parent);
scene.unfreezeActiveMeshes();
scene.forceModelToUpdate(modelInstance);
scene.render(false, true);
scene.freezeActiveMeshes(true);
scene.forceModelToUpdate(modelInstance);

I think I just doing something wrong with mesh’s freeze / unfree or I forgot about some buffers clearing… IDK.

I have questions:

  • Do I use freeze/unFreeze right?
  • How to properly add a new instance when I apply freezing to scene with aggressive mode?
  • How to visually hide objects? Right now I use model.position.y = 10000; but maybe there is more suitable way.

Please, help me to investigate and fix the issue.

I found that drawElementsInstanced been called with different count:

Before scene.unfreeze

After scene.unfreeze

115 vs 58.

In scene.meshes:

16:46:58.933 __world.sceneEntity.scene.meshes.filter(m=>m.id.startsWith('SM_Env_Bushes_03')).length
16:46:58.950 58

this is probably because the root bush of the instances for instance is going out of screen.

A repro would help here.

They are all marked as alwaysSelectedAsActive

Another interesting thing:

visibleInstances contains one element two times for each instance and the mesh itself.

Is it OK or it is an issue?

UPDATED1:

Found the issue:

scene.render(false, true);
scene.freezeActiveMeshes(true);

It gives double render into visibleInstances

It will be really hard to fix without a repro. Is that possible ?

Seems like I found the root of problem. I called

scene.unfreezeActiveMeshes();
scene.forceModelToUpdate(modelInstance);
scene.render(false, true);
scene.freezeActiveMeshes(true);

inside Promise callback, so it doesn’t guarantee the order of execution. So I could have two renders for one frame.

There is more suitable way to update scene when add a new instance:

//call it inside onBeforeRender event
activateNewInstance(modelInstance: BABYLON.AbstractMesh) {
    this._activeMeshesFrozen = false;
    this.forceModelToUpdate(modelInstance); // modeInstance._unFreeze() + modelInstance.sourceMesh._unFreeze();

// copy-pasted from freezeActiveMeshes but without evaluation, because Babylon itself does it for us in the render loop.
    this.onAfterRenderObservable.addOnce(() => {
      this._activeMeshesFrozen = true;
      this._activeMeshesFrozenButKeepClipping = false;
      //@ts-ignore
      this._skipEvaluateActiveMeshesCompletely = true;
    });
}
2 Likes