Skip to content

Latest commit

 

History

History
596 lines (392 loc) · 33.4 KB

File metadata and controls

596 lines (392 loc) · 33.4 KB

四、React 虚拟现实库

本章是关于 React VR 库的布局;其中的对象和组件。本章中的许多概念将在后面的章节中引用,因此,如果您正在阅读本书的电子版,它将与您的享受和乐趣紧密链接。

React-VR 包含六个基本元素,并使用一个新的但熟悉的范式 JSX(JavaScript 扩展)进行编码。如果您已经知道 React,那么您已经熟悉 React VR,尽管有一些重要的区别。我们将介绍以下内容:

  • JSX,React VR 的语言和语法:

    • React 与 React 的区别
  • 组件和虚拟现实组件:

    • 道具
    • 状态
    • 事件
    • 布局
    • 风格
  • 所有组件和关键字的详细信息:

    • 可见和不可见的对象
    • 多媒体-声音和视频
    • 摄像机和观察

我还没有涵盖所有可用的 API,因为这大部分是一个冗长的、类似词典的背诵,如果您使用网站上的文档来探索 API,那会更好。在后面的章节中,我们将使用关键 API 为我们的世界添加生命并在其中导航。有关完整、最新的 API 列表,请查看文档(https://facebook.github.io/react-vr/docs/getting-started.html )。

JSX—React VR 的语法

React-VR 看起来对 HTML 很熟悉;这使其易于阅读、编辑和部署。在幕后,React 和 React VR 使用的 UI 语法胶水将被编译成 JSX 或 JavaScript 扩展。JSX 是一个 React 语法扩展,允许混合使用 HTML 和 JavaScript 进行编码。您还可以直接编写 JSX 代码。

React JSX 的示例如下所示:

const element = <h1>My title!</h1>;

这不是字符串,因为它不在引号中,也不是 JavaScript。与直接用 JavaScript 编写代码相比,它可读性更强,使用更方便。JSX 使编程更快,更具声明性。

It is useful, but all of this readability and easy-to-program nature comes with a few pitfalls. One of them is that semicolons will automatically get entered. Just like with HTML, you can include extra lines, but your code may get extra semicolons that you didn't intend. 

Put parentheses around your code to avoid this--I also highly recommend reading up on the JavaScript syntax. A few of the things in this book took me longer than they should have, as I'm a C++ programmer, not a native JavaScript programmer. 

编译 React VR 后,JSX 会自动转换为 JavaScript。这意味着您可以在任何使用 JavaScript 的地方包含 JSX

React 与 React 的区别

在 React 中,您的大部分想法都围绕着自 JavaScript 开始以来就让我们既着迷又愤怒的文档对象模型DOM)。使用 React VR,您需要忘记 DOM;这样,React VR 与 React Native 更相似。即使这样,也有一些概念需要忘记。

忘掉像素作为一个维度;这个概念对于虚拟现实来说毫无意义。

你可以把一张巨大的照片放在世界上很多地方,看起来像颗粒状的,而一张小照片放在一个小的物理物体的侧面,看起来非常锐利。你可以离物体更近或更远(假设你已经编程了移动),这将极大地改变物体的“像素”宽度。取而代之的是,一切都是以米为单位的(如果你来自一个坚持使用过时的“英尺”单位的国家,你可以假装这些单位是以码为单位的。足够接近虚拟现实工作)。

另一个在 React VR 中似乎有点奇怪的概念是渲染速度**。**使用 React,您的页面被加载,然后显示,然后页面的元素可以交互(点击),但除非有人点击刷新,否则整个页面很少被重新呈现。属性改变时调用对象的render方法。这并不意味着你必须有一个计时器来“挠痒痒”在虚拟现实中呈现你的页面。

随着反应 VR,整个页面以较少的(希望)超过 16 毫秒呈现,使得每秒 60 帧,现在认为是 VR 必不可少的。不重新分析整个页面。这在某种程度上与常规 HTML 相反。特别是,对于活动网页,单个 VR 组件将以每秒 60 帧的速度呈现(显示),当其属性更改时,将呈现(到 three.js 代码)以更新该表示。

