three.js射线:THREE.Raycaster实现鼠标选取几何图元

学习交流欢迎加群:789723098,博主会将一些demo整理共享

一、介绍

有时候我们在对三角网格模型进行操作的时候可能会需要对三角面进行选择,而实现这一功能最方便快捷的方法就是利用THREE.Raycaster创建射线来实现,在这边就不详细介绍射线的原理了,如果有兴趣的同学可以自行百度查询,有很多介绍射线的文章。Raycaster类的使用方法可以在官方文档中查询到:Raycaster使用方法, 如下图所示;

利用射线选取三角面最直观的实现就是利用鼠标点击,对鼠标点击的屏幕坐标位置的三角面进行选取,在这里屏幕坐标是2D的,需要先将屏幕左边转换为3D坐标(世界坐标系),具体方法如下:

let mouse = new THREE.Vector2();//创建2D坐标
let raycaster = new THREE.Raycaster();//创建射线

//将m屏幕坐标转换成3D坐标
mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
raycaster.setFromCamera(mouse, camera);

二、实现效果

接下来是本文的实现效果,博主实现了利用鼠标点击选取一个球体上的三角面片,如下图所示:

三、代码实现

接下来将本例的实现代码附上,分享给大家,如果对大家有帮助请记得点赞哦!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>threejs-select-triangle</title>
    <style>
        body{
            font-family: Monospace;
            background: #f0f0f0;
            margin: 0px;
            overflow: hidden;
        }
    </style>
</head>
<body>
<script type="text/javascript" src="build/three.js"></script>
<script type="text/javascript" src="js/Detector.js"></script>
<script type="text/javascript" src="js/controls/OrbitControls.js"></script>
<script type="text/javascript">
    //检测是否支持webgl
    if (!Detector.webgl) {
        Detector.addGetWebGLMessage();
    }
    //div元素
    let container = document.createElement('div');
    document.body.appendChild(container);

    //相机,场景,渲染器
    let camera, scene, renderer;

    //射线
    let raycaster = new THREE.Raycaster();
    let mouse = new THREE.Vector2();

    //球体
    let sphereMesh = undefined;

    //轨道控件
    let orbitControls = undefined;

    main();
    render();

    function main() {
        initScene();
        initCamera();
        initRenderer(container);
        initControls();
        initLights();
        sphere();
        addEventListeners();
    }

    function initScene() {
        scene = new THREE.Scene();
    }

    function initCamera() {
        camera = new THREE.PerspectiveCamera(30,
            window.innerWidth/window.innerHeight, 1, 1000);
        camera.position.set(100, 300, 100);//设置相机位置
        camera.lookAt(new THREE.Vector3(0,0,0));//让相机指向原点
    }

    function initRenderer(container) {
        //渲染器
        //antialias:true增加抗锯齿效果
        renderer = new THREE.WebGLRenderer({antialias:true});
        renderer.setClearColor(new THREE.Color(0xffffff));//设置窗口背景颜色为黑
        renderer.setSize(window.innerWidth, window.innerHeight);//设置窗口尺寸
        //将renderer关联到container,这个过程类似于获取canvas元素
        container.appendChild(renderer.domElement);
    }

    function initControls() {
        orbitControls = new THREE.OrbitControls(camera, renderer.domElement);
        orbitControls.target = new THREE.Vector3(0, 0, 0);//控制焦点
        orbitControls.autoRotate = false;//将自动旋转关闭
        clock = new THREE.Clock();//用于更新轨道控制器
    }

    function initLights() {
        let ambient = new THREE.AmbientLight(0xffffff, 0.35);
        camera.add(ambient);

        let point = new THREE.PointLight(0xffffff);
        point.position.set(2, 20, 15);
        camera.add(point);

        scene.add(camera);
    }

    function sphere(){
        let sphereGeo = new THREE.SphereGeometry(80, 20, 20);//创建球体
        let sphereMat = new THREE.MeshLambertMaterial({//创建材料
            color:0x000000,
            wireframe:true
        });
        sphereMesh = new THREE.Mesh(sphereGeo, sphereMat);//创建球体网格模型
        sphereMesh.position.set(0, 0, 0);//设置球的坐标
        scene.add(sphereMesh);//将球体添加到场景
    }

    function render(){
        delta = clock.getDelta();
        orbitControls.update(delta);
        requestAnimationFrame(render);
        renderer.render(scene, camera);
    }

    function addEventListeners() {
        window.addEventListener("resize", onWindowResize, false);//重置窗口尺寸
        window.addEventListener("mousedown", onDocumentMouseDown, false);//鼠标点击监听
    }

    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);
        render();
    }

    function onDocumentMouseDown(event) {
        mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
        mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;
        raycaster.setFromCamera(mouse, camera);
        let intersects = raycaster.intersectObject(sphereMesh);
        if (intersects.length > 0) {
            let intersect = intersects[0];
            let face = intersect.face;
            console.log(face);//将选中的三角面信息打印到控制台
            //通过面的三个点索引值找到顶点坐标
            let v1 = sphereMesh.geometry.vertices[face.a];
            let v2 = sphereMesh.geometry.vertices[face.b];
            let v3 = sphereMesh.geometry.vertices[face.c];

            //显示三角面
            let material = new THREE.MeshStandardMaterial( {
                color: 0x00cc00, 
                side: THREE.DoubleSide
            } );
            let faceGeometry = new THREE.Geometry();
            faceGeometry.vertices.push(new THREE.Vector3(v1.x, v1.y, v1.z));
            faceGeometry.vertices.push(new THREE.Vector3(v2.x, v2.y, v2.z));
            faceGeometry.vertices.push(new THREE.Vector3(v3.x, v3.y, v3.z));

            let face3 = new THREE.Face3(0, 1, 2, face.normal, 0x00cc00, 0);
            faceGeometry.faces.push(face3);
            faceGeometry.computeFaceNormals();
            faceGeometry.computeVertexNormals();
            let faceMesh = new THREE.Mesh(faceGeometry, material);

            scene.add(faceMesh);
        }
    }
</script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/qq_37338983/article/details/89522483
今日推荐