THREE.JS 实现看房自由(VR 看房)

简介: 目前随着元宇宙概念的爆火,THREE技术已经深入到了物联网、VR、游戏、数据可视化等多个平台,今天我们主要基于THREE实现一个三维的VR看房小项目

一、前言

概述:基于WebGL的三维引擎,目前是国内资料最多、使用最广泛的三维引擎,可以制作一些3D可视化项目


网络异常,图片无法展示
|


目前随着元宇宙概念的爆火,THREE技术已经深入到了物联网、VR、游戏、数据可视化等多个平台,今天我们主要基于THREE实现一个三维的VR看房小项目


网络异常,图片无法展示
|


网络异常,图片无法展示
|


二、基础知识

网络异常,图片无法展示
|


Three.js一般分为三个部分:场景相机渲染器,这三个主要的分支就构成了THREE.JS的主要功能区,这三大部分还有许多细小的分支,这些留到我们后续抽出一些章节专门讲解一下。


网络异常,图片无法展示
|


工作流程场景——相机——渲染器


实际生活中拍照角度立方体网格模型和光照组成了一个虚拟的三维场景,相机对象就像你生活中使用的相机一样可以拍照,只不过一个是拍摄真实的景物,一个是拍摄虚拟的景物。拍摄一个物体的时候相机的位置和角度需要设置,虚拟的相机还需要设置投影方式,当你创建好一个三维场景,相机也设置好,就差一个动作“咔”,通过渲染器就可以执行拍照动作。

三、场景

概述:场景主要由网络模型与光照组成,网络模型分为几何体与材质

3.1 网络模型

几何体就像我们小时候学我们就知道点线面体四种概念,点动成线,线动成面,面动成体,而材质就像是是几何体上面的涂鸦,有不同的颜色、图案......


例子如下


网络异常,图片无法展示
|


//打造酷炫三角形for (leti=0; i<50; i++) { 
constgeometry=newTHREE.BufferGeometry();
constarr=newFloat32Array(9);
for (letj=0; j<9; j++) { 
arr[j] =Math.random() *5;
    }
geometry.setAttribute('position', newTHREE.BufferAttribute(arr, 3));
letrandomColor=newTHREE.Color(Math.random(), Math.random(), Math.random());
constmaterial=newTHREE.MeshBasicMaterial({
color: randomColor,
transparent: true,
opacity:0.5,
    });
constmesh=newTHREE.Mesh(geometry, material);
scene.add(mesh);
}



网络异常,图片无法展示
|


constgeometry=newTHREE.BoxGeometry(100, 100, 100);
constmaterial=newTHREE.MeshStandardMaterial({ color: 0x0000ff });
constcube=newTHREE.Mesh(geometry, material);
scene.add(cube);



网络异常,图片无法展示
|


constgeometry=newTHREE.ConeGeometry(5, 15, 32);//底面半径 高 侧边三角分段constmaterial=newTHREE.MeshStandardMaterial({ color: 0x0000ff });
constclone=newTHREE.Mesh(geometry, material);
scene.add(clone);

3.2 光照

3.2.1 环境光

概念:光照对three.js的物体全表面进行光照测试,有可能会发生光照融合


网络异常,图片无法展示
|


//环境光constambient=newTHREE.AmbientLight(0x404040);
scene.add(ambient);

3.2.2 平行光

概念:向特定方向发射的光,太阳光也视作平行的一种,和上面比较,物体变亮了


//平行光  颜色 强度constdirectionalLight=newTHREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(100, 100, 100);//光源位置directionalLight.target=cube;//光源目标 默认 0 0 0scene.add(directionalLight);

3.2.3 点光源

概念:由中间向四周发射光、强度比平行光小


网络异常,图片无法展示
|

// 颜色 强度 距离 衰退量(默认1)constpointLight=newTHREE.PointLight(0xff0000, 1, 100, 1);
pointLight.position.set(50, 50, 50);
scene.add(pointLight);

3.2.4 聚光灯

概念:家里面的节能灯泡,强度较好


网络异常,图片无法展示
|

//聚光灯constspotLigth=newTHREE.PointLight(0xffffff);
spotLigth.position.set(50, 50, 50);
spotLigth.target=cube;
spotLigth.angle=Math.PI/6;
scene.add(spotLigth);


3.2.5 半球光

概念:光源直接放置于场景之上,光照颜色从天空光线颜色渐变到地面光线颜色


网络异常,图片无法展示
|


//半球光constlight=newTHREE.HemisphereLight(0xffffbb, 0x080820, 1);
scene.add(light);

复制代码

四、相机

4.1 正交相机

网络异常,图片无法展示
|


