虚拟现实 (VR) 正在进入各个行业,但尚未成为主流。 WebVR 和边缘计算有可能提高 VR 的采用率并将 VR 带给更广泛的受众。 在本系列文章中,我会向你介绍 WebVR 和边缘计算的基础知识,并附有详细的示例。

虚拟现实(VR)是一个巨大的技术浪潮,它已经到来。 无论你第一次拿着智能手机时的感受如何,第一次体验 VR 时计算机都会在各个方面提供更丰富的情感体验。 作为一个概念,VR 的存在时间比第一部 iphone 的时间更长,但将 VR 带给普通用户所需的技术直到最近才出现。

Oculus Quest 是 Facebook 的 VR 消费者游戏平台。 它的主要特点是不需要PC。 **因为它提供无线、移动的 VR 体验。 **你可以在咖啡店里给某人一个 VR 头显来分享一个 3D 模型,虽然这么做与在对话中使用谷歌搜索一样尴尬,但它的共享体验所带来的的回报却更引人注目。因此,我可以预见的是,VR 将改变我们工作、购物、分享内容等的方式。

在本系列中,我们将探索当前支持 WebVR 和浏览器边缘计算的浏览器技术。 本篇文章重点介绍会使用到的这些相关技术。

为了探索这项技术,我制作了一个 Canvas 和 WebVR 演示。

在这里插入图片描述

VR 对用户体验意味着什么?

就像在移动设备上那样,娱乐内容将会引领虚拟现实技术的普及。然而,一旦 VR 像移动应用一样成为主流,或许行业里就会蹦出这么一句:“VR First”,即 VR 优先。对于设计师和开发人员来说,这是一个非常激动人心的时刻,因为 VR 是一种完全不同的设计范式。

VR 始于个人计算 (PC) 革命,但正在作为移动革命的下一步到来。 Facebook 的 Oculus Quest 使用高通公司的 Snapdragon 835 系统级芯片 (SoC)、耳机跟踪(使用移动摄像头)在 Google Cardboard 上构建,并在 Android 上运行。所有这些技术都经过封装的,可以舒适地安装在你脸部的柔软感觉器官上。

VR 的行业应用

VR 开始在众多行业和计算领域中得到体现。 除了经常受到媒体报道的内容消费和游戏之外,VR 正在从建筑到医疗保健行业慢慢改变。

  • 建筑和房地产以非凡的成本创造了物理现实的价值,因此建筑师和房地产经纪人很适合通过虚拟现实来展示客户体验。
  • VR 在学习和教育中可以传达原本无法通过图像或视频复制的体验。
  • 汽车公司也从 VR 中受益了,从设计、安全到培训和营销方方面面。
  • 斯坦福大学露西尔帕卡德儿童医院的医疗保健专业人员一直在使用 VR 来计划心脏手术,让他们能够在进行单个切口之前了解患者的解剖结构。 VR 也正在取代药物来缓解疼痛。
  • 零售、营销和酒店业也已经提供产品和地点来供顾客进行虚拟游览。

随着技术的进步,我们将看到各个行业增加对 VR 的采用。 现在的问题是这种转变将以多快的速度发生,哪些行业将受到最大的影响。

VR 对 Web 和边缘计算意味着什么

“边缘计算”是将计算从你的主应用服务器集群中移出,并更靠近你的最终用户。 这个技术引起了营销行情,因为托管公司迫不及待地在每个城市为你租用低延迟服务器。
例如,在 B2C 边缘计算中, Google 的 Stadia 服务就是其中一个,它在 Google 的服务器上运行 CPU/GPU 密集型游戏工作负载,然后将游戏发送到 Netflix 等设备。 任何笨拙的 Netflix Chromebook 都可以突然像高端游戏电脑一样玩游戏
而 B2B 边缘计算中,Nvidia 的 GRID 可以为廉价的 Netflix 类设备提供支持 Nvidia GPU 的虚拟远程工作站

问题:为什么不将边缘计算从数据中心转移到浏览器中?

