Spark AR —— 信号绑定与操作【脚本】

691 阅读4分钟

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

143973710_164827641845017_8444225531664743306_n.gif

Spark AR Studio 使用响应式编程模型的一种方法是允许你将值视为信号,这些信号是包含一个可以随时间变化的值的特殊对象。

信号可以绑定到对象的属性,这样当信号的值改变时,对象属性的值就会自动更新。

对于基本数据类型,有一些等效信号,包括数字(ScalarSignal【监控数值标量的信号】)、字符串(StringSignal【监控字符串的信号】)和布尔值(BoolSignal【监控布尔的信号】)。

绑定对象到对象属性

将信号绑定到对象的语法与执行标准赋值相同。

在下面的例子中,我们将来自源对象(用户的脸)的信号绑定到目标对象(plane,平面)上。因此,当 FaceTracking.face(0).cameratransform.rotationY 的信号变化时,plane.transform.x 的值就会被更新。

// 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]
})();

该语句被视为信号绑定,因为赋值操作符(=)的左边值是响应对象,右边值是信号。

如果右值是标准 Scalar、String 或 Bool 类型,则该语句将被视为标准赋值。

转换值为信号

当将数字、字符串或布尔值传递给需要信号的函数或属性设置器(Setter)时,该值会隐式转换为常量信号:

// Load in the required modules
const FaceTracking = require('FaceTracking');

// Enables async/await in JS [part 1]
(async function() { 

    // The numerical value 0.1 is automatically converted to a ScalarSignal
    const mouthOpen = FaceTracking.face(0).mouth.openness.gt(0.1);
    
// Enables async/await in JS [part 2]
})();
             

您还可以使用 ReactiveModule 类公开的 val() 方法显式地将原始数据类型转换为其等效信号(稍后将在用信号进行操作详细介绍这个类)。下面的示例将 Scalar(数值)值转换为 ScalarSignal

// Load in the required modules
const FaceTracking = require('FaceTracking');
const Reactive = require('Reactive');

// Enables async/await in JS [part 1]
(async function() { 

    // Convert the numerical value 0.1 to a ScalarSignal
    const scalarSignal = Reactive.val(0.1);
    
    // Use the converted value
    const mouthOpen = FaceTracking.face(0).mouth.openness.gt(scalarSignal);

// Enables async/await in JS [part 2]
})();
      

您可以使用相同的方法将布尔值转换为 BoolSignal,或将字符串转换为 StringSignal

// Load in the required modules
const Reactive = require('Reactive');

// Enables async/await in JS [part 1]
(async function() { 

    // Convert the bool value 'true' to a BoolSignal
    const boolSignal = Reactive.val(true);
    
    // Convert the string value to a StringSignal
    const stringSignal = Reactive.val("This is a string");

// Enables async/await in JS [part 2]
})();

从信号中检索值

如果你需要检索一个信号包含的值,你可以使用由 ScalarSignal, StringSignalBoolSignal 类公开的 pinLastValue() 方法:

// Load in the required modules
const Diagnostics = require('Diagnostics');
const FaceTracking = require('FaceTracking');

// Enables async/await in JS [part 1]
(async function() { 

    // Get the value of mouth openness when this line of code is executed
    const mouthOpennessValue = FaceTracking.face(0).mouth.openness.pinLastValue();
    
    // Log the value
    Diagnostics.log(mouthOpennessValue);

// Enables async/await in JS [part 2]
})();

当值随时间变化时,将返回调用方法之前信号所包含的最后一个值。

或者,可以通过 subscribeWithSnapshot() 方法订阅事件,该方法提供信号的值,以便在回调函数中使用:

// Load in the required modules
const Diagnostics = require('Diagnostics');
const FaceTracking = require('FaceTracking');
const TouchGestures = require('TouchGestures');

// Enables async/await in JS [part 1]
(async function() { 

    // Subscribe to tap gestures
    TouchGestures.onTap().subscribeWithSnapshot({
        
        // Get the value of mouth openness when the tap gesture is detected
        'val' : FaceTracking.face(0).mouth.openness
        
    }, function (gesture, snapshot) {
    
        // Log the value from the snapshot
        Diagnostics.log(snapshot.val);
    });

// Enables async/await in JS [part 2]
})();

用信号进行操作

由于它们的值随时间而变化,标准的 JavaScript 操作符,如 +、-、* 和 / 不能直接在信号上执行。

作为替代,这些类型的计算是通过 ReactiveModule 类和 ScalarSignal 类公开的方法执行的,如下面的示例所示。

// Load in modules
const Diagnostics = require('Diagnostics');
const Reactive = require('Reactive');

// Enables async/await in JS [part 1]
(async function() {

    // Create a new scalar signal with an initial value of 5
    const originalValue = Reactive.val(5);

    // Add 1 to the signal with the add() method exposed by the ScalarSignal
    // class and store the result in a new variable
    const valuePlusOne = originalValue.add(1);

    // Add 2 to the signal with the add() method exposed by the ReactiveModule
    // class and store the result in a new variable
    const valuePlusTwo = Reactive.add(originalValue, 2);

    // Multiply the signal by 2 with the mul() method exposed by the ReactiveModule
    // class and store the result in a new variable
    const valueDoubled = Reactive.mul(originalValue, 2);

    // Log the signals' values to the console
    Diagnostics.log(originalValue.pinLastValue());
    Diagnostics.log(valuePlusOne.pinLastValue());
    Diagnostics.log(valuePlusTwo.pinLastValue());
    Diagnostics.log(valueDoubled.pinLastValue());

// Enables async/await in JS [part 2]    
})();

此外,BoolSignalStringSignal 类公开了它们自己的一组用于操作信号的方法:

// Load in modules
const Diagnostics = require('Diagnostics');
const Reactive = require('Reactive');

// Enables async/await in JS [part 1]
(async function() {

    // Create a BoolSignal object
    const boolSignal = Reactive.val(true);

    // Perform a logical 'not' operation with boolSignal and store the result in a new variable
    const newBool = boolSignal.not();

    // Create a StringSignal object
    const stringSignal = Reactive.val("This is a string");

    // Concatenate 'stringSignal' with a new string and store the result in a new variable
    const newString = stringSignal.concat(" made longer.");

    // Log the signals' values to the console
    Diagnostics.log(boolSignal.pinLastValue());
    Diagnostics.log(newBool.pinLastValue());
    Diagnostics.log(stringSignal.pinLastValue());
    Diagnostics.log(newString.pinLastValue());

// Enables async/await in JS [part 2]
})();

监视一个信号的值

DiagnosticsModule (支持诊断日志记录)类暴露的 watch() 方法允许您向 Spark AR Studio 中 的 watch 视图添加一个信号,以监控其值如何随时间变化。

// Load in the required modules
const Diagnostics = require('Diagnostics');
const FaceTracking = require('FaceTracking');

// Add the mouth openness signal to the watch view
Diagnostics.watch("Mouth Openness - ", FaceTracking.face(0).mouth.openness);

观察视图出现在控制台的右上方:

143973710_164827641845017_8444225531664743306_n.gif