• 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;
                     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

  • 相关阅读:
    mybatis0206 延迟加载
    怎样关闭“粘滞键”?
    TNS-12557: TNS:protocol adapter not loadable TNS-12560: TNS:protocol adapter error
    HTTP协议头部与Keep-Alive模式详解
    oracle定时器执行一遍就不执行或本就不执行
    Inflation System Properties
    https://stackoverflow.com/questions/16130292/java-lang-outofmemoryerror-permgen-space-java-reflection
    java spring中对properties属性文件加密及其解密
    annotation配置springMVC的方法了事务不起作用
    SQLPlus在连接时通常有四种方式
  • 原文地址:https://www.cnblogs.com/ThisYbc/p/16066129.html
Copyright © 2020-2023  润新知