Can't dispose of cloned and impostorized meshes

Hi there !

So I have an annoying one, because I haven’t yet been able to reproduce a playground, I’m stuck because the scene.onAfterStepObservable listener doesn’t seem to be listening.

So my real issue is as follows :
I want to create a dice rolling app. So I clone the original dice a certain amount of time, set physicsImpostors and once they finished rolling I want to get rid of them. And basically the getting rid thing doesn’t work, the dispose() throws this error :

image

But I can’t reproduce my issue yet (although the playground is all set) because the part where I watch the moment the mesh stops moving is not called. Sorry to ask, but it seems I need help even for showing my actual problem… does somebody have a clue ?

The playground is here.
I’ll try to provide a simple description of what it contains :

  • I set up the basic scene environment, with enabled Physics (using deterministic cannon engine)
  • In importOriginal() I import the mesh and store it as the “original”
  • In instantiate(), I create a certain amount of clones, and give them a physical body. I then try to listen to the moment they immobilize (but the listener doesn’t work as demonstrated by line 83). When they all do, I want to dispose of all the meshes. The current playground doesn’t show it yet, but on my project that’s when the above error is thrown.
  • impostorize() is called in instantiate(), this is where the instance is given the PhysicsImpostor needed for collisions.

[ EDIT 10 Aug ]
A Pull Request solving this problem has been accepted. The fix should be available next week
[ / EDIT ]

You need to create the engine with deterministicLockstep=true (see lines 1-3):

https://playground.babylonjs.com/#66PS52#126

Thank you ! I missed that part.

But now I got a problem… My playground doesn’t reproduce my issue, once they all immobilized the meshes get disposed() just as expected, which is what I want but not what I have on my local project.

I’ll look further into it and try to set up a playground that throws the same error I have. I guess the mere log I showed above doesn’t hint at anything ?

The error you pasted shows that remove is not a function of world. You should check that your CannonJSPlugin.world property is ok and not overriden at some point.

In the constructor, it is created as this.world = new this.BJSCANNON.World();.

Thanks for the suggestion, I’ll check that out asap !

So… it turns out it’s a little bigger than I thought.
I looked into the world property as you suggested and found this
:

It seems the prototype doesn’t have an remove() method indeed (but removeBody() instead). So I figured it must be an issue about cannon. And doing my research, I realized :

  • I am actually using cannon-es instead of cannon. That is why my issue wasn’t reproduced on the playground.
  • Cannon-es has had several threads regarding this kind of problems, some of them discussing an awkwardly similar issue, that has been brought up here on babylon’s forum.

A Babylon PR has since fixed this issue (in 5.0.0-alpha.16), following this issue here.

But while the deprecated add() method was replaced with addBody(), the remove() method is still used and I assume that it is what’s throwing the error (the parallel seems obvious).

Since I can’t reproduce the problem on the playground due to cannon-es being used instead of cannon, here is a stand alone html file that demonstrates the issue :

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8" />
  <title>cannon.js + babylon.js - basic integration example</title>
  <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
  <style>
    body {
      margin: 0;
      padding: 0;
    }

    canvas {
      width: 100vw;
      height: 100vh;
    }

    #scene-explorer-host,
    #inspector-host {
      position: absolute !important;
    }
  </style>
</head>

<body>
  <canvas id="renderCanvas"></canvas>
<!-- replace below CDN with 5.0.0-alpha.15 version and you'll see the fixed issue about deprecated world.add()-->
  <script src="https://unpkg.com/babylonjs@5.0.0-alpha.16/babylon.js"></script>
  <script type="module">
    import * as CANNON from 'https://unpkg.com/cannon-es@0.17.0/dist/cannon-es.js'

    // Canvas
    const canvas = document.querySelector('#renderCanvas')

    // Engine
    const engine = new BABYLON.Engine(canvas, true)
    window.addEventListener('resize', () => engine.resize())

    // Scene
    const scene = new BABYLON.Scene(engine)

    // Camera
    const camera = new BABYLON.ArcRotateCamera(
      'camera',
      -Math.PI / 2,
      Math.PI / 2.5,
      15,
      new BABYLON.Vector3(0, 0, 0),
      scene
    )
    camera.attachControl(canvas, true)

    // Light
    const light = new BABYLON.HemisphericLight('light', new BABYLON.Vector3(0, 1, 0), scene)

    // Box
    const box = BABYLON.MeshBuilder.CreateBox('box', {}, scene)

    // Physics
    window.CANNON = CANNON // force the usage of cannon-es
    const physEngine = new BABYLON.CannonJSPlugin(false)
    scene.enablePhysics(undefined, physEngine)

    // Ground
    const ground = BABYLON.Mesh.CreateGround('ground1', 10, 10, 2, scene)
    ground.physicsImpostor = new BABYLON.PhysicsImpostor(
      ground,
      BABYLON.PhysicsImpostor.BoxImpostor,
      { mass: 0, friction: 0.5, restitution: 0.7 },
      scene
    )
    ground.position.y -= 2

    // Box body
    box.physicsImpostor = new BABYLON.PhysicsImpostor(box, BABYLON.PhysicsImpostor.BoxImpostor, { mass: 5 }, scene)
    box.physicsImpostor.setAngularVelocity(new BABYLON.Quaternion(0, 10, 0, 0))
    box.physicsImpostor._physicsBody.angularDamping = 0.5

    scene.debugLayer.show()
    engine.runRenderLoop(() => {
      scene.render()
    })
    setTimeout(() => {
      /** ---------------------------------------------
        * BELOW IS THE BREAKING LINE
        */
      box.dispose()
    }, 3000)
  </script>
</body>

</html>

I’d like to submit a PR about this based on the merge that fixed the add() part, but not before confirming my conclusion was right. Sorry to bother, hope I made it clear enough to evaluate. :smiley:

That’s very clear, thanks! However, I don’t know physic engines, so I will let @RaananW or @Cedric answer this one.

Hey! thanks for the analysis :slight_smile:

So you are saying that you want to change remove to removeBody? if it is available in the old cannon implementation - be my guest! If it isn’t, you can check if the function exists and run the right one. In both cases - a PR will be very appreciated :slight_smile:

I forgot the “what’s new” notes in the PR so I immediately closed it, I hope it doesn’t matter !

The PR is now available here
The method falls back to old cannon’s implementation in case (just like the fix for world.addBody() does)

merged, thank you very much!

Sure, I’m really new to this stuff but I’ll enjoy contributing wherever I can in the future. :slight_smile:
Will the fix be available in the upcoming 5.0.0-alpha.38 ?

Yes it will be. not sure when alpha 38 will be released. This week for sure.