Synchronizing the scaling of PhysicsShapes with a Mesh

Dear friends :face_with_peeking_eye:, I have a question about synchronizing the scaling of PhysicsShapes with a Mesh in the Havok physics engine. I’m animating the growth of a mesh, but while the mesh scales up, its physical shape remains unchanged. How can I synchronize the scaling of the physical shape with the mesh?

I do scaling animation with a function:

import { AbstractMesh, Animation, Vector3 } from 'babylonjs'

class MeshAnimator {

fps: number = 60

  async animateScaling(mesh: AbstractMesh, targetScaling: Vector3 = new Vector3(-1, 1, 1), animationSpeedRatio: number = 1): Promise<void> {
    return new Promise<void>((resolve) => {
      if (mesh && mesh.scaling) {
        const scalingAnimation = new Animation(
          'scalingAnimation',
          'scaling',
          this.fps,
          Animation.ANIMATIONTYPE_VECTOR3,
          Animation.ANIMATIONLOOPMODE_CONSTANT,
        )

        const keys = [
          {
            frame: 0,
            value: mesh.scaling,
          },
          {
            frame: this.fps,
            value: targetScaling,
          },
        ]

        scalingAnimation.setKeys(keys)
        mesh.animations.push(scalingAnimation)
        const onAnimationEnd = () => {
          if (scalingAnimation) {
            mesh.animations = mesh.animations.filter((anim) => anim !== scalingAnimation)
          }
          animation.onAnimationEndObservable.removeCallback(onAnimationEnd)
          resolve()
        }

        const animation = mesh.getScene().beginAnimation(mesh, 0, this.fps, false, animationSpeedRatio, onAnimationEnd)
      }
    })
  }
}

I also wanted to animate the mesh.physicsBody.shape, but I couldn’t find this feature mentioned in the documentation. :face_with_monocle:

Thank you in advance for any advice and recommendations on how to best implement parallel scaling of the physical shape.

See the last section “if you scale the mesh”

1 Like

Thank you, HiGreg. That sounds like a reasonable suggestion. I’ll try updating it not on every frame of the render loop, but at some interval, and I’ll let you know how much it impacts performance. I’ll try using a multiplier and update the shape from the start to the end of the animation every 60th frame, for example. So, the shape will catch up with the mesh size once per second. Thanks, I’ll give it a try.

Actually, it works quite well. Here’s an example with the apple mesh, where I get and replace the shape every second. The apples grow properly. I simply call the function with the mesh as an argument and recreate the shape based on the mesh’s scaling. Of course, in the future, I’d like to have the ability to attach the shape to the mesh, allowing the shape to automatically follow the mesh’s scaling.

  getShape(mesh: AbstractMesh, initialRadius: number = 0.12) {
    const scaling = mesh.scaling.y
    const calculatedRadius = scaling * initialRadius
    const center = new Vector3(0, calculatedRadius, 0)
    const shape = new PhysicsShapeSphere(center, calculatedRadius, mesh.getScene());

    return shape;
  }

:+1:

1 Like

There is a potential performance optimization if scaling a complicated or hard-to-regenerate shape. I note that “addChild()” on a SHAPE_CONTAINER includes a scaling vector. With this in mind, adding an existing shape to a container shape and using the scale parameter might perform better than regenerating the shape from the original mesh.

I don’t know if a container shape can be added to another container shape. If not, then my (possible) optimization is likely only useful for hull or mesh shapes. It might be prudent to save the original shape and scale always from there rather than a continuous up or down scaling which might introduce errors from floating point precision.

As a framework user, it would be convenient for me if there were a parameter like mesh.physicsBody.syncShapeWithMesh = true for physicsBody (or something like that). However, if I need to update the shape programmatically, it would probably be enough to have the ability to change the parameters of the existing shape without having to recreate it through dispose() and regenerate it again. Right now, when I use shape recreation, it’s hard to debug because I have to click the toggle back and forth in the Inspector to update the shape sizes. image
The Inspector doesn’t refresh them on its own. That’s why an shape update would be more convenient than deleting and creating the shape again.

1 Like