Physics body falling down after scaling

I am scaling my canon body with a transform controller and it scales fine.

When I make mass 0, then I can see it scale perfectly.

and when mass is greater than 0, and the body is in the floor and I scale the physics body, it is in this state.

image

half of the body is under the floor which is also a physics body created by this:

    const planeShape = new CANNON.Plane()
    const planeBody = new CANNON.Body({ mass: 0 })
    planeBody.addShape(planeShape)
    planeBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), -Math.PI / 2)
    world.addBody(planeBody)

and for this physics body, first i am creating a box physics body and scaling it by transform controller

for scaling first i calculate the new value of halfExtents it will have after scaling and update that by

function scalePhysicsBody(movingBody, x, y, z) {
    let currentShape = movingBody.shapes[0]
    movingBody.removeShape(currentShape)
    if (myShape == 'SPHERE') {
        currentShape.radius = Math.max(x, y, z)
        movingBody.addShape(currentShape)
    } else if (myShape == 'BOX') {
        currentShape.halfExtents.set(x / 2, y / 2, z / 2)
        movingBody.addShape(currentShape)
    }
    return movingBody
}

before scaling or doing anything, it need to be selected and moving body is the selected physics body which need to be scaled.

after i add shape to the body, do i need to call anything to update it ?

I am sorry if i am not providing much detail, i am just trying to give required detail so that it wont be clumsy.

I am afraid if i am able to articulate the situation, this is demo if it help !!

Do i need to add any other code?

This is scaling but mesh fall down the plane after scaling !!

1 Like

You are entering a whole new world of extra problems to solve.

Easiest thing to do is to create a new shape based on the new scale of the mesh and replace the shape of the body.

JSFiddle : Cannon Modify Scale (See lines 85-92)

I guess that’s what I am doing right?

function scalePhysicsBody(movingBody, x, y, z) {
    let currentShape = movingBody.shapes[0]
    movingBody.removeShape(currentShape)
    if (myShape == 'SPHERE') {
        currentShape.radius = Math.max(x, y, z)
        movingBody.addShape(currentShape)
    } else if (myShape == 'BOX') {
        currentShape.halfExtents.set(x / 2, y / 2, z / 2)
        movingBody.addShape(currentShape)
    }
    return movingBody
}

this is a function I am using where I pass a body to be scaled and x, y, and z are the dimension after scaling is done.

you are not doing that.
you are detaching the shape object from its parent, changing halfextents, then reattaching the same object back again.
In your case, the detach (removeShape), and reattach (addShape) is doing nothing.
Also, your line return movingBody is also likely pointless, since movingBody in your function is a reference to the original object. Any changes to the reference affect the original object that was passed into the function anyway.

Also look at my example. and you can see that it works.

Why doesn’t yours work, I don’t really know. Maybe you can find some documentation on the cannonjs repository or related websites about how to properly scale a cannon body or shape.

1 Like

oh god, I never doubted that because I learned to do that from the developer of the cannon himself.

https://github.com/schteppe/cannon.js/issues/270

Right now I changed it to:

function scalePhysicsBody(movingBody, x, y, z) {
    let currentShape = movingBody.shapes[0]
    movingBody.removeShape(currentShape)
    if (myShape == 'SPHERE') {
        let newradius = Math.max(x, y, z)
        movingBody.addShape(new CANNON.Sphere(newradius))
    } else if (myShape == 'BOX') {
        movingBody.addShape(new CANNON.Box(new CANNON.Vec3(x / 2, y / 2, z / 2)))
    }
}

you are right, I don’t need that return !!
I added that to the console after scaling is done and forgot to remove it.

I guess it is working now:

Thank you again. I was so scared because i was not able to understand what is wrong and you saw the wrong. Thank you

you are awesome !!!

much better.

I did some more experimenting and improved my version so that it no longer creates any new objects in the transformControls change event.
JSFiddle : Scale Cannon Body (see lines 83-92)

transformControls.addEventListener('change', function() {
 cubeShape.halfExtents.set(
    Math.abs(cubeMesh.scale.x / 2),
    Math.abs(cubeMesh.scale.y / 2),
    Math.abs(cubeMesh.scale.z / 2))
  cubeShape.updateConvexPolyhedronRepresentation()
  cubeBody.updateBoundingRadius();
})

bounce

3 Likes

awesome !! can i ask why did you change the attribute rather than creating new shape because though it was not working, the author of cannon es suggested that making a new shape is better than changing it and computing everything again.