呈现对象与页面呈现不同。这可能有点令人困惑。您的页面将在开始加载时立即呈现,即使各种对象的render()方法(将它们转换为 three.js 代码)尚未运行。

最终的结果是,在没有任何额外编程的情况下,当世界中的属性更新时,对象将根据这些属性的更改而显示。这是 React 工作原理的基石,同样适用于 React VR。这将添加每秒多个帧速率的渲染

既然我们已经介绍了 React VR 不是什么,那么让我们来介绍 React VR 是什么。

核心部件

React VR 具有可重用的 UI 元素,您可以在各种地方使用。这些被称为组件。有两个内置组件:

  • 文本
  • 形象

您还可以通过扩展React.Component来构建自己的组件。

组件是真实的东西,而不仅仅是标签或占位符,因为它们是通过render()函数在世界上展示自己的方式构建的。这不仅仅是一个功能;与 React VR 的所有内容一样,render()通常有一组呈现或描述其内容的子组件。组件的示例如下所示:

<Greeting/>

这将是一个文本组件,一个内置类型。

虚拟现实组件

VR 对象,即您通常认为的组件,将在后面介绍。React VR 文档在核心组件一节中没有提到它们,这有点令人困惑。您可能在想*“只有文本和图像?对象呢?”*VR 组件是我对以下内容的术语:

  • VR 物理组件:这些是你在世界上可以“看到”的对象:
    • 三维基本体,包括长方体、圆柱体、平面、球体和导入的对象(可以非常详细)
    • UI 元素,如面板和按钮
  • :这些灯照亮前面的物体,可以有几种类型。请注意,在 React VR 中,当前照明不会为实时速度投射阴影。
  • 多媒体:包括视频和声音。通过这种方式,您既可以为 360 视频创建移动背景,也可以在您正在创建的世界中拥有“电视”。
  • 摄影机和场景:摄影机控制渲染,场景包含您放置在其中的所有对象。

我们将在后面的下一级小节中介绍这些关键词

道具

如果组件没有属性,它们会很无聊。我们向您致意的物业示例如下:

<Greeting name='Hello React VR Dude!'/>

name和其他类似的值被称为道具。道具是 name,有一个值,我将其设置为一个幽默的字符串。可以通过编程方式访问它们,例如,{this.props.name}

许多三维对象也具有属性;这些因对象而异。

状态

也许我们正处于混乱状态,但 React VR 状态非常重要,因为它会影响所有组件的显示,从而影响这些组件的各种道具。如果组件的道具(外部)或状态(内部)更改,组件将重新渲染自身。

Rendering does not necessarily refer to "creating an image for the eyeball", although it can. Rendering, in this case, can refer to building code through the React VR/JSX compilation process. 

React VR 按照面向对象原理/编码范式进行封装,因此可修改状态位于组件内的this.state对象内。只能通过“设置”功能进行修改,具体如下:this.setState({myStateVariableBeers: 99 })

注意,虽然一开始这看起来像是在扩展 HTML/JSX 格式,但这正是 React VR 如此强大和简单的原因。

事件

活动不仅仅是在你的邻居家里玩的有趣的事情,它们也是让你的虚拟现实世界变得活灵活现的方式。当用户通过用户界面UI进行某些操作时,会生成事件。当您将光标移入和移出视图区域时,View组件发送onEnteronExit事件。

精明的读者应该感到困惑——我们正在谈论虚拟现实,我刚才提到了这个领域。为什么 2D 概念作为 3D 语言的基本组成部分被讨论?

事件和布局(下面将介绍)遵循 2D 范式,是您习惯于使用的东西(HTML、CSS 和 JavaScript,以及虚拟现实世界)之间的一个简单桥梁示例。然而,两者之间存在着差异,而且在任何道具和关键词中都没有考虑“像素”的说法可能从根本上看起来很奇怪。这是因为在真实的 3D 世界中,使用像素作为测量单位的想法基本上是无用的。在你前面一米的物体比在你后面十米的物体有更宽的屏幕。因此,尺寸以世界空间为单位;一个是一米(比一码多一点)。

