本文概述
- VR对UX意味着什么
- VR行业应用
- VR对Web和边缘计算的意义
- Web Workers, WebAssembly, AssemblyScript, 画布, 汇总, WebVR, Aframe
- 在深入研究代码之前,先回顾一下架构
- API设计与仿真循环
- 发射!
巨大的技术浪潮已经到来-虚拟现实(VR)。无论你第一次拿着智能手机时的感受如何, 第一次体验VR都会在计算的各个方面带来更丰富的情感体验。距第一部iPhone才十二年。作为一个概念, VR的存在时间甚至更长, 但是直到最近才出现了将VR带给普通用户所需的技术。
Oculus Quest是Facebook的VR消费者游戏平台。它的主要特点是不需要PC。它提供了无线的移动VR体验。你可以将某人的VR耳机交给咖啡店的某人, 以共享3D模型, 而笨拙程度与在对话中搜索某些东西一样, 但是共享体验的回报却更具吸引力。
VR将改变我们的工作, 购物, 享受内容等方式。
在本系列中, 我们将探讨支持WebVR和浏览器边缘计算的当前浏览器技术。第一篇文章重点介绍了这些技术和我们的仿真架构。
在以下文章中, 我们将重点介绍代码中的一些独特挑战和机遇。为了探索这项技术, 我制作了一个Canvas和WebVR演示并将代码发布在GitHub上。
有关更多详细信息, 请参见Canvas演示, WebVR演示和示例代码。
VR对UX意味着什么
作为srcmini开发人员, 我帮助企业将项目从构思到用户的beta测试。那么, VR与业务Web应用程序有何关系?
娱乐内容将引领虚拟现实的普及(就像在移动设备上一样)。但是, 一旦VR像移动设备一样成为主流, ” VR优先设计”将是预期的体验(类似于”移动优先”)。
“移动优先”是一种范式转变, “离线优先”是当前的范式转变, ” VR优先”即将出现。这对于成为设计师和开发人员来说是一个非常激动人心的时刻, 因为VR是一种完全不同的设计范例(我们将在本系列的最后一篇文章中对此进行探讨)。如果你抓不住, 你不是VR设计师。
VR始于个人计算(PC)革命, 但随着移动革命的下一步而来。 Facebook的Oculus Quest使用高通公司的Snapdragon 835片上系统(SoC), 耳机跟踪(使用移动摄像头)在Google Cardboard上构建, 并在Android上运行-所有这些包装都可以舒适地安装在你面部柔嫩的感觉器官上。
售价400美元的Oculus Quest拥有令人惊叹的体验, 我可以与朋友分享。售价1000美元的新iPhone不再给任何人留下深刻的印象。人类不会吐出VR迷。
VR行业应用
虚拟现实开始在众多行业和计算领域中崭露头角。除了内容消费和游戏(它们往往会获得大量媒体报道)之外, VR还在缓慢改变着从建筑到医疗保健的行业。
- 建筑和房地产以不菲的成本(与数字产品相比)创造了物理现实的价值, 因此, 建筑师和房地产经纪人很自然地可以通过虚拟现实带给客户以展示体验。 VR提供了对你2亿美元体育场的” beta测试”, 或者通过电话进行虚拟演练。
- 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应用程序分发模型(SaaS就是关于分发)带回到桌面计算中。示例包括[受电子邮件保护], [受电子邮件保护](蛋白质折叠)之类的项目或各种渲染农场。现在不必访问安装程序, 而只需访问网站即可加入计算场。
问题:WebVR是”真实的东西”还是VR内容会充斥在”应用商店”和围墙花园中?
作为srcmini自由职业者和技术专家, 这是我的工作。因此, 我建立了一个技术原型来回答自己的问题。我发现的答案非常令人兴奋, 因此我撰写了本博客系列文章以与你分享。
剧透:是的, WebVR是真实的东西。是的, 浏览器边缘计算可以使用相同的API来访问启用WebVR的计算能力。
写作很有趣!让我们建立概念验证
为了验证这一点, 我们将对n体问题进行天体物理学模拟。
宇航员可以使用方程式来计算两个物体之间的重力。但是, 对于具有三个或三个以上物体的系统, 没有方程式, 这是已知宇宙中每个系统的不便之处。科学!
尽管n体问题没有解析解(等式), 但确实具有计算解(算法), 为O(n²)。 O(n²)几乎是最糟糕的情况, 但这是如何获得我们想要的东西, 也是为什么首先发明Big O表示法的一种原因。
图2:”在右上方?好吧, 我不是工程师, 但是性能对我来说不错!”
如果你要利用Big O技能, 请记住, Big O表示法会根据算法所处理的数据大小来衡量算法的工作方式。
我们的收藏是模拟中的所有物体。添加新实体意味着为集合中的每个现有实体添加新的两实体重力计算。
虽然我们的内部循环为<n, 但不是<= O(log n), 所以整个算法为O(n²)。这些是休息时间, 没有额外的信用。
for (let i: i32 = 0; i < numBodies; i++) { // n
// Given body i: pair with every body[j] where j > i
for (let j: i32 = i + 1; j < numBodies; j++) { // ½ n is > log n, so n.
// Calculate the force the bodies apply to one another
stuff = stuff
}
}
N-body解决方案还使我们进入了物理/游戏引擎领域, 并探索了WebVR所需的技术。
对于我们的原型, 一旦我们建立了仿真, 我们将进行2D可视化。
最后, 我们将Canvas可视化换成WebVR版本。
如果你不耐烦, 可以直接跳至该项目的代码。
Web Workers, WebAssembly, AssemblyScript, 画布, 汇总, WebVR, Aframe
通过一系列现代技术已经出现在你的现代移动浏览器中(抱歉, 不是Safari), 为充满动感, 充满乐趣的漫游锦上添花:
- 我们将使用Web Workers将模拟移至其自己的CPU线程中-改善感知性能和实际性能。
- 我们将使用WebAssembly在该新线程中以高性能(C / C ++ / Rust / AssemblyScript / etc。)编译的代码运行O(n²)算法。
- 我们将使用Canvas在2D模式下可视化我们的模拟。
- 我们将使用Rollup和Gulp作为Webpack的轻量级替代方案。
- 最后, 我们将使用WebVR和Aframe为你的手机创建虚拟现实。
在深入研究代码之前,先回顾一下架构
我们将从Canvas版本开始, 因为你可能在工作中阅读此版本。
在前几篇文章中, 我们将使用现有的浏览器API来访问创建CPU密集型仿真所需的计算资源, 而不会降低用户体验。
然后, 我们将使用Canvas在浏览器中对此进行可视化, 最后使用Aframe将我们的Canvas可视化交换为WebVR。
API设计与仿真循环
我们的n体模拟使用重力来预测天体的位置。我们可以使用方程式计算两个对象之间的精确力, 但是要计算三个或更多对象之间的力, 我们需要将模拟分解为较小的时间段并进行迭代。我们的目标是30帧/秒(电影速度)或〜33 ms /帧。
为了更容易理解, 以下是代码的快速概述:
- 浏览器GET的index.html
- 运行main.js作为下面的代码。导入由Rollup处理, Webpack的替代方法。
- 这将创建一个新的nBodySimulator()
- 具有外部API:
- sim.addVisualization()
- sim.addBody()
- sim.start()
// src/main.js
import { nBodyVisPrettyPrint, nBodyVisCanvas } from "./nBodyVisualizer"
import { Body, nBodySimulator } from "./nBodySimulator"
window.onload = function() {
// Create a Simulation
const sim = new nBodySimulator()
// Add some visualizers
sim.addVisualization(new nBodyVisPrettyPrint(document.getElementById("visPrettyPrint")))
sim.addVisualization(new nBodyVisCanvas(document.getElementById("visCanvas")))
// This is a simulation, using opinionated G = 6.674e-11
// So boring values are allowed and create systems that collapse over billions of years.
// For spinny, where distance=1, masses of 1e10 are fun.
// Set Z coords to 1 for best visualization in overhead 2D Canvas.
// lol, making up stable universes is hard
// 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))
// A couple far-out asteroids to pin the canvas visualization in place.
sim.addBody(new Body("asteroid", "black", -15, -15, 0, 0))
sim.addBody(new Body("asteroid", "black", 15, 15, 0, 0))
// Start simulation
sim.start()
// Add another
sim.addBody(new Body("saturn", "blue", -8, -8, .1, 1e3, .07, -.035, 0))
// That is the extent of my effort to handcraft a stable solar system.
// We can now play in that system by throwing debris around (inner plants).
// Because that debris will have significantly smaller mass, it won't disturb our stable system (hopefully :-)
// This requires we remove bodies that fly out of bounds past our 30x30 space created by the asteroids.
// See sim.trimDebris(). It's a bit hacky, but my client (me) doesn't want to pay for it and wants the WebVR version.
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)))
}
})
}
这两个小行星的质量为零, 因此不受重力影响。它们使2D可视化缩小到至少30×30。代码的最后一点是我们的”混乱”按钮, 添加了10个小内行星, 以获得一些有趣的乐趣!
接下来是我们的”模拟循环”-每33ms, 重新计算并重新绘制一次。如果你很开心, 我们可以称之为”游戏循环”。实现我们的循环可能最简单的方法是setTimeout()-实现了我的目的。另一种可能是requestAnimationFrame()。
sim.start()通过每33ms(每秒约30帧)调用sim.step()开始操作。
// Methods from class nBodySimulator
// The simulation loop
start() {
// This is the simulation loop. step() calls visualize()
const step = this.step.bind(this)
setInterval(step, this.simulationSpeed)
}
// A step in the simulation loop.
async step() {
// Skip calculation if worker not ready. Runs every 33ms (30fps), so expect skips.
if (this.ready()) {
await this.calculateForces()
} else {
console.log(`Skipping: ${this.workerReady}, ${this.workerCalculating}`)
}
// Remove any "debris" that has traveled out of bounds - this is for the button
this.trimDebris()
// Now Update forces. Reuse old forces if we skipped calculateForces() above
this.applyForces()
// Ta-dah!
this.visualize()
}
欢呼!我们正在从设计过渡到实现。我们将在WebAssembly中实现物理计算, 并在单独的Web Worker线程中运行它们。
nBodySimulator封装了实现的复杂性, 并将其分为几个部分:
- computeForces()承诺计算要施加的力。
- 这些主要是浮点操作, 并在WebAssembly中完成。
- 这些计算是O(n²)和我们的性能瓶颈。
- 我们使用Web Worker将它们移出主线程, 以获得更好的感知和实际性能。
- trimDebris()删除不再有用的所有碎片(并缩小我们的可视化效果)。上)
- applyForces()将计算出的力应用于实体。上)
- 如果由于工人已经很忙而跳过了calculateForces(), 我们将重用旧的力量。这以准确性为代价提高了可感知的性能(消除了抖动)。
- 即使计算时间超过33ms, 主UI线程也可以绘制旧的力。
- visualize()将主体数组传递给每个可视化工具进行绘制。上)
这一切都在33ms内完成!我们可以改善这种设计吗?是。好奇还是有建议?检查下面的评论。如果你正在寻找高级的现代设计和实现, 请查看开源的Matter.js。
发射!
创造这个过程非常有趣, 很高兴与你分享。跳后见!
- 介绍-此页面
- Web Workers-访问多个线程
- WebAssembly-不使用JavaScript的浏览器计算
- 汇总和Gulp-WebPack的替代方法
- 画布-绘制到画布API和” sim循环”
- WebVR-为WebVR和Aframe交换我们的Canvas可视化工具
娱乐将引领虚拟现实(如移动设备)中的内容, 但是一旦VR正常(如移动设备), 它将成为预期的消费者和生产力体验(如移动设备)。
我们从未被赋予创造人类体验的能力。成为设计师和开发商, 再没有比现在更激动人心的时刻了。忘记网页-我们将建立世界。
我们的旅程始于谦虚的Web Worker, 因此请继续关注我们的WebVR系列的下一部分。