| 参数(属性) | 含义                                                         |
| :--------- | :----------------------------------------------------------- |
| left       | 渲染空间的左边界                                             |
| right      | 渲染空间的右边界                                             |
| top        | 渲染空间的上边界                                             |
| bottom     | 渲染空间的下边界                                             |
| near       | near属性表示的是从距离相机多远的位置开始渲染,一般情况会设置一个很小的值。 默认值0.1 |
| far        | far属性表示的是距离相机多远的位置截止渲染,如果设置的值偏小小,会有部分场景看不到。 默认值1000 |                                                       || :--------- | :----------------------------------------------------------- || left       | 渲染空间的左边界                                             || right      | 渲染空间的右边界                                             || top        | 渲染空间的上边界                                             || bottom     | 渲染空间的下边界                                             || near       | near属性表示的是从距离相机多远的位置开始渲染,一般情况会设置一个很小的值。 默认值0.1 || far        | far属性表示的是距离相机多远的位置截止渲染,如果设置的值偏小小,会有部分场景看不到。 默认值1000 |



letwidth=window.innerWidth;
letheight=window.innerHeight;
constcamera=newTHREE.OrthographicCamera(width/-2, width/2, height/2, height/-2, 1, 1000);
scene.add(camera);
camera.position.set(100, 200, 100);


4.2 透视相机

网络异常,图片无法展示
|


| 参数   | 含义                                                         | 默认值                               |
| :----- | :----------------------------------------------------------- | :----------------------------------- |
| fov    | fov表示视场,所谓视场就是能够看到的角度范围,人的眼睛大约能够看到180度的视场,视角大小设置要根据具体应用,一般游戏会设置60~90度 | 45                                   |
| aspect | aspect表示渲染窗口的长宽比,如果一个网页上只有一个全屏的canvas画布且画布上只有一个窗口,那么aspect的值就是网页窗口客户区的宽高比 | window.innerWidth/window.innerHeight |
| near   | near属性表示的是从距离相机多远的位置开始渲染,一般情况会设置一个很小的值。 | 0.1                                  |
| far    | far属性表示的是距离相机多远的位置截止渲染,如果设置的值偏小,会有部分场景看不到 | 1000                                 |                                                     | 默认值                               || :----- | :----------------------------------------------------------- | :----------------------------------- || fov    | fov表示视场,所谓视场就是能够看到的角度范围,人的眼睛大约能够看到180度的视场,视角大小设置要根据具体应用,一般游戏会设置60~90度 | 45                                   || aspect | aspect表示渲染窗口的长宽比,如果一个网页上只有一个全屏的canvas画布且画布上只有一个窗口,那么aspect的值就是网页窗口客户区的宽高比 | window.innerWidth/window.innerHeight || near   | near属性表示的是从距离相机多远的位置开始渲染,一般情况会设置一个很小的值。 | 0.1                                  || far    | far属性表示的是距离相机多远的位置截止渲染,如果设置的值偏小,会有部分场景看不到 | 1000                                 |

复制代码


letwidth=window.innerWidth;
letheight=window.innerHeight;
constcamera=newTHREE.PerspectiveCamera(45, width/height, 1, 1000);
camera.position.set(150, 100, 300);
camera.lookAt(scene.position);


五、渲染器

概述:从WEBGL的角度来看,three就是对它的进一步封装,想要进一步了解渲染器这方面的知识点还需要了解一下WEBGL,这里我们就不做过多介绍了。

六、贴图纹理

6.1 基础介绍

概述:这部分对于我们是否能够给别人呈现一个真实的渲染场景来说,很重要,比如下面一个普普通通的正方体,我们只要一加上贴图,立马不一样了。


以前


网络异常,图片无法展示
|


之后


网络异常,图片无法展示
|

6.2 环境贴图

概述:目前有许许多多的贴图,比如基础、透明、环境、法线、金属、粗糙、置换等等,今天我们呢主要讲解一下环境和一点 HDR处理


THREE的世界里面,坐标抽x、y、z的位置关系图如下所示:


网络异常,图片无法展示
|


红、绿、蓝分别代表x、z、y,我们的贴图就是在px nx py ny pz  nz这六个方向防止一张图片,其中 p 就代表坐标轴的正方向


CubeTextureLoader:加载CubeTexture的一个类。 内部使用ImageLoader来加载文件。


//场景贴图constsphereTexture=newTHREE.CubeTextureLoader().setPath('./textures/course/environmentMaps/0/');
constenvTexture=sphereTexture.load([
'px.jpg',
'nx.jpg',
'py.jpg',
'ny.jpg',
'pz.jpg',
'nz.jpg']);
//场景添加背景scene.background=envTexture;
//场景的物体添加环境贴图(无默认情况使用)scene.environment=envTexture;
constsphereGeometry=newTHREE.SphereGeometry(5, 30, 30);
constsphereMaterial=newTHREE.MeshStandardMaterial({
roughness: 0,//设置粗糙程度metalness: 1,//金属度envMap:envTexture,
});
constsphere=newTHREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);