React-VR 的目的是快速而明确地构建伟大的 3D 世界。它是一种声明式编程方法。如果您想构建更复杂的世界,React VR 的强大之处在于您可以使用 React Native 和其他 Node.js 编程方法添加到 React VR 中。

布局与风格

WebVR 和 React VR 的各个方面仍然遵循浏览器范式。光标被视为二维交互,UI 元素通常根据二维弹性框和布局规则进行描述,以便在二维中布局这些组件。这并不意味着我们没有开发虚拟现实环境;尽管大多数 UI 是 2D 格式的,但它们在 VR 环境中完全存在

布局和样式自然地进入 3D。您可以设置类似于样式表或 CSS 的内容,而不必描述每个项目的 3D 对象(内联)。它实际上与样式表不同,它是一个样式表,所以你的所有技能都会转移。

样式表可能会很凌乱,因此 React VR 使布局 UI 元素更加容易。它使用 Flexbox,通过 YogaLayout(在处)https://github.com/facebook/yoga )。React 虚拟现实就是快速创造现实。React 是关于用户界面的,所以 React VR 中的 UI 元素功能强大是很自然的。

下一个层面——细节

尽管 React VR 库很简单,但要真正了解它的全部内容,您需要学习很多语法。你可以略读一下,但在不熟悉任何东西的情况下了解一点是有危险的。

"A little Learning is a dang'rous Thing; Drink deep, or taste not the Pierian Spring: There shallow Draughts intoxicate the Brain, And drinking largely sobers us again." -An Essay on Criticism, by Alexander Pope.

你可能会想*“好吧,但是虚拟现实的东西都在哪里?你知道,桌子、椅子、灯、人……**等等。”*这些确实是一种深度饮料——有很多成分。

最好的参考是在线文档,尽管它们有时有点稀疏。请记住,在线文档是live,这意味着您可以提交一个问题,甚至修改它,如果您看到输入错误或需要澄清的话。

我强烈建议您将下一节视为参考节。当然,你可能需要帮助才能在晚上入睡,在这种情况下,请继续阅读!说到这里,本节非常重要,因为您需要使用许多或所有这些组件来实际构建您的虚拟现实世界。我将尝试使这一部分有趣。我在写一本书,而不是试图在舞台上谋生,这是一件好事。

填充(对象,无论是否可见)

世界上大多数有趣的东西都是可见的或可以与之交互的对象。大致上,按照复杂性的顺序,如下所示:

  • 圆柱
  • 飞机
  • 圆柱状耳
  • 模型
  • 帕诺
  • 视频控制
  • VrButton

原语

长方体、圆柱体、平面和球体是三维基本体。他们有littexturewireframe道具。照明对象将受场景中灯光的影响。如果指定了纹理(通常是图像文件),浏览器将查找(获取或渲染)该图像,并使用它环绕 3D 基本体。我们将在第 6 章与 Poly 和 Gon 家族合作第 7 章与(虚拟)茶壶坐在一起中讨论 UV 映射,但大多数 3D 原语的映射方式与您期望的方式相同。

注意,纹理可以是string(指图像文件)、asset()调用或require()

Box是一个基本立方体。如果未指定,其尺寸将默认为一(单位)。

<Box
 dimWidth={4}
 dimDepth={1}
 dimHeight={9}
 lit
/>

这将是 2001 年太空漫游中的巨石;尺寸是前三个素数的平方。更多信息,请参见https://facebook.github.io/react-vr/docs/box.html

圆柱

Cylinder是一个基本的有盖圆筒。它还可以通过使顶部半径为零(或关闭漏斗的底部半径)来制作圆锥体。

The Cylinder uses radius, not diameter. Don't make your cylinders twice as large as they need to be!

