Three.js之Raycaster cube边角碰撞检测

  网上包括很多API 的参考文档都是根据摄像机和鼠标操控来测试碰撞效果的,利用了 raycaster.setFromCamera( ) 函数

但是,如果物体运动的过程中,并不涉及鼠标的操作,利用键盘控制物体的运动,模拟物体自主运行。需要直接调用 raycaster.set(from, toVecNormalize) 函数,以下做简要案例测试,暂没有对多边形的边界进行细微调整。

有几点需要注意:

1 构造  THREE.BoxGeometry() 函数中,构建的cude 的八个边角坐标通过   cube.geometry.attributes.position.array;   函数获取到有序列坐标的数组,通过对 3 取余即可获取 x,  y, z 坐标

2   rcaster.set(dcubevertices[vi], dirv.clone().normalize());  第一个参数是基准点,一般会和当前计算的边角坐标点函数同样的数值,设置的点在哪里,碰撞的基准点就在哪里。

完整代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>物体碰撞检测</title>
</head>
<body>
<script src="../build/three.js"></script>
<script src="../build/OrbitControls.js"></script>
<script src="../build/MTLLoader.js"></script>
<script src="../build/OBJLoader.js"></script>
</body>


<script type="text/javascript">

    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500);
    camera.position.set(50, 10, 100);

    const scene = new THREE.Scene();
    var ambient = new THREE.AmbientLight( 0xffffff );  // 增加光源
    scene.add( ambient );

    let collLst = [];

    //create a blue LineBasicMaterial
    const material = new THREE.LineBasicMaterial({color: 0x0000ff});
    const points = [];
    points.push(new THREE.Vector3(-10, 0, 0));
    points.push(new THREE.Vector3(0, 10, 0));
    points.push( new THREE.Vector3( 10, 0, 0 ) );

    const geometry = new THREE.BufferGeometry().setFromPoints( points );
    const line = new THREE.Line( geometry, material );
    scene.add(line);


    // 构造等腰三角形
    let geom = new THREE.BufferGeometry();
    const vertices = [];
    vertices.push(0, 0, 0);
    vertices.push(4, 1, 0);
    vertices.push(4, -1, 0);

    geom.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
    let args = {color: 0xFF00FF, side: THREE.DoubleSide};
    let mat = new THREE.MeshBasicMaterial(args);
    let mesh = new THREE.Mesh(geom, mat);
    mesh.position.set(30, 10, 0);
    mesh.name = "cbb";
    scene.add(mesh);


    // General box mesh data
    var boxGeometry = new THREE.BoxGeometry(40, 40, 20, 1, 1, 1);
    var boxMaterial = new THREE.MeshBasicMaterial({color: 0x8888ff, wireframe: true});
    var dcube = new THREE.Mesh(boxGeometry, boxMaterial);
    scene.add(dcube);


    // 获取矩形的 8个边角坐标,geometry 是通过四个点组成面的,所以有12个点坐标
    var posArr = dcube.geometry.attributes.position.array;
    var dcubevertices = [];
    for (let i =0; i < posArr.length; i = i+ 3){
        let x = posArr[i];
        let y = posArr[i + 1];
        let z = posArr[i + 2];
        let ppt = new THREE.Vector3(x, y, z);
        dcubevertices.push(ppt);

        const getemp = new THREE.BoxGeometry(1, 1, 1);
        const mattemp = new THREE.MeshBasicMaterial( { color: 0xFFA9F2 } );
        let cbetemp = new THREE.Mesh( getemp, mattemp );
        cbetemp.position.set(x, y, z);
        scene.add(cbetemp );
    }


    // 通过键盘码,根据cube.name 控制移动
    setupKeyControls();
    function setupKeyControls() {
        var cube = scene.getObjectByName('cbb');
        document.onkeydown = function(e) {
            switch (e.keyCode) {
                case 37:
                    cube.position.x -= 1;
                    break;
                case 38:
                    cube.position.y += 1;
                    break;
                case 39:
                    cube.position.x += 1;
                    break;
                case 40:
                    cube.position.y -= 1;
                    break;
                case 104:
                    cube.position.z += 0.21;
                    break;
                case 98:
                    cube.position.z -= 0.21;
                    break;

            }
        };
    }


    // Create ray caster
    var rcaster = new THREE.Raycaster();
    const animate = function () {
        requestAnimationFrame(animate);
        renderer.render(scene, camera);

        // 把每个角点坐标都设置为碰撞点检测点
        for(var vi = 0, l = dcubevertices.length; vi < l; vi++){
            var glovert = dcubevertices[vi].clone().applyMatrix4(dcube.matrix);
            // 检测方向向量
            var dirv = glovert.sub(dcube.position);

            // set函数 参1:从当前点开始检测的基准点,参2:检测方向
            rcaster.set(dcubevertices[vi], dirv.clone().normalize());
            // 获取碰撞结果
            var hitResult = rcaster.intersectObject(mesh);

            // 判断是否碰撞
            if(hitResult.length && hitResult[0].distance < dirv.length()){
                console.log("接触");
            }
        }

    }

    animate();
    var controls = new THREE.OrbitControls(camera, renderer.domElement);//创建控件对象
    controls.addEventListener('change', renderer);//监听鼠标、键盘事件
    // // 加入坐标系帮助
    // var axes = new THREE.AxesHelper(20);
    // scene.add(axes);

</script>



</html>

 运行效果图:

左侧有个推荐,有用就推荐下吧?

posted @ 2021-08-19 16:49  谦曰盛  阅读(564)  评论(0编辑  收藏  举报