复制代码


gif图片有点大上传不了,我就截了几张图


网络异常,图片无法展示
|


网络异常,图片无法展示
|


网络异常,图片无法展示
|


这里我们换几张贴图就可以让上面一个外景的 VR 变成内景的房间,如下图所示:


网络异常,图片无法展示
|


网络异常,图片无法展示
|


6.3 HDR 处理

概述:高动态范围图像,相比普通的图像,能够提供更多的动态范围和图像细节,一般被运用于电视显示产品以及图片视频拍摄制作当中。


网络异常,图片无法展示
|


import { RGBELoader } from'three/examples/jsm/loaders/RGBELoader;constrgbeLoader=newRGBELoader().setPath('./textures/course/hdr/');
//异步加载rgbeLoader.loadAsync('002.hdr').then((texture) => {
//设置加载方式 等距圆柱投影的环境贴图texture.mapping=THREE.EquirectangularReflectionMapping;
scene.background=texture;
 })

复制代码

七、拓展

7.1 坐标系

概述:坐标轴能够更好的反馈物体的位置信息,红、绿、蓝分别代表x、z、y


网络异常,图片无法展示
|


const axesHelper = new THREE.AxesHelper(20);//里面的数字代表坐标抽长度scene.add(axesHelper);

复制代码

7.2 控制器

概述:通过鼠标控制物体和相机的移动、旋转、缩放


导包


import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

复制代码


应用


const controls = new OrbitControls(camera, renderer.domElement)

复制代码


自旋转


网络异常,图片无法展示
|


controls.autoRotate = true

复制代码


必须在render函数调用update实时更新才奏效

7.3 自适应

概述:根据屏幕大小自适应场景


网络异常,图片无法展示
|


//自适应屏幕window.addEventListener('resize', () => {     camera.aspect = window.innerWidth / window.innerHeight    camera.updateProjectionMatrix()    renderer.setSize(window.innerWidth, window.innerHeight)    renderer.setPixelRatio(window.devicePixelRatio)})

复制代码


设置相机的宽高比、重新更新渲染相机、渲染器的渲染大小、设备的像素比

7.4 全屏响应

概述:双击进入全屏,再次双击/ESC 退出全屏

网络异常,图片无法展示
|


window.addEventListener('dblclick', () => {     let isFullScreen = document.fullscreenElement    if (!isFullScreen) {        renderer.domElement.requestFullscreen()    }    else {         document.exitFullscreen()    }})

复制代码

7.5 信息面板

概述;通过操作面板完成界面的移动物体的相关应用


链接https://www.npmjs.com/package/dat.gui


//安装npmnpm install --save dat.gui//如果出现...标记错误,安装到开发依赖就可以了npm i --save-dev @types/dat.gui

复制代码


网络异常,图片无法展示
|


//界面操作const gui = new dat.GUI();
//操作物体位置gui    .add(cube.position, 'x')    .min(0)    .max(10)    .step(0.1)    .name('X轴移动')    .onChange((value) => {        console.log('修改的值为' + value);    })    .onFinishChange((value) => {        console.log('完全停止' + value);    });//操作物体颜色const colors = {    color: '#0000ff',};gui    .addColor(colors, 'color')    .onChange((value) => {        //修改物体颜色        cube.material.color.set(value);    });

复制代码

7.6 频率检测

概述:检测帧率


导包


import Stats from 'three/addons/libs/stats.module.js';

复制代码


应用


const stats = new Stats();document.body.appendChild(stats.dom);

复制代码


自变化



stats.update()

复制代码


必须在render函数调用update实时更新才奏效

7.7 导航网格

概述:底部二维平面的网格化,帮助我们更好的创建场景


网络异常,图片无法展示
|


const gridHelper = new THREE.GridHelper(10, 20)//网格大小、细分次数scene.add(gridHelper)

复制代码

八、源码

