【js&tres.js】Versión avanzada de visualización panorámica de la casa en realidad virtual

tres resumen:

Scene场景

Se refiere al entorno que contiene todos los objetos tridimensionales, luces, cámaras y otros elementos relacionados que se van a renderizar y presentar; la escena puede ser cargada y procesada por el motor de renderizado o la biblioteca de gráficos para generar la imagen o animación final.

  • Atributos comunes:
scene.background = new THREE.Color(0x000000); // 设置背景颜色为黑色

scene.fog = new THREE.Fog(0x000000, 0.1, 100); // 创建线性雾效,颜色为黑色,起始距离为0.1,结束距离为100
  • Métodos comunes:
scene.add(mesh); // 将名为mesh的对象添加到场景中

scene.remove(mesh); // 从场景中移除名为mesh的对象

var obj = scene.getObjectByName('mesh'); // 获取名称为mesh的对象

scene.traverse(function(object) {
  // 对每个对象执行的操作
  console.log(object);
});

scene.dispose(); // 清除场景及其相关资源

Geometry Geometría

Se refiere a datos que representan y describen la forma de un objeto tridimensional, describiendo la forma de un objeto.

Geometría de uso común:

  • BufferGeometry es un objeto de geometría de alto rendimiento en three.js
  • BoxGeometry Un objeto geométrico que representa un cubo.
  • SphereGeometry Un objeto geométrico que representa una esfera.
  • PlaneGeometry representa un objeto de geometría plana.
  • CilindroGeometría Un objeto geométrico que representa un cilindro, incluidos cilindros, conos y tuberías.

Material Material

Se refiere a los atributos y características de la apariencia superficial de una geometría determinada, definiendo los atributos de apariencia del objeto.

Materiales comúnmente utilizados:

  • MeshBasicMaterial es el material más simple y no se ve afectado por la iluminación de la escena.
  • MeshStandardMaterial es un material de renderizado de base física (PBR) que proporciona efectos de renderizado más realistas y realistas.
  • MeshPhysicalMaterial es otro material físico basado en MeshStandardMaterial

Mesh modelo de cuadrícula

Es una entidad compuesta de geometría y material, la geometría y el material se combinan en una entidad completa.

  • Ejemplos de métodos:
mesh.material = new THREE.MeshBasicMaterial({ color: 0xff0000 }); // 设置网格的材质为红色基础材质

mesh.rotation.set(Math.PI / 2, 0, 0); // 设置网格绕X轴旋转90度

mesh.rotateY(Math.PI / 4); // 将网格绕Y轴旋转45度

mesh.position.set(0, 0, 0); // 设置网格的位置为原点

  • Ejemplos de propiedades: 
mesh.visible = false; // 隐藏网格

mesh.material.opacity = 0.5; // 将网格材质的透明度设置为0.5

cámara cámara

Dispositivo virtual utilizado para simular la perspectiva del ojo humano y la observación de escenas.

Cámaras fotográficas de uso común:

  • PerspectiveCamera simula el efecto de los ojos humanos al observar objetos, con las características de cerca y de lejos.
  • OrthographicCamera (cámara ortogonal) representa objetos en la escena en un tamaño fijo, independientemente del efecto de perspectiva causado por la distancia.

Ejemplos de métodos:

camera.lookAt(new THREE.Vector3(0, 0, 0)); // 将相机对准场景原点

camera.updateProjectionMatrix(); // 更新相机的投影矩阵

const newCamera = camera.clone(); // 克隆相机

Ejemplos de propiedades: 

camera.position.set(0, 0, 10); // 设置相机在场景中的位置

camera.rotation.set(0, Math.PI / 2, 0); // 设置相机的旋转角度

camera.fov = 60; // 设置透视相机的视角大小为60度

camera.zoom = 2; // 将正交相机设置为缩放倍数为2

fuente de luz

 

AmbientLight: la luz ambiental es una fuente de luz uniforme y no direccional que se utiliza para simular la luz ambiental ubicua en la escena. No crea sombras y produce efectos de iluminación uniformes en todos los objetos de la escena.

const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); // 环境光

