1. 程式人生 > 其它 >Three.js之Raycaster cube邊角碰撞檢測

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>

執行效果圖:

有用就推薦下吧?