and one more issue I am having with transform control is that it looks like its axis is not aligned with the local mesh so I don’t know the exact reason but translation is a bit painful in my case.

I will upload video showcasing this with you.

Yes, this is the demo

This the trim of the video i was recording to make a demo but positioning became so painful so avoided the idea !!

at 0:31 you can see that the direction of translation is not horizontal or vertical !!!

Oh, I was doing it wrong, I tried it earlier but it was not working and I never tried that again but it worked now. May be webpack did not reload the page.

I did set

transformControl.space = “local”

and when I rotated it, its translation axis is aligned in the vertical and horizontal directions.

awesome !!

Bravo

I you look at the source code of what happens when you create a new cannon.shape based on a cannon.box, it’s about 20 lines of many things happening.
I cherry picked the bits I actually needed.
This will run faster and reduce the chances of memory filling up with unused left-over objects.
I didn’t have any memory or speed issues anyway, since my example was very minimal, but this way is better.

can u share with us the link of ur faster version cannon-es, the cannon-es is painfully slow

see my earlier comments. It was already updated. Link is in the comments.

what? is cannon-es have an issue with its speed?

I am curious to know.

1 Like

your solution looks smarter than adding a new shape to the body.

am just curious to know do we need to call any of the other functions inside the shape just to update attributes like the bounding box.

This is my new function ( thanks to you)


function scalePhysicsBody(movingBody, x, y, z) {
    let currentShape = movingBody.shapes[0]
    // movingBody.removeShape(currentShape)
    if (myShape == 'SPHERE') {
        let newradius = Math.max(x, y, z)
        currentShape.radius = newradius
        currentShape.updateBoundingSphereRadius()
        movingBody.updateBoundingRadius()
    } else if (myShape == 'BOX') {
        currentShape.halfExtents.set(Math.abs(x / 2), Math.abs(y / 2), Math.abs(z / 2))
        currentShape.updateConvexPolyhedronRepresentation()
        movingBody.updateBoundingRadius()
    }
}

but in the sphere, I have one problem

When I scale the sphere and stop dragging that axis and again start to scale, I can’t scale down it to smaller than its starting size.

I mean that I can only scale up not scale down the sphere.

But I can scale down the box.

I will upload a video for this but I did not make it clear.

I can see that my box scaling works with the absolute minimum. Thats enough for me. It works, and I can verify it.
With sphere, its more complicated. Thats why schteppe says it’s easier just to create new shapes. Save yourself the problems. Other cannon shapes are also much more difficult to scale after they’ve been created.

The reason why your spehere doesn’t shrink is because you are using Math.max(x,y,z). It will always use the largest value from the set.

Thank you, now it’s working !!

My now code is:


function scalePhysicsBody(movingBody, x, y, z) {
    let currentShape = movingBody.shapes[0]
    if (myShape == 'SPHERE') {
        let newradius = x
        if (x != y && x == z) {
            newradius = y
        } else if (x == y && y != z) {
            newradius = z
        }
        currentShape.radius = newradius
        currentShape.updateBoundingSphereRadius()
        movingBody.updateBoundingRadius()
    } else if (myShape == 'BOX') {
        currentShape.halfExtents.set(Math.abs(x / 2), Math.abs(y / 2), Math.abs(z / 2))
        currentShape.updateConvexPolyhedronRepresentation()
        movingBody.updateBoundingRadius()
    }
}

what do you suggest for the sphere, this code is good enough, or make a new shape?
do you believe that making a new shape is risk-free?
I don’t know about the memory problem but if I create a new sphere in every scale which I believe is called 100 times while scaling that wireframe, does create a new shape every time, does those old shape stays in memory?

When I was creating new objects, I didn’t have the memory problems. I presume the GC can figure it out, all by its little bidy little self, that an object is now orphaned, and it can be removed. But you can’t always be sure. Since I don’t really know what’s really happening inside Cannonjs without checking it with a fine-tooth comb. I’m not doing that. I just use the stats panel, with the MB window displayed, press things a million times, and I can see no problems. I am still using 2mb. This to me means that it’s really not worth worrying about.

You can spend hours and days micromanaging, panicking and losing sleep over the fragile GC. You can do this if you really want to. There are plenty of resources on the internet for people who feel they must approach their problems this way.

2 Likes

Oh wow, i did not know there is stats panel to show MB, awesome.
I will try it