// Round cylinder 
//Doric order column
<Cylinder 
   radiusTop={.825} 
   radiusBottom={1} 
   dimHeight={8} 
   segments={20} /> 

// Great Pyramid
<Cylinder 
   radiusTop={0} 
   radiusBottom={2.20} 
   dimHeight={2.8} 
   segments={4} 
/>

注意创造性地使用了边数,使圆锥体成为金字塔。有关更多信息,请参见https://facebook.github.io/react-vr/docs/cylinder.html

与所有 3D 原语一样,Cylinderlittexturewireframe道具

飞机

这不是空中客车,而是一个平面。虽然它被称为一个平面,但它更像一个平面、正方形的 2D 平板。它不是立方板,这将是一个Box

//concrete slab using industry norms for size
<Plane
   dimWidth={2.4}
   dimHeight={2.4}
 />

飞机有一点很难使用;它们仅从其主侧可见。它们是快速、轻量级的对象,但只能有一个纹理贴图,因此如果使用大平面,它们可能看起来重复。如果你把一个平面旋转错了方向,你可能什么也看不见;你可以从后面看。注意变换或使用Box而不是Plane

更多信息,请参见https://facebook.github.io/react-vr/docs/plane.html

与所有 3D 原语一样,Cylinderlittexturewireframe道具

跟随反弹的球,尽管稍后将介绍动画。与Cylinder一样,Sphere有一个可以改变其分辨率的道具:

<Sphere
  radius={0.5}
  widthSegments={20}
  heightSegments={12}
/>

与我们制作金字塔的方式类似,在宽度和高度上加入非常少的线段可以使Sphere看起来像不同类型的实体。有关更多信息,请参阅https://facebook.github.io/react-vr/docs/sphere.html

与所有 3D 原语一样,Spherelittexturewireframe道具

模型

Model组件允许我们做真正有趣的事情。到目前为止,VR 对象相当简单,但模型允许您导入任意复杂度的 CAD 模型。

Be careful with Model:

You can easily import objects that are more complex than your platform can handle. Remember, you still maintain the smooth frame rates that are required for Virtual Reality to seem real.

第 6 章中,我们将与 Poly 和 Gon 家族合作,探讨有效使用Model的细节。显示Model的基本方法如下:

Model带物料档案:

 <Model
 source={{
 obj: asset('sculpture.obj'),
 mtl: asset('sculpture.mtl'),
 }}
/>

Model无材料档案:

<Model
 source={{
 obj: asset('standalone.obj'),
 }}
/>

截至撰写本书时,Model导入波前 OBJ 文件格式,以及GL 传输格式glTF)。OBJ 是最常见的三维模型格式。人们可能会想,为什么 React 不导入 X3D,这是 WebVR 的首选格式。这是我在 VRML 和 X3D 上投入这么多精力的原因之一

在任何情况下,OBJ 文件通常由两个文件组成;filename.obj包含对象的几何体,附带的.MTL文件(材质)包含颜色、材质和对外部纹理(图像文件)的引用。请注意,这意味着,如果 OBJ 文件在材质文件中加载了许多纹理,则可能需要的不仅仅是这两个文件。

我们将在第 6 章与 Poly 和 Gon 家族的合作中更深入地介绍这一点。

注意,Modellittexturewireframe道具。纹理道具应用于整个模型,该模型可能具有多个 UV 映射。通常最好通过.MTL文件指定纹理,这可以通过建模程序自动完成。

Don't plan on the texture keyword to apply to a Model that you have imported. It's far better to texture and map the model in the CAD program you are using, than to try to override it in React VR.

Secondly, you may need to hand edit the .MTL file; my experience is that most exporters can't handle all of the complexity of a nodal-based shader that even real-time engines make dramatic use of; as a result, your .MTL file is almost certainly not going to have all of the different baked-in maps.

圆柱状耳

CylindricalPanel是一个有点过渡的对象。它旨在拥有子对象,并提供在以当前视点为中心的不可见圆柱体上绘制这些对象的功能。它的主要目的是允许在 3D 世界中放置熟悉的 2D 元素。要做到这一点,需要一些不合时宜的因素

