[SOLVED] setLocalScale - Collision mesh

Hi there,

Apparently setLocalScale only affects visual mesh, what about collision? Any ways to scale/update it without reloading model? Thanks

I’ve not tried this myself but you could try:

  • Disable collision and rigidbody component
  • Set the scale of the entity
  • Enable collision and rigidbody component

That should remove and re-add the physics body to the world

No effect unfortunately


      scale = otherEntity.getLocalScale();
      otherEntity.collision.enabled = false;
      otherEntity.rigidbody.enabled = false;  
      otherEntity.setLocalScale(scale.x + 0.05, scale.y + 0.05, scale.z + 0.05);
      otherEntity.collision.enabled = true;
      otherEntity.rigidbody.enabled = true;  

You probably need to remove the cashed mesh in order for the engine to generate a new one with a new scale. So, after you disabled the components, and before you enable them, something like:

// when using render
for (const mesh of entity.collision.render.meshes) {
    delete this.app.systems.collision._triMeshCache[mesh.id];
}

// when using model
for (const instance of entity.collision.model.meshInstances) {
    delete this.app.systems.collision._triMeshCache[instance.mesh.id];
}
2 Likes

Hi, no effect either

  scale = otherEntity.getLocalScale();
  otherEntity.collision.enabled = false;
  otherEntity.rigidbody.enabled = false;  
  otherEntity.setLocalScale(scale.x + 0.05, scale.y + 0.05, scale.z + 0.05);

  for (const instance of otherEntity.collision.model.meshInstances) {
  delete this.app.systems.collision._triMeshCache[instance.mesh.id];
  }

  otherEntity.collision.enabled = true;
  otherEntity.rigidbody.enabled = true;  

Using debug draw

It should work. You need to debug and see why it doesn’t, if it doesn’t.
First, I’d check if it really doesn’t work by changing the scale to something much larger, e.g. multiply the current by 10 scale.x * 10. Perhaps 0.05 is not a noticeable change. I would also try to reset the cache completely, instead of only the affected mesh.

Couldn’t get it to work, tried deleting this.app.systems.collision._triMeshCache - no luck either
Here’s repro PlayCanvas 3D HTML5 Game Engine
KEY_PAGE_UP to increase scale/clear cache

Has to be something else than triMeshCache

You may need in addition to destroy the shape in Ammo:

for (const mesh of entity.collision.render.meshes) {
    const shape = this.app.systems.collision._triMeshCache[mesh.id];
    Ammo.destroy(shape);
    delete this.app.systems.collision._triMeshCache[mesh.id];
}

Have you tried this on render? Model throws errors

Isn’t it that Ammo.destroy(this._triMeshCache[key]); requires meshInstance key? As these are actually stored
Nevertheless, using ammo destroy with valid keys throwing ‘Error: Cannot destroy object. (Did you create it yourself?)’

No it’s being actually used in the PlayCanvas engine, I’ve shared the link above.

The logic is it’s not enough to remove the JS reference, Ammo.js occupies a different memory chunk than the one used by regular JS data. So that Ammo.destroy() call is required to clean up that memory.

Now if that solves your problem or not I’m not quite sure. But definitely it shouldn’t give any error if the object is valid. Try using the JS debugger or the console to check that you are using it as expected.

for (const instance of otherEntity.collision.model.meshInstances) {

       const shape = this.app.systems.collision._triMeshCache[instance.mesh.id];

        Ammo.destroy(shape);

  delete this.app.systems.collision._triMeshCache[instance.mesh.id];

  }

RuntimeError: indirect call to null


for (const instance of otherEntity.collision.model.meshInstances) {

       const shape = this.app.systems.collision._triMeshCache[instance.key];

        Ammo.destroy(shape);

  delete this.app.systems.collision._triMeshCache[instance.mesh.id];

  }

TypeError: a is undefined

It looks like it is not easy to change a scale of a collision mesh at runtime at the moment.

Before clearing the cache, you also want to destroy the reference stored in the collision component:

Ammo.destroy(otherEntity.collision.shape);
otherEntity.collision.shape = null;

Related issue:

1 Like

I can confirm it works as expected

    scale = otherEntity.getLocalScale();
    
    otherEntity.enabled = false;
    Ammo.destroy(otherEntity.collision.shape);
    otherEntity.collision.shape = null;
    otherEntity.setLocalScale(scale.x + 0.05, scale.y + 0.05, scale.z + 0.05);

  for (const instance of otherEntity.collision.model.meshInstances) {
  delete this.app.systems.collision._triMeshCache[instance.mesh.id];
  }

console.log(this.app.systems.collision._triMeshCache);
otherEntity.enabled = true;


}

Thank you folks

1 Like