aframe-physics-extras: collision of dynamic entity with static gltf model

前端 未结 2 1848
难免孤独
难免孤独 2021-01-27 10:39

I\'m trying to catch collision event between a dynamic sphere and a static gltf model. I\'m building the gltf entity the following way:

    const template = docum         


        
相关标签:
2条回答
  • 2021-01-27 11:12

    Meanwhile I was able to implement animated collision mesh for a gltf model. I used a helper function implemented by @Piotr Adam Milewski here. See more details about the function in this answer. Any other suggestions to improve performance are appreciated.

    AFRAME.registerComponent('animated-collision-shape', {
        init: function () {
            this.nodeMap = {};
    
            this.el.setAttribute('body', 'type: static; shape: none;')
    
            this.el.addEventListener('model-loaded', () => {
                const size = new THREE.Vector3();
                let box = new THREE.Box3().setFromObject(this.el.object3D);
                box.getSize(size);
                this.offset = new CANNON.Vec3(0, size.y / 2, 0);
    
                let mesh = this.el.getObject3D("mesh");
                mesh.traverse(node => {
                    if (node.isSkinnedMesh) {
                        this.skinnedMesh = node;
                        this.nodeMap[node.uuid] = {
                            mesh: node,
                            box: new THREE.Box3()
                        }
                    }
                });
    
                if (!Object.keys(this.nodeMap).length) {
                    this.nodeMap[0] = {
                        mesh: this.el.object3D,
                        box: new THREE.Box3()
                    };
                }
    
                this.el.components["body"].shouldUpdateBody = true;
            })
        },
    
        remove: function () {
            this.removeBoxes();
        },
    
        tick: (function () {
            const size = new THREE.Vector3();
            let common_box_uuid = null;
    
            return function tick() {
                if (
                    !Object.keys(this.nodeMap).length ||
                    !this.el.body) {
                    return;
                }
    
                let combine = this.data.combine === true
    
                let i = 0;
                for (let uuid in this.nodeMap) {
                    // Non - skinned case
                    if (!this.nodeMap[uuid].mesh.isSkinnedMesh) {
                        this.nodeMap[uuid].box.setFromObject(this.el.object3D);
                        return;
                    }
                    // skinned model. Either separate boxes, or combined
                    if (common_box_uuid && combine) {
                        utils.SkinnedMeshBBox.expandAABB(this.nodeMap[uuid].mesh, this.nodeMap[common_box_uuid].box);
                    } else {
                        utils.SkinnedMeshBBox.getAABB(this.nodeMap[uuid].mesh, this.nodeMap[uuid].box);
                        common_box_uuid = uuid
                    }
    
                    if (isFinite(this.nodeMap[common_box_uuid].box.max.x)) {
                        this.nodeMap[common_box_uuid].box.getSize(size);
                        if (this.el.body.shapes[i]) {
                            this.el.body.shapes[i].halfExtents = new CANNON.Vec3(size.x / 2, size.y / 2, size.z / 2);
                            this.el.body.shapes[i].updateConvexPolyhedronRepresentation();
                        } else {
                            let shape = new CANNON.Box(new CANNON.Vec3(size.x / 2, size.y / 2, size.z / 2))
                            this.el.body.addShape(shape, this.offset, shape.orientation);
                        }
                        i++;
                    }
                }
    
                this.el.components["body"].shouldUpdateWireframe = true;
            };
        })()
    })
    
    0 讨论(0)
  • 2021-01-27 11:18

    0. using setAttribute

    setAttribute won't handle a list like:

    template.setAttribute('body', 'type:static; shape:none');
    

    Rather provide an object of the new attributes:

    element.setAttribute("name", {
      "property 1": "value 1",
      "property 2": "value 2"
    }); 
    

    1. dynamic body/shape set-up

    That being said, you can create a custom static cylinder like this:

    element.setAttribute("body", {
       "type": "static",
       "shape": "none"
    })
    
    element.setAttribute("shape__cylinder", {
       'shape': 'cylinder',
       "height": 1.5,
       "radiusTop": 0.1,
       "radiusBottom": 0.2
    })
    

    check it out in this fiddle


    2. dynamic shape for models

    As for creating a dynamic shape for a gltf model. Personally i had no luck using cannon, although it worked well with the ammo driver. On the other hand I've had a huge FPS drop (on ~older mobile devices), so If possible, try using simple collision meshes for performance sake.

    You can get a bounding box of a skinned model with a simple function I made:

    let box = new THREE.Box3()
    THREE.Box3Utils.fromSkinnedMesh(skinnedMesh, box);
    // box should be the bounding box of the skinned mesh
    

    3. animated models

    I'd highly recommend creating simple collision shapes and attaching them to a certain bone in the model. A starting point could be this component:

    <a-gltf-model bone-collider="bone: boneName; halfExtents: 0.15 0.15 0.15">
    

    The bounding box approach will be very complicated since:
    • You'd have to compute a bounding box for an non-rotated mesh
    • apply the rotation to the result (bounding boxes are world-aligned)
    • update the body on each tick, or even remove the shape and add it anew (source)

    You can see both approaches in this example

    0 讨论(0)
提交回复
热议问题