web前端

three.js(21)-元素拾取

2022-12-30  本文已影响0人  姜治宇

光线投射

以智慧园区为例。
当我们点击某一个建筑物模型时,页面就会弹出一个对话框,告知这个建筑的有关信息,这是如何做到的呢?
我们可以用raycaster光线投射来解决。
光线投射,就是向特性方向发出射线,并测试哪些对象与之相交。


GIF 2022-12-31 11-47-47.gif
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="http://www.yanhuangxueyuan.com/threejs/build/three.min.js"></script>
    <script src="http://www.yanhuangxueyuan.com/threejs/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
    <div id="webgl"></div>

</body>
</html>
<script>

    //场景
    var scene = new THREE.Scene();
    //相机设置为世界坐标原点
    var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

    camera.position.set(0, 0, 10);
    scene.add(camera);//添加相机
    //添加坐标轴
    var axes = new THREE.AxesHelper(500);//500表示xyz轴的长度,红:x,绿:y,蓝:z
    scene.add(axes);

    //设置物体
    const object1 = new THREE.Mesh(
        new THREE.SphereBufferGeometry(0.5,10,10),
        new THREE.MeshBasicMaterial({color:'#ff0000'})

    );
    const object2 = new THREE.Mesh(
        new THREE.SphereBufferGeometry(0.5,10,10),
        new THREE.MeshBasicMaterial({color:'#ff0000'})

    );
    const object3 = new THREE.Mesh(
        new THREE.SphereBufferGeometry(0.5,10,10),
        new THREE.MeshBasicMaterial({color:'#ff0000'})

    );

    object1.position.x = 2;
    object2.position.x = 5;
    object3.position.x = 7;
    scene.add(object1,object2,object3);//添加物体


    var renderer = new THREE.WebGLRenderer();//画布
    renderer.setSize(window.innerWidth, window.innerHeight);//设置渲染区域尺寸
    renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色





    //将渲染好的canvas追加到dom
    var cont = document.getElementById('webgl');
    cont.appendChild(renderer.domElement); 
    var controls = new THREE.OrbitControls( camera, renderer.domElement );
    const raycaster = new THREE.Raycaster();
    function raycast(raycaster){
        //设置射线
        const rayOrigin = new THREE.Vector3(0,0,0);//从原点出发射一根射线
        const rayDir = new THREE.Vector3(1,0,0);//方向向量
        raycaster.set(rayOrigin,rayDir);
        //未射中的还是红色
        const objs = [object1,object2,object3];

        for(const obj of objs){
            obj.material.color.set('#ff0000');
        }
        //射中的为绿色
        const intersects = raycaster.intersectObjects([object1,object2,object3]);
        
        for(const intersect of intersects) { 
            intersect.object.material.color.set('#00ff00');
        }
    }
    const clock = new THREE.Clock();
    function animate(){
        const elaTime = clock.getElapsedTime();
        //不断改变物体的位置
        object1.position.y = Math.sin(elaTime*0.5)*1.5;
        object2.position.y = Math.sin(elaTime*0.8)*1.5;
        object3.position.y = Math.sin(elaTime*1.2)*1.5;

        raycast(raycaster);
        
        controls.update();
        renderer.render(scene, camera);//开始渲染
        requestAnimationFrame(animate);
        
    }
    animate();
</script>

通过鼠标发射射线

鼠标只在屏幕移动,所以使用二维向量来创建鼠标变量即可。
设想一下,如果从相机到鼠标的位置连一根线(向量减法),这样就可以得到一条方向向量。沿着这个方向向量发射一条射线,击中的就是我们点击的目标物体。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="http://www.yanhuangxueyuan.com/threejs/build/three.min.js"></script>
    <script src="http://www.yanhuangxueyuan.com/threejs/examples/js/controls/OrbitControls.js"></script>
</head>

<body>
    <div id="webgl"></div>

</body>

</html>
<script>

    //场景
    var scene = new THREE.Scene();
    //相机设置为世界坐标原点
    var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

    camera.position.set(0, 0, 10);
    scene.add(camera);//添加相机
    //添加坐标轴
    var axes = new THREE.AxesHelper(500);//500表示xyz轴的长度,红:x,绿:y,蓝:z
    scene.add(axes);

    //设置物体
    const object1 = new THREE.Mesh(
        new THREE.SphereBufferGeometry(0.5, 10, 10),
        new THREE.MeshBasicMaterial({ color: '#ff0000' })

    );

    const object2 = new THREE.Mesh(
        new THREE.SphereBufferGeometry(0.5, 10, 10),
        new THREE.MeshBasicMaterial({ color: '#ff0000' })

    );

    const object3 = new THREE.Mesh(
        new THREE.SphereBufferGeometry(0.5, 10, 10),
        new THREE.MeshBasicMaterial({ color: '#ff0000' })

    );
    object1.name = 'object1';
    object2.name = 'object2';
    object3.name = 'object3';
    object1.position.x = 2;
    object2.position.x = 5;
    object3.position.x = 7;
    scene.add(object1, object2, object3);//添加物体

    const size = {
        width: window.innerWidth,
        height: window.innerHeight
    };
    var renderer = new THREE.WebGLRenderer();//画布
    renderer.setSize(size.width, size.height);//设置渲染区域尺寸
    renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色

    //将渲染好的canvas追加到dom
    var cont = document.getElementById('webgl');
    cont.appendChild(renderer.domElement);
    var controls = new THREE.OrbitControls(camera, renderer.domElement);

    const mouse = new THREE.Vector2(0, 0);
    window.addEventListener('mousemove', e => {
        mouse.x = (e.clientX / size.width * 2) - 1;
        mouse.y = -(e.clientY / size.height * 2) + 1;
    });
    window.addEventListener('click', e => {
        
        if (currentIntersect) {
            console.log('点击了物体》》》', currentIntersect.object.name);
        }
    });
    const raycaster = new THREE.Raycaster();
    let currentIntersect = null;//当前被射线击中的物体

    function raycast(raycaster) {
        //设置射线
        raycaster.setFromCamera(mouse, camera);
        // const rayOrigin = new THREE.Vector3(0,0,0);//从原点出发射一根射线
        // const rayDir = new THREE.Vector3(1,0,0);//方向向量
        // raycaster.set(rayOrigin,rayDir);
        //未射中的还是红色
        // const objs = [object1,object2,object3];

        // for(const obj of objs){
        //     obj.material.color.set('#ff0000');
        // }

        const intersects = raycaster.intersectObjects([object1, object2, object3]);
        //射中的为绿色
        // for(const intersect of intersects) { 
        //     intersect.object.material.color.set('#00ff00');
        // }
        if (intersects.length > 0) {

            currentIntersect = intersects[0];
        } else {

            currentIntersect = null;
        }
    }
    const clock = new THREE.Clock();
    function animate() {
        const elaTime = clock.getElapsedTime();
        //不断改变物体的位置
        object1.position.y = Math.sin(elaTime * 0.5) * 1.5;
        object2.position.y = Math.sin(elaTime * 0.8) * 1.5;
        object3.position.y = Math.sin(elaTime * 1.2) * 1.5;

        raycast(raycaster);

        controls.update();
        renderer.render(scene, camera);//开始渲染
        requestAnimationFrame(animate);

    }
    animate();
</script>
GIF 2022-12-31 12-19-45.gif
上一篇下一篇

猜你喜欢

热点阅读