答案是可以的。其中,浏览器边缘计算的一个案例就是计算机的“动画渲染农场”,它通过将长达一天的过程分解成数以千计的计算机可以在几分钟内处理的块来渲染 3D 电影

Electron 和 NW.js 等技术将 Web 编程带入了桌面应用程序。 新的浏览器技术(如 PWA)正在将 Web 应用程序分发模型带回桌面计算。 用户无需下载安装程序,现在只需访问网站即可加入计算场中。

问题:WebVR 是“真实的东西”吗?

WebVR 是真实存在的。 浏览器的边缘计算可以使用相同的 API 来访问支持 WebVR 的计算能力。为了验证这一点,我将对 N 体问题进行天体物理学模拟。

N体问题是指找出已知初始位置、速度和质量的多个物体在经典力学情况下的后续运动

天文学家可以使用方程式来计算两个物体之间的引力。 然而,对于具有三个或更多物体的系统,没有方程,这对于已知宇宙中的每个系统来说都是不方便的。

虽然 n 体问题没有解析方程,但它确实有一个计算解,即 O(n²)。 O(n²) 几乎是最坏的情况。

在这里插入图片描述

n-body 解决方案也让我们置身于物理/游戏引擎的世界,探索 WebVR 所需的技术。

在这里插入图片描述

Web Workers、WebAssembly、AssemblyScript、Canvas、Rollup、WebVR、Aframe

一系列新的 Web 技术,已经出现在现代移动浏览器。例如我们可以:

  • 使用 Web Workers 模拟转移到自己的 CPU 线程中,以便提高感知和实际性能。
  • 使用 WebAssembly 在提升编译代码的运行效率。
  • 使用 Canvas 进行 2D 可视化模拟。
  • 使用 Rollup 和 Gulp 作为 Webpack 的轻量级替代品。
  • 使用 WebVR 和 Aframe 为你的手机创建虚拟现实场景。

API 设计和仿真循环

我们的 n 体模拟使用重力来预测天体的位置。 我们可以用方程计算两个对象之间的确切力,但要计算三个或更多对象之间的力,我们需要将模拟分解成小的时间段并进行迭代。 假设我们的目标是 30 帧/秒(或 ~33 毫秒/帧)。
下面有这么一段 index.html 代码:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <style>
    html,
    body,
    #visCanvas {
      margin: 0;
      padding: 0;
      background-color: #1F1F1F;
      overflow: hidden;
      width: 100vw;
      height: 100vh;
    }

    #hud {
      color: white;
      position: absolute;
      top: 10px;
      left: 10px;
    }

    #hud a {
      color: white
    }

    #controls {
      color: white;
    }

    #controls button {
      color: white;
      background-color: green;
    }

    #visPrettyPrint {
      color: white;
      min-width: 310px;
      font-size: 10px;
    }
  </style>
</head>

<body>
  <canvas id="visCanvas"></canvas>

  <div id="hud">
    <h4>Demo: WebAssembly + Web Workers + Canvas</h4>
    <p>This "n-body problem" is CPU intensive, and this demo uses new browser tech to push hardware limits: WebAssembly,
      AssemblyScript, Web Workers, and Canvas.</p>
    <p>Solar system = stars + gas giants + "debris". Here is a barely stable star and 3 gas giants. Can you add inner
      planets, without destabilizing your gas giants?
      <div id="controls">
        <button id="mayhem">Throw Inner Planet Debris!</button>
        &nbsp;&nbsp;- &nbsp;&nbsp;
        <a href="#" target="_blank">Code</a>
        &nbsp;&nbsp;- &nbsp;&nbsp;
        <a class="glow" href="#"> 3d WebVR Version</a>
      </div>

      <pre id="visPrettyPrint"></pre>
  </div>

  <script src="main.js"></script>
</body>

</html>

这段代码中它运行了 main.js :

//  src/main.js

import { nBodyVisPrettyPrint, nBodyVisCanvas } from "./nBodyVisualizer"
import { Body, nBodySimulator } from "./nBodySimulator"

