Spark AR —— SparkSL 总览【二】

378 阅读3分钟

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

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

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

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

导出函数

函数可以在着色器之间共享,使得重用代码变得容易。

要使一个函数对其他着色器可用,使用 export 关键字。

// FirstShader.sca
                  
 export vec3 red() {
     return 0xFF0000;
 }
                  
 export vec3 green() {
     return 0x00FF00;
 }
                  
 export vec3 blue() {
     return 0x0000FF;
 }

使用这个方法导出的函数可以通过在 #import 指令中包含原始着色器文件来访问其他着色器。

 // SecondShader.sca

 #import <FirstShader.sca>

 vec4 main() {
     return vec4(red() + green() + blue(), 1.0);
 }

组合着色器

与其编写单独的顶点和片段着色器,SparkSL 允许你编写一个单独的组合阶段着色器,然后自动分割成顶点和片段着色器。

默认情况下,框架将尝试在顶点着色器中计算尽可能多的着色器,然后再传递给片段着色器。如果一个计算依赖于一个片段值,那么该计算的结果和所有引用该结果的后续计算将只在片段阶段可用。此外,顶点着色器的值可以通过使用 fragment 函数强制到片段阶段。这允许在每个阶段精确控制可用的数据,同时仍然保持一个单一的着色器。

考虑有下面的组合阶段着色器。

 vec4 main(vec2 uv) {
     float r = length(fragment(uv - 0.5));
     float g = (uv.x + uv.y) * 0.5;
     return vec4(r, g, 0.0, 1.0);
 }

上面的例子是基于如下顶点和碎片着色器优化得到的结果。请注意 varying 变量是自动生成的。

 // [Vertex shader]
     varying vec2 v_var1;
     varying float v_var2;

 void main() {
     // ...
     v_var1 = uv - 0.5;
     v_var2 = (uv.x + uv.y) * 0.5;
 }

 // [Fragment shader]
 varying vec2 v_var1;
 varying float v_var2;

 void main() {
     float r = length(v_var1);
     float g = v_var2;
     gl_FragColor = vec4(r, g, 0.0, 1.0);
 }

注意,顶点值是线性插值到片段阶段,线性操作可以在顶点或片段着色器中执行,而不影响结果。

然而,这并不适用于非线性运算,因为计算的结果会根据所执行的阶段而有所不同。您可以通过使用前面介绍的 fragment 函数将操作的一个参数设置为 fragment 值来强制在片段阶段执行操作。

在决定是在片段阶段还是在顶点阶段执行操作时,需要考虑一些权衡。

  • 在片段着色器中执行的操作通常比在顶点着色器中等效的计算性能更低。

  • 片段着色器操作更容易出现精度问题,因为它们没有提供顶点着色器在精度方面提供的相同保证。

  • 在顶点着色器中执行计算,并在片段着色器中使用结果将导致隐式使用变化。由于 varying 是一种有限的资源,使用大量的 varying 会导致着色器无效。