前言 html
混跡VR屆的發燒友兼開發者們必定不要錯過這款FaceBook推出的跨端VR開發框架——React360,稱爲360全景體驗框架更爲準確,由於其前身是FaceBook和Oculus2017年發佈的一個叫做「Racet VR」的JS庫,用來在web端建立3D和VR體驗。後來Oculus使用該框架的原生C++版本構建本身部分應用,隨着時間推移,因爲要求框架解決不一樣需求,項目的APIs開始發生分叉。爲了不兩個系統的混淆,開源框架重命名爲React360,這更好地反映它的使用場景:建立橫跨PC,移動端,VR設備上的沉浸式360體驗。react
能夠先看一下官方示例效果,這是一個稍複雜的應用,加入了3D模型,在3D模型和2D面板間共享數據。git
體驗github
工做原理web
官方提供了構建工具react-360-cli,內部使用和ReactNative同樣的打包工具Metro,基於JS Bundle在本身的JS Runtime中進行解析,經過事件機制與客戶端通訊,其實該框架還有不少方面相像或依賴於RN。構建一個React360應用程序須要完成兩部分,須要渲染的Raect組件和Runtime定義(這種角色劃分直接借鑑於React Native)。這也很清楚地反映出React360的工做流程,能夠參見下圖:(工做流程圖)數組
基於JavaScript Core/V8引擎,React360提供了Runtime須要的APIs,在客戶端(頭戴設備,移動端,瀏覽器等)完成構建界面,web端的渲染底層依賴於Three.js,這是業界較爲成熟的3D圖形框架,通常須要手動設置3D網格和紋理,而框架中的react-360-web模塊隱藏了這些細節。當建立了新的React組件,框架會指示Runtime將它們添加到3D場景中,當用戶提供輸入將做爲事件經過Runtime傳遞給React,這兩部分相互合做造成一個凝合系統。若是想在系統中分享數據,就須要藉助框架提供的Native Modules。瀏覽器
須要注意的是,因爲JS運做在瀏覽器中是單線程的,應用中任何阻礙行爲都有可能形成渲染延遲,這對於VR這種即時性很強的體驗是十分致命的,因此框架將React組件和渲染過程放在分離的上下文中情有可原。框架
默認狀況下,React360使用Web Worker執行你的React代碼,而不是標準瀏覽器,這就意味着在組件定義的文件中訪問不到原生window.location這類APIs。並非嚴格意義上的沒法訪問,事實上當你打印window對象時React360提供了一個DedicatedWorkerGlobalScope類型實例,它包裝了window的一些內容。異步
Surfaces
Surfaces其實是一個載體,容許你添加2D內容到3D場景,開發者依據像素定義Surfaces寬高,React360獲取信息產生合適尺寸的對象,官方介紹了兩種類型的Surfaces,Cylinder和Flat。一個Cylinder Surface讓2D內容投射到半徑爲4m的Cylinder內部,實際上是假想的圓柱模式。一個Flat Surface位於4m半徑的球體外側,一個假想的球體模式。APIs也提供了像yaw(垂搖),pitch(縱搖),roll(橫搖)這些物體自由度控制信息。ide
爲了將React組建附着在Surface上,須要使用AppRegistry註冊組件,又一次與ReactNative類似。這會告知Runtime你的組件經過id字段被惟一肯定。
AppRegistry.registerComponent('MyAppName', () => MyAppName);
同時在Runtime文件中引用。
r360.renderToSurface( r360.createRoot('MyAppName'), r360.getDefaultSurface(), 'default' /* 可選項,引用的surface的名稱 */ );
Components
官方提供了呈現2D,3D內容的展現組件和交互按鈕組件。
Layout
支持2D Surface佈局,徹底以Flexbox格式佈局,又是一個和RN類似的點。支持3D Space佈局,使用Entity組件時候,經過transform完成3D對象放置,x軸指向用戶右側,y軸指向上方,z軸指向用戶後方。
APIs
官方提供了常見的APIs,例如來自React Native的Animated;鍵值對存儲系統AsyncStorage;值得一提的是提供的ControllerInfo能夠被用來響應控制器的connect/disconnect事件,獲取關於所鏈接的遊戲手柄和控制器的靜態信息,好比惟一標識符,按鈕,軸數等信息。環境API Environment用來改變場景的背景,包括圖片,音頻,視頻。
實例解讀
利用react-360-cli生成的項目中主要有這三個文件:
1 import {ReactInstance} from 'react-360-web'; 2 3 function init(bundle, parent, options = {}) { 4 const r360 = new ReactInstance(bundle, parent, { 5 fullScreen: true, 6 ...options, 7 }); 8 9 r360.renderToSurface( 10 r360.createRoot('SlideshowSample', { 11 photos: [ 12 {uri: './static_assets/360_world.jpg', title: '360 World1', format: '2D'}, 13 {uri: './static_assets/360_world2.jpg', title: '360 World2', format: '2D'}, 14 // Add your own 180 / 360 photos to this array, 15 // with an associated title and format 16 ], 17 }), 18 r360.getDefaultSurface(), 19 ); 20 } 21 22 window.React360 = {init};
Native Modules
前面說過React組件運行在單獨上下文中,那麼如何與主窗口通訊,官方提供了Native Modules模塊,讓React代碼有了回調到Runtime的能力,包括在加載中存值,請求有關鏈接控制器信息或操縱渲染環境。Native模塊被建立在Runtime代碼中,使用Native Module須要自定義類,繼承自Module,使用前需註冊,這個示例模板代碼演示了Native Modules的許多用法
1 import {Module} from 'react-360-web'; 2 3 class MyModule extends Module { 4 constructor() { 5 // 使這個模塊在NativeModules.MyModule可用 6 super('MyModule'); 7 } 8 9 // 這個方法將被暴露到React應用一側 10 doSomething() { 11 12 } 13 } 14 15 const r360 = new ReactInstance( 16 'MyApp.bundle?platform=vr', 17 document.getElementById('container'), 18 { 19 // 在初始時刻註冊自定義模塊,接收Native Module實例,或一個返回實例的函數(須要傳遞上下文) 20 nativeModules: [ 21 new MyModule(), 22 ctx => new MyModule(ctx) 23 ] 24 } 25 );
一般有兩種使用場景,暴露常量和普通到React(同步),回調函數或返回Promise方法(異步)。這一段代碼同時演示了這幾種使用場景,這是一個發送瀏覽器信息到React側的應用示例,在註冊階段,模塊構造時常量生成並添加模塊實例的userAgent屬性上,這個值被直接傳遞給React。第二個例子是暴露了同步setTitle()方法,只須要一個字符串設置窗口標題欄。剩下兩個異步方法展現了異步數據如何返回到React。當getBatteryLevel()在React側被調用,開發者傳遞的回調在數據可用時觸發,調用上下文提供的invokeCallback,將參數放置在數組中,你能夠給回調傳遞任意數量的參數。儘管回調是處理異步任務的一種方式,但咱們更偏向於用Promise建立有組織可讀性強的異步邏輯鏈。經過Native Module,你可使用$符號前綴形式來暴露這種行爲,兩個回調ID會做爲Promise的resolve, reject自動傳遞給Runtime,該方法會返回一個Promise到調用端。
1 import {Module} from 'react-360-web'; 2 3 export default class BrowserInfoModule extends Module { 4 constructor(ctx) { 5 super('BrowserInfo'); 6 this._rnctx = ctx; 7 this.userAgent = navigator.userAgent; 8 } 9 /*
*/ 10 setTitle(title) { 11 document.title = title; 12 } 13 14 getBatteryLevel(cb) { // 讀取window信息 15 const getBattery = navigator.mozGetBattery || navigator.getBattery; 16 getBattery 17 .call(navigator) 18 .then( 19 battery => { 20 // extract the level and return it 21 return battery.level; 22 }, 23 e => { 24 // if an error occurs, return null 25 return null; 26 } 27 ) 28 .then(level => { 29 if (this._rnctx) { 30 this._rnctx.invokeCallback(cb, [level]); 31 } 32 }); 33 } 34 35 $getConfirmation(message, resolve, reject) { 36 const result = window.confirm(message); 37 if (this._rnctx) { 38 if (result) { 39 this._rnctx.invokeCallback(resolve, []); 40 } else { 41 // When rejecting a Promise, a message should be provided to populate 42 // the Error object on the React side 43 this._rnctx.invokeCallback(reject, [{message: 'Canceled the dialog'}]); 44 } 45 } 46 } 47 }
後記
對於React360的總體一覽,官方文檔仍是對在web端介紹比較多,官方開發團隊在GitHub也比較活躍,因此有問題能夠及時issue都會有人回覆。Facebook在幾年前收購了Oculus足已看出其進軍VR屆的雄心已經初見倪端,目前市面上許多APP對360全景圖的應用也萬象回春,微博的全景圖藉助手機的陀螺儀和重力傳感器在不點擊圖片詳情的狀況下跟隨用戶手勢動態變化,自如的VR看房,在咱們APP裏也引入了全景酒店實景體驗。在昂貴的VR設備消費者負擔不起的狀況下,360度全境體驗正是VR在當今階段最普及的形態,雖然只是純粹的平面圖像,卻也必定程度上營造了沉浸式感覺,而React360在靜態全景的基礎上引入了多種交互,這更加方便消費者瞭解需求,相信360全景的將來還能作得更多。
參考
https://facebook.github.io/react-360/
原文出處:https://www.cnblogs.com/venoral/p/10914222.html