three.js加载模型,鼠标操作模型,点击获取对象信息


<style>
            body {
                margin: 0;
                overflow: hidden;
            }

            #label {
                position: absolute;
                padding: 10px;
                background: rgba(255, 255, 255, 0.6);
                line-height: 1;
                border-radius: 5px;
            }

            #display {
                height: 600px;
                width: 1200px;
            }
        </style>
<script src="js/three.js"></script>
        <script src="js/GLTFLoader.js"></script>
        <script src="js/OrbitControls.js"></script>
        <div id="WebGL-output"></div>
        <div id="Stats-output"></div>
        <div id="label"></div>
        <div>
            <canvas id="display"></canvas>
        </div>
        <script src="js/stats.min.js"></script>
        <script src="js/dat.gui.min.js"></script>
        <script type="module">
            //性能优化插件
            let stats = initStats();
            let scene, camera, renderer, controls, light, selectObject, canvas;
            //加载器
            let gltfLoader;
            //用来存外部引入的模型
            let group = new THREE.Group();

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

            //相机
            function initCamera() {
                //与视点坐标系联动
                camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 10000);
                camera.position.set(-1, 0.5, 0);
                camera.lookAt(new THREE.Vector3(0, 0, 0));
            }

            //渲染器
            function initRenderer() {
                canvas = document.querySelector('#display');
                renderer = new THREE.WebGLRenderer({
                    canvas,
                    antialias: true //抗锯齿
                });
                renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);
                renderer.setClearColor(0xFDE7CA);
            }

            //初始化模型
            function initContent() {
                let helper = new THREE.GridHelper(100, 50, 0xCD3700, 0x4A4A4A);//网格线
                scene.add(helper);

                gltfLoader = new THREE.GLTFLoader();
                gltfLoader.load('model/c1.glb', (gltf) => {

                    let model = gltf.scene;

                    //遍历模型的每一部分
                    //traverse这个方法可以遍历调用者和调用者的所有后代
                    //所以这里的o就是模型的每一部分
                    model.traverse((o) => {
                        //将图片作为纹理加载
                        //let explosionTexture = new THREE.TextureLoader().load(
                        //    'static/seraphine/textures/Mat_cwfyfr1_userboy17.bmp_diffuse.png'
                        //);
                        ////调整纹理方向,默认为真。翻转图像的Y轴以匹配WebGL纹理坐标空间。
                        ////此处不需要反转,当然也可以试试反转以后什么效果
                        //explosionTexture.flipY = false;
                        ////将纹理图生成基础网格材质(meshBasicMaterial)
                        //const material = new THREE.MeshBasicMaterial({
                        //    map: explosionTexture
                        //});
                        ////给模型每部分上材质
                        //o.material = material;

                    });
                    //加载外部模型时候基本上都是一个组合对象.

                    group.add(model)
                    scene.add(group);
                });

            }

            //函数:重新设置渲染器的展示大小
            function resizeRendererToDisplaySize(renderer) {
                //这里没看明白往上翻
                const canvas = renderer.domElement;
                let width = window.innerWidth;
                let height = window.innerHeight;
                //判断css像素分辨率就和物理像素分辨率是否统一
                let canvasPixelWidth = canvas.width / window.devicePixelRatio;
                let canvasPixelHeight = canvas.height / window.devicePixelRatio;
                //判断是否需要调整
                const needResize = canvasPixelWidth !== width || canvasPixelHeight !== height;
                if (needResize) {
                    renderer.setSize(width, height, false);
                }
                return needResize;
            }


            //鼠标双击触发的方法
            function onMouseDblclick(event) {
                //alert("a");
                //获取raycaster和所有模型相交的数组,其中的元素按照距离排序,越近的越靠前
                let intersects = getIntersects(event);
                 console.log(intersects);
                // console.log(intersects[0].object);

                //获取选中最近的Mesh对象
                //instance坐标是对象,右边是类,判断对象是不是属于这个类的
                if (intersects.length !== 0 && intersects[0].object.type === 'Mesh') {
                    intersects[0].object.material.color.set(0x00FF00);
                    //console.log(intersects[0].object.material.color);
                    selectObject = intersects[0].object;
                    //changeMaterial(selectObject)
                } else {
                    console.log('未选中 Mesh!');
                }
            }

            //获取与射线相交的对象数组
            function getIntersects(event) {
                event.preventDefault();// 阻止默认的点击事件执行, https://developer.mozilla.org/zh-CN/docs/Web/API/Event/preventDefault
                //console.log("event.clientX:" + event.clientX);
                //console.log("event.clientY:" + event.clientY);

                //声明 rayCaster 和 mouse 变量
                let rayCaster = new THREE.Raycaster();
                let mouse = new THREE.Vector2();

                //通过鼠标点击位置,计算出raycaster所需点的位置,以屏幕为中心点,范围-1到1
                mouse.x = ((event.clientX - canvas.getBoundingClientRect().left) / canvas.offsetWidth) * 2 - 1;
                mouse.y = -((event.clientY - canvas.getBoundingClientRect().top) / canvas.offsetHeight) * 2 + 1; //这里为什么是-号,没有就无法点中

                //通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
                rayCaster.setFromCamera(mouse, camera);

                //获取与射线相交的对象数组, 其中的元素按照距离排序,越近的越靠前。
                //+true,是对其后代进行查找,这个在这里必须加,因为模型是由很多部分组成的,后代非常多。
                let intersects = rayCaster.intersectObjects(group.children, true);

                //返回选中的对象
                return intersects;
            }

            // 窗口变动触发的方法
            function onWindowResize() {
                camera.aspect = window.innerWidth / window.innerHeight;
                camera.updateProjectionMatrix();
                renderer.setSize(window.innerWidth, window.innerHeight);
            }

            //键盘按下触发的方法
            function onKeyDown(event) {
                switch (event.keyCode) {
                    case 13:
                        initCamera();
                        initControls();
                        break;
                }
            }

            //改变对象材质属性
            function changeMaterial(object) {
                let material = new THREE.MeshLambertMaterial({
                    color: 0xffffff * Math.random(),
                    transparent: object.material.transparent ? false : true,
                    opacity: 0.8
                });
                object.material = material;
            }

            //初始化轨道控制器
            function initControls() {
                controls = new THREE.OrbitControls(camera, renderer.domElement);
                //controls.enableDamping = true;
            }

            // 初始化灯光
            function initLight() {
                light = new THREE.SpotLight(0xffffff);
                light.position.set(-300, 600, -400);
                light.castShadow = true;

                scene.add(light);
                scene.add(new THREE.AmbientLight(0x5C5C5C));
            }

            //初始化 dat.GUI
            function initGui() {
                //保存需要修改相关数据的对象
                let gui = new function () {

                }
                //属性添加到控件
                let guiControls = new dat.GUI();
            }

            //初始化性能插件
            function initStats() {
                let stats = new Stats();

                stats.domElement.style.position = 'absolute';
                stats.domElement.style.left = '0px';
                stats.domElement.style.top = '0px';

                document.body.appendChild(stats.domElement);
                return stats;
            }

            //更新div的位置
            // function renderDiv(object) {
            //     //获取窗口的一半高度和宽度
            //     let halfWidth = window.innerWidth / 2;
            //     let halfHeight = window.innerHeight / 2;
            //
            //     //逆转相机求出二维坐标
            //     let vector = object.position.clone().project(camera);
            //
            //     //修改div的位置
            //     $("#label").css({
            //         left: vector.x * halfWidth + halfWidth,
            //         top: -vector.y * halfHeight + halfHeight - object.position.y
            //     });
            //
            //     //显示模型信息
            //     $("#label").text("name:" + object.name);
            // }

            //更新控件
            function update() {
                stats.update();
                controls.update();
            }

            //初始化
            function init() {
                initScene();
                initCamera();
                initRenderer();
                initContent();
                initLight();
                initControls();
                initGui();//显示隐藏右上角的控制器开关
                addEventListener('click', onMouseDblclick, false);
                addEventListener('resize', onWindowResize, false);
                addEventListener('keydown', onKeyDown, false);
            }

            function animate() {
                if (selectObject != undefined && selectObject != null) {
                    //renderDiv(selectObject);
                }
                requestAnimationFrame(animate);
                renderer.render(scene, camera);
                update();
                //判断渲染器是否调整,若调整,相机也需要调整aspect
                if (resizeRendererToDisplaySize(renderer)) {
                    const canvas = renderer.domElement;
                    //重新设置摄像机看视锥体的横纵比,横纵比一般为屏幕宽高比,不然会挤压变形
                    camera.aspect = canvas.clientWidth / canvas.clientHeight;
                    camera.updateProjectionMatrix();
                }
            }

            init();
            animate();
        </script>

 用到的一些JS:https://github.com/ThisCabbage/CabbageGarden/blob/58cedeb52eed245fbbe349f21a5cfaf6905b794f/threeJs.zip


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM