实现threeJS 测距(距离并不能显示出来)

本文介绍了如何使用Three.js库在网页上实现动态的3D空间,通过鼠标交互创建线段和点,同时展示了关键的事件处理和几何体操作。读者将了解如何利用CSS2DRenderer创建标签,以及如何跟踪鼠标位置来生成和移动几何对象。
摘要由CSDN通过智能技术生成
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            position: relative;
        }

        .label {
            margin-top: -1em;
            border: 10px;
            border-radius: 8px;
            width: 85px;
            text-align: center;
            cursor: pointer;
            color: rgb(0, 155, 234);
            line-height: 1.2;
            background-color: rgb(244, 244, 244);
            box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.25);
        }

        .label:hover {
            box-shadow: 0px 0px 20px rgba(0, 155, 234, 0.8);
        }
    </style>
    <script src="./three.js-r139/build/three.js"></script>
    <script src="./three.js-r139/examples/js/controls/OrbitControls.js"></script>
    <script src="./three.js-r139/examples/js/renderers/CSS2DRenderer.js"></script>
</head>

<body>

</body>
<script>
    var scene, camera, renderer, controls, labelRenderer
    // var stats = initStats()

    // 地面网格所需变量
    var length = 200

    // 场景
    function initScene() {
        scene = new THREE.Scene()
    }

    /* 相机 */
    function initCamera() {

        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
        camera.position.set(0, 200, 250);
        camera.lookAt(new THREE.Vector3(0, 0, 0));

    }
    /* 渲染器 */
    function initRender() {

        renderer = new THREE.WebGLRenderer({
            antialias: true
        });
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        labelRenderer = new THREE.CSS2DRenderer();
        labelRenderer.setSize(window.innerWidth, window.innerHeight);
        labelRenderer.domElement.style.position = 'absolute'
        labelRenderer.domElement.style.top = '0px'
        document.body.appendChild(labelRenderer.domElement);

    }

    /* 生成标签 */
    function createLabel(text, pos) {
        const div = document.createElement('div')
        // div.className = 'label'
        div.innerHTML = text
        div.style.padding = "2px";
        div.style.color = "#fff";
        div.style.height = "20px";
        div.style.fontSize = "16px";
        div.style.lineHeight = "16px";
        div.style.position = "absolute";
        // div.style.top = '0px';
        div.style.backgroundColor = "rgba(25,25,25,0.5)";
        div.style.borderRadius = "5px";
        console.log('div', div);
        const divLabel = new THREE.CSS2DObject(div)
        divLabel.position.set(pos.x, pos.y, pos.z);
        return divLabel
    }

    /* 灯光 */
    function initLight() {

        var ambientLight = new THREE.AmbientLight(0x333333);
        scene.add(ambientLight);

        var directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight.position.set(100, 300, 200);
        scene.add(directionalLight);

    }

    /* 控制器 */
    function initControls() {

        controls = new THREE.OrbitControls(camera, labelRenderer.domElement);
        /* 其它属性默认 */

    }

    /* 场景内容 */
    function initContent() {

        // const geometry1 = new THREE.BoxGeometry(50, 50, 50);
        // const material = new THREE.MeshPhongMaterial({
        //     color: 0x00ff00,
        // });
        // const cube = new THREE.Mesh(geometry1, material);
        // scene.add(cube);
        //这里用这个构造
        const geometry = new THREE.BufferGeometry()
        // console.log(geometry);
        const pointsArray = new Array()
        pointsArray.push(new THREE.Vector3(-length / 2, 0, 0))
        pointsArray.push(new THREE.Vector3(length / 2, 0, 0))
        //用这个api传入顶点数组
        geometry.setFromPoints(pointsArray)
        var lineMaterial = new THREE.LineBasicMaterial({
            color: 0x808080
        }); /* 基础线材质 */

        var planeGeometry = new THREE.PlaneGeometry(length, 10); /* 平面 width:200,、height:10 */
        var planeMaterial = new THREE.MeshBasicMaterial({
            color: 0xD9D9D9,
            side: THREE.DoubleSide
        }); /* 平面材质 */

        // geometry.vertices.push(new THREE.Vector3(-length / 2, 0, 0)); /* 顶点(-100, 0, 0) */
        // geometry.vertices.push(new THREE.Vector3(length / 2, 0, 0)); /* 顶点( 100, 0, 0) */

        /* 循环创建线段 */
        for (var i = 0; i <= length / 10; i++) {

            /* 横向线段 */
            var lineX = new THREE.Line(geometry, lineMaterial);
            lineX.position.z = (i * 10) - length / 2;
            scene.add(lineX);

            /* 纵向线段 */
            var lineY = new THREE.Line(geometry, lineMaterial);
            lineY.rotation.y = 0.5 * Math.PI;
            lineY.position.x = (i * 10) - length / 2;
            scene.add(lineY);

        }

        /* 创建包围平面 */
        var planeX_left = new THREE.Mesh(planeGeometry, planeMaterial);
        planeX_left.rotation.y = 0.5 * Math.PI;
        planeX_left.position.x = -length / 2;

        var planeX_right = planeX_left.clone();
        planeX_right.position.x = length / 2;

        var planeY_top = new THREE.Mesh(planeGeometry, planeMaterial);
        planeY_top.position.z = -length / 2;

        var planeY_bottom = planeY_top.clone();
        planeY_bottom.position.z = length / 2;

        scene.add(planeY_bottom);
        scene.add(planeY_top);
        scene.add(planeX_left);
        scene.add(planeX_right);

        /* 四个包围面的位置 y轴向上5 */
        scene.traverse(function (object) {

            if (object.isMesh) {

                if (object.geometry.type === 'PlaneGeometry') {

                    object.position.y = 5;

                }

            }

        });

    }

    /* 获取射线与平面相交的交点 */
    function getIntersects(event) {

        var raycaster = new THREE.Raycaster();
        var mouse = new THREE.Vector2();

        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;

        var normal = new THREE.Vector3(0, 1, 0);
        /* 创建平面 */
        var planeGround = new THREE.Plane(normal, 0);

        /* 从相机发出一条射线经过鼠标点击的位置 */
        raycaster.setFromCamera(mouse, camera);

        intersects = raycaster.intersectObjects(scene.children, true);
        console.log('dddddddddddd', intersects);

        /* 获取射线 */
        // var ray = raycaster.ray;
        /* 计算相机到射线的对象,可能有多个对象,返回一个数组,按照距离相机远近排列 */
        // var intersects = ray.intersectPlane(planeGround);
        // var intersects = ray.direction;
        if (intersects.length) {
            var object = intersects[0].point

            // console.log("x:" + intersects.x + " y:" + intersects.y + " z:" + intersects.z);

            /* 返回向量 */
            return object;
        }


    }

    var pointsArray = [];
    var window_mouse = true;
    /* 鼠标按下事件 */
    function onMouseDown(event) {

        /* 获取相机发出的射线与 Plane 相交点*/
        let intersects = getIntersects(event);

        /* 存放网格的三维坐标 */
        var vector3_x, vector3_z;

        /* 鼠标左键按下时,创建点和线段 */
        if (event.button === 0) {

            if (!window_mouse) {

                window.addEventListener('mousemove', onMouseMove, false);

                /* 依据 windwo_mouse 标识避免事件的重复添加 */
                window_mouse = true;

            }

            /* 若交点此时在平面之内则创建点(Points) */
            var pointsGeometry = new THREE.BufferGeometry();
            // var pointsGeometry = new THREE.SphereGeometry( 15, 32, 16 );
            // pointsGeometry.vertices.push(intersects);
            pointsGeometry.setFromPoints([intersects])

            var pointsMaterial = new THREE.PointsMaterial({
                color: 0xff0000,
                size: 3
            });
            var points = new THREE.Points(pointsGeometry, pointsMaterial);
            // points.position.set(intersects)
            // console.log('points',points);
            pointsArray.push(intersects);


            scene.add(points);
            /* 创建线段 */
            var lineGeometry = new THREE.BufferGeometry();
            var lineMaterial = new THREE.LineBasicMaterial({
                color: 0x000fff
            });

            if (pointsArray.length >= 2) {

                // lineGeometry.vertices.push(pointsArray[0].geometry.vertices[0], pointsArray[1].geometry.vertices[
                //     0]);
                lineGeometry.setFromPoints([pointsArray[0], pointsArray[1]])
                console.log('pointsArray', pointsArray);
                var line = new THREE.Line(lineGeometry, lineMaterial);
                pointsArray.shift();
                scene.add(line);

            }



        }

        /* 鼠标右键按下时 回退到上一步的点,并中断绘制 */
        if (event.button === 2) {

            window.removeEventListener('mousemove', onMouseMove, false);

            /* 移除事件之后,要设置为 false 为了避免事件的重复添加 */
            window_mouse = false;

            /* 鼠标左键未点击时线段的移动状态 */
            if (scene.getObjectByName('line_move')) {

                scene.remove(scene.getObjectByName('line_move'));

                /* 删除数组中的元素,否则的话再次重绘会链接之前的点接着重绘 */
                pointsArray.shift();

            }

        }

    }

    /* 鼠标移动事件 */
    function onMouseMove(event) {

        var intersects = getIntersects(event);
        // console.log(intersects);

        /* 判断交点是否在 x(-100, 100) ,z(-100, 100)(平面)之间 */


        /* 鼠标左键未点击时线段的移动状态 */
        if (scene.getObjectByName('line_move')) {

            scene.remove(scene.getObjectByName('line_move'));

        }
        /* 创建线段 */
        var lineGeometry = new THREE.BufferGeometry();
        var lineMaterial = new THREE.LineBasicMaterial({
            color: 0x000fff
        });

        if (pointsArray.length > 0) {

            // lineGeometry.vertices.push(pointsArray[0].geometry.vertices[0]);
            console.log('pointsArray', pointsArray);
            // lineGeometry.setFromPoints([pointsArray[0]])

            var mouseVector3 = new THREE.Vector3(intersects.x, 0, intersects.z);

            // lineGeometry.vertices.push(mouseVector3);
            lineGeometry.setFromPoints([pointsArray[0], mouseVector3])
            // console.log('distance', pointsArray[0].distanceTo(mouseVector3), pointsArray[0]);
            console.log('distance', mouseVector3.distanceTo(pointsArray[0]), pointsArray[0]);
            let dis = mouseVector3.distanceTo(pointsArray[0]).toFixed(2)
            let pos = new THREE.Vector3().copy(mouseVector3)
            pos.add(pointsArray[0]) // 两个向量相加
            pos.multiplyScalar(0.5) // 乘以二分之一 取中点
            let label = scene.getObjectByName('active-label');
            if (label) {
                console.log('label2', label);
                label.element.innerHTML = '~' + dis;
                label.position.set(pos.x, pos.y, pos.z);
                scene.add(label);
            } else {
                label = this.createLabel('~' + dis, pos);
                console.log('label1', label);
                label.name = 'active-label';
                scene.add(label);
            }
            var line = new THREE.Line(lineGeometry, lineMaterial);
            line.name = 'line_move';

            scene.add(line);

        }



    }

    /* 键盘按下事件 */
    function onKeyDown(event) {

        /* ESC键 回退上一步绘制,结束绘制*/
        if (event.key === 'Escape') {

            window.removeEventListener('mousemove', onMouseMove, false);

            /* 移除事件之后,要设置为 false 为了避免 mousemove 事件的重复添加 */
            window_mouse = false;

            /* 鼠标左键未点击时线段的移动状态 */
            if (scene.getObjectByName('line_move')) {

                scene.remove(scene.getObjectByName('line_move'));

                /* 删除数组中的元素,否则的话再次重绘会链接之前的点接着重绘 */
                pointsArray.shift();

            }

            var length = scene.children.length - 1;
            console.log(scene.children);
            /* 按步骤移除点和先 */
            if (scene.children[length].isLine || scene.children[length].isPoints) {

                scene.children.pop();
                length = scene.children.length - 1;

                /* 若最后一项不是线段或者点就不移除 */
                if (!scene.children[length].isMesh) {

                    scene.children.pop();

                }

            }

        }

    }


    /* 更新数据 */
    function update() {

        // stats.update();
        controls.update();

    }

    /* 窗口自动适应 */
    function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);

    }


    /* 循环调用 */
    function animate() {

        requestAnimationFrame(animate);
        renderer.render(scene, camera);
        update();

    }

    /* 初始化 */
    function init() {

        /* 兼容性判断 */
        //if (!Detector.webgl) Detector.addGetWebGLMessage();

        initScene();
        initCamera();
        initRender();
        initLight();
        initContent();
        initControls();

        /* 事件监听 */
        window.addEventListener('resize', onWindowResize, false);
        window.addEventListener('mousedown', onMouseDown, false); /* 使用mousedown的时候可以判断出点击的鼠标左右键之分 */
        window.addEventListener('mousemove', onMouseMove, false);
        window.addEventListener('keydown', onKeyDown, false); /* 使用事件的时候要把前面的on给去掉 */
    }

    /* 初始加载 */
    (function () {

        console.log('three start...');

        init();
        animate();

        console.log('three end...');

    })();
</script>

</html>

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值