async await_面向初学者的Async,Await Spark AR脚本指南

async await

This article is first published on GOWAAA.

本文首先在GOWAAA发布

One of the most exciting (and most underrated) updates in Spark AR V91 is the support for Async/await scripting that makes scripting in promise a lot easier to understand! In this article tutorial, I am going to show a few examples of how you can use Async, Await to script in Spark AR much like the article I wrote on scripting in Promise.

Spark AR V91中最令人兴奋(也是最被低估的)更新之一是对Async / await脚本的支持,这使得promise中的脚本更容易理解! 在本文的教程中,我将展示一些示例,说明如何使用Async,Await在Spark AR中编写脚本,就像我在Promise中编写脚本文章一样。

For those unfamiliar with Async/await and are probably wondering what’s the differences with promise, here’s a brief explanation.

对于那些不熟悉Async / await并可能想知道promise与有什么不同的人,这里有一个简短的解释。

  • All functions that return a promise is an async function

    所有返回promise的函数都是异步函数
  • Await is used to call an async function when it is resolved or rejected

    解决或拒绝时,使用Await来调用异步函数
  • Promise.all runs all promise in parallel

    Promise.all并行运行所有承诺
  • Await only runs the next line of code when the current promise is resolved

    当前的诺言得到解决后,“等待”仅运行下一行代码

If the explanation above is too technical for you, you can just think of Async/await as a friendlier alternative for scripting in promise in Spark AR. You can learn both or just learn one to script smoothly without a problem in Spark AR.

如果以上说明对您来说太技术性了,您可以将Async / await视为在Spark AR中使用promise编写脚本的更友好的选择。 您可以学习两者,也可以只学习一种脚本,而无需在Spark AR中顺利进行脚本编写。

使用脚本在Spark AR中查找对象 (Finding Objects In Spark AR With Scripting)

//Pre Promise (V85) Way Of Finding Object
const plane = Scene.root.find('plane0')
//Post Promise (V85-90) Way of Finding Object
Promise.all([
S.root.findFirst('plane0'),
]).then(function(results){
const plane = results[0];
plane.transform.x = 0.5;
})

From V85 — V90, one of the most common way of finding objects from Spark AR in scripting is to use Promise.all. With the support of async, await, you can now find objects in script easier with the following 2 methods.

在V85-V90中,在脚本编写中从Spark AR查找对象的最常见方法之一是使用Promise.all。 有了async,await的支持,您现在可以使用以下两种方法在脚本中更轻松地查找对象。

//V91 Method 1
(async function (){
const planes = await S.root.findByPath('**/plane*');
const canvas = await S.root.findFirst('canvas0');
const text = await S.root.findFirst('3dText0');
const nullobj = await S.root.findFirst('nullObject0');
planes.forEach(plane=>{
plane.transform.x = 0.5;
})
canvas.transform.x = 0.1;
text.text = 'yay to async!';
nullobj.transform.y = 0.1;
})();

In method 1, you can write an empty async function, locate the objects from Spark AR with “await S.root.findFirst(‘your object’) and assign a constant variable name to it just like pre promise time. After that, you can write all the code needed in your filter within the same async function and it will run the same as writing your code in .then(). Just make sure you bracket the whole async function and end off with another pair of brackets for the purpose of calling the function so the codes within it will run.

在方法1中,您可以编写一个空的异步函数,使用“ await S.root.findFirst('your object')”从Spark AR中定位对象,并为其分配一个常量变量名称,就像预承诺时间一样。 之后,您可以在同一个异步函数中编写过滤器中所需的所有代码,其运行方式与在.then()中编写代码的方式相同。 只要确保将整个异步函数放在括号中并以另一对括号结束就可以调用该函数,以便该函数中的代码可以运行。

//Method 2
async function findobj(){
const planes = await S.root.findByPath('**/plane*');
const canvas = await S.root.findFirst('canvas0');
const text = await S.root.findFirst('3dText0');
const nullobj = await S.root.findFirst('nullObject0');
return {
planes: planes,
canvas: canvas,
text: text,
nullobj: nullobj
}
}
//calls the async function which returns a promise
findobj().then(obj =>{
obj.planes.forEach(plane=>{
plane.transform.x = 0.5;
})
obj.canvas.transform.x = 0.1;
obj.text.text = 'yay to async!';
obj.nullobj.transform.y = 0.1;
})

Method 2 is probably more organised but there is probably no difference in term of efficiency compared to method 1. You start by writing a findobj async function with the sole purpose of finding the objects from Spark AR, assign a constant variable and return them when all objects are found. Next, you can call the function findobj which will return a promise; in which case you need to use .then() just like promise.all and write all your code within it. The only difference as compared to using promise.all is you no longer need to remember which obj[num] refers to which objects! You get the object you need, you just need to type obj.yourobjectname which was defined in the async function findobj, within the return {}. As long as you assigned the obj name properly in the async function, calling the objects and changing their value is as simple as pre promise time. The downside of method 2 is that you have more lines of code to write as compared to method 1.