当您使用 HTML 时,为了精确地布局 HTML 元素,您可能需要考虑并使用像素编码;例如,某个元素可以是 200 像素宽。这允许您精确地布局图形。

在 3D 中,这些都不适用。月球是 1、2 还是 10 像素宽?世界上没有每英寸上的点。因此,大多数虚拟现实原语建立了它们的实际尺寸,以及它们的虚拟尺寸,单位为米。然后,您的 VR 显示方法将显示适当数量的像素。如果你把你的头向上移动到那个立方体,它可能是 2000 像素;如果你在走廊尽头看到它,它可能有 10 像素宽。因此,通常情况下,您不会将像素用于 React VR 的大小。

然而,CylindricalPanel对象需要像素数量的属性。这不是为了对象本身(嗯,有点),而是为了一个屏幕外缓冲区来保存任何子对象的可见渲染。和网络上的许多东西一样,它也有合理的默认值。默认值相当大,但如果你靠近它,它看起来就不那么粗糙了。

I highly recommend not using CylindricalPanel, but rather recode your UI into actual 3D objects. The resolution and system resource use (RAM mainly) could actually be lower this way.

例如:

<CylindricalPanel
 layer={{
 width: bufferWidthPx,
 height: bufferHeightPx,
 density: numberOfPxForACompleteTurn,
 radius: distanceFromTheViewer
 }}>
 ... Child components ...
</CylindricalPanel>

The Child components line is very important--here is where you put the actual 2D objects that will show up spread across CylindricalPanel. It is not literal code.

视频控制

VideoControl是具有正常VideoPlayer功能的物理对象,即启动、暂停等。由于它旨在用于播放视频,因此这里的示例(直接来自文档)将显示它嵌入了动画对象:

class VideoPlayer extends React.Component {
constructor(props) {
   super(props);
   this.state = {
   // init with muted, autoPlay
   playerState: new MediaPlayerState({autoPlay: true, muted: true}), 
 };
}
render() {
   return (
   <View>
      <Video
      style={{height: 2.25, width: 4}}
      source={{uri: 'img/1.webm'}}
      playerState={this.state.playerState} />
   <VideoControl
      style={{height: 0.2, width: 4}}
      playerState={this.state.playerState} />
   </View>
   );
}
}

不要觉得自己仅限于预期用途。你也可以用它做实验——也许它是一个好的列车控制器!

VrButton

VrButton实际上不是一个真正的按钮(好吧,它都是虚拟的,对吧?),这意味着它没有任何几何图形,但它是一个你可能会发现非常有用的对象,可以包含在这个世界中

VrButton主要用于凝视检测。我们在第 11 章野外散步中讨论了这一点以及其他 VR 运动(移动)技术。现在,让我们来讨论一下VrButton是什么:

<VrButton
 style={{width: 0.7}}
   onClickSound={{    
      ogg: asset('click.ogg'),    
      mp3: asset('click.mp3'),   }}
 onClick={()=>this._onViewClicked()}>
 <Image style={{width:1, height:1}}
 source={{uri:'../../Assets/img/gaze_cursor_cross_hi.png'}}
 inset={[0.2,0.2,0.2,0.2]}
 insetSize={[0.05,0.45,0.55,0.15]} >
 </Image>
</VrButton>

这个VrButton包装一个图像并播放一个声音。我们将在第 8 章呼吸生活在你的世界中进一步讨论声音,但这里简单介绍一下,文件格式允许浏览器决定在你选择的浏览器中播放哪种声音。

如果我们没有灯光,世界将是一个相当黑暗的地方,充满了吸血鬼。让我们把那些不死生物赶走。有四个主要指示灯:

  • 环境光
  • 平行光
  • 点光源节点
  • 聚光灯

普通光特性

