Mesh / Model into Canon Convex/Trimesh

Hi there I want to get a body on my imported 3d model i saw the three-to-cannon but i didn’t get to work. Im not using npm and I’m new to Javascript and I only see typescript module that i dont know how to use.

I already see some examples like this:

const icosahedronGeometry = new THREE.IcosahedronGeometry(1, 0)
const icosahedronMesh = new THREE.Mesh(icosahedronGeometry, normalMaterial)
icosahedronMesh.position.x = 1
icosahedronMesh.position.y = 3
icosahedronMesh.castShadow = true
scene.add(icosahedronMesh)
const position = icosahedronMesh.geometry.attributes.position.array
const icosahedronPoints: CANNON.Vec3[] = []
for (let i = 0; i < position.length; i += 3) {
    icosahedronPoints.push(
        new CANNON.Vec3(position[i], position[i + 1], position[i + 2])
    )
}
const icosahedronFaces: number[][] = []
for (let i = 0; i < position.length / 3; i += 3) {
    icosahedronFaces.push([i, i + 1, i + 2])
}
const icosahedronShape = new CANNON.ConvexPolyhedron({
    vertices: icosahedronPoints,
    faces: icosahedronFaces,
})
const icosahedronBody = new CANNON.Body({ mass: 1 })
icosahedronBody.addShape(icosahedronShape)
icosahedronBody.position.x = icosahedronMesh.position.x
icosahedronBody.position.y = icosahedronMesh.position.y
icosahedronBody.position.z = icosahedronMesh.position.z
world.addBody(icosahedronBody)

But is in typescript and im using only Javascript, can someone help me to make this work on javascript or another solution.
Thanks in advance!

I presume you got the code from this page - Physics with Cannon - Three.js Tutorials
There is a working example on that page where you can view the JavaScript source. Press the <>

const icosahedronGeometry = new THREE.IcosahedronGeometry(1, 0)
const icosahedronMesh = new THREE.Mesh(icosahedronGeometry, normalMaterial)
icosahedronMesh.position.x = 1
icosahedronMesh.position.y = 3
icosahedronMesh.castShadow = true
scene.add(icosahedronMesh)
let position = icosahedronMesh.geometry.attributes.position.array
const icosahedronPoints = []
for (let i = 0; i < position.length; i += 3) {
    icosahedronPoints.push(new CANNON.Vec3(position[i], position[i + 1], position[i + 2]))
}
const icosahedronFaces = []
for (let i = 0; i < position.length / 3; i += 3) {
    icosahedronFaces.push([i, i + 1, i + 2])
}
const icosahedronShape = new CANNON.ConvexPolyhedron({
    vertices: icosahedronPoints,
    faces: icosahedronFaces,
})
const icosahedronBody = new CANNON.Body({ mass: 1 })
icosahedronBody.addShape(icosahedronShape)
icosahedronBody.position.x = icosahedronMesh.position.x
icosahedronBody.position.y = icosahedronMesh.position.y
icosahedronBody.position.z = icosahedronMesh.position.z
world.addBody(icosahedronBody)

Thanks now I can get the icosahedron but when I use imported models I cannot get geometry.atributes.position.array always says undefined do you have some example with imported 3d models?

Thanks in advance!

Cannon Debug Renderer
Convex Geometry to CANNON.Trimesh
Finger Physics
FCS
Ball-VR

Did you have Canon Utils in JavaScript I cannot use it in Typescript?

all the working examples are written in JavaScript. Look for the <> in the working examples.
Typescript gets converted into JavaScript before it can run in your browser.

I get it but Im using Classes and I get this error in console.

THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values. 

Here is my code:

import * as THREE from './three/three.module.js';
import Stats from './three/stats.module.js';
// import {OrbitControls} from './three/OrbitControls.js';
import * as CANNON from './teste/cannon-es.js';
import CannonDebugger from './teste/cannon-es-debugger.js';
import {PointerLockControlsCannon} from './teste/PointerLockControlsCannon.js';
import {GLTFLoader} from "./three/GLTFLoader.js";
import CannonUtils from "./teste/cannonUtils.js";


let lastCallTime = performance.now();

