Spark AR —— 响应式编程【脚本】

476 阅读5分钟

这是我参与8月更文挑战的第22天,活动详情查看: 8月更文挑战

Spark AR 是 Facebook 免费创作 AR 作品的平台,使用户能够为 Facebook 和 Instagram 创建交互式增强现实体验,超过 40 万名创作者,190个国家/地区,使用 Spark AR 来创作自己的AR作品

由于该软件无需任何编码知识即可使用,因此任何人现在都可以在 AR 世界中几乎没有经验地制作下一个疯狂式传播的 Instagram AR 特效,引领世界潮流。

专门的 AR 滤镜设计师单价甚至可达到 1000 美元到 3 万美元不等。

SparkAR Studio 使用响应式编程模型,这是一种主要围绕异步数据流和变更传播构建的声明式范例。

什么是响应式编程

响应式编程模型允许您定义对象和值之间的关系,以便绑定到信号的值在信号改变时自动更新。

考虑值 A ,它是绑定给 B 的信号。当B的值发生变化时,系统会对这个变化做出反应,并自动更新 A 的值,而不需要将 B 的新值重新赋给 A。

反应性原则在实践中的一个常见例子是电子表格中的单元格表达式。当单元格 A1 的值依赖于单元格 B2 的值,并且 B2 被更改时,A1 会自动更新。

另一个例子是通用的模型-视图-控制器(MVC)设计模式,在这种模式中,对底层模型的更改会自动反映在相关的视图中。

响应式编程和命令式编程的区别

如果您以前使用过其他开发工具,那么您可能对命令式编程更熟悉。此模型与响应式编程的不同之处在于,语句是按顺序执行的,值仅在表达式计算时设置。

让我们看看这个表达式是如何工作的: x = y + z,其中 y 的值为 5 , z 的值为10。在命令式编程中,x 的值是在计算表达式时设置的,x 的值为 15。

x 的值不会改变,除非它被重新计算,所以即使 y 在以后的时间被赋值为 10 , x 仍然等于 15 。

// With imperative programming, y and z are regular values
var z = 10;
var y = 5;
var x = y + z; 

Console.log(x); // Result: 15

// Even if the value of y changes...
y = 10;

// ...the value of x will not change
Console.log(x); // Result: 15

通过响应式编程,y 和 z 的值可以被视为 x 值的界限所在的信号。给定相同的初始值 x 将等于 15。

然而,如果 y 的值在以后变为 10 , x 的值将自动更新,因为它绑定到 y 。在这种情况下,x 将自动被赋值为 20,而无需显式地重新计算。

// With reactive programming, y and z can be treated as signals
var z = 10;
var y = 5;
var x = y + z; 

Console.log(x); // Result: 15

// If the value of y changes...
y = 10;

// ...the value of x will be automatically updated
Console.log(x); // Result: 20
                    

为什么要使用响应式编程?

由于响应式编程是基于通过持续观察传播数据,所以在执行常见任务(如动画内容或重新调整对象到检测到的人脸)时,引擎不必每一帧都执行 JavaScript 代码。

考虑一个场景,在这个场景中,我们希望对象的 x 位置根据相机视图中人脸的旋转而改变。通常情况下,我们会在更新循环中实现这个逻辑,这意味着 JavaScript 会运行每一帧来更新对象的位置:

// Called every frame, regardless of whether the value of rotation.y has changed or not
function Update(){
    myObject.x = face.rotation.y.currentValue;
}

对于响应式模型,值的更新发生在本地代码而不是 JavaScript 中,从而减少了对应用程序性能的影响。

// Here we only need to bind the y rotation to the x position once
// The reactive model will automatically update the value of x when y changes, avoiding unnecessary calls
myObject.x = face.rotation.y;

响应式模型与可视化编程的兼容性还意味着对脚本引擎的调用频率降低了。这一点和前面的几点都会提高您的效果的性能。

此外,由于响应式模型被设计成无阻塞的,其他数据流可以异步传播而不会产生问题。

这与Spark AR Studio的开发有什么关系?

在 Spark 中使用响应式编程意味着改变在效果运行时对数据流的思考方式。

这主要意味着您能够将值视为信号,这些信号是包含随时间变化的值的特殊对象。通过将这些信号绑定到一个变量或一个对象的属性,你就创建了一个响应系统。

让我们看一下下面的示例,它将来自源对象(用户的脸)的信号绑定到目标对象(平面)。

// Load in the required modules
const Scene = require('Scene');
const FaceTracking = require('FaceTracking');
    
// Enables async/await in JS [part 1]
(async function() {

    // Locate the plane we've added to the Scene panel
    const plane = await Scene.root.findFirst('plane0');
    
    // Bind the user's face rotation in the Y-axis to the X-position of our plane
    plane.transform.x = FaceTracking.face(0).cameraTransform.rotationY;
    
// Enables async/await in JS [part 2]
})();

作为赋值左边的对象,plane.transform.x 是响应式对象,该语句被视为绑定,而不是像在标准 JavaScript 中那样的简单赋值。

要使这些绑定工作,绑定右侧的值必须是一个信号,例如 ScalarSignal 或StringSignal ,而不是标准标量或字符串值。

这意味着,您不是使用命令式风格(使用条件逻辑来控制数据流和执行显式赋值来更新值)编程,而是使用声明式风格编程,在声明式风格中,数据会自动传播。