其他分享
首页 > 其他分享> > three.js 针对光源的移动控制 demo

three.js 针对光源的移动控制 demo

作者:互联网

import * as THREE from 'three';
// 视图旋转控件
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
// 可视化平移控件
import { TransformControls } from 'three/examples/jsm/controls/TransformControls';

/**
 * 3d 鼠标拖拽,测试光源
 */
export class ThreeDragLight {
    constructor(canvasId) {
        this.work(canvasId);
    }

    work(canvasId) {
        // 创建 3d 场景
        let scene = new THREE.Scene();

        let width = window.innerWidth;
        let height = window.innerHeight;
        let renderer = new THREE.WebGLRenderer({
            antialias: true
        });

        renderer.setSize(width, height);
        // 最后一步很重要,我们将renderer(渲染器)的dom元素(renderer.domElement)添加到我们的HTML文档中。这就是渲染器用来显示场景给我们看的<canvas>元素。
        document.getElementById(canvasId).appendChild(renderer.domElement);
        scene.background = new THREE.Color(0x9e9e9e);

        let camera = new THREE.PerspectiveCamera(45, width / height, 1, 10000);
        // 3d 视图(主视角)
        camera.position.set(240, 50, 240);
        //设置照相机的位置
        camera.lookAt(new THREE.Vector3(0, 0, 0)); //设置照相机面向(0,0,0)坐标观察 照相机默认坐标为(0,0,0); 默认面向为沿z轴向里观察;

        // 聚光灯
        let spotLight = new THREE.SpotLight(0xffffff, 100, 0);  //创建光源
        // 光源移动
        spotLight.position.set(0, 100, 0);
        scene.add(spotLight);  //在场景中添加光源

        // 网格辅助线
        let gridHelper = new THREE.GridHelper(200, 10, 0x444444, 0xffffff);
        scene.add(gridHelper);

        // 三维坐标轴参考线
        let axes = new THREE.AxesHelper(100);
        scene.add(axes);

        // 添加物体
        let geo = this.addBox(scene);

        // 渲染
        renderer.render(scene, camera);

        // 添加鼠标操作视图
        let tackBallC, orbC;
        orbC = this.initMouseControl(scene, camera, renderer);

        // 添加拖动事件,返回平移控件对象
        let transformControls = this.initDragControl(scene, camera, renderer, orbC);


        // 添加操作面板,绑定按钮事件,可切换光源对象
        this.addControlPanel(renderer, scene, camera, transformControls, spotLight);


        /**
         * 使用官方的THREE.Raycaster
         * THREE.Raycaster是three.js中的射线类,其实现监听的原理是由相机位置为射线起点,由鼠标位置为射线方向发射射线,
         * 其穿过的所有几何体都会被监测到。
         * @type {*[]}
         */
        let intersects = []; //几何体合集
        const pointer = new THREE.Vector2();
        // 给 canvas 加监听点击事件
        document.getElementsByTagName('canvas')[0].addEventListener('click', meshOnClick);
        let raycaster = new THREE.Raycaster();
        function meshOnClick(event) {

            //geometrys 为需要监听的Mesh合集,可以通过这个集合来过滤掉不需要监听的元素例如地面天空
            let geometrys = [];
            for (let i = 0; i < scene.children.length; i++) {
                console.log(scene.children[i].isLight);
                // 物体 和 光源都监听点击
                if (scene.children[i].isMesh || scene.children[i].isLight) {
                    geometrys.push(scene.children[i]);
                }
            }
            console.log(geometrys);
            pointer.x = (event.clientX / window.innerWidth) * 2 - 1;
            pointer.y = -(event.clientY / window.innerHeight) * 2 + 1;
            raycaster.setFromCamera(pointer, camera);
            // true为不拾取子对象
            intersects = raycaster.intersectObjects(geometrys, true);
            // 被射线穿过的几何体为一个集合,越排在前面说明其位置离端点越近,所以直接取[0]
            console.log(intersects);
            if (intersects.length > 0) {
                transformControls.attach(intersects[0].object);
            } else {
                //若没有几何体被监听到,可以做一些取消操作,判断不到光源点击,直接移除控制不可行
                // transformControls.detach();
                // 当前控制器操控的对象
                // console.log(transformControls.object);
                console.log(1);
            }
            renderer.render(scene, camera);

        }
    }