class Application {
    constructor() {
        this.objects = [];
        this.createScene();
    }
    createScene() {
        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(60,
            window.innerWidth / window.innerHeight, 0.1, 1000);
        this.camera.position.y = 0;

        this.renderer = new THREE.WebGLRenderer({
            antialias: true,
            powerPreference: "high-performance",
        });
        this.renderer.outputEncoding = THREE.sRGBEncoding;
        this.renderer.autoClear = false;
        this.renderer.info.autoReset = false;
        this.renderer.setSize(window.innerWidth, window.innerHeight);
        this.renderer.shadowMap.enabled = false;
        this.renderer.shadowMap.type = THREE.VSMShadowMap;
        this.renderer.physicallyCorrectLights = true;
        this.renderer.setClearColor(0xcccccc);
        document.body.appendChild(this.renderer.domElement);
        this.stats = Stats()
        document.body.appendChild(this.stats.dom)





        this.world = new CANNON.World();
        this.world.defaultContactMaterial.contactEquationStiffness = 1e9;
        this.world.defaultContactMaterial.contactEquationRelaxation = 4

        this.cannonDebugger = new CannonDebugger(this.scene, this.world);

        const solver = new CANNON.GSSolver()
        solver.iterations = 7
        solver.tolerance = 0.1
        this.world.solver = new CANNON.SplitSolver(solver)
        // use this to test non-split solver
        // world.solver = solver

        this.world.gravity.set(0, -50, 0)

        // Create a slippery material (friction coefficient = 0.0)
        const physicsMaterial = new CANNON.Material('physics')
        const physics_physics = new CANNON.ContactMaterial(physicsMaterial, physicsMaterial, {
            friction: 0.0,
            restitution: 0.3,
        })

        // We must add the contact materials to the world
        this.world.addContactMaterial(physics_physics);

        const material = new THREE.MeshStandardMaterial( {color: 0x434c5e, side: THREE.DoubleSide} );


        const halfExtents = new CANNON.Vec3(100, 1, 100);
        const boxShape = new CANNON.Box(halfExtents);
        const boxGeometry = new THREE.BoxBufferGeometry(halfExtents.x * 2, halfExtents.y * 2, halfExtents.z * 2);
        this.boxBody = new CANNON.Body({ mass: 0 })
        this.boxBody.addShape(boxShape)
        this.boxMesh = new THREE.Mesh(boxGeometry, material)
        const x = 0
        const y = 0
        const z = 0
        this.boxBody.position.set(x, y, z)
        this.boxMesh.position.copy(this.boxBody.position)
        this.world.addBody(this.boxBody)
        this.scene.add(this.boxMesh)




        const radius = 0.3
        this.sphereShape = new CANNON.Sphere(radius)
        this.sphereBody = new CANNON.Body({ mass: 5, material: physicsMaterial })
        this.sphereBody.addShape(this.sphereShape)
        this.sphereBody.position.set(0, 5, 0)
        this.sphereBody.linearDamping = 0.9
        this.world.addBody(this.sphereBody)


        const normalMaterial = new THREE.MeshNormalMaterial()

        const icosahedronGeometry = new THREE.IcosahedronGeometry(1, 0)
        this.icosahedronMesh = new THREE.Mesh(icosahedronGeometry, normalMaterial)
        this.icosahedronMesh.position.x = 1
        this.icosahedronMesh.position.y = 3
        this.icosahedronMesh.castShadow = true
        this.scene.add(this.icosahedronMesh)
        let position = this.icosahedronMesh.geometry.attributes.position.array
        const icosahedronPoints = []
        for (let i = 0; i < position.length; i += 3) {
            icosahedronPoints.push(new CANNON.Vec3(position[i], position[i + 1], position[i + 2]))
        }
        const icosahedronFaces = []
        for (let i = 0; i < position.length / 3; i += 3) {
            icosahedronFaces.push([i, i + 1, i + 2])
        }
        const icosahedronShape = new CANNON.ConvexPolyhedron({
            vertices: icosahedronPoints,
            faces: icosahedronFaces,
        })
        this.icosahedronBody = new CANNON.Body({ mass: 1 })
        this.icosahedronBody.addShape(icosahedronShape)
        this.icosahedronBody.position.x = this.icosahedronMesh.position.x
        this.icosahedronBody.position.y = this.icosahedronMesh.position.y
        this.icosahedronBody.position.z = this.icosahedronMesh.position.z
        this.world.addBody(this.icosahedronBody)

        this.mundo = new THREE.Group();
        this.mundo.name = "world";
        this.scene.add(this.mundo)



        this.monkeyMesh;
        this.monkeyBody;
        const objLoader = new GLTFLoader()
        objLoader.load(
            './models/bench/bench.glb',
            (object) => {
                this.scene.add(object.scene)
                this.monkeyMesh = object.scene.children[0]
                this.monkeyMesh.material = normalMaterial
                this.monkeyMesh.position.x = -2
                this.monkeyMesh.position.y = 20
                const monkeyShape = CannonUtils.CreateTrimesh(this.monkeyMesh.geometry)
                // const monkeyShape = CannonUtils.CreateConvexPolyhedron(
                //     (monkeyMesh as THREE.Mesh).geometry
                // )
                this.monkeyBody = new CANNON.Body({ mass: 1 })
                this.monkeyBody.addShape(monkeyShape)
                // monkeyBody.addShape(cubeShape)
                // monkeyBody.addShape(sphereShape)
                // monkeyBody.addShape(cylinderShape)
                // monkeyBody.addShape(icosahedronShape)
                // monkeyBody.addShape(new CANNON.Plane())
                // monkeyBody.quaternion.setFromAxisAngle(new CANNON.Vec3(1, 0, 0), Math.PI / 2)
                this.monkeyBody.position.x = this.monkeyMesh.position.x
                this.monkeyBody.position.y = this.monkeyMesh.position.y
                this.monkeyBody.position.z = this.monkeyMesh.position.z
                this.world.addBody(this.monkeyBody)
                // monkeyLoaded = true
            },
            (xhr) => {
                console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
            },
            (error) => {
                console.log('An error happened')
            }
        )














        const ambientLight = new THREE.AmbientLight(0xfdffe1, 0.4);

        var hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.6);
        hemiLight.position.set(0, 500, 0);