window.onload = function() {
  // 创建一个 nBodySimulator 实例
  const sim = new nBodySimulator()
  
  sim.addVisualization(new nBodyVisPrettyPrint(document.getElementById("visPrettyPrint")))
  sim.addVisualization(new nBodyVisCanvas(document.getElementById("visCanvas")))
  //                   name            color     x    y    z    m      vz    vy   vz
  sim.addBody(new Body("star",         "yellow", 0,   0,   0,   1e9))
  sim.addBody(new Body("hot jupiter",  "red",   -1,  -1,   0,   1e4,  .24,  -0.05,  0))
  sim.addBody(new Body("cold jupiter", "purple", 4,   4, -.1,   1e4, -.07,   0.04,  0))
  sim.addBody(new Body("asteroid",     "black", -15,  -15,  0,  0))
  sim.addBody(new Body("asteroid",     "black",  15,   15,  0,  0))

  sim.start()
  
  sim.addBody(new Body("saturn",       "blue",  -8,  -8,  .1,   1e3,   .07,   -.035,  0))

  function rando(scale) {
    return (Math.random()-.5) * scale
  }

  document.getElementById("mayhem").addEventListener('click', () => {
    for (let x=0; x<10; x++) {
      sim.addBody(new Body("debris", "white", rando(10), rando(10), rando(10), 1, rando(.1), rando(.1), rando(.1)))
    }
  })

}
  1. 它创建了一个新的 nBodySimulator()
  2. 同时,这个 nBodySimulator 实例包含了一些API:
  • sim.addVisualization()
  • sim.addBody()
  • sim.start()


这两颗小行星的质量为零,因此不受重力影响。 他们将我们的 2D 可视化缩小到至少 30x30。 最后一段代码是用于添加 10 个小内行星以获得的按钮事件!

接下来是我们的“模拟循环”——每 33 毫秒,重新计算和重新绘制。 如果你玩得开心,我们可以称之为“游戏循环”。 可能实现我们的循环的最简单的事情是 setTimeout() - 这实现了我的目的。 另一种方法是 requestAnimationFrame()。

sim.start() 通过每 33 毫秒(大约每秒 30 帧)调用 sim.step() 来启动操作。

// Methods from class nBodySimulator

  start() {
    const step = this.step.bind(this)
    setInterval(step, this.simulationSpeed)
  }

  async step() {
    if (this.ready()) {
      await this.calculateForces()
    } else {
      console.log(`Skipping:  ${this.workerReady}, ${this.workerCalculating}`)
    }
    this.trimDebris()
    this.applyForces()
    this.visualize()
  }


我们将在 WebAssembly 中实现物理计算,并在单独的 Web Worker 线程中运行它们。

  1. nBodySimulator 包装了该实现的复杂性并将其拆分为几个部分:
  • calculateForces() 承诺计算要应用的力。这些主要是浮点运算并在 WebAssembly 中完成。
  • 这些计算是 O(n²) 和我们的性能瓶颈。
  • 我们使用 Web Worker 将它们移出主线程,以获得更好的感知和实际性能。
  1. trimDebris() 删除任何不再有趣的碎片(并且会缩小我们的可视化)。 O(n)
  2. applyForces() 将计算的力应用于实体。 O(n)
  • 如果我们跳过calculateForces(),我们会重用旧的力量,因为工人已经很忙了。 这以准确性为代价提高了感知性能(消除抖动)。
  • 即使计算时间超过 33ms,主 UI 线程也可以绘制旧势力。
  1. Visualize() 将物体数组传递给每个可视化器进行绘制。 O(n)

这一切都发生在 33 毫秒内! 我们可以改进这个设计吗? 是的。 好奇或有什么建议? 检查下面的评论。 如果你正在寻找先进的现代设计和实现,请查看开源的 Matter.js。

结尾

娱乐将引领虚拟现实(如移动)的内容,但一旦 VR 成为常态(如移动),它将成为预期的消费者和生产力体验(如移动)。

我们从未像现在这样更有能力创造人类体验。 成为一名设计师和开发人员从未像现在这样激动人心。 忘记网页——我们将建立世界。

我们的旅程从不起眼的 Web Worker 开始,敬请期待我们 WebVR 系列的下一部分。