React
是一個開放源代碼的JavaScript
庫,爲HTML呈現的數據提供了視圖渲染。React
視圖一般使用指定的像HTML標籤同樣的組件來進行UI渲染。它目前是最流行的JavaScript庫之一,它擁有強大的基礎和龐大的社區。javascript
$ npm install -g create-react-app $ create-react-app my-app $ cd my-app $ npm start
React Native
是僅使用Javascript的移動應用構建框架。它使用與React
相同的設計,包含豐富的UI庫和組件聲明。php
它使用與常規iOS和Android應用程序相同的基本UI構建塊。html
使用React-Native
最讚的地方是還能夠經過原生的Objective-C
, Java
, 或者Swift
來構建組件。java
React VS React Native:node
React Native bridge:react
環境安裝android
查看官網http://facebook.github.io/react-native/docs/getting-started.htmlios
建立項目git
$ react-native init my-rn-app
運行項目github
To run your app on iOS: cd /Users/liyuechun/Pictures/my_rn_app react-native run-ios - or - Open ios/my_rn_app.xcodeproj in Xcode Hit the Run button To run your app on Android: cd /Users/liyuechun/Pictures/my_rn_app Have an Android emulator running (quickest way to get started), or a device connected react-native run-android
效果圖
iOS | Android |
---|---|
![]() |
![]() |
React VR旨在容許Web開發人員使用React的聲明方法(特別是React Native)來創做虛擬現實(VR)應用程序。
React VR
使用Three.js 來支持較低級別的WebVR 和 WebGL API. WebVR是用於訪問Web上VR設備的API。 WebGL(Web圖形庫)是一種無需使用插件便可用於在任何兼容的Web瀏覽器中渲染3D圖形的API。
React VR相似於React Native,由於它使用View
,Image
和Text
做爲核心組件,而且支持Flexbox佈局。 此外,React VR還將Pano
,Mesh
和PointLight
等VR組件添加相關庫中。
在本篇文章中,我將帶領你們建立一個簡單的VR應用程序來學習如何建立一個全景圖片,3D對象模型,按鈕和flexbox佈局的使用場景。咱們的模擬應用程序基於React VR的兩個網格
和佈局
的官方示例。
該應用程序將渲染一個可以放大和縮小的地球
和月球
的3D模型,效果圖以下所示:
這些模型中,它們的尺度和旋轉不是地球-月球系統
的真實複製品。 這種關係只是爲了展現React VR的工做原理。 與此同時,咱們將解釋一些關鍵的3D建模概念。 一旦掌握了ReactVR,就能夠隨意創造更多的做品。
你可以從 GitHub找到最後的項目源代碼。
到目前爲止,虛擬現實是一項至關新的技術,開發或測試咱們的VR應用程序的方法不多。
WebVR 和 Is WebVR Ready? 能夠幫助您瞭解哪些瀏覽器和設備支持最新的VR規範。
可是你也沒必要過於擔憂, 你如今不須要任何特殊的設備,例如: Oculus Rift, HTC Vive, 或者 Samsung Gear VR 來測試一個WebVR APP。
下面是你如今 所須要 準備的:
一臺Windows/Mac電腦。
Google瀏覽器。
最新版本的Node.js
若是您也有Android設備和Gear VR耳機,您能夠安裝Carmel Developer Preview瀏覽器來探索您的React VR 應用程序。
首先,咱們須要使用NPM
來安裝React VR CLI
工具:
$ npm install -g react-vr-cli
使用React VR CLI來建立一個名字叫作EarthMoonVR
的新項目:
$ react-vr init EarthMoonVR
在建立過程當中您須要等一下子,這將建立一個EarthMoonVR
目錄,目錄裏面就是相關項目文件,若是但願建立速度快一些,您能夠安裝 Yarn 來提升速度。
一旦項目建立完畢,能夠經過cd
切換到EarthMoonVR
文件路徑下面:
$ cd EarthMoonVR
在終端經過npm start
來啓動程序以便查看效果:
$ npm start
在瀏覽器中輸入http://localhost:8081/vr
。稍微等一下子,便可查看到VR效果:
下面是初始化的React VR新項目的項目結構:
+-__tests__ +-node_modules +-static_assets +-vr \-.babelrc \-.flowconfig \-.gitignore \-.watchmanconfig \-index.vr.js \-package.json \-rn-cli-config.js \-yarn.lock
我將index.vr.js
文件呈現高亮狀態,它包含了您應用程序的源碼,static_assets
目錄包含像圖片和3D模型的外部資源文件。
你能夠從這裏瞭解更多項目結構。
index.vr.js
文件的內容以下:
import React from 'react'; import { AppRegistry, asset, StyleSheet, Pano, Text, View, } from 'react-vr'; class EarthMoonVR extends React.Component { render() { return ( <View> <Pano source={asset('chess-world.jpg')}/> <Text style={{ backgroundColor:'blue', padding: 0.02, textAlign:'center', textAlignVertical:'center', fontSize: 0.8, layoutOrigin: [0.5, 0.5], transform: [{translate: [0, 0, -3]}], }}> hello </Text> </View> ); } }; AppRegistry.registerComponent('EarthMoonVR', () => EarthMoonVR);
咱們能夠看到React VR使用了ES2015 和 JSX。
這個代碼經過React Native packager進行預編譯,它提供了(ES2015, JSX)編譯和其餘資源加載。
在render
函數中,return
了一個頂級標籤,裏面包含:
View
組件, 它是能夠包含其餘全部組件的容器組件。
Pano
組件, 用於將(chess-world.jpg
)渲染一張360度的圖片。
Text
組件, 用於渲染字體的3D空間。
注意,Text
組件經過一個內聯的樣式對象來設置樣式。在React VR中的每個組件都有一個style
屬性來控制控制它的外觀和佈局。
除了添加Pano
或VrButton
等特殊組件以外,React VR還使用了與React和React Native相同的概念,例如組件,屬性,狀態,生命週期,事件和彈性佈局。
最後,項目根組件應該經過AppRegistry.registerComponent
來進行註冊,以便App可以進行打包和正常運行。
如今咱們知道代碼是作什麼用的,接下來咱們將全景圖片
拖拽到項目中。
一般,咱們的VR應用程序中的空間由全景(pano)圖像組成,它建立了一個1000米的球體(在React VR距離中,尺寸單位爲米),並將用戶置於其中心。
一張全景圖像容許你從上面,下面,後面以及你的前面去觀察它,這就是他們也被稱爲360的圖像或球面全景的緣由。
360全景圖有兩種主要格式:平面全景圖和立方體。 React VR支持二者。
平面全景圖由寬高比爲2:1的單個圖像組成,意味着寬度必須是高度的兩倍。
這些照片是經過360度照相機建立的。一個很好的平面圖像來源是Flickr,你打開這個網站嘗試搜索equirectangular
關鍵字,例如:我經過equirectangular
關鍵字嘗試搜索就找到這張圖片:
看起來很奇怪,不是嗎?
不管如何,下載最高可用分辨率的照片,將其拖拽到項目中static_assets
的路徑下面,而且修改render
函數中的代碼,以下所示:
render() { return ( <View> <Pano source={asset('sample_pano.jpg')}/> </View> ); }
Pano
組件的source
屬性接收一個當前圖片位置的uri
屬性值。這裏咱們使用了asset
函數,將sample_pano.jpg
做爲參數,這個函數將會返回static_assets
路徑下的圖片的正確的uri
。換句話說,上面的方法等價於下面的方法:
render() { return ( <View> <Pano source={ {uri:'../static_assets/sample_pano.jpg'} }/> </View> ); }
假設本地服務器一直在運行,當咱們在瀏覽器中刷新頁面時,咱們將看到以下效果:
順便說一下,若是咱們想避免在每次更改時都須要從新刷新頁面,咱們能夠經過在URL(http://localhost:8081/vr/?hot... 中添加 ?hotreload
來啓用 熱刷新。
立方體全景圖是360度全景圖的其餘格式。這種格式使用六個圖像做爲一個多維數組集的六個面,它將填充咱們周圍的球體。 它也被稱爲天空盒。
基本思想是渲染一個立方體,並將觀衆置於中心,隨後移動。
例如,下面的這張大圖中,每個方位的小圖表明立方體的一面:
爲了可以在React VR中使用立方體全景圖,Pano
組件的source
屬性的uri
值必須指定爲一個數組,數組中的每一張圖片分別表明[+x, -x, +y, -y, +z, -z]
,以下所示:
render() { return ( <View> <Pano source={ { uri: [ '../static_assets/sample_right.jpg', '../static_assets/sample_left.jpg', '../static_assets/sample_top.jpg', '../static_assets/sample_bottom.jpg', '../static_assets/sample_back.jpg', '../static_assets/sample_front.jpg' ] } } /> </View> ); }
在2D佈局中,X軸越向右x值越大,Y軸越向下值越大,(0,0)座標爲最左上角,右下角表明元素的寬和高(width, height)。
然而,在3D空間中,React VR使用了同OpenGL使用的右手座標系統,正X指向右邊,正Y指向上邊,正Z指向用戶的方向。由於用戶的默認視圖從原點開始,這意味着它們將從負Z方向開始:
你能夠從React VR coordinate system here瞭解更多React VR座標系統.
這樣,咱們的立方體(或天空盒)將以下所示:
Skybox在Unity中使用了不少,因此有不少地方能夠找到他們並進行下載。 例如,我從這個頁面下載了撒哈拉沙漠。我將圖片拖拽到項目中,並修改代碼以下所示:
render() { return ( <View> <Pano source={ { uri: [ '../static_assets/sahara_rt.jpg', '../static_assets/sahara_lf.jpg', '../static_assets/sahara_up.jpg', '../static_assets/sahara_dn.jpg', '../static_assets/sahara_bk.jpg', '../static_assets/sahara_ft.jpg' ] } } /> </View> ); }
效果以下所示:
你能注意到頂部和底部的圖像不協調嗎?咱們能夠經過將頂部圖像順時針旋轉90度,底部逆時針旋轉90度來校訂它們:
如今讓咱們爲咱們的應用建立一個空間天空盒。
最好的程序是Spacescape, 它一個免費的工具,可在Windows和Mac上建立空間天空盒(包括星星和星雲)。
建立一個sampleSpace.xml
文件,將下面的代碼拷貝到sampleSpace.xml
文件中:
<?xml version="1.0" encoding="utf-8" ?> <spacescapelayers> <layer> <destBlendFactor>one</destBlendFactor> <farColor>0 0 0 1</farColor> <hdrMultiplier>1</hdrMultiplier> <hdrPower>1</hdrPower> <maskEnabled>false</maskEnabled> <maskGain>0.5</maskGain> <maskLacunarity>2</maskLacunarity> <maskNoiseType>fbm</maskNoiseType> <maskOctaves>1</maskOctaves> <maskOffset>1</maskOffset> <maskPower>1</maskPower> <maskScale>1</maskScale> <maskSeed>1</maskSeed> <maskThreshold>0</maskThreshold> <name>Fuzzy Blue Stars</name> <nearColor>1 1 1 1</nearColor> <numPoints>3000</numPoints> <pointSize>3</pointSize> <seed>4</seed> <sourceBlendFactor>one</sourceBlendFactor> <type>points</type> </layer> <layer> <destBlendFactor>one</destBlendFactor> <ditherAmount>0.03</ditherAmount> <gain>1.5</gain> <hdrMultiplier>1</hdrMultiplier> <hdrPower>1</hdrPower> <innerColor>1 1 1 1</innerColor> <lacunarity>2</lacunarity> <name>Fuzzy White Star Overlay</name> <noiseType>ridged</noiseType> <octaves>8</octaves> <offset>0.94</offset> <outerColor>0 0 0 1</outerColor> <powerAmount>1</powerAmount> <previewTextureSize>1024</previewTextureSize> <scale>10</scale> <seed>4</seed> <shelfAmount>0.81</shelfAmount> <sourceBlendFactor>one</sourceBlendFactor> <type>noise</type> </layer> </spacescapelayers>
而且經過Spacescape
軟件打開sampleSpace.xml
文件,效果圖以下所示:
咱們能夠導出天空盒的六張圖像:
若是咱們修改代碼以下所示:
<Pano source={ { uri: [ '../static_assets/space_right.png', '../static_assets/space_left.png', '../static_assets/space_up.png', '../static_assets/space_down.png', '../static_assets/space_back.png', '../static_assets/space_front.png' ] } }/>
將獲得以下結果:
如今讓咱們來討論討論3D模型。
React VR 有一個 Model 組件,它支持Wavefront .obj file format 來表明3D建模。
mesh是定義3D對象形狀的頂點、邊和麪的集合。
.obj文件是一個純文本文件,其中包含幾何頂點,紋理座標,頂點法線和多邊形面元素的座標。
一般,.obj文件引用一個外部.mtl file文件,其中存儲了描述多邊形視覺方面的材質(或紋理)。
您可使用Blender, 3DS Max,和Maya等程序建立3D模型並將其導出爲這些格式。
還有不少網站能夠免費下載或免費下載3D模型。 如下是其中三個很不錯的:
對於咱們的應用程序,咱們將使用這個3D地球模型和這個來自TF3DM的3D月球模型 。
當咱們將地球模型的文件提取到咱們應用程序的static_assets
目錄時,咱們能夠看到有一堆圖像(紋理)以及.obj和.mtl文件。 若是咱們在文本編輯器中打開後者,咱們將看到以下所示定義:
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware # File Created: 25.01.2016 02:22:51 newmtl 01___Default Ns 10.0000 Ni 1.5000 d 1.0000 Tr 0.0000 Tf 1.0000 1.0000 1.0000 illum 2 Ka 0.0000 0.0000 0.0000 Kd 0.0000 0.0000 0.0000 Ks 0.0000 0.0000 0.0000 Ke 0.0000 0.0000 0.0000 map_Ka 4096_earth.jpg map_Kd 4096_earth.jpg map_Ke 4096_night_lights.jpg map_bump 4096_bump.jpg bump 4096_bump.jpg newmtl 02___Default Ns 10.0000 Ni 1.5000 d 1.0000 Tr 0.0000 Tf 1.0000 1.0000 1.0000 illum 2 Ka 0.5882 0.5882 0.5882 Kd 0.5882 0.5882 0.5882 Ks 0.0000 0.0000 0.0000 Ke 0.0000 0.0000 0.0000 map_Ka 4096_earth.jpg map_Kd 4096_earth.jpg map_d 4096_earth.jpg
如今咱們將添加Model
組件,以下面的代碼所示:
<Model source={{obj:asset('earth.obj'), mtl:asset('earth.mtl')}} lit={true} />
lit
屬性指定網格中使用的材料應使用Phong shading處理燈。
同時,也不要忘了從react-vr
中導入Model
組件:
import { ... Model, } from 'react-vr';
可是,若是咱們只將該組件添加到咱們的應用程序中,則不會顯示任何內容。 咱們首先須要添加一個光源。
React VR 有四種光源類型:
AmbientLight表示全方位,固定強度和固定顏色的光源,能夠均勻地影響場景中的全部對象。
DirectionalLight表示從指定方向平均照亮全部物體的光源。
PointLight 表明光的起源來源於一個點,並向各個方向傳播。
SpotLight 表明光的起源來源於一個點,並以錐形向外擴散。
您能夠嘗試全部類型的燈光,看看哪個能夠爲您帶來最佳效果。 在這種狀況下,咱們將使用強度值爲2.6
的AmbientLight
:
import React from 'react'; import { AppRegistry, asset, StyleSheet, Pano, Text, View, Model, AmbientLight, } from 'react-vr'; class EarthMoonVR extends React.Component { render() { return ( <View> ... <AmbientLight intensity={ 2.6 } /> <Model source={{obj:asset('earth.obj'), mtl:asset('earth.mtl')}} lit={true} /> </View> ); } }; AppRegistry.registerComponent('EarthMoonVR', () => EarthMoonVR);
接下來,咱們須要給咱們的模型一些用於放置、大小、和旋轉的樣式屬性。 經過嘗試不一樣的值,我想出瞭如下配置:
class EarthMoonVR extends React.Component { render() { return ( <View> ... <Model style={{ transform: [ {translate: [-25, 0, -70]}, {scale: 0.05 }, {rotateY: -130}, {rotateX: 20}, {rotateZ: -10} ], }} source={{obj:asset('earth.obj'), mtl:asset('earth.mtl')}} lit={true} /> </View> ); } }; AppRegistry.registerComponent('EarthMoonVR', () => EarthMoonVR);
Transforms被表示爲一個樣式對象中的對象數組,請記住它們最後被應用的單位是米。
translate
將您的模型的位置轉換爲x,y,z空間,scale
給您的模型一個大小,並根據提供的度數繞軸旋轉。
這是效果圖:
這個地球模型能夠應用多個紋理。 默認狀況下它帶 clouds 紋理,可是咱們能夠經過用4096_earth.jpg
替換最後三行中的4096_clouds.jpg
來更改.mtl文件中的內容:
# 3ds Max Wavefront OBJ Exporter v0.97b - (c)2007 guruware # File Created: 25.01.2016 02:22:51 newmtl 01___Default ... newmtl 02___Default ... map_Ka 4096_earth.jpg map_Kd 4096_earth.jpg map_d 4096_earth.jpg
效果圖以下:
順便說一下,若是您的模型不帶有.mtl文件,React VR容許您經過下面的代碼指定紋理:
<Model source={{obj:asset('model.obj'), texture:asset('model.jpg')}} lit={true} />
咱們對月球模型作一樣的操做,將紋理的路徑修復到.mtl文件中,並嘗試使用不一樣的比例和放置值。 您不須要添加另外一個光源,AmbientLight
將適用於兩種模型。
這是我想出的月球模型的代碼:
render() { return ( <View> ... <Model style={{ transform: [ {translate: [10, 10, -100]}, {scale: 0.05}, ], }} source={{obj:asset('moon.obj'), mtl:asset('moon.mtl')}} lit={true} /> </View> ); }
效果圖:
若是你想在WebVR上下文中瞭解更多關於360度全景圖的信息,你能夠查看the developer documentation at Oculus這篇文章。
如今,咱們一塊兒來爲模型添加動畫。
React VR 有一個 動畫庫來以簡單的方式組合一些類型的動畫。
在這個時候,只有幾個組件能夠本身動畫(View
使用 Animated.View
, Text
使用 Animated.Text
, Image
使用 Animated.Image
). 這個文檔 提醒你能夠經過createAnimatedComponent
來建立更多的動畫,可是目前爲止還找不到更多的相關信息。
另位一種選擇是使用requestAnimationFrame , 它是基於JavaScript動畫API的重要組成部分。
那麼咱們能夠作的就是要有一個狀態屬性來表示兩個模型的Y軸上的旋轉值(在月球模型上,爲了使它變慢讓旋轉是地球旋轉的三分之一):
class EarthMoonVR extends React.Component { constructor() { super(); this.state = { rotation: 130, }; } render() { return ( <View> ... <Model style={{ transform: [ {translate: [-25, 0, -70]}, {scale: 0.05 }, {rotateY: this.state.rotation}, {rotateX: 20}, {rotateZ: -10} ], }} source={{obj:asset('earth.obj'), mtl:asset('earth.mtl')}} lit={true} /> <Model style={{ transform: [ {translate: [10, 10, -100]}, {scale: 0.05}, {rotateY: this.state.rotation / 3}, ], }} source={{obj:asset('moon.obj'), mtl:asset('moon.mtl')}} lit={true} /> </View> ); } };
如今咱們來編寫一個rotate
函數,它將經過requestAnimationFrame
函數調用每一幀,在必定時間基礎上更新旋轉:
class EarthMoonVR extends React.Component { constructor() { super(); this.state = { rotation: 130, }; this.lastUpdate = Date.now(); this.rotate = this.rotate.bind(this); } rotate() { const now = Date.now(); const delta = now - this.lastUpdate; this.lastUpdate = now; this.setState({ rotation: this.state.rotation + delta / 150 }); this.frameHandle = requestAnimationFrame(this.rotate); } ... }
幻數 150只是控制旋轉速度(這個數字越大,旋轉速度越慢)。 咱們保存由requestAnimationFrame
返回的處理程序,以便當組件卸載並啓動componentDidMount
上的旋轉動畫時,咱們能夠取消動畫:
class EarthMoonVR extends React.Component { constructor() { super(); this.state = { rotation: 130, }; this.lastUpdate = Date.now(); this.rotate = this.rotate.bind(this); } componentDidMount() { this.rotate(); } componentWillUnmount() { if (this.frameHandle) { cancelAnimationFrame(this.frameHandle); this.frameHandle = null; } } rotate() { const now = Date.now(); const delta = now - this.lastUpdate; this.lastUpdate = now; this.setState({ rotation: this.state.rotation + delta / 150 }); this.frameHandle = requestAnimationFrame(this.rotate); } ... }
這是效果圖(你可能沒有注意到,可是月亮旋轉得很慢):
如今讓咱們來添加一些button來增長一些交互。
爲咱們的button建立一個新的組件。在實際開發中,咱們也能使用View
或者VrButton
,這倆都能設置像onEnter
同樣的有效的事件來達到咱們的目的。
然而,咱們將使用VrButton,由於它有和其餘組件不同的狀態機,而且很方便的添加onClick
和 onLongClick
事件。
同時,咱們爲了讓button外觀更好看一些,咱們將使用StyleSheet 來建立一個樣式對象,並經過一個樣式ID來對button進行引用。
下面是button.js
的內容:
import React from 'react'; import { StyleSheet, Text, VrButton, } from 'react-vr'; export default class Button extends React.Component { constructor() { super(); this.styles = StyleSheet.create({ button: { margin: 0.05, height: 0.4, backgroundColor: 'red', }, text: { fontSize: 0.3, textAlign: 'center', }, }); } render() { return ( <VrButton style={this.styles.button} onClick={() => this.props.callback()}> <Text style={this.styles.text}> {this.props.text} </Text> </VrButton> ); } }
一個VrButton
沒有外觀效果,所以咱們必須給它添加樣式。它也能夠包裝一個Image
或Text
組件。當點擊這個button時,咱們能夠給它傳遞一個事件函數來接收點擊事件。
如今在咱們的根組件中,咱們倒入Button
組件而且在render
函數中,以下所示添加兩個Button。
... import Button from './button.js'; class EarthMoonVR extends React.Component { ... render() { return ( <View> ... <AmbientLight intensity={ 2.6 } /> <View> <Button text='+' /> <Button text='-' /> </View> ... </View> ); } };
這兩個Button在被觸發時將會改變模型的Z座標值並進行相應的縮放。所以,咱們添加一個zoom
狀態機變量值,讓它的初始值爲-70
(地球的Z軸值),當咱們點擊+
和-
時會增長
和減小
zoom
的值。
class EarthMoonVR extends React.Component { constructor() { super(); this.state = { rotation: 130, zoom: -70, }; ... } render() { return ( <View> ... <View> <Button text='+' callback={() => this.setState((prevState) => ({ zoom: prevState.zoom + 10 }) ) } /> <Button text='-' callback={() => this.setState((prevState) => ({ zoom: prevState.zoom - 10 }) ) } /> </View> <Model style={{ transform: [ {translate: [-25, 0, this.state.zoom]}, {scale: 0.05 }, {rotateY: this.state.rotation}, {rotateX: 20}, {rotateZ: -10} ], }} source={{obj:asset('earth.obj'), mtl:asset('earth.mtl')}} lit={true} /> <Model style={{ transform: [ {translate: [10, 10, this.state.zoom - 30]}, {scale: 0.05}, {rotateY: this.state.rotation / 3}, ], }} source={{obj:asset('moon.obj'), mtl:asset('moon.mtl')}} lit={true} /> </View> ); } };
如今咱們經過StyleSheet.create
來給包含兩個Button的View
添加flexbox佈局樣式。
class EarthMoonVR extends React.Component { constructor() { super(); ... this.styles = StyleSheet.create({ menu: { flex: 1, flexDirection: 'column', width: 1, alignItems: 'stretch', transform: [{translate: [2, 2, -5]}], }, }); ... } render() { return ( <View> ... <View style={ this.styles.menu }> <Button text='+' callback={() => this.setState((prevState) => ({ zoom: prevState.zoom + 10 }) ) } /> <Button text='-' callback={() => this.setState((prevState) => ({ zoom: prevState.zoom - 10 }) ) } /> </View> ... </View> ); } };
在flexbox佈局中,子組件會經過flexDirection:'column'
屬性值垂直佈局,經過flexDirection:'row'
屬性值水平佈局。在這個案例中,flex設置爲1表明兩個button大小同樣,flexDirection
設置爲column
表明兩個button從上往下排列。alignItems
的值爲stretch
表明兩個Button和父視圖寬度同樣。
看看 this page on the React Native documentation 和 this one on the React VR documentation 這兩篇文章來了解更多關於flexbox佈局的相關知識。
最後,咱們能夠從render
函數中將天空盒的圖片移除,以便render
中的代碼看起來不至於那麼擁擠:
import React from 'react'; import { AppRegistry, asset, StyleSheet, Pano, Text, View, Model, AmbientLight, } from 'react-vr'; import Button from './button.js'; class EarthMoonVR extends React.Component { constructor() { super(); this.state = { rotation: 130, zoom: -70, }; this.lastUpdate = Date.now(); this.spaceSkymap = [ '../static_assets/space_right.png', '../static_assets/space_left.png', '../static_assets/space_up.png', '../static_assets/space_down.png', '../static_assets/space_back.png', '../static_assets/space_front.png' ]; this.styles = StyleSheet.create({ menu: { flex: 1, flexDirection: 'column', width: 1, alignItems: 'stretch', transform: [{translate: [2, 2, -5]}], }, }); this.rotate = this.rotate.bind(this); } componentDidMount() { this.rotate(); } componentWillUnmount() { if (this.frameHandle) { cancelAnimationFrame(this.frameHandle); this.frameHandle = null; } } rotate() { const now = Date.now(); const delta = now - this.lastUpdate; this.lastUpdate = now; this.setState({ rotation: this.state.rotation + delta / 150 }); this.frameHandle = requestAnimationFrame(this.rotate); } render() { return ( <View> <Pano source={ {uri: this.spaceSkymap} }/> <AmbientLight intensity={ 2.6 } /> <View style={ this.styles.menu }> <Button text='+' callback={() => this.setState((prevState) => ({ zoom: prevState.zoom + 10 }) ) } /> <Button text='-' callback={() => this.setState((prevState) => ({ zoom: prevState.zoom - 10 }) ) } /> </View> <Model style={{ transform: [ {translate: [-25, 0, this.state.zoom]}, {scale: 0.05 }, {rotateY: this.state.rotation}, {rotateX: 20}, {rotateZ: -10} ], }} source={{obj:asset('earth.obj'), mtl:asset('earth.mtl')}} lit={true} /> <Model style={{ transform: [ {translate: [10, 10, this.state.zoom - 30]}, {scale: 0.05}, {rotateY: this.state.rotation / 3}, ], }} source={{obj:asset('moon.obj'), mtl:asset('moon.mtl')}} lit={true} /> </View> ); } }; AppRegistry.registerComponent('EarthMoonVR', () => EarthMoonVR);
若是咱們測試這個應用程序,咱們將看到兩個button均觸發了相關事件。
React Native 是基於React的一個移動端的JavaScrpit庫,而React VR又是基於React Native的適用於虛擬現實的JavaScrpit庫。React VR容許咱們快速方便的建立VR體驗。
有不少相關的社區,如A-Frame和React VR 中文網。若是你想在App中製做360度的VR全景效果,而且若是你瞭解React/React Native,那麼React VR是很是不錯的選擇。
記住,你可以從GitHub下載本篇文章中的源碼。
謝謝閱讀!
社羣品牌:從零到壹全棧部落
定位:尋找共好,共同窗習,持續輸出全棧技術社羣
業界榮譽:IT界的邏輯思惟
文化:輸出是最好的學習方式
官方公衆號:全棧部落
社羣發起人:春哥(從零到壹創始人,交流微信:liyc1215)
技術交流社區:全棧部落BBS
全棧部落完整系列教程:全棧部落完整電子書學習筆記
關注全棧部落官方公衆號,每晚十點接收系列原創技術推送 |
---|
![]() |