所有灯光都有两个公共属性:

  • intensity:这就是场景中灯光的亮度。默认值为{1.0},但可以更高。实际上,更高的设置会使对象(例如球体)弯曲边缘上的阴影更锐利,看起来更亮(褪色),但在最亮的面上,阴影实际上不会比白色(RGB 255、255、255)更白。
  • color:颜色未列在灯光属性下,但它是所有灯光都具有的样式道具。这是一个 RGB 属性。您甚至可以使用彩色环境光,它可以用于暗褐色色调等,也可以模拟来自明亮颜色环境的背景照明。例如,在森林中,可能是浅绿色环境色。默认值为白色。

其他灯光具有特定于其所代表的照明类型的特性。

环境光

AmbientLight是使场景可见的最简单方法。它实际上不是灯光,但它确实照亮了场景中的所有东西。

现实世界中的照明非常复杂。光子在物体周围反弹、反射、穿透,甚至使某些物体发光(荧光和发光)。一个有用的技巧是,即使没有灯光,也可以使对象变亮,或者为房间添加灯光填充,以帮助模拟背景光散射,而无需计算此项的开销。

这称为环境光。许多 CAD 系统将环境作为材料的一种价值。AmbientLight让你照亮整个房间。对于喜欢迪斯科、热爱节日的人们来说,它甚至可以让你将颜色从白色变为你想要的任何颜色。现在,你可以制作一个看起来像 W 连锁酒店走廊的场景。

奇怪的是,React VR 下载中没有一个示例演示如何使用AmbientLight;虽然没那么难,但很重要。

以下是环境温度为.2的球体的屏幕截图:

代码如下:

<AmbientLight
intensity={.2}
/>

注意一些事情——在最后一张照片中,我们也有一个平行光,所以你可以看到不同之处。从平行光看,球体是白色的,但底部是黑色的,但不是漆黑的。AmbientLight可以实时模拟一点全局照明或光能传递。GI 是从其他对象反弹并在真实、非虚拟世界中创建“填充光”的光量。Three.js 也为这个*、*添加了一个THREE.HemisphereLight,您可以通过本机视图或本机桥添加它来反应 VR。

平行光

AmbientLightDirectionalLight,我们正在从抽象走向稍微不那么抽象。ADirectionalLight真的是用来代替太阳的。太阳光线总是相互平行;同样地,DirectionalLight也不会像一盏离得更近的灯那样展开

这是一个DirectionalLight和编号AmbientLight

代码如下:

<DirectionalLight
  intensity={.9}
  style={{ transform: [{ rotateZ: 35 }] }}
/>

In the picture, we've rotated the DirectionalLight to the side slightly; the sphere looks interesting, but not quite right compared to the rest of the scene. This is because the lighting for the Pano background is substantially different than the scene. You would want to try to match the two up with the appropriate transform statement for your <DirectionalLight>.

点光源节点

APointlight就像一个老式的灯泡;光从该点向各个方向传播。关于点光源和聚光灯的一个有趣的事情是再次简化,使我们的虚拟现实看起来真实。为了避免渲染速度非常慢,大气没有严格建模。这意味着通常会因大气而褪色的光线会照数英里(除非你住在月球上,否则在我居住的地方,大气效应可能比你居住的地方更重要。如果你住在月球上,给我一张票,我会亲自来给你大声读这本书)。

为了避免模拟诸如消光(褪色)、雾、云等大气效应,PointLightSpotLight都使用衰减和距离道具。

distance是光照的距离。如果它不是零,则该距离处的光强度将为零。

decay是 if 消失的频率。这是一种通用(无量纲)数字;2是物理真实的灯光衰减。0.1使褪色更加锐利,有助于艺术效果。

例如:

<PointLight 
  intensity={1}
  style={{ transform: [ { translate: [0, 0, -5] }]}}
  distance={10}
  decay={2}
/>

为了更好地可视化前面的内容,我已经构建了三次演示场景;第一个距离为 10,第二个距离为 4,第三个距离为 4,衰减为0.1,而不是 2。你可以看到第三个场景看起来很不自然。请注意,所有三个场景的强度正好为一。