PointLight (fuente de luz puntual): una fuente de luz puntual es una fuente de luz que emite luz en todas las direcciones desde un punto. Produce efectos de iluminación que se desvanecen en la escena y puede proyectar sombras. Generalmente se utiliza para simular fuentes de luz puntuales, como bombillas y velas. 

const pointLight = new THREE.PointLight(0xff0000, 1, 10); // 红色点光源
pointLight.position.set(0, 3, 0)

DirectionalLight (luz paralela): la luz paralela es una fuente de luz paralela infinitamente lejana que simula la luz solar. Es luz que proviene de una dirección concreta, todos los rayos son paralelos. La luz paralela puede producir sombras y producir un efecto directo similar a la luz natural sobre los objetos de la escena. 

const directionalLight = new THREE.DirectionalLight(0x00ff00, 1); // 绿色平行光
directionalLight.position.set(-1, 2, 4);

SpotLight: Un foco es un cono de luz que emana de un punto con una dirección y un ángulo de haz específicos. Proyecta un cono de luz y puede proyectar sombras. Los focos se utilizan a menudo para simular linternas, luces de escenario, etc.

const spotLight = new THREE.SpotLight(0x0000ff, 1, 10, Math.PI / 4, 0.5); // 蓝色聚光灯
spotLight.position.set(2, 3, 0);
spotLight.target.position.set(0, 0, 0);

WebGLRenderer renderizador

Se utiliza para dibujar y renderizar gráficos 3D usando WebGL en un navegador web.

Herramienta de control de cámara OrbitControls

Permite a los usuarios rotar, hacer zoom y desplazar la cámara con el mouse o gestos táctiles para cambiar la perspectiva de la escena.

Ejemplos de propiedades: 

controls.enabled = true; // 启用控制器

controls.minZoom = 0.5; // 设置相机的最小缩放倍数为0.5
controls.maxZoom = 2; // 设置相机的最大缩放倍数为2

controls.enableRotate = true; // 启用旋转操作
controls.enableZoom = true; // 启用缩放操作
controls.enablePan = true; // 启用平移操作

Mostrar resultados:

Visualización del catálogo:

 Visualización de código:

 ruta.js

function path() {
    return [{
        name: "中式",
        styleObj: {
            background: '#409EFF'
        },
        children: [{
            name: "客餐厅",
            styleObj: {
                background: '#409EFF'
            },
            jpgNameArr: ["00125.jpg"]
        }, {
            name: "客厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "餐厨",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "卧室",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "卫浴",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "书房",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }]
    }, {
        name: "现代",
        styleObj: {
            background: null
        },
        children: [{
            name: "客餐厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "客厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "餐厨",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "卧室",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "卫浴",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }]
    }, {
        name: "新古典",
        styleObj: {
            background: null
        },
        children: [{
            name: "客餐厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "客厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "餐厨",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "卧室",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "卫浴",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }]
    }, {
        name: "欧式",
        styleObj: {
            background: null
        },
        children: [{
            name: "客餐厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "客厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "餐厨",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "卧室",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "卫浴",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }]
    }, {
        name: "美式",
        styleObj: {
            background: null
        },
        children: [{
            name: "客餐厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "客厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "餐厨",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "卧室",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "卫浴",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }]
    }, {
        name: "北欧",
        styleObj: {
            background: null
        },
        children: [{
            name: "客餐厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "客厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        },{
            name: "卧室",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }]
    }, {
        name: "法式",
        styleObj: {
            background: null
        },
        children: [{
            name: "客厅",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }, {
            name: "餐厨",
            styleObj: {
                background: null
            },
            jpgNameArr: ["0011.jpg"]
        }]
    }]

}

índice.html

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Three.js-webgl室内设计效果全景在线预览</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }

        #menu {
            position: absolute;
            bottom: 0px;
            color: #fff;
            background: rgba(0, 0, 0, 0.5);
            padding: 10px;
            z-index: 102;
            width: 500px;
            height: 80px
        }

        #menu>div {
            padding: 5px;
        }

        #menu span {
            display: inline-block;
            padding: 5px 10px;
            cursor: pointer;
        }

        .el-button--danger {
            font-size: 25px !important;
            background: rgba(0, 0, 0, 0.5) !important;
            border-width: 0px !important;
            width: 50px !important;
            height: 50px !important;
        }

        [v-cloak] {
            display: none;
        }
    </style>
    <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.min.js"></script>
    <script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/controls/OrbitControls.js"></script>
    <script src="http://www.yanhuangxueyuan.com/js/[email protected]"></script>
    <!-- 主要用于功能按钮 -->
    <script src="http://www.yanhuangxueyuan.com/js/element-ui/index.js"></script>
    <!-- 主要用于弹出框 -->
    <link rel="stylesheet" href="http://www.yanhuangxueyuan.com/js/element-ui/index.css">
    <script src="path.js"></script>
