在现代开发过程当中,3D开发是越来越不可或缺的一部门,在前面的文章当中简单的说明了一些threeJs的基础,从这里开始,我们将对ThreeJs整体进行一定的应用。
我们先看一下这篇文章主要要实现的一个demo效果,现如今在第三方租房、买房App、或者百度、高德地图上会出现这种全景视图,当手势操作时,他对应的景色也会发生一定的变化。又或者你最近刷抖音看到了HM玩的图寻,给了一张可以旋转的3D全景图片,然后找这张图片在哪拍摄的,你可能会好奇这种效果在前端是如何实现的。这就是这篇文章将会教会你的一个小demo。由于视频过大,直接插入链接,可在该链接查看效果:https://live.csdn.net/v/297465
在这里创建好一个vue脚手架的项目,这里不做过多的赘述,并且安装threeJs的依赖,创建好一个vue文件的threejs开发的基本模板,也就是对之前介绍的抽离出来放到了vue当中,启动项目查看效果是否出现,这里就简单的添加了一个坐标系用来验证3D效果
<template>
<div id="home" class="home">
</div>
</template>
<script>
import * as THREE from 'three'
import {
OrbitControls
} from 'three/examples/jsm/controls/OrbitControls.js'
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 1);
scene.add(camera);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);
export default {
data() {
return {
controls: null
}
},
mounted() {
this.windownEvent()
document.getElementById('home').appendChild(renderer.domElement);
this.render()
},
methods: {
windownEvent() {
window.addEventListener('resize', (e) => {
// 宽高比
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
})
},
render() {
renderer.render(scene, camera);
requestAnimationFrame(this.render);
},
}
}
</script>
<style>
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#home {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
</style>
Three.js 中 RGBELoader 是一种用于加载高动态范围图像(High Dynamic Range,HDR)的 Loader,它可以将 .hdr 或 .rgbe 格式的 HDR 图像文件加载到 Three.js 的 WebGL 场景中,并方便地应用于场景渲染和光照等方面。
下面是 RGBELoader 主要的特点和使用方式:
HDR是一种用于表示图像的技术,它可以在不失真地呈现高亮度和阴影细节的情况下,显示更广泛、更丰富的颜色和亮度范围。常见的传统图像格式,如 JPEG、PNG 等都是 LDR (Low Dynamic Range) 图像,其表示的颜色和亮度值受到比较大的限制,并且不能储存超出一定范围的亮度信息。
HDR 图像通常被保存为高精度的 32 位或 16 位浮点数格式,每个像素颜色通道的值可以表示比较大的亮度范围,例如标准化后的亮度值可以达到 0 到 1 之间或更高。使用 HDR 技术,有助于突破 LDR 图像表现能力的瓶颈,解决了过曝和欠曝等高光/暗部细节损失的问题。
相比于 LDR 图像,HDR 图像具有很高的动态范围,支持更加复杂和真实的光影效果。通过处理 HDR 图像,可以对导致渲染物体看上去真实的环境光、反射和折射、散射等进行精确的计算和模拟,从而呈现更真实精细的场景。例如,可以创建栩栩如生的光源、镜面和玻璃材质,产生更自然的阴影和高光反射效果等。
除了在娱乐和游戏领域得到广泛应用外,HDR 技术还被用于物理模拟、医学成像、地球科学、工业制造和计算机视觉等领域。值得一提的是,HDR 图像的制作和处理需要耗费较大的计算资源和专业知识,且其数据量相对较大,需要特殊的压缩技术来减少文件大小。
在熟悉了一下RGBELoader和HDR大概的就了解了这样子的全景视图是如何做的,就像前面说到的Threejs的纹理一样,我们通过ThreeJs的RGBELoader加载HDR静态文件渲染就完事了。具体如何实现呢?直接看以下代码:
先导入这个RGBELoader加载器,并且引入对应的HDR资源,这里新加了一个方法,通过RGBELoader加载器异步加载这个HDR资源,加载完成之后会得到一个texture纹理,将得到的纹理渲染到场景之上就完成了这个3D全景视图的开发了。最后在mounted生命周期上调用一下这个addHdr方法就实现了效果:也就是:https://live.csdn.net/v/297465
注:当然了这里你也可以不通过import引入HDR,直接将HDR地址写到loadAsync()当中也是一样。但是由于Vue是会先编译的,如果你没有对HDR文件编译打包进行处理,这里直接写路径是找不到这个资源的
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader'
import BOLLROOM from '../assets/hdr/ballroom_4k.hdr'
addHdr() {
rgbeloader.loadAsync(BOLLROOM).then((texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping
scene.background = texture
scene.environment = texture
})
}
这里推荐几个获取HDR资源的网站:
在前面我们可以创建一个3D的正方体,并且我们发现给正方体设置texture的时候可以渲染两面,那这一个的实现思路就是:给正方体设置的大一点,而我们的视角(摄像头)设置到正方体的内部,这样我们看到的就是正方体的内部六个面,而再通过加载图片得到纹理,将纹理依次设置到六个面上,这样从里面看起来依然还是全景视图的效果。看一下代码如何实现:
查看效果:https://live.csdn.net/v/297468
// 先引入六个面的图片
import ONE from '../assets/img/1.jpg'
import TWO from '../assets/img/2.jpg'
import TWOPLUS from '../assets/img/3.jpg'
import FOUR from '../assets/img/4.jpg'
import FIVE from '../assets/img/5.jpg'
import SIX from '../assets/img/6.jpg'
addBox() {
const geometry = new THREE.BoxGeometry(10, 10, 10);
var arr = [ONE, TWO, TWOPLUS, FOUR, FIVE, SIX]
var boxMaterial = []
arr.forEach(item => {
let textureLoader = new THREE.TextureLoader().load(item)
boxMaterial.push(new THREE.MeshBasicMaterial({ map: textureLoader }))
})
console.log(boxMaterial)
const cube = new THREE.Mesh(geometry, boxMaterial);
cube.geometry.scale(1, 1, -1)
scene.add(cube);
},