If your point lights seem dim, check the distance parameter. I recommend leaving decay at two.

聚光灯

ASpotLight就像那些灯罩一样,它们在黑色电影或手电筒里的坏人脸上发光。像PointLight一样,它也有衰减和距离道具(如前所示)。

distancedecay道具与PointLight道具相同。SpotLight还有penumbraangle道具;这两个是光的传播距离。角度是angle之外的最大值,penumbra是一个从 1 到 100 的数字,定义SpotLight的柔软程度。

<SpotLight
    intensity={1}
    style={{ transform: [{ translate: [0, 2, -5] }] }}
    distance={25}
    decay={.1}
    penumbra={1}
    angle={40}
  />

Currently, the position of the SpotLight defines where the light is shining "from." The target of the light, in other words what it is pointed at, is currently not exposed in React VR. At the time of the writing of this book, this issue is not resolved. 

Using a View to wrap the SpotLight doesn't seem to change the target either.

I recommend not using SpotLight, unless you can arrange your scene to have the object of interest located at [0,0,0].

多媒体-声音和视频

如果你什么都听不见,这个世界会很无聊。视频通常是动态网页的一部分,尽管在虚拟现实中,我们有一点挑战——视频本身可能不会吸引人,除非它是 360 视频,有些人称之为虚拟现实(它不能给你更多的是虚无的鬼魂感觉,所以在我看来,它不是真正的虚拟现实,因为你不能完全沉浸其中,但其他人可能会觉得它是虚拟现实。在虚拟现实/AR/XR 中,我们真的需要相处!)。

虚拟现实世界中的视频是营造氛围的重要组成部分。如果你走进一个房间,一个视频正在播放,它会看起来更像大多数家庭。

声音

虚拟现实中的Sound比最初听起来要复杂得多(双关语)。Sound节点允许将音频源放入您的虚拟现实世界。Sound将使您的世界充满活力。

从反应 VR 手册,考虑一个例子的 T0 T0:

<Image style={{height: 2.0, width: 2.0}} 
   source={uri: 'images/waterfall.jpg'}>   
   <Sound source={uri: 'sounds/waterfall.wav'} /> 
</Image>

这个例子展示了通过在 React VR 中声明来添加东西是多么容易。waterfall声音简单地附加到waterfall图像的位置。如果你在 3D 世界里走来走去,你会听到瀑布的声音,仿佛它就在图像所在的地方;这一切都是通过简单地添加Sound组件作为叶节点(本例中为图像的子节点)来完成的。Sound节点本身不应该有任何子组件。

如果Sound节点未连接到具有位置的对象,则默认为绝对位置,例如位置:绝对。

Sound节点有很多道具。详情如下:

  • autoPlay:布尔值 当加载组件时音频开始自动播放。默认为true
  • loop:布尔值 当音频播放完毕自动重复时。默认为false
  • muted:音频静音时的布尔值 。默认为false
  • onDurationChange:(回调函数) 当声音持续时间改变时调用此函数,参数为声音持续时间。
  • onEnded:(回调函数) 音频播放完成后调用函数onEnded
  • onPlayStatusChange:(回调函数) 播放状态改变时调用此函数。event.nativeEvent.playStatus:这是声音的播放状态;字符串'closed''loading''error''ended''paused''playing''ready'之一。
  • onTimeUpdate:(callback函数) 当声音的currentTime发生变化时调用此函数。
  • event.nativeEvent.currentTime:声音文件的currentTime
  • playControl播放暂停停止。 此变量控制播放状态。如果未设置,autoPlay的值确定加载组件时是否播放音频。
  • playerState:(对象)

playerState是一个MediaPlayerState,通过其内部状态控制视频播放。设置playerState时,autoPlay、静音音量和playControl属性的值将被忽略,因为它们将由playerState设置。参见MediaPlayerState

  • source:(对象)