方法2可能更有条理,但与方法1相比,效率方面可能没有差异。您首先编写findobj异步函数,其唯一目的是从Spark AR中找到对象,分配一个常量变量,并在所有对象返回时返回它们找到对象。 接下来,您可以调用函数findobj,该函数将返回promise; 在这种情况下,您需要像promise.all一样使用.then()并在其中编写所有代码。 与使用promise.all相比,唯一的区别是您不再需要记住哪个obj [num]指向哪个对象! 获得所需的对象后,只需在return {}中键入在异步函数findobj中定义的obj.yourobjectname。 只要您在async函数中正确分配了obj名称,调用对象和更改它们的值就如同预承诺时间一样简单。 方法2的缺点是与方法1相比,您需要编写更多的代码行。

热门AR VR文章: (Trending AR VR Articles:)

1. How to use subtle AR filters to survive your Zoom meetings?

1.如何使用微妙的AR滤镜在Zoom会议中生存?

2. The First No-Headset Virtual Monitor

2.第一个无耳机虚拟监视器

3. Augmented reality (AR) is the future of Restaurant Menu?

3.增强现实(AR)是Restaurant Menu的未来吗?

4. Creating remote MR productions

4.创建远程MR产品

For both methods, if you have a new object to add halfway through your project, you would not need to worried about your arrangement of findFirst code and how it will affect the sequence which you called and assigned them like in promise.all. All you need is to assign a new variable name and call it in your code to use it!

对于这两种方法,如果您有一个要在项目中途添加的新对象,则无需担心findFirst代码的安排以及它如何影响您调用和分配它们的顺序(如promise.all)。 您所需要做的就是分配一个新的变量名,并在代码中调用它以使用它!

NOTE: Each line of await is a promise waiting to be resolved before Spark AR will move on to the next line. So the efficiency of your Instagram filter might be affected especially when you have many objects to find from the project. If you are worried about this, stick back to using Promise.all to be safe as that method find objects in parallel instead of line by line using await.

注意:等待的每一行都是一个承诺,在Spark AR移至下一行之前,等待解决。 因此,Instagram过滤器的效率可能会受到影响,特别是当您有很多要从项目中查找的对象时。 如果您对此感到担心,请放心使用Promise.all,因为该方法可以并行查找对象,而不是使用await逐行查找对象。

Personally I prefer method 2, but I will show a mixture of both methods in the examples below.

我个人更喜欢方法2,但在下面的示例中将展示两种方法的混合。

带有脚本的本机UI选择器 (Native UI Picker With Script)

Even though we now have a ready to use patch for native UI, I still insist to use native UI as an example to prevent the art of native UI scripting from being forgotten.

即使我们现在已经准备好使用本机UI补丁,但我仍然坚持以本机UI为例,以防止忘记本机UI脚本。

const S = require('Scene');
const T = require('Textures');
const M = require('Materials');
const NativeUI = require('NativeUI');
//write an async function to find objects
async function findobj(){
const plane = await S.root.findFirst('plane0');
const button1 = await T.findFirst('1');
const button2 = await T.findFirst('2');
const button3 = await T.findFirst('3');
const red = await M.findFirst('red');
const blue = await M.findFirst('blue');
const green = await M.findFirst('green');
return {
plane:plane,
button1:button1,
button2:button2,
button3:button3,
red:red,
blue:blue,
green:green
}
};
//Calls the async function which return a promise, write the remaining codes in it
findobj().then(obj=>{
//Setup configuration
const configuration = {
selectedIndex: 0,

items: [
{image_texture: obj.button1},
{image_texture: obj.button2},
{image_texture: obj.button3}
],
mats: [
{material: obj.red},
{material: obj.green},
{material: obj.blue}
]

};

const picker = NativeUI.picker;
// Load configuration
picker.configure(configuration);
// Show the NativeUI Picker
picker.visible = true;
// This is a monitor that watches for the picker to be used.
picker.selectedIndex.monitor().subscribe(function(val) {
// When a button is selected, we select the corresponding material.
// When they pick the first button then the first material loads, etc

obj.plane.material = configuration.mats[val.newValue].material

});
});

The code is definitely neater now without the need to count & assign obj[num].

现在,该代码绝对是整洁的,无需计算和分配obj [num]。

脚本修补桥 (Script To Patch Bridge)

Lucky for us, there is no major change from V85 when you want to pass value from script to patch.

对我们来说幸运的是,当您要将值从脚本传递到补丁时,V85并没有重大变化。

var mynum = 10;
//Pre Promise
Patches.setScalarValue("num",mynum);
//Post Promise
Patches.inputs.setScalar("num",mynum);

Patch to script, however, has some minor change that makes our life easier.

但是,对脚本的补丁程序有一些细微的变化,使我们的生活更加轻松。

