• 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>

     运行效果图:

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

  • 相关阅读:
    SpringBoot Jpa 双数据源mysql + oracle + liquibase+参考源码
    C#:将字符串中连续空格作为分隔符获取多段模糊查询的字符串
    C# 传入参数2021-05-18T00:00:00.000Z使用ToDateTime日期在此基础上加8小时
    修改DbContext并不是线程安全的bug处理。
    产品经理推荐书籍
    抽象类、类和接口
    git 分支合并主干出现冲突的解决办法
    HttpClient请求设置Content-Type标头空格问题
    C# 3Des加密解密
    WPF 颜色选择器
  • 原文地址:https://www.cnblogs.com/qianyuesheng/p/15162348.html
Copyright © 2020-2023  润新知