着色器的ARKit + SceneKit简介


之前我谈到过如何在SceneKit中创建自己的自定义几何,结果您可以使用它们进行某些操作,例如偏斜或动画。

请参阅此处的第2部分的第1部分:

ARKit + SceneKit几何图形教程(第1部分)

在SceneKit中创建自己的几何形状,无需离开即可拥有各种场景和动画。

medium.com

在该系列的第二篇文章的结尾处,我展示了如何使用看起来像字符串的标志来设置标志的动画,这是在SceneKit中向几何体或材质添加着色器的一种方法。

在许多情况下,比起我所展示的其他示例,诸如我上一篇文章底部所示的着色器是使几何图形动画化的更好选择。 主要原因是这些功能由SceneKit接受,编译为Metal,然后在设备的GPU上运行,该GPU比要在其他地方运行的CPU强大得多。 这主要是因为GPU是专门为处理图形而构建的(因此,其名称为Gphphics Processing U nit),所以我们希望尽可能多地使用它!

我想在本文中提到的应用着色器的方法主要是通过使用SCNGeometry对象的shaderModifiers属性。 首先,请看这里:

SCNShadable – SceneKit | Apple开发人员文档

着色器修改器是Metal着色器语言或OpenGL着色器语言(GLSL)中的源代码片段,可用于…

developer.apple.com

作为一个简单的示例,请看以下小片段:

 如果(_geometry.position.y> 0){ 
_geometry.position.x + = 0.5;
}

假设我们将其应用于尺寸为SCNBox类型的几何。

_geometry代表顶点,正如我之前的文章中所述,其位置当然是其在3D空间[x, y, z] 。 在此代码段中,我们获取位置在立方体中心上方的所有顶点,并将其向x方向正方向的侧面推0.5m。

我们可以迅速使它变得更有趣,而无需考虑太多,例如:

 如果(_geometry.position.y> 0){ 
_geometry.position.x + = 0.5 * sin(u_time);
}

u_time是SceneKit开始渲染此着色器以来的时间(以秒为单位)。 因此,这将在正弦缓和之后以平滑的方式将立方体的局部x轴上+0.5的这4个点动画化为-0.5。

最后,我将演示的多维数据集示例是使用单位圆方程将前四个点从沿直线移动更改为沿圆移动。 单击此处以查看Desmos的快速图表,以防万一您不确定该如何组合。

 如果(_geometry.position.y> 0.0){ 
_geometry.position.xz + = vec2(
0.5 * sin(3.0 * u_time),
0.5 * cos(3.0 * u_time)
)*(u_time <3.0?u_time / 3.0:1.0);
}

这里用于制作着色器的语言具有一些不错的功能,例如在上面的示例中,您可以通过直接vec2添加vec2来直接操纵位置的x和y轴。 vec2也可以乘以标量值。 在上面的代码段中,我们在前3秒钟将(sin, cos)圆方程乘以0.0-1.0范围内的值,这只是使动画在开始时不会如此突然。

好的,我看完立方体摆动了。 进入领域!

首先,让我们在SCNSphere上尝试使用相同的着色器,其中仅顶点的上半部分再次在圆周上移动:

我们将再介绍2个带有球体的几何着色器和1个表面着色器。

如果我们看起来有些摇摆不定,那么涟漪就会向上移动。 为此,我们只需要在水平面(x,z)上移动顶点,因为它是一个球体,因此我们可以使它们在平面中的初始位置乘以一个常数(5%的声音听起来足够可见) ,并且随着波纹将沿y轴移动,我们可以将其与时间一起用于我们的正弦函数。

到目前为止,我在想的是:

  _geometry.position.xz + = _geometry.position.xz 
* sin(30.0 * _geometry.position.y-3.0 * u_time)* 0.05
*(u_time <3.0?u_time / 3.0:1.0);

现在到最后一节,我们将把一个黄色的球变成类似于太阳的东西!

我走开了,对Desmos有点混乱,然后想到了这个:

太阳

太阳

Sunwww.desmos.com

好的,所以这可能需要一点时间来理解,尤其是如果您不熟悉径向图。 但是知道r < 1会用虚线填充一个圆,下面方程式中的所有其他内容都添加了该值,并且θ是从x轴正方向起的逆时针角度。 正弦函数之一是随时间移动的,另一个是固定的。 我大部分时间只是在Desmos周围弄乱,找到了可行的方法,这就是我最终得到的结果。

可以使用atan函数来计算float theta = atan(_geometry.position.x, _geometry.position.y); ,如下所示: float theta = atan(_geometry.position.x, _geometry.position.y);

从技术上讲,这是旋转90度,因为我将x值放在第一位,但是出于所有意图和目的,这就像我将x放在y之前一样。

我将尝试直接将其放入着色器中,看看会发生什么:

  float theta = atan(_geometry.position.x,_geometry.position.y); 
浮动pi = 3.14159;
_geometry.position.xy + = _geometry.position.xy
* sin(theta1 * pi-u_time * 2.0)* sin(6.0 * theta1)/ 8;

看起来很有趣,但不像太阳,我将摆脱光线并将背景更改为蓝色。 因为太阳不能受光影响,因为它本身就是光源。

更好一点,但是现在我想让边缘更多地融合到背景上,这是曲面着色器的时间。

尝试使边缘融合时,我们需要查看所有边缘的相似之处。 我要说的相似之处是边缘的法线将远离视图(相机视图)。 找到它的最好方法是取这两个向量的点积,它将为我们提供1-1的值。 如果该值接近1,则法线朝向视图(或摄影机), 0表示垂直于摄影机的视图,而-1表示它是对象的另一侧。

  //我们希望它在边缘上是透明的,所以我们需要这2个 
#pragma透明
#pragma身体
float dotProduct = dot(_surface.view,_surface.normal); //我将其夹紧,因此所有负值都仅为0
dotProduct = dotProduct <0.0? 0.0:dotProduct;
_surface.diffuse.rgb = vec3(1.0,1.0,0.0); float a = dotProduct;
_surface.diffuse = vec4(_surface.diffuse.rgb * a,a);

看起来还可以,但实际上,如果中心的纯色稍大,易于修复,则看起来会更好,只需将其设置为在点积足够小之前就不会开始更改颜色。 以下是此着色器的最终代码段,我突出显示了已更改的行。

  #pragma透明 
#pragma身体
浮点dotProductEdge = 0.5; float dotProduct = dot(_surface.view,_surface.normal);
dotProduct = dotProduct <0.0? 0.0:dotProduct;
_surface.diffuse.rgb = vec3(1.0,1.0,0.0); 如果(dotProduct <= dotProductEdge){
float a = dotProduct / dotProductEdge;
_surface.diffuse = vec4(_surface.diffuse.rgb * a,a);
}

由于我将其称为“ ARKit”着色器简介,因此,我创建了一个存储库,该库显示了如何在ARKit中使用上述所有示例,并且在下面的GIF中将显示其中两个示例。

maxxfrazer / SCNShaderModifier-示例

SceneKit + ARKit中的着色器的基本示例。 为maxxfrazer / SCNShaderModifier做出贡献-通过…开发示例

github.com


感谢您的阅读,我很高兴这篇文章假设您对方程式有很多了解,我建议您打开Desmos链接并在其中使用方程式以尝试更好地理解,尤其是对径向图。

经常在Twitter或LinkedIn上找到我,如果有任何不清楚的地方或对本帖子有任何建议或对未来帖子的想法; 还可以在GitHub上查看我正在从事的其他公共项目。