//V85-V90 Promise.all method: 8 lines of code
Promise.all([
S.root.findFirst('2DText0')
//Finding object
]).then(function(results){
const scoretext = results[0];

P.outputs.getScalar('numnew').then(val=>{
val.monitor().subscribe(({newValue}) => {
scoretext.text = newValue.toString();
}) })})
//V91 async,await method 1: 5 lines of code
(async function getvalue(){
const value = await P.outputs.getScalar('numnew');
const scoretext = await S.root.findFirst('2dText0');
scoretext.text = value.toString();
})();

The number of lines of code reduces from 8 to 5, and most important of all, the async, await method makes a lot more sense than promise.all when we just need to get a number from patch to script!

代码行数从8减少到5,最重要的是,async,await方法比promise有意义得多。当我们只需要从补丁到脚本获取一个数字时!

看一下API (Look at API)

Now we look at how async, await can be used to script look at API.

现在我们来看看如何使用异步,等待来编写脚本来查看API。

const S = require('Scene');
const R = require('Reactive');
const Time = require('Time');
async function findobj(){
const plane = await S.root.findFirst('plane0');
const followNull = await S.root.findFirst('followNull');
const targetNull = await S.root.findFirst('targetNull');
return{
plane:plane,
followNull:followNull,
targetNull:targetNull
}
};
findobj().then(obj => {
// Finds an element in the scene
// - Parameters:
// e: The object to find
//const find = e => S.root.find(e); *NOT NEEDED FOR V85*
// Gets the position of an object as an R.point
// - Parameters:
// e: The object to get the transform from
const getPosition = e => R.point(e.transform.x, e.transform.y, e.transform.z);
// Sets the rotation based on a transform
// - Parameters:
// e: The object to rotate
// p: The transform to use
const setRotation = (e, p) => {
e.transform.rotationX = p.rotationX;
e.transform.rotationY = p.rotationY;
e.transform.rotationZ = p.rotationZ;
};
// Look at utility function.
// Because of reactive stupidness, we can't actually apply the lookat directly to the looker itself
// We get around this by nesting the looker object inside a null with no values applied to it's transform
//
// - Parameters:
// _target: The object in the scene you want to face
// _lookerParent: The parent object of the object you want to rotate. Should have no transform applied to it
// _looker: The object that you want to rotate towards the target
const lookAt = (_target, _lookerParent, _looker) => {
const ptToLookAt = getPosition(_target);
const lookAtTransform = _lookerParent.transform.lookAt(ptToLookAt);
setRotation(_looker, lookAtTransform);
};
// Random animation
const scl = R.val(0.1);
obj.targetNull.transform.x = R.sin(Time.ms.mul(R.val(0.001))).mul(scl);
obj.targetNull.transform.y = R.cos(Time.ms.mul(R.val(0.0007))).mul(scl);
obj.targetNull.transform.z = R.sin(Time.ms.mul(R.val(0.0005))).mul(scl);
// Do the look at
lookAt(obj.targetNull, obj.followNull, obj.plane);
})

从脚本获取2D人脸位置 (Getting 2D Face Position from Script)

Finally, we look at how we can get 2D face position with code based on Josh Beckwith’s Vignettes and 2d Face Tracking tutorial.

最后,我们看一下如何使用基于Josh Beckwith的Vignettes和2d Face Tracking教程的代码获得2D人脸位置。

const S = require('Scene');
const R = require('Reactive');
const FaceTracking = require('FaceTracking')
const face = FaceTracking.face(0)
const camCoords = face.cameraTransform.applyTo(face.nose.tip)
//Method 1
(async function(){
const camera = await S.root.findFirst('Camera');
const focalPlane = camera.focalPlane
const u = R.add(R.div(R.div(camCoords.x, R.div(focalPlane.width, 2)), 2), .5)
var v = R.add(R.div(R.div(camCoords.y, R.div(focalPlane.height, 2)), 2), .5)
v = R.sub(1, v)
P.inputs.setPoint(`face_2d`, R.point(u, v, 0));
})();

摘要 (Summary)

Async, await really helps to make coding in promise a lot neater and organised! If you have not yet gotten used to promise, it is highly recommended to just go ahead and get used to async, await! If you are like me, spent hours to get used to promise.all before, life is gonna get better for you buddy!

异步,等待确实有助于使编码更加整洁有序! 如果您还没有习惯承诺,强烈建议您继续并习惯异步,等待! 如果您像我一样,花了几个小时来习惯承诺。在此之前,哥们的生活会变得更好!

I hope this gets you to understand async, await more and let me know if there is anything more you wish for me to add in this article!

我希望这能使您理解异步,等待更多,并告诉我您是否希望在本文中添加更多内容!

Find more useful tips for making Instagram & Facebook filters at GOWAAA!

GOWAAA上找到制作Instagram和Facebook过滤器的更多有用技巧!

Follow us on Instagram to see our filters!

Instagram上关注我们以查看我们的过滤器

Watch our Swizzle Hack Livestream on our Youtube Channel!

在我们的YouTube频道上观看我们的Swizzle Hack直播!

别忘了给我们您的👏! (Don’t forget to give us your 👏 !)

Image for post

翻译自: https://arvrjourney.com/async-await-spark-ar-scripting-guide-for-beginners-3226dd836b02

async await

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值