dimforge / rapier.js

Official JavaScript bindings for the Rapier physics engine.
https://rapier.rs
Apache License 2.0
394 stars 55 forks source link

Bind gltf model #256

Open Steve245270533 opened 1 year ago

Steve245270533 commented 1 year ago

How can the gltf model be bound to a static collision scene? I don't know where the problem is. My code doesn't work

gltf_loader.load("/src/assets/world.glb", gltf => {
        scene.add(gltf.scene);

        gltf.scene.traverse(item => {
            if (item.isMesh) {
                const bodyDesc = RAPIER.RigidBodyDesc.fixed()
                    .setTranslation(item.position.x, item.position.y, item.position.z);

                const body = world.createRigidBody(bodyDesc);

                const colliderDesc = RAPIER.ColliderDesc.trimesh(
                    item.geometry.attributes.position.array,
                    item.geometry.index.array
                );

                world.createCollider(colliderDesc, body);
            }
        });
    });
sylwesterdigital commented 10 months ago

I have found that RAPIER.ColliderDesc does not properly assign trimesh Here is the snippet of the code which worked for me:

let RAPIER
window.myRapierWorld
window.rigidBodies = window.rigidBodies || [];
window.threeCubes = window.threeCubes || [];

function validateMapping(vertices, indices) {
    if (!vertices || !indices) {
        console.error("Vertices or indices are missing.");
        return false;
    }

    const maxIndexValue = vertices.length / 3 - 1;

    for (let i = 0; i < indices.length; i++) {
        if (indices[i] > maxIndexValue) {
            console.error(`Index value at position ${i} exceeds vertex limit. Value: ${indices[i]}, Max Allowed: ${maxIndexValue}`);
            return false;
        }
    }

    console.log("Mapping validation passed.");
    return true;
}
   import('@dimforge/rapier3d').then(rapierModule => {

    // set up ThreeJS Scene, Camera
    setupScene();

    RAPIER = rapierModule;
    console.log("initRapier()");

    let gravity = { x: 0.0, y: -2.1, z: 0.0 };
    let world = new RAPIER.World(gravity);
    const eventQueue = new RAPIER.EventQueue(true);

    const loader = new GLTFLoader();
    loader.load('models/lejek.glb', gltf => {
        scene.add(gltf.scene);

        gltf.scene.traverse(item => {

            if (item.isMesh) {

                const geometry = item.geometry;

                console.log(geometry);

                try {

                    const vertices = geometry.attributes.position.array;
                    const indices = geometry.index.array;

                    const trimesh = new RAPIER.TriMesh(vertices, indices);

                    console.log('TriMesh created successfully', trimesh);

                    const isValid = validateMapping(trimesh.vertices, trimesh.indices);

                    console.log("isValid", isValid);

                    console.log('Vertices length:', vertices.length);
                    console.log('Indices length:', indices.length);

                    let groundColliderDesc = RAPIER.ColliderDesc.trimesh(trimesh)
                        .setTranslation(0, groundHeight, 0)
                        .setActiveEvents(RAPIER.ActiveEvents.COLLISION_EVENTS);

                    console.log(groundColliderDesc);

                    // this part is a kind of hack, check the groundColliderDesc.shape - it has undefined values - 
                    groundColliderDesc.shape.indices = indices;
                    groundColliderDesc.shape.vertices = vertices;

                    console.log(groundColliderDesc.shape);

                    let groundCollider = world.createCollider(groundColliderDesc);

                    window.groundColliderHandle = groundCollider.handle;
                    window.myRapierWorld = world;
                    window.eventQueue = eventQueue;

                    // add additional elements to the ThreeJS scene
                    init();

                } catch (error) {

                    console.error('Failed to create TriMesh:', error);

                }
            }
        });
    });
});

So I looked into what is created by groundColliderDesc = RAPIER.ColliderDesc.trimesh(trimesh) and it seems like shape (TriMesh) is somehow wrongly constructed, it has value indices: undefined and vertices contains indices and vertices

Screenshot 2023-09-13 at 11 15 45

I directly re-assigned these values, see this line of code:

                    groundColliderDesc.shape.indices = indices;
                    groundColliderDesc.shape.vertices = vertices;

And it worked.

upisfree commented 4 months ago

@sylwesterdigital seems like this issue is fixed in 0.12.0. Can't reproduce it now.