对象源音频的格式为{uri:http}。

  • volume:音频音量的 0-1.0(实际不受限制) 值。最小值为零,使声音静音,建议的最大值为 1.0,这也是默认值。允许大于 1 的值;这可能会导致剪辑/失真,具体取决于音频硬件。 示例:将音量降低 50%设置volume={0.5}。由于不同的平台可能具有不同的音频功能(叹气),因此源文件可以是几种不同的文件格式,浏览器将选择它可以读取的适当格式。

It appears that mono files work best; not all browsers seem to support stereo sound files. This is because the browser will convert the sound to a stereo sound and try to replicate 3D audio (which can be done with only two speakers through a Head Related Transfer Function).

Use mono files for the best compatibility.

视频

因为Video只是一个二维(2D)对象,所以它具有宽度和高度。正如您可能习惯的那样,这不是以像素为单位的,而是以世界单位为单位的,原因在前面讨论过。如果人们将视角移近或移远 2D 视频,它将从每英寸点数的角度改变分辨率。您可能需要尝试大小和视频压缩/存储,以找到质量、下载速度和分辨率(颗粒度)的理想平衡

VideoVideoControl一起使用时效果最好(本章前面已经介绍过)。

此示例显示了一个Video和一个VideoController

<Video 
   style={{height: 3, width: 4}} 
   source={{uri: 'img/Video1.webm'}} 
   playerState={this.state.playerState} 
/> 
<VideoControl 
   style={{height: 0.2, width: 4}} 
   playerState= {this.state.playerState} 
/>

注意,VideoControl不是Video的子项;它是一个具有自己位置的独立对象。在本例中,可能播放 4:3 的视频,它通过this.state.playerState协调停止/启动/暂停活动。实际上,您可以将VideoControlplayerState视为输出,VideoplayerState视为输入。

摄像机和观察

有一个摄影机对象,称为LiveEnvCamera,尽管它不是您通常期望的对象。

在大多数 CAD 系统中,相机设置基本统计信息,如焦距、焦距、相机的观察方向等。

使用 React VR,我们在index.vr.js的顶层有一个<View>;这就是构建 VR 视图的原因。

视图的可见性参数实际上由物理查看设备控制。如果您的 HMD 具有 110 度水平视野,您将看到 110 度水平视野。

这是传统 3D 艺术家必须习惯的东西——虚拟现实是不同的。

Along the same lines, lens flares and other effects, although they look great in movies, look terrible in VR. Your eyes don't have lens flares.

Don't try to add them with React Native.

你可能会想,我们怎么移动摄像机?答案是你改变了<View>。如果要向前移动(例如向前移动 5 米),请向后变换视图 5 米,然后视点将移动到场景中。请注意,这不适用于SpotLight

现场摄像机

此对象显示面向环境的摄影机。这可能是也可能不是查看器硬件的一部分。例如,GearVR 可能有一个面向环境的摄像头;Vive 有,Google 硬纸板可能没有。

相机默认为位置:绝对<LiveEnvCamera />。相机图像显示在距离查看器 1000 米的几何体上。

The LiveEnvCamera is probably intended for Augmented Reality (AR) applications; its use in React VR is experimental at best.

看法

一个View对象既是世界上的初始场景又是相机;聚合世界中的对象也很有用。这样,它与传统 CAD 程序中的组节点非常相似。作为一个分组节点,而不仅仅是主渲染循环,有效地反应 VR 软件是非常重要的。

我们提到视图是摄影机的原因是它具有布局道具和变换。如果,在你的主render()循环中,你变换了<View>,你实际上是在移动相机,你当前的视角,正在看的地方。

如果将<View>用作分组节点,则变换将应用于其所有子节点。您可以通过适当地公开其属性和转换,以这种方式构建关节模型,尽管更可能通过 glTF 文件来实现这一点。

总结

在本章中,我们介绍了 React VR 库的基础知识,其中包含哪些组件,以及它们将用于构建应用的 API 和编码技术。足够的背景!现在我们已经完成了,在下一章中,让我们创建一个实际的 VR 应用。