摘要:全景在以前帶寬有限的條件下常常用來作為街景和全景圖片的查看。后面,我們來了解一下,如何在端實現(xiàn)全景視頻?,F(xiàn)在對支持度也不是特別友好,但是,對于全景視頻來說,在機器換代更新的前提下,全景在性能方面的瓶頸慢慢消失了。
Web 全景在以前帶寬有限的條件下常常用來作為街景和 360° 全景圖片的查看。它可以給用戶一種 self-immersive 的體驗,通過簡單的操作,自由的查看周圍的物體。隨著一些運營商推出大王卡等免流服務,以及 4G 環(huán)境的普及,大流量的應用也逐漸得到推廣。比如,我們是否可以將靜態(tài)低流量的全景圖片,變?yōu)閯討B(tài)直播的全景視頻呢?在一定網(wǎng)速帶寬下,是可以實現(xiàn)的。后面,我們來了解一下,如何在 Web 端實現(xiàn)全景視頻。先看一下實例 gif:
tl;dr;使用 three.js 實現(xiàn)全景技術(shù)
UV 映射原理簡介
3D 坐標原理和移動控制
Web 陀螺儀簡介
iv-panorama 簡單庫介紹
基于 Three.js全景視頻是基于 3D 空間,而在 Web 中,能夠非常方便觸摸到 3D 空間的技術(shù),就是 WebGL。為了簡化,這里就直接采用 Three.js 庫。具體的工作原理就是將正在播放的 video 元素,映射到紋理(texture) 空間中,通過 UV 映射,直接貼到一個球面上。精簡代碼為:
let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1100); // 添加相機 camera.target = new THREE.Vector3(0, 0, 0); // 設(shè)置相機的觀察位置,通常在球心 scene = new THREE.Scene(); let geometry = new THREE.SphereBufferGeometry(400, 60, 60); // 在貼圖的時候,讓像素點朝內(nèi)(非常重要) geometry.scale(-1, 1, 1); // 傳入視頻 VideoEle 進行繪制 var texture = new THREE.VideoTexture(videoElement); var material = new THREE.MeshBasicMaterial({ map: texture }); mesh = new THREE.Mesh(geometry, material); scene.add(mesh); renderer = new THREE.WebGLRenderer(); renderer.setPixelRatio(window.devicePixelRatio); // canvas 的比例 renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(renderer.domElement);
具體的過程差不多就是上面的代碼。上面代碼中有兩塊需要注意一下,一個是 相機的視野范圍值,一個是幾何球體的相關(guān)參數(shù)設(shè)置。
相機視野范圍
具體代碼為:
let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1100);
這里主要利用透視類型的相機,模擬人眼的效果。設(shè)置合適的視野效果,這里的范圍還需要根據(jù)球體的直徑來決定,通常為 2*radius + 100,反正只要比球體直徑大就行。
幾何球體的參數(shù)設(shè)置
let geometry = new THREE.SphereBufferGeometry(400, 60, 60); // 在貼圖的時候,讓像素點朝內(nèi)(非常重要) geometry.scale(-1, 1, 1);
上面其實有兩個部分需要講解一下
球體參數(shù)設(shè)置里面有三個屬性值比較重要,該 API 格式為:SphereBufferGeometry(radius, widthSegments, heightSegments,...)。
raidus: 設(shè)置球體的半徑,半徑越大,視頻在 canvas 上繪制的內(nèi)容也會被放大,該設(shè)置值合適就行。
width/height Segments: 切片數(shù),主要用來控制球體在寬高兩個維度上最多細分為多少個三角切片數(shù)量,越高紋理拼接的邊角越清晰。不過,并不是無限制高的,高的同時性能損耗也是有的。
在幾何繪制時,通過坐標變換使 X 軸的像素點朝內(nèi),讓用戶看起來不會存在 凸出放大的效果。具體代碼為:geometry.scale(-1, 1, 1)。
UV 映射上面只是簡單介紹了一下代碼,如果僅僅只是為了應用,那么這也就足夠了。但是,如果后面遇到優(yōu)化的問題,不知道更底層的或者更細節(jié)內(nèi)容的話,就感覺很尷尬。在全景視頻中,有兩個非常重要的點:
UV 映射
3D 移動
這里,我們主要探索一下 UV 映射的細節(jié)。UV 映射主要目的就是將 2D 圖片映射到三維物體上,最經(jīng)典的解釋就是:
盒子是一個三維物體,正如同加到場景中的一個曲面網(wǎng)絡(luò)("mesh")方塊.
如果沿著邊縫或折痕剪開盒子,可以把盒子攤開在一個桌面上.當我們從上往下俯視桌子時,我們可以認為U是左右方向,V是上下方向.盒子上的圖片就在一個二維坐標中.我們使用U V代表"紋理坐標系"來代替通常在三維空間使用的 X Y.
在盒子重新被組裝時,紙板上的特定的UV坐標被對應到盒子的一個空間(X Y Z)位置.這就是將2D圖像包裹在3D物體上時計算機所做的.
from 浙江研報
這里,我們通過代碼來細致講解一下。我們需要完成一個貼圖,將如下的 sprite,貼到一個正方體上。
from iefreer
這里,我們先將圖片加載到紋理空間:
var material = new THREE.MeshPhongMaterial( { map: THREE.ImageUtils.loadTexture("images/texture-atlas.jpg") } );
那么,現(xiàn)在我們有一個如下的紋理空間區(qū)域:
這塊內(nèi)容,就實際涉及到 WebGL 的知識,紋理空間和物理空間并不是在一塊,WebGL 中的 GLSL 語法,就是將紋理內(nèi)容通過相關(guān)規(guī)則,映射到指定的三角形區(qū)域的表面。
這里需要注意的是,紋理空間并不存在所謂的最小三角區(qū)域,這里適應的只是在物理空間中劃分的三角區(qū)域。為了簡單起見,我們設(shè)置的 boxGeometry 只使用單位為 1 的 Segments,減少需要劃分的三角形數(shù)量。
這樣,就存在 12 塊需要貼的三角區(qū)域。這里,我們就需要利用 Vector2 來手動劃分一下紋理空間的區(qū)域,實際在映射的時候,就是按順序,將物理空間的定點 和 紋理空間的定點一一映射,這樣就實現(xiàn)了將紋理和物理空間聯(lián)系到一起的步驟。
因為,Three.js 中 geometry.faceVertexUvs 在劃分物理空間時,定義的面分解三角形的順序 是 根據(jù)逆時針方向,按序號劃分,如下圖所示:
根據(jù)上圖的定義,我們可以得到每個幾何物體的面映射到紋理空間的坐標值可以分為:
left-bottom = [0,1,3] right-top = [1,2,3]
所以,我們需要定義一下紋理坐標值:
face1_left = [new THREE.Vector2(0, 0),new THREE.Vector2(.5, 0),new THREE.Vector2(0, .333)] face1_right = [new THREE.Vector2(.5, 0),new THREE.Vector2(.5, .333),new THREE.Vector2(0, .333)] //... 剩下 10 個面
定點 UV 映射 API 具體格式為:
geometry.faceVertexUvs[ 0 ][ faceIndex ][ vertexIndex ]
則定義具體面的映射為:
geometry.faceVertexUvs[0][0] = face1_left; geometry.faceVertexUvs[0][0] = face1_right; //...剩下 10 個面
如果,你寫過原生的 WebGL 代碼,對于理解 UV 映射原理應該很容易了。
3D 移動原理這里需要注意的是 Web 全景不是 WebVR。全景沒有 VR 那種沉浸式體驗,單單只涉及三個維度上的旋轉(zhuǎn)而沒有移動距離這個說法。
上面的描述中,提到了三維,旋轉(zhuǎn)角度 這兩個概念,很容易讓我們想到《高中數(shù)學》學到的一個坐標系--球坐標系(這里默認都是右手坐標系)。
φ 是和 z 軸正方向 <=180°的夾角
? 是和 x 軸正方向 <=180°的夾角
p 是空間點距離原點的直線距離
計算公式為:
現(xiàn)在,如果應用到 Web 全景,我們可以知道幾個已知條件:
p:定義的球體(SphereBufferGeometry)的半徑大小
?φ:用戶在 y 軸上移動的距離
??:用戶在 x 軸上移動的距離
p 這個是不變的,而 ?φ 和 ?? 則是根據(jù)用戶輸入來決定的大小值。這里,就需要一個算法來統(tǒng)一協(xié)定。該算法控制的主要內(nèi)容就是:
用戶的手指在 x/y 平面軸上的 ?x/?y 通過一定的比例換算成為 ?φ/??
如果考慮到陀螺儀就是:
用戶的手指在 x/y 平面軸上的 ?x/?y 通過一定的比例換算成為 ?φ/??,用戶在 x/y 軸上旋轉(zhuǎn)的角度值 ?φ"/??",分別和視角角度進行合并,算出結(jié)果。
為了更寬泛的兼容性,我們這里根據(jù)第二種算法的描述來進行講解。上面 ?φ/?? 的變動主要映射的是我們視野范圍的變化。
在 Threejs 中,就是用來控制相機的視野范圍。那我們?nèi)绾卧?ThreeJS 控制視野范圍呢?下面是最簡代碼:
phi = THREE.Math.degToRad(90 - lat); theta = THREE.Math.degToRad(-lon); camera.position.x = distance * Math.sin(phi) * Math.cos(theta); camera.position.y = distance * Math.cos(phi); camera.position.z = distance * Math.sin(phi) * Math.sin(theta);
這里主要模擬地球坐標:
lat 代表維度(latitude): 用戶上下滑動改變的值,或者手機上下旋轉(zhuǎn)
lon 代表經(jīng)度(lontitude): 用戶左右滑動改變的值,或者手機左右旋轉(zhuǎn)
具體內(nèi)容為:
在通常實踐當中,改變?nèi)耙暯堑木S度有兩種,一種直接通過手滑,一種則根據(jù)陀螺儀旋轉(zhuǎn)。
簡單來說,就是監(jiān)聽 touch 和 orientation 事件,根據(jù)觸發(fā)信息來手動改變 lat/lon 的值。不過,這里有一個注意事項:
latitude 方向上最多只能達到 (-90,90),否則會造成屏幕翻轉(zhuǎn)的效果,這種體驗非常不好。
我們分別通過代碼來實踐一下。
添加 touch 控制Touch 相關(guān)的事件在 Web 中,其實可以講到你崩潰為止,比如,用戶用幾個手指觸摸屏幕?用戶具體在屏幕上的手勢是什么(swipe,zoom)?
這里,我們簡單起見,只針對一個手指滑動的距離來作為 相機 視角移動的數(shù)據(jù)。具體代碼為:
// 為了給自己博客拉量,完整版可以去我的博客查看:
https://www.villainhr.com
iv-panorama 是 IVWEB 團隊,針對于全景直播這個熱點專門開發(fā)的一個播放器?,F(xiàn)在 Web 對 VR 支持度也不是特別友好,但是,對于全景視頻來說,在機器換代更新的前提下,全景在性能方面的瓶頸慢慢消失了。其主要特性為:
依賴于 Three.js,需要預先掛載到 window 對象上
靈活配置,內(nèi)置支持陀螺儀和 touch 控制。
支持靈敏度參數(shù)的動態(tài)調(diào)整
使用 ES6 語法
兼容 React,jQuery(簡單湊數(shù)的)
項目地址為:iv-panorama。該項目使用非常簡單,有兩種全景模式,一個是 圖片,一個是視頻:
import VRPlayer from "iv-panorama"; new VRPlayer({ player: { url: "/test/003.mp4" }, container:document.getElementById("container") }); // image let panorama = new VRPlayer({ image: { url: "./banner.png" }, container:document.getElementById("container") });
全景資源都已經(jīng)放在 github 倉庫了,有興趣的可以實踐觀察一下。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/90628.html
摘要:快速入門什么是是一個開放源代碼的庫,為呈現(xiàn)的數(shù)據(jù)提供了視圖渲染。最后,項目根組件應該通過來進行注冊,以便能夠進行打包和正常運行。基本思想是渲染一個立方體,并將觀眾置于中心,隨后移動。表示從指定方向平均照亮所有物體的光源。 React VR 快速入門 什么是React React是一個開放源代碼的JavaScript庫,為HTML呈現(xiàn)的數(shù)據(jù)提供了視圖渲染。React視圖通常使用指定的像H...
摘要:淘寶造物節(jié)的活動頁就是全景的一個很贊的頁面,它將全景圖分割成等份,相鄰的元素構(gòu)成的夾角,相鄰兩側(cè)面相對于棱柱中心所構(gòu)成的夾角。 本文轉(zhuǎn)自凹凸實驗室:https://aotu.io/notes/2016/08... showImg(https://segmentfault.com/img/remote/1460000011381045); 前言 3D 全景并不是什么新鮮事物了,但以前...
摘要:全景旋轉(zhuǎn)首先學習一下基礎(chǔ)坐標系這個只要記住一下軸各自方向就可以,下面分析會用到。 開始 從這里開始準備攻略webgl(準備挖新坑),F(xiàn)lutter框架當然也會繼續(xù)補充,但是今天學習的不是webgl,而是css3d-engine這個庫,因為之前搞活動看到了一個全景旋轉(zhuǎn)活動就是使用這個庫完成,頗為驚艷(一開始以為是webgl實現(xiàn)的,但是看了代碼才知道用CSS3就可以完成,雖然覺得還是應該用...
閱讀 1202·2021-11-24 09:38
閱讀 2608·2021-09-27 14:00
閱讀 1166·2019-08-30 15:55
閱讀 1345·2019-08-30 14:16
閱讀 1495·2019-08-30 10:54
閱讀 2869·2019-08-28 17:58
閱讀 762·2019-08-26 13:22
閱讀 1238·2019-08-26 12:01