React VR 快速入门完全教程
React VR 快速入门什么是React
创建一个React App$ npm install -g create-react-app $ create-react-app my-app $ cd my-app $ npm start 效果图
什么是React Native?
它使用与常规iOS和Android应用程序相同的基本UI构建块。 使用
创建一个React Native App
查看官网http://facebook.github.io/react-native/docs/getting-started.html
$ react-native init my-rn-app
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
联系我
开始使用React VRReact VR旨在允许Web开发人员使用React的声明方法(特别是React Native)来创作虚拟现实(VR)应用程序。
React VR类似于React Native,因为它使用 在本篇文章中,我将带领大家创建一个简单的VR应用程序来学习如何创建一个全景图片,3D对象模型,按钮和flexbox布局的使用场景。我们的模拟应用程序基于React VR的两个 该应用程序将渲染一个能够放大和缩小的
这些模型中,它们的尺度和旋转不是 你能够从 GitHub找到最后的项目源代码。 要求到目前为止,虚拟现实是一项相当新的技术,开发或测试我们的VR应用程序的方法很少。 WebVR 和 Is WebVR Ready? 可以帮助您了解哪些浏览器和设备支持最新的VR规范。 但是你也不必过于担心, 你现在不需要任何特殊的设备,例如: Oculus Rift,HTC Vive,或者 Samsung Gear VR 来测试一个WebVR APP。 下面是你现在 所需要 准备的:
如果您也有Android设备和Gear VR耳机,您可以安装Carmel Developer Preview浏览器来探索您的React VR 应用程序。 创建项目首先,我们需要使用 $ npm install -g react-vr-cli 使用React VR CLI来创建一个名字叫做 $ react-vr init EarthMoonVR 在创建过程中您需要等一会儿,这将创建一个 一旦项目创建完毕,可以通过 $ cd EarthMoonVR 在终端通过 $ npm start 在浏览器中输入 React VR下面是初始化的React VR新项目的项目结构: +-__tests__ +-node_modules +-static_assets +-vr -.babelrc -.flowconfig -.gitignore -.watchmanconfig -index.vr.js -package.json -rn-cli-config.js -yarn.lock 我将 你可以从这里了解更多项目结构。
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,-3]}],}}> hello </Text> </View> ); } }; AppRegistry.registerComponent('EarthMoonVR',() => EarthMoonVR); 我们可以看到React VR使用了ES2015 和 JSX。 这个代码通过React Native packager进行预编译,它提供了(ES2015,JSX)编译和其他资源加载。 在
注意, 除了添加 最后,项目根组件应该通过 现在我们知道代码是做什么用的,接下来我们将 全景图像通常,我们的VR应用程序中的空间由全景(pano)图像组成,它创建了一个1000米的球体(在React VR距离中,尺寸单位为米),并将用户置于其中心。 一张全景图像允许你从上面,下面,后面以及你的前面去观察它,这就是他们也被称为360的图像或球面全景的原因。 360全景图有两种主要格式:平面全景图和立方体。 React VR支持两者。 平面全景图平面全景图由宽高比为2:1的单个图像组成,意味着宽度必须是高度的两倍。 这些照片是通过360度照相机创建的。一个很好的平面图像来源是Flickr,你打开这个网站尝试搜索
看起来很奇怪,不是吗? 无论如何,下载最高可用分辨率的照片,将其拖拽到项目中 render() { return ( <View> <Pano source={asset('sample_pano.jpg')}/> </View> ); }
render() { return ( <View> <Pano source={ {uri:'../static_assets/sample_pano.jpg'} }/> </View> ); } 假设本地服务器一直在运行,当我们在浏览器中刷新页面时,我们将看到如下效果:
顺便说一下,如果我们想避免在每次更改时都需要重新刷新页面,我们可以通过在URL(http://localhost:8081/vr/?hot... 中添加 立方体全景图立方体全景图是360度全景图的其他格式。这种格式使用六个图像作为一个多维数组集的六个面,它将填充我们周围的球体。 它也被称为天空盒。 基本思想是渲染一个立方体,并将观众置于中心,随后移动。 例如,下面的这张大图中,每一个方位的小图代表立方体的一面:
为了能够在React VR中使用立方体全景图, 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上创建空间天空盒(包括星星和星云)。 创建一个 <?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> 并且通过
我们可以导出天空盒的六张图像:
如果我们修改代码如下所示: <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模型。 联系我
3D 模型React VR 有一个 Model 组件,它支持Wavefront .obj file format 来代表3D建模。 mesh是定义3D对象形状的顶点、边和面的集合。 .obj文件是一个纯文本文件,其中包含几何顶点,纹理坐标,顶点法线和多边形面元素的坐标。 通常,.obj文件引用一个外部.mtl file文件,其中存储了描述多边形视觉方面的材质(或纹理)。 您可以使用Blender,3DS Max,和Maya等程序创建3D模型并将其导出为这些格式。 还有很多网站可以免费下载或免费下载3D模型。 以下是其中三个很不错的:
对于我们的应用程序,我们将使用这个3D地球模型和这个来自TF3DM的3D月球模型 。 当我们将地球模型的文件提取到我们应用程序的 # 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 source={{obj:asset('earth.obj'),mtl:asset('earth.mtl')}} lit={true} />
同时,也不要忘了从 import { ... Model,} from 'react-vr'; 但是,如果我们只将该组件添加到我们的应用程序中,则不会显示任何内容。 我们首先需要添加一个光源。 React VR 有四种光源类型:
您可以尝试所有类型的灯光,看看哪一个可以为您带来最佳效果。 在这种情况下,我们将使用强度值为 import React from 'react'; import { AppRegistry,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,-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被表示为一个样式对象中的对象数组,请记住它们最后被应用的单位是米。
这是效果图:
这个地球模型可以应用多个纹理。 默认情况下它带 clouds 纹理,但是我们可以通过用 # 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文件中,并尝试使用不同的比例和放置值。 您不需要添加另一个光源, 这是我想出的月球模型的代码: 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 有一个 动画库来以简单的方式组合一些类型的动画。 在这个时候,只有几个组件可以自己动画( 另位一种选择是使用requestAnimationFrame ,它是基于JavaScript动画API的重要组成部分。 那么我们可以做的就是要有一个状态属性来表示两个模型的Y轴上的旋转值(在月球模型上,为了使它变慢让旋转是地球旋转的三分之一): class EarthMoonVR extends React.Component { constructor() { super(); this.state = { rotation: 130,}; } render() { return ( <View> ... <Model style={{ transform: [ {translate: [-25,{rotateY: this.state.rotation},mtl:asset('earth.mtl')}} lit={true} /> <Model style={{ transform: [ {translate: [10,{rotateY: this.state.rotation / 3},mtl:asset('moon.mtl')}} lit={true} /> </View> ); } }; 现在我们来编写一个 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只是控制旋转速度(这个数字越大,旋转速度越慢)。 我们保存由 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并设置样式为我们的button创建一个新的组件。在实际开发中,我们也能使用 然而,我们将使用VrButton,因为它有和其他组件不一样的状态机,并且很方便的添加 同时,我们为了让button外观更好看一些,我们将使用StyleSheet 来创建一个样式对象,并通过一个样式ID来对button进行引用。 下面是 import React from 'react'; import { StyleSheet,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> ); } } 一个 现在在我们的根组件中,我们倒入 ... 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坐标值并进行相应的缩放。因此,我们添加一个 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,this.state.zoom]},this.state.zoom - 30]},mtl:asset('moon.mtl')}} lit={true} /> </View> ); } }; 现在我们通过 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布局中,子组件会通过 看看 this page on the React Native documentation 和 this one on the React VR documentation 这两篇文章来了解更多关于flexbox布局的相关知识。 最后,我们可以从 import React from 'react'; import { AppRegistry,} from 'react-vr'; import Button from './button.js'; class EarthMoonVR extends React.Component { constructor() { super(); this.state = { rotation: 130,}; this.lastUpdate = Date.now(); this.spaceSkymap = [ '../static_assets/space_right.png','../static_assets/space_front.png' ]; this.styles = StyleSheet.create({ menu: { flex: 1,}); 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,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下载本篇文章中的源码。 谢谢阅读! 联系我
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |