4

I am learning Three.js. I am trying to use Cannon-es to attach a cylinder body to a rose mesh I created in blender allowing it to fall into a vase. My issue is when I try to update the rose's position to equal the body's position it states that the rose does not have a position element, but I log it after loading it with gltf-loader and it has a position so I think I am just not coding it correctly. Here is what I tried, Thank you for any help!

The createRose function is called from a dat.gui button, the rose and Cannon body are created fine when the code in the tick function at the bottom is commented.

const objectsToUpdate = []

const createRose = (px, py, pz, rx, ry, rz) =>{
   gltfLoader.load('/models/pieces/Rose.glb',
      (gltf) =>{
      let rose = gltf.scene.children[0]
      rose.position.set(px, py, pz)
      rose.rotation.set(rx, ry, rz)
      scene.add(rose)
   })

   // Cannon.js body
   const shape = new CANNON.Cylinder(2, 1, 5, 20)
   const body = new CANNON.Body({
      mass: 1,
      position: new CANNON.Vec3(0, 3, 0),
      shape: shape,
      material: defaultMaterial
   })
   world.addBody(body)

   // Save in objects to update
   objectsToUpdate.push({ 
      roseAndBody:{
         rose: rose,
         body: body
      }
   })
}

This is inside a function called tick that is updated with window.requestAnimationFrame(tick)

for(const object of objectsToUpdate){
    object.roseAndBody.rose.position.copy(object.roseAndBody.body.position)
    object.roseAndBody.rose.quaternion.copy(object.roseAndBody.body.quaternion)
 }

For more information, I am following the paid tutorial by Bruno SIMON and a lot of the code is modified from his physics lesson that I am trying to make work for this. I am perfectly okay with using a different format or another add-on instead of Cannon.js, whatever will make this work!

adelriosantiago
  • 7,762
  • 7
  • 38
  • 71

1 Answers1

1

The issue is that the gltfLoader function is async, and when you try to add the rose object to the objectsToUpdate array, the rose object has not been created yet, and is therefore undefined.

You should move the creation of the Cannon.js body inside the gltfLoader's callback function, after the rose object has been created. Something like this:

const createRose = (px, py, pz, rx, ry, rz) =>{
   gltfLoader.load('/models/pieces/Rose.glb',
      (gltf) =>{
         let rose = gltf.scene.children[0]
         rose.position.set(px, py, pz)
         rose.rotation.set(rx, ry, rz)
         scene.add(rose)

         // Cannon.js body
         const shape = new CANNON.Cylinder(2, 1, 5, 20)
         const body = new CANNON.Body({
            mass: 1,
            position: new CANNON.Vec3(0, 3, 0),
            shape: shape,
            material: defaultMaterial
         })
         world.addBody(body)

         // Save in objects to update
         objectsToUpdate.push({ 
            roseAndBody:{
               rose: rose,
               body: body
            }
         })
      })
}
Raghav Kukreti
  • 552
  • 5
  • 18