//导入包import*asTHREEfrom'three';
import { OrbitControls } from'three/examples/jsm/controls/OrbitControls';
import*asdatfrom'dat.gui';
importStatsfrom'three/addons/libs/stats.module.js';
letscene,camera,renderer//场景scene=newTHREE.Scene();
//坐标抽constaxesHelper=newTHREE.AxesHelper(20);
scene.add(axesHelper);
//场景贴图constsphereTexture=newTHREE.CubeTextureLoader().setPath('./textures/course/environmentMaps/0/');
constenvTexture=sphereTexture.load([
'px.jpg',
'nx.jpg',
'py.jpg',
'ny.jpg',
'pz.jpg',
'nz.jpg']);
//场景添加背景scene.background=envTexture;
//场景的物体添加环境贴图(无默认情况使用)scene.environment=envTexture;
constsphereGeometry=newTHREE.SphereGeometry(5, 30, 30);
constsphereMaterial=newTHREE.MeshStandardMaterial({
roughness: 0,//设置粗糙程度metalness: 1,//金属度envMap:envTexture,
});
constsphere=newTHREE.Mesh(sphereGeometry, sphereMaterial);
scene.add(sphere);
//光照constambient=newTHREE.AmbientLight(0xffffff);
scene.add(ambient);
constdirectionalLight=newTHREE.DirectionalLight(0xffffff, 0.05);
directionalLight.position.set(10,10,10);
directionalLight.lookAt(scene.position);
scene.add( directionalLight );
//相机camera=newTHREE.PerspectiveCamera(
60,
window.innerWidth/window.innerHeight,
1,
2000,
);
camera.position.set(10,10,20);
camera.lookAt(scene.position);
scene.add(camera);
//渲染器renderer=newTHREE.WebGLRenderer({
//防止锯齿antialias: true,
});
renderer.setSize(window.innerWidth, window.innerHeight);
// renderer.setClearColor(0xb9d3ff, 1);document.body.appendChild(renderer.domElement);
//鼠标控制器constcontrols=newOrbitControls(camera, renderer.domElement);
//阻尼 必须在 render函数调用  controls.update();controls.dampingFactor=true;
controls.autoRotate=trueconststats=newStats()
document.body.appendChild(stats.dom);
functionrender () { 
renderer.render(scene, camera);
requestAnimationFrame(render);
controls.update();//调用stats.update()
}
render();
//全屏操作window.addEventListener('dblclick', () => { 
//查询是否全屏letisFullScene=document.fullscreenElement;
console.log(isFullScene);
if (!isFullScene) {
renderer.domElement.requestFullscreen();
    }
else { 
document.exitFullscreen();
    }
})
//自适应window.addEventListener('resize', () => { 
//宽高比camera.aspect=window.innerWidth/window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);//设置像素比})
//界面操作constgui=newdat.GUI();
//操作物体位置gui    .add(sphere.position, 'x')
    .min(0)
    .max(10)
    .step(0.1)
    .name('X轴移动')
    .onChange((value) => {
console.log('修改的值为'+value);
    })
    .onFinishChange((value) => {
console.log('完全停止'+value);
    });
//操作物体颜色constcolors= {
color: '#0000ff',
};
gui    .addColor(colors, 'color')
    .onChange((value) => {
//修改物体颜色sphere.material.color.set(value);
    });
相关文章
|
vr&ar 开发工具
一起来云赏月把!three.js实现vr赏月!
一起来云赏月把!three.js实现vr赏月!
239 0
一起来云赏月把!three.js实现vr赏月!
|
存储 前端开发 搜索推荐
基于threejs的商品VR展示平台的设计与实现思路
本设计针对目前互联网销售传统展示的现状,考虑当前市场形式,利用虚拟现实技术理论,结合计算机网络、交互设计实现一个以普通终端浏览器为载体的适用于用户或消费者需求的VR展示平台系统,打造一种全新的商品展示方式,拉近用户或者消费者于商品的距离,提供商品全面的信息,提高商品的可信度,降低交易失败的风险,带来一次愉快完美的购物体验。
929 1
基于threejs的商品VR展示平台的设计与实现思路
|
传感器 前端开发 vr&ar
三种前端实现VR全景看房的方案!说不定哪天就用得上!(上)
事情是这样的,前几天我接到一个外包工头的新需求,某品牌要搭建一个在线VR展厅,用户可以在手机上通过陀螺仪或者拖动来360度全景参观展厅,这个VR展厅里会有一些信息点,点击之后可以呈现更多信息(视频,图文等)... 我第一反应是用3D引擎,因为我不久前刚用three.js做过一个BMW的在线展厅,基本把three.js摸熟了。
562 0
三种前端实现VR全景看房的方案!说不定哪天就用得上!(上)
|
传感器 移动开发 数据可视化
三种前端实现VR全景看房的方案!说不定哪天就用得上! (下)
事情是这样的,前几天我接到一个外包工头的新需求,某品牌要搭建一个在线VR展厅,用户可以在手机上通过陀螺仪或者拖动来360度全景参观展厅,这个VR展厅里会有一些信息点,点击之后可以呈现更多信息(视频,图文等)... 我第一反应是用3D引擎,因为我不久前刚用three.js做过一个BMW的在线展厅,基本把three.js摸熟了。
1068 0
三种前端实现VR全景看房的方案!说不定哪天就用得上! (下)
|
人工智能 算法 数据可视化
线下看房难?VR带看成为行业复工利器
VR技术对于房地产行业的本质,不仅是信息传递效率的提升和增强客户线上看房的真实感,更为重要的是它是对卖房流程的再造,带动“住”的互联网化。
线下看房难?VR带看成为行业复工利器