Three.Js 實現 360 度全景瀏覽的簡單方式
什么是全景圖?
一般我們拍照都是拍一個方向,而全景圖是拍上下左右前后 6 個方向,360 度,這樣能夠立體的記錄所在的場景。
那全景圖怎么瀏覽呢?
全景圖拍的是六個方向的圖,放在一個平面看會很別扭,所以會有專門的瀏覽的工具,根據視角的改變來切換看到的內容,這樣就能 360 度的還原拍照的場景。
用 Three.js 做這樣的一個全景圖瀏覽工具,是再簡單不過的事情,只需要幾行代碼,但卻很有用。
那我們就來學一下 Three.js 怎么做全景圖瀏覽吧。
Three.js 基礎回顧
我們簡單回顧下 Three.js 的基礎:
Three.js 是通過場景 Scene 來管理 3D 場景中的各種物體的,有一個三維坐標系,每個物體放在不同的位置,然后在某個位置放置相機,來觀察 Scene 中的各種物體,看到的內容就是二維的,通過渲染器 Renderer 渲染出來就行。這就是 Three.js 的 3D 場景的創建和渲染成 2D 的流程。
簡單回顧了下基礎,那全景圖改怎么瀏覽呢?
全景圖瀏覽的原理
全景圖是六個方向的照片,我們可以在 3D 的場景中放一個立方體,六個面貼上不同方向的圖,相機放在其中,轉動相機就可以看到不同方向的內容。這也是為什么全景圖瀏覽也叫天空盒,因為就是通過立方體貼圖的方式實現的。
當然,也可以用球體來做,直接貼上一個大的全景圖,相機放在中間,轉動相機也可以看到不同方向的內容。
那這么說做全景圖瀏覽需要先創建個立方體或者球體嘍?
其實不用,場景 Scene 是可以設置背景的紋理的,我們可以設置成立方體紋理 CubeTexture,也就是 6 個面的圖片,這樣轉動相機,就能看到場景 Scene 的不同方向的內容。根本不用單獨創建立方體或球體。
設置個紋理也就幾行代碼的事情,我們來寫下代碼。
Three.js 實現全景圖瀏覽
我們創建 3D 場景 Scene:
- const scene = new THREE.Scene();
然后設置它的背景,用立方體的紋理來設置,需要分別指定左右上下前后的 6 個方向的圖:
- 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;
這樣整個背景就是一個全景圖,就這么幾行代碼。
當然,我們還要設置下相機位置,這里用透視相機就行,它的特點是從一個點去看 3D 場景,看到的內容是近大遠小的。
- 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);
需要設置看到的角度,這里設置了 45 度,看到內容的寬高比,這里用窗口寬高比,再就是遠近范圍,這個設置范圍大一點就行。
相機位置設置在了 z 軸 100 的位置,這樣看 z 為 0 的位置就是從正面去看的,可以感受下這個看的方向。
有了 3D 的 Scene,設置好了相機,就可以用 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 來一幀幀的調用 renderer 渲染。
當然,還要加上鼠標控制,可以通過鼠標的拖動方向來改變相機看到的角度,這個用 Three.js 提供的 Controls 就行,不用自己寫。
我們需要 360 度的看,用 OrbitsControls 來做交互就行,他叫軌道控制器,也就是衛星繞地球的那種軌道的感覺。
- const controls = new THREE.OrbitControls(camera);
OrbitControls 參數是 camera,因為它就是通過改變 camera 位置實現的。
至此,我們就實現了全景圖的瀏覽。來看下效果:
全部代碼上傳了 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>
一共也沒幾行代碼。
我們來做下小結:
全景圖瀏覽不用創建立方體或者球體,直接給場景(Scene)設置立方體紋理(CubeTexture)的背景就可以了,貼上 6 張圖。之后設置下相機(Camera)位置,用渲染器(Renderer)一幀幀渲染出來,還要加上軌道控制器來支持拖拽改變相機位置。
主要的邏輯講完了,但還有一個支線劇情要講:6 張圖是怎么來的?
全景圖轉 6 張貼圖
全景圖網上能搜到很多,我們手機的相機也都能拍全景圖,但是它是一張完整的大圖,而立方體紋理要加載 6 張不同方向的圖,如果把全景圖裁切成 6 張圖呢?
這個有工具來做,我是用的 PTGui (試用版)來做的裁切。
官網有下載地址:https://www.ptgui.com/download.html?ps=main
點擊 tools 里面的 convert to cube faces,會打開一個窗口,然后選擇一個全景圖,設置導出的格式,點導出就行了,就能生成上下左右前后的六個方向的圖。
總結
一般的照片只是一個方向的畫面,而全景圖是上下左右前后 360 度的畫面,它能立體的記錄拍照位置的場景。
全景圖需要專門的工具來瀏覽,我們可以用 Three.js 來實現。原理就是通過立方體貼 6 張圖(也叫天空盒),或者通過球體貼一張大圖,把相機設置在中間,轉動相機就可以看到不同方向的畫面。
其實實現全景圖瀏覽更簡單的方式是直接給 Scene 設置立方體紋理,不用再單獨創建立方體或球體,用 CubeTextureLoader 加載六張圖,設置到 Scene 的背景上就行。
還要設置下相機,加上軌道控制器,通過渲染器一幀幀的渲染出來,這樣就實現了全景圖瀏覽的功能。
至于那六張貼圖,通過 PTGui 或者類似的工具就可以裁切出來。
全景圖瀏覽一共也沒幾行代碼,但是這個功能還是很有用的。如果你會拍全景圖,那就更棒了,可以把生活中一些場景立體的記錄下來,自己寫一個工具來瀏覽。