    /**
     * 鼠标操作
     */
    initMouseControl(scene, camera, renderer) {
        // 添加鼠标操作
        let controls = new OrbitControls(camera, renderer.domElement);
        controls.addEventListener('change', () => {
            renderer.render(scene, camera);
        });
        return controls;
    }

    // 添加拖拽控件
    initDragControl(scene, camera, renderer, orbC) {
        /**
         * 添加平移控件,可视化操作,默认显示三维坐标系(因为是一个三维模型,所以需要添加到场景中)
         *
         * 变换控制器(TransformControls)
         * 该类可提供一种类似于在数字内容创建工具(例如Blender)中对模型进行交互的方式,来在3D空间中变换物体。 和其他控制器不同的是,变换控制器不倾向于对场景摄像机的变换进行改变。
         * TransformControls 期望其所附加的3D对象是场景图的一部分。
         *
         * TransformControls( camera : Camera, domElement : HTMLDOMElement )
         * camera: 被控制的摄像机。
         * domElement: 用于事件监听的HTML元素。
         * 创建一个新的 TransformControls 实例。
         *
         * 文档:https://threejs.org/docs/index.html#examples/zh/controls/TransformControls.detach
         *
         * .attach ( object : Object3D ) 设置应当变换的3D对象,并确保控制器UI是可见的。
         * .detach () 从控制器中移除当前3D对象,并确保控制器UI是不可见的。
         * @type {TransformControls}
         */
        let transformControls = new TransformControls(camera, renderer.domElement);
        scene.add(transformControls);
        // 监听改变,则更新界面
        transformControls.addEventListener("change", () => {
            renderer.render(scene, camera);
        });
        // 变换控制器监听 mousedown,禁用 鼠标拖拽
        transformControls.addEventListener("mouseDown", () => {
            orbC.enabled = false;
        });
        //
        transformControls.addEventListener("mouseUp", () => {
            orbC.enabled = true;
        });

        return transformControls;
    }

    /**
     * 添加物体,此为十二面体,可观察光影效果
     * @param scene
     * @return {Mesh}
     */
    addBox(scene) {
        // 添加 十二面体
        const geometry = new THREE.DodecahedronGeometry(20, 0);
        const material = new THREE.MeshStandardMaterial({ color: 0x049EF4 });
        const dodecahedron = new THREE.Mesh(geometry, material);
        scene.add(dodecahedron);
        // 添加边缘辅助线
        let edges = new THREE.EdgesHelper(dodecahedron, 0x00ff00);
        scene.add(edges);

        const box = new THREE.BoxHelper(dodecahedron, 0xffff00);
        scene.add(box);
        // 后续增加点击事件,抛出物体对象
        return dodecahedron;
    }

    /**
     * 添加操作面板,按钮控制光源对象切换,添加平移控件关联
     * @param renderer
     * @param scene
     * @param camera
     * @param transformControls 平移控制器对象
     * @param spotLight 聚光灯对象
     */
    addControlPanel(renderer, scene, camera, transformControls, spotLight) {
        let ele = `
            <div class="control-panel">
                <button class="spot-light">聚光灯</button>
            </div>
        `;
        $('body').append(ele);
        // 绑定按钮事件
        $('.spot-light').on('click', function (e) {
            // 标记光源控制器,测试光源拖拽效果,后续单独搞个 demo
            transformControls.attach(spotLight);
            renderer.render(scene, camera);
        });
    }
}

 

标签:demo,scene,three,camera,let,renderer,new,js,THREE
来源: https://www.cnblogs.com/guofan/p/16333145.html