</head>

<body>
    <div id="app" z-index="105">
        <!-- 底部选择栏 -->
        <div id="menu" :style="{left:width/2 + -250+'px'}">
            <div><span style="font-weight:bold;cursor:default;"> 风格:</span><span v-for="obj in styleArr"
                    @click="styleClick(obj)" :style="obj.styleObj"> {
   
   { obj.name }}</span></div>
            <div><span style="font-weight:bold;cursor:default;"> 位置:</span><span v-for="obj in posArr"
                    @click="posClick(obj)" :style="obj.styleObj" v-if="obj.jpgNameArr.length"> {
   
   { obj.name }}</span>
            </div>
        </div>
        <!-- 顶部功能栏 使用的element-->
        <div style="position: absolute;right:20px;top:20px">
            <el-button type="danger" circle @click="audioClick()"><i><img
                        :src="(audioBoool)?('./UI/打开声音.png'):('./UI/关闭声音.png')" alt="" height="20"
                        width="20"></i></el-button>
            <el-button type="danger" circle @click="ScreenClick()"><i><img
                        :src="(ScreenBoool)?('./UI/全屏5.png'):('./UI/退出全屏.png')" alt="" width="18"
                        height="18"></i></el-button>
            <el-button type="danger" circle @click="rotateClick()"><i><img
                        :src="(rotateBoool)?('./UI/旋转.png'):('./UI/停止旋转.png')" alt="" width="20"
                        height="20"></i></el-button>
            <el-button type="danger" circle @click="questionClick()"><i><img src="./UI/帮助5.png" alt="" width="22"
                        height="22"></i></el-button>
        </div>
    </div>
    <script>
        // 创建场景
        var scene = new THREE.Scene();
        // 创建一个球体(Sphere)几何体
        var box = new THREE.SphereGeometry(25, 50, 50);
        // 创建一个基本网格材质
        var material = new THREE.MeshBasicMaterial({
            color: 0xffffff,
            side: THREE.BackSide,
        });
        // 创建了一个网格对象实例
        var mesh = new THREE.Mesh(box, material);
        // 将网格对象添加到场景中,以便在渲染时呈现出来
        scene.add(mesh);
        // 创建了一个纹理加载器实例
        var textureLoader = new THREE.TextureLoader();
        // 创建了一个音频监听器实例
        var listener = new THREE.AudioListener();
        // 创建一个用于播放音频的对象
        var audio = new THREE.Audio(listener);
        // 创建一个纹理加载器,并调用 load() 方法加载指定路径的纹理图像
        var texture = textureLoader.load('./风格/中式/客餐厅/00125.jpg', function (obj) {
            vm.loading.close();
            // 创建一个音频加载器
            var audioLoader = new THREE.AudioLoader();
            audioLoader.load('./音乐/琵琶语.mp3', function (AudioBuffer) {
                // 将加载的音频数据设置给 audio 对象
                audio.setBuffer(AudioBuffer);
                // 设置音频循环播放
                audio.setLoop(true);
                // 设置音频音量
                audio.setVolume(0.3);
                // 开始播放音频
                audio.play()
            });
            // 执行渲染
            render()
        });
        // 网格对象将使用加载的纹理作为材质的贴图
        mesh.material.map = texture;
        // 当前窗口的宽度
        var width = window.innerWidth;
        // 获取当前窗口的高度
        var height = window.innerHeight;
        // 计算宽高比
        var k = width / height;
        // 创建相机
        var camera = new THREE.PerspectiveCamera(60, k, 1, 1000);
        // 设置相机的缩放比例为 1。表示相机的视野不进行缩放
        camera.zoom = 1;
        // 修改相机的属性后,需要调用该方法来更新相机的投影矩阵,确保改变后的属性生效
        camera.updateProjectionMatrix();
        // 设置相机的位置坐标   通过设置相机的位置,可以决定场景中的视角
        camera.position.set(-0.87, 0.03, 0.4);
        // 设置相机的视线方向朝向场景的原点
        camera.lookAt(scene.position);
        // 创建一个基于 WebGL 的渲染器对象
        var renderer = new THREE.WebGLRenderer({
            // 开启抗锯齿效果,提高渲染的质量
            antialias: true,
        });
        // 设置渲染器的输出画布大小为窗口的宽度和高度
        renderer.setSize(width, height);
        // 将渲染器的 canvas 元素添加到页面的 body 中
        document.body.appendChild(renderer.domElement);
        // 创建时钟对象  用于跟踪时间的流逝,可以用来控制动画和其他与时间相关的操作
        var clock = new THREE.Clock();
        // 表示每秒帧数,这里设置为 30 帧
        var FPS = 30;
        // 计算每帧的时间间隔
        var 刷新时间 = 1 / FPS;
        var timeS = 0;

        function render() {
            // 浏览器执行下一次渲染时调用 render 函数
            requestAnimationFrame(render);
            // getDelta() 返回上一次调用之后的时间差,即两次渲染之间的时间间隔
            var 渲染间隔 = clock.getDelta();
            timeS = timeS + 渲染间隔;
            // 总运行时间是否大于刷新时间
            if (timeS > 刷新时间) {
                // 使用渲染器对象 renderer 来渲染场景 scene 和相机 camera
                renderer.render(scene, camera);
                if (vm.rotateBoool) {
                    // mesh 沿 Y 轴旋转 0.002 弧度
                    mesh.rotateY(0.002)
                }
                timeS = 0
            }
        }
        render();
        // 创建了一个控制器对象,用于控制相机的旋转、缩放和平移等操作
        var controls = new THREE.OrbitControls(camera);
        // 禁用 OrbitControls 控制器对象的平移功能
        controls.enablePan = false;
        // 获取本地数据
        var styleObjArr = path();
        var vm = new Vue({
            el: "#app",
            data: {
                loading: null,
                styleArr: styleObjArr,
                styleChoose: null,
                posArr: null,
                posChoose: null,
                width: window.innerWidth,
                height: window.innerHeight,
                classPath: '中式/客餐厅',
                path: '',
                audioBoool: true,
                ScreenBoool: true,
                rotateBoool: true,
                N: styleObjArr[0].children[0].jpgNameArr.length,
                num: 1,
            },
            methods: {
                audioClick: function () {
                    // 播放音乐
                    if (this.audioBoool) {
                        this.audioBoool = false;
                        audio.pause()
                    } else {
                        // 暂停音乐
                        this.audioBoool = true;
                        audio.play()
                    }
                },
                // 全屏方法
                ScreenClick: function () {
                    if (this.ScreenBoool) {
                        this.ScreenBoool = false;
                        requestFullScreen()
                    } else {
                        this.ScreenBoool = true;
                        exitFullscreen()
                    }
                },
                questionClick: function () {
                    // element弹框的的this.$alert
                    this.$alert('按住左键不放上下左右拖动,可以旋转整个场景', '旋转操作', {})
                },
                // 旋转
                rotateClick: function () {
                    if (this.rotateBoool) {
                        this.rotateBoool = false
                    } else {
                        this.rotateBoool = true
                    }
                },
                nextClick: function () {
                    if (this.num < this.N) {
                        this.num += 1
                    } else {
                        this.num = 1
                    }
                },
                upClick: function () {
                    if (this.num > 1) {
                        this.num -= 1
                    } else {
                        this.num = this.N
                    }
                },
                // 风格选择
                styleClick: function (styleObj) {
                    this.loading = this.$loading({
                        lock: true,
                        text: 'Loading',
                        spinner: 'el-icon-loading',
                        background: 'rgba(0, 0, 0, 0.7)'
                    });
                    this.num = 1;
                    this.styleChoose.styleObj.background = null;
                    this.posChoose.styleObj.background = null;
                    this.styleChoose = styleObj;
                    this.styleChoose.styleObj.background = '#409EFF';
                    this.posArr = this.styleChoose.children;
                    this.posChoose = this.posArr[0];
                    this.posArr[0].styleObj.background = '#409EFF';
                    this.N = this.posChoose.jpgNameArr.length;
                    this.classPath = this.styleChoose.name + '/' + this.posChoose.name;
                    this.path = this.classPath + '/' + this.posChoose.jpgNameArr[this.num - 1];
                    var texture = textureLoader.load('./风格/' + this.path, function (obj) {
                        // 关闭加载中的提示框
                        vm.loading.close();
                        render()
                    });
                    mesh.material.map = texture
                },
                // 位置选择
                posClick: function (posObj) {
                    this.loading = this.$loading({
                        lock: true,
                        text: 'Loading',
                        spinner: 'el-icon-loading',
                        background: 'rgba(0, 0, 0, 0.7)'
                    });
                    this.num = 1;
                    this.posChoose.styleObj.background = null;
                    this.posChoose = posObj;
                    this.N = this.posChoose.jpgNameArr.length;
                    this.posChoose.styleObj.background = '#409EFF';
                    this.classPath = this.styleChoose.name + '/' + this.posChoose.name;
                    this.path = this.classPath + '/' + this.posChoose.jpgNameArr[this.num - 1];
                    var texture = textureLoader.load('./风格/' + this.path, function (obj) {
                        vm.loading.close();
                        render()
                    });
                    mesh.material.map = texture
                }
            },
            watch: {
                num: function (value) {
                    this.loading = this.$loading({
                        lock: true,
                        text: 'Loading',
                        spinner: 'el-icon-loading',
                        background: 'rgba(0, 0, 0, 0.7)'
                    });
                    this.path = this.classPath + '/' + this.posChoose.jpgNameArr[this.num - 1];
                    console.log(this.path);
                    var texture = textureLoader.load('./风格/' + this.path, function (obj) {
                        vm.loading.close();
                        render()
                    });
                    mesh.material.map = texture;
                    render()
                }
            },
            created() {
                this.posArr = styleObjArr[0].children;
                this.styleChoose = this.styleArr[0];
                this.posChoose = styleObjArr[0].children[0];
                this.loading = this.$loading({
                    lock: true,
                    text: 'Loading',
                    spinner: 'el-icon-loading',
                    background: 'rgba(0, 0, 0, 0.7)'
                })
            }
        });

        window.onresize = onresizeFun;
        function onresizeFun() {
            renderer.setSize(window.innerWidth, window.innerHeight);
            // 设置相机的视图比例(即宽高比)
            camera.aspect = window.innerWidth / window.innerHeight;
            // 修改相机的属性后,需要调用该方法来更新相机的投影矩阵,确保改变后的属性生效
            camera.updateProjectionMatrix();
            vm.width = window.innerWidth;
            vm.height = window.innerHeight;
        };

        function requestFullScreen() {
            // 获取文档的根元素
            var de = document.documentElement;
            // 检查当前浏览器是否支持 requestFullscreen 方法
            if (de.requestFullscreen) {
                // 全屏显示模式
                de.requestFullscreen()
            } else if (de.mozRequestFullScreen) { //进一步检查当前浏览器是否支持 mozRequestFullScreen 方法
                de.mozRequestFullScreen()
            } else if (de.webkitRequestFullScreen) { //再进一步检查当前浏览器是否支持 webkitRequestFullScreen 方法
                de.webkitRequestFullScreen()
            }
        }
        // 与上相反 退出全屏
        function exitFullscreen() {
            var de = document;
            if (de.exitFullscreen) {
                de.exitFullscreen()
            } else if (de.mozCancelFullScreen) {
                de.mozCancelFullScreen()
            } else if (de.webkitCancelFullScreen) {
                de.webkitCancelFullScreen()
            }
        }
    </script>
</body>

</html>

Supongo que te gusta

Origin blog.csdn.net/weixin_52479803/article/details/132276368
Recomendado
Clasificación