Three.Js 實(shí)現(xiàn) 360 度全景瀏覽的簡(jiǎn)單方式
什么是全景圖?
一般我們拍照都是拍一個(gè)方向,而全景圖是拍上下左右前后 6 個(gè)方向,360 度,這樣能夠立體的記錄所在的場(chǎng)景。
那全景圖怎么瀏覽呢?
全景圖拍的是六個(gè)方向的圖,放在一個(gè)平面看會(huì)很別扭,所以會(huì)有專門的瀏覽的工具,根據(jù)視角的改變來切換看到的內(nèi)容,這樣就能 360 度的還原拍照的場(chǎng)景。
用 Three.js 做這樣的一個(gè)全景圖瀏覽工具,是再簡(jiǎn)單不過的事情,只需要幾行代碼,但卻很有用。
那我們就來學(xué)一下 Three.js 怎么做全景圖瀏覽吧。
Three.js 基礎(chǔ)回顧
我們簡(jiǎn)單回顧下 Three.js 的基礎(chǔ):
Three.js 是通過場(chǎng)景 Scene 來管理 3D 場(chǎng)景中的各種物體的,有一個(gè)三維坐標(biāo)系,每個(gè)物體放在不同的位置,然后在某個(gè)位置放置相機(jī),來觀察 Scene 中的各種物體,看到的內(nèi)容就是二維的,通過渲染器 Renderer 渲染出來就行。這就是 Three.js 的 3D 場(chǎng)景的創(chuàng)建和渲染成 2D 的流程。
簡(jiǎn)單回顧了下基礎(chǔ),那全景圖改怎么瀏覽呢?
全景圖瀏覽的原理
全景圖是六個(gè)方向的照片,我們可以在 3D 的場(chǎng)景中放一個(gè)立方體,六個(gè)面貼上不同方向的圖,相機(jī)放在其中,轉(zhuǎn)動(dòng)相機(jī)就可以看到不同方向的內(nèi)容。這也是為什么全景圖瀏覽也叫天空盒,因?yàn)榫褪峭ㄟ^立方體貼圖的方式實(shí)現(xiàn)的。
當(dāng)然,也可以用球體來做,直接貼上一個(gè)大的全景圖,相機(jī)放在中間,轉(zhuǎn)動(dòng)相機(jī)也可以看到不同方向的內(nèi)容。
那這么說做全景圖瀏覽需要先創(chuàng)建個(gè)立方體或者球體嘍?
其實(shí)不用,場(chǎng)景 Scene 是可以設(shè)置背景的紋理的,我們可以設(shè)置成立方體紋理 CubeTexture,也就是 6 個(gè)面的圖片,這樣轉(zhuǎn)動(dòng)相機(jī),就能看到場(chǎng)景 Scene 的不同方向的內(nèi)容。根本不用單獨(dú)創(chuàng)建立方體或球體。
設(shè)置個(gè)紋理也就幾行代碼的事情,我們來寫下代碼。
Three.js 實(shí)現(xiàn)全景圖瀏覽
我們創(chuàng)建 3D 場(chǎng)景 Scene:
- const scene = new THREE.Scene();
然后設(shè)置它的背景,用立方體的紋理來設(shè)置,需要分別指定左右上下前后的 6 個(gè)方向的圖:
- let urls = [
- './img/home.left.jpg',
- './img/home.right.jpg',
- './img/home.top.jpg',
- './img/home.bottom.jpg',
- './img/home.front.jpg',
- './img/home.back.jpg'
- ];
- let cubeTexture = new THREE.CubeTextureLoader().load(urls);
- scene.background = cubeTexture;
這樣整個(gè)背景就是一個(gè)全景圖,就這么幾行代碼。
當(dāng)然,我們還要設(shè)置下相機(jī)位置,這里用透視相機(jī)就行,它的特點(diǎn)是從一個(gè)點(diǎn)去看 3D 場(chǎng)景,看到的內(nèi)容是近大遠(yuǎn)小的。
- const width = window.innerWidth;
- const height = window.innerHeight;
- const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
- camera.position.set(0,0, 100);
- camera.lookAt(scene.position);
需要設(shè)置看到的角度,這里設(shè)置了 45 度,看到內(nèi)容的寬高比,這里用窗口寬高比,再就是遠(yuǎn)近范圍,這個(gè)設(shè)置范圍大一點(diǎn)就行。
相機(jī)位置設(shè)置在了 z 軸 100 的位置,這樣看 z 為 0 的位置就是從正面去看的,可以感受下這個(gè)看的方向。
有了 3D 的 Scene,設(shè)置好了相機(jī),就可以用 Renderer 把它渲染出來了。
- const renderer = new THREE.WebGLRenderer();
- renderer.setSize(width, height);
- document.body.appendChild(renderer.domElement)
- function render() {
- renderer.render(scene, camera);
- requestAnimationFrame(render);
- }
- render();
我們用 requestAnimationFrame 來一幀幀的調(diào)用 renderer 渲染。
當(dāng)然,還要加上鼠標(biāo)控制,可以通過鼠標(biāo)的拖動(dòng)方向來改變相機(jī)看到的角度,這個(gè)用 Three.js 提供的 Controls 就行,不用自己寫。
我們需要 360 度的看,用 OrbitsControls 來做交互就行,他叫軌道控制器,也就是衛(wèi)星繞地球的那種軌道的感覺。
- const controls = new THREE.OrbitControls(camera);
OrbitControls 參數(shù)是 camera,因?yàn)樗褪峭ㄟ^改變 camera 位置實(shí)現(xiàn)的。
至此,我們就實(shí)現(xiàn)了全景圖的瀏覽。來看下效果:
全部代碼上傳了 github:https://github.com/QuarkGluonPlasma/threejs-exercize
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>全景圖</title>
- <style>
- body {
- margin: 0;
- overflow: hidden;
- }
- </style>
- <script src="./js/three.js"></script>
- <script src="./js/OrbitControls.js"></script>
- </head>
- <body>
- <script>
- const width = window.innerWidth;
- const height = window.innerHeight;
- const camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
- const scene = new THREE.Scene();
- const renderer = new THREE.WebGLRenderer();
- camera.position.set(0,0, 100);
- camera.lookAt(scene.position);
- renderer.setSize(width, height);
- document.body.appendChild(renderer.domElement)
- function create() {
- let urls = [
- './img/home.left.jpg',
- './img/home.right.jpg',
- './img/home.top.jpg',
- './img/home.bottom.jpg',
- './img/home.front.jpg',
- './img/home.back.jpg'
- ];
- let cubeTexture = new THREE.CubeTextureLoader().load(urls);
- scene.background = cubeTexture;
- }
- function render() {
- renderer.render(scene, camera);
- requestAnimationFrame(render);
- }
- create();
- render();
- const controls = new THREE.OrbitControls(camera);
- </script>
- </body>
- </html>
一共也沒幾行代碼。
我們來做下小結(jié):
全景圖瀏覽不用創(chuàng)建立方體或者球體,直接給場(chǎng)景(Scene)設(shè)置立方體紋理(CubeTexture)的背景就可以了,貼上 6 張圖。之后設(shè)置下相機(jī)(Camera)位置,用渲染器(Renderer)一幀幀渲染出來,還要加上軌道控制器來支持拖拽改變相機(jī)位置。
主要的邏輯講完了,但還有一個(gè)支線劇情要講:6 張圖是怎么來的?
全景圖轉(zhuǎn) 6 張貼圖
全景圖網(wǎng)上能搜到很多,我們手機(jī)的相機(jī)也都能拍全景圖,但是它是一張完整的大圖,而立方體紋理要加載 6 張不同方向的圖,如果把全景圖裁切成 6 張圖呢?
這個(gè)有工具來做,我是用的 PTGui (試用版)來做的裁切。
官網(wǎng)有下載地址:https://www.ptgui.com/download.html?ps=main
點(diǎn)擊 tools 里面的 convert to cube faces,會(huì)打開一個(gè)窗口,然后選擇一個(gè)全景圖,設(shè)置導(dǎo)出的格式,點(diǎn)導(dǎo)出就行了,就能生成上下左右前后的六個(gè)方向的圖。
總結(jié)
一般的照片只是一個(gè)方向的畫面,而全景圖是上下左右前后 360 度的畫面,它能立體的記錄拍照位置的場(chǎng)景。
全景圖需要專門的工具來瀏覽,我們可以用 Three.js 來實(shí)現(xiàn)。原理就是通過立方體貼 6 張圖(也叫天空盒),或者通過球體貼一張大圖,把相機(jī)設(shè)置在中間,轉(zhuǎn)動(dòng)相機(jī)就可以看到不同方向的畫面。
其實(shí)實(shí)現(xiàn)全景圖瀏覽更簡(jiǎn)單的方式是直接給 Scene 設(shè)置立方體紋理,不用再單獨(dú)創(chuàng)建立方體或球體,用 CubeTextureLoader 加載六張圖,設(shè)置到 Scene 的背景上就行。
還要設(shè)置下相機(jī),加上軌道控制器,通過渲染器一幀幀的渲染出來,這樣就實(shí)現(xiàn)了全景圖瀏覽的功能。
至于那六張貼圖,通過 PTGui 或者類似的工具就可以裁切出來。
全景圖瀏覽一共也沒幾行代碼,但是這個(gè)功能還是很有用的。如果你會(huì)拍全景圖,那就更棒了,可以把生活中一些場(chǎng)景立體的記錄下來,自己寫一個(gè)工具來瀏覽。
































