Three-js 實現 360 度全景瀏覽的最簡單方式

什麼是全景圖?

一般我們拍照都是拍一個方向,而全景圖是拍上下左右前後 6 個方向,360 度,這樣能夠立體的記錄所在的場景。

那全景圖怎麼瀏覽呢?

全景圖拍的是六個方向的圖,放在一個平面看會很彆扭,所以會有專門的瀏覽的工具,根據視角的改變來切換看到的內容,這樣就能 360 度的還原拍照的場景。

#three.js 實現全景圖瀏覽,也就幾行代碼

用 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 位置實現的。

至此,我們就實現了全景圖的瀏覽。來看下效果:

#three.js 實現全景圖瀏覽,也就幾行代碼

全部代碼上傳了 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 或者類似的工具就可以裁切出來。

全景圖瀏覽一共也沒幾行代碼,但是這個功能還是很有用的。如果你會拍全景圖,那就更棒了,可以把生活中一些場景立體的記錄下來,自己寫一個工具來瀏覽。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/LyRjT5fkpSLtMYxXzO7KRQ