0

I have a THREE.js plane that the points are moved up and down using Perlin noise to make terrain. Now I need to add physics to the camera to stop it from just falling through the plane.

I'm hoping to make a function that can retrieve the vertices and faces out of the mesh and copy them over to a CANNON body as a Convex Polyhedron. Here's what I have so far but doesn't work:

function setPhysicsGeometry(mesh, body) {
    const vertices = mesh.geometry.vertices;
    const shape = new CANNON.ConvexPolyhedron();

    vertices.forEach(function(vertex) {
        // Adjust vertex position based on the physics properties
        vertex.z = 0; // Assuming initial z position is 0

        // Add the vertex to the shape
        shape.vertices.push(new CANNON.Vec3(vertex.x, vertex.y, vertex.z));
    });

    // Compute the faces of the shape
    const faces = [];
    for (let i = 0; i < mesh.geometry.faces.length; i++) {
        const face = mesh.geometry.faces[i];
        faces.push([face.a, face.b, face.c]);
    }
    shape.faces = faces;

    // Update the shape's bounding box
    shape.updateNormals();
    shape.updateEdges();

    // Assign the shape to the body
    body.addShape(shape);
}

This is an error that I get: Uncaught TypeError: shape.updateNormals is not a function

Same thing happens for shape.updateEdges()

Is this a problem with those two functions or am I over simplifying something that is difficult/impossible.

Thanks

UPDATE: I have made a function that sort of works but its super slow:

function createShape(geo) {
    const bufferedGeo = new THREE.BufferGeometry().fromGeometry(geo); // Turn geometry into buffer geo

    let position = bufferedGeo.attributes.position.array
    const points = []

    for (let i = 0; i < position.length; i += 3) {
        points.push(new CANNON.Vec3(position[i], position[i + 1], position[i + 2]))
    }
    const faces = []
    
    for (let i = 0; i < position.length / 3; i += 3) {
        faces.push([i, i + 1, i + 2])
    }

    const shape = new CANNON.ConvexPolyhedron(points, faces)
    
    return shape
}

Here is an error I get that shows that the normals are being ordered in the wrong order:

.faceNormals[1011] = Vec3(-0.38237948261368415,0.4673447646702331,-0.7971040096570934) looks like it points into the shape? The vertices follow. Make sure they are ordered CCW around the normal, using the right hand rule.

I don't know how to fix it since they are just taken from the geometry

5
  • 1
    I found an example using a torusKnot, maybe it can help? It uses a CANNON.Trimesh object and copies the geometry, not the verticies. sbedit.net/cfc3121bcf3f13fe27d426be3d50876f29a6c683 Commented Mar 6, 2024 at 18:41
  • That does look like it could work. Although when I copy and pasted the "CreateTrimesh()" function into my code the page doesn't load at all soo I don't really know what I'm doing wrong. The mesh is a plane but I don't know if that's whats wrong with it Commented Mar 6, 2024 at 23:00
  • Correction: I've just discovered that the trimesh is not able to collide with anything. A test shows that it just goes right through the floor for some reason. Any ideas? Commented Mar 7, 2024 at 1:46
  • I'm at a loss for experience on that. Can you maybe try, in a similar fashion to copy the geometry, rather than the vertices? Commented Mar 7, 2024 at 15:09
  • I've discovered that you need a buffer geometry to get the attributes like the normals vertices and faces. I've made a function that actually works but its so unbelievably slow when a collision occurs but instead of using Trimesh it uses the convex polyhedron. I'm going to add the function that I made to the original question because it says the faces are ordered in the wrong order or something Commented Mar 7, 2024 at 15:36

1 Answer 1

2

I solved it (Not completely, still bugs with the physics but that's a different problem).

Thanks to This Guy for sending me an amazing example of where I got the solution from. I was attempting to use ConvexPolyhedron to get my own body shape. I think it is still possible to do that but ordering the faces and normals in the correct syntax is really difficult. Instead, I used Trimesh which was much simpler.

However, in the example, he used new THREE.TorusKnotGeometry() and then went straight into createTrimesh(). For me this would return an error because the THREE.js geometry was not a buffer geometry. So I changed with a simple function and it returned no errors. Still physics wouldn't work on the object. So after what felt like two long I copied the position and quartation from the THREE.js mesh to the CANNON body and it works pretty well. Here is the completed code:

Code to Copy position and quartation

function copy(threeMesh, cannonBody) {
    // Copy position
    const position = new CANNON.Vec3(
        threeMesh.position.x,
        threeMesh.position.y,
        threeMesh.position.z
    );
    cannonBody.position.copy(position);

    // Copy rotation
    const quaternion = new CANNON.Quaternion(
        threeMesh.quaternion.x,
        threeMesh.quaternion.y,
        threeMesh.quaternion.z,
        threeMesh.quaternion.w
    );
    cannonBody.quaternion.copy(quaternion);
}

Code to create Trimesh:

function buffer(geo) {
    const bufferedGeo = new THREE.BufferGeometry().fromGeometry(geo);
    return bufferedGeo;
}

function CreateTrimesh(geometry) {
    const vertices = buffer(geometry).attributes.position.array
    const indices = Object.keys(vertices).map(Number)
    return new CANNON.Trimesh(vertices, indices)
}

And Mesh and Body code:

var platformGeometry = createCustomGeometry(terrain, size + 1, size + 1)
var platformMaterial = new THREE.MeshPhongMaterial({ color: 0x00ff00, wireframe: false, side: THREE.DoubleSide});
var platform = new THREE.Mesh(platformGeometry, platformMaterial);
platform.receiveShadow = true;
platform.castShadow = true
platform.position.set(0, 0, 0)
platform.rotation.x = Math.PI / 2
scene.add(platform);

var platShape = CreateTrimesh(platformGeometry, platform)
var platBody = new CANNON.Body({ mass: 0, shape: platShape });
copy(platform, platBody)
world.addBody(platBody)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.