        var dirLight = new THREE.DirectionalLight(0xffffff, 2);
        dirLight.position.set(-2.3, 3, 3);

        dirLight.position.multiplyScalar(50);
        dirLight.name = "dirlight";

        dirLight.castShadow = true;
        dirLight.shadow.mapSize.width = dirLight.shadow.mapSize.height = 1024 * 2;

        var d = 350;

        dirLight.shadow.camera.left = -d;
        dirLight.shadow.camera.right = d;
        dirLight.shadow.camera.top = d;
        dirLight.shadow.camera.bottom = -d;

        dirLight.shadow.camera.far = 3500;
        dirLight.shadow.bias = -0.0001;
        dirLight.shadow.mapSize.width = 512 * 4;
        dirLight.shadow.mapSize.height = 512 * 4;

        this.scene.add(dirLight);
        this.scene.add(hemiLight);
        this.scene.add(ambientLight)

        this.controls = new PointerLockControlsCannon(this.camera, this.sphereBody);
        this.scene.add(this.controls.getObject())


        this.render();






        // this.controls = new OrbitControls(this.camera, this.renderer.domElement);
        // this.controls = new PointerLockControlsCannon(this.camera, this.sphereBody);
        // this.scene.add(this.controls.getObject())
        const instructions = document.getElementById('instructions')
        instructions.addEventListener('click', () => {
           this.controls.lock()
        })

        this.controls.addEventListener('lock', () => {
            this.controls.enabled = true
            instructions.style.display = 'none'
        })

        this.controls.addEventListener('unlock', () => {
            this.controls.enabled = false
            instructions.style.display = null
        })
    }
    render() {
        requestAnimationFrame((t) => {
            if (this.time === null) {
                this.time = t;
            }

            this.render();
            this.renderer.render(this.scene, this.camera);
            this.update(t-this.time);
            this.time = t;
        });
    }

    update(timeElapsed){
        const delta = timeElapsed * 0.001;
        this.objects.forEach((object) => {
            // if(object instanceof PortalCreator){
            // // }else if(object instanceof AnimatedModel){
            // //     object.update(delta);
            // } else{
            object.update();
            // }
        });
        const time = performance.now() / 1000
        const dt = time - lastCallTime
        lastCallTime = time


        this.world.fixedStep(1/60, dt);
        this.boxMesh.position.copy(this.boxBody.position);
        this.boxMesh.quaternion.copy(this.boxBody.quaternion);
        this.icosahedronMesh.position.copy(this.icosahedronBody.position);
        this.icosahedronMesh.quaternion.copy(this.icosahedronBody.quaternion);
        // this.monkeyMesh.position.set(
        //     this.monkeyBody.position.x,
        //     this.monkeyBody.position.y,
        //     this.monkeyBody.position.z
        // )
        // this.monkeyMesh.quaternion.set(
        //     this.monkeyBody.quaternion.x,
        //     this.monkeyBody.quaternion.y,
        //     this.monkeyBody.quaternion.z,
        //     this.monkeyBody.quaternion.w
        // )
        this.cannonDebugger.update();
        this.controls.update(dt);
        this.stats.update();

    }

    add(mesh) {
        if (Array.isArray(mesh)){
            for(var index in mesh){
                this.objects.push(mesh[index]);
                this.mundo.add( mesh[index].getMesh() );
            }
        }
        else{
            this.objects.push(mesh);
            this.mundo.add(mesh.getMesh());
        }
    }
}

let app = new Application();
let objs = [

];
app.add(objs);

Thanks for your help!

Two of my examples in my links use classes. I won’t write your code for you. But your employer could try to convince me.

No problem! Still thanks for your help <3

Now i know my problem, the problem is that my models / meshes have children so i get the error do you know any way to transform models into only 1 mesh or create a convex to a mesh with childrens.

Thanks for your attencion!

There is no simple way that works for everything.
Get good at doing things manually.
I discuss that on this page : Trimeshes, ConvexPolyhedrons and Compound Shapes

Here are some more examples of manually applying customised solutions.
Kick Boxing
Glasses
Random Number Generator

I got the same issues. I presume you were updating THREE.Mesh.position from Cannon world like the examples, then NaN value maybe resulted from the world.step(delta) function at delta = 0. Try delta += 0.00001 as a simple workaround and check if this helps.

I use ‘three-to-cannon’;

example

  addMeshToWorldViaThreeToCannon = (meshItem: any, type = ShapeType.MESH) => {
    const { shape, offset, orientation } = threeToCannon(meshItem, { type });
    const meshCannon = new CANNON.Body({
      shape,
      position: new CANNON.Vec3(meshItem.position.x, meshItem.position.y, meshItem.position.z),
      type: CANNON.Body.STATIC,
    });

    meshCannon.quaternion.copy(meshItem.quaternion);
    this.world.addBody(meshCannon);
  };

Make sure your model is hull model