今天我要为大家介绍偏导数函数DDX、DDY和FWIT

虽然这些函数主要用于在幕后选择要渲染的MipMap级别

但它们还有许多其他用途

这些正是我今天要重点讲解的内容

偏导数函数概念解释

偏导数概念图解

你可能在微积分项目中听说过偏导数这个概念

但这些C的函数仅与偏导数在概念上相关

因此,在这里你不需要掌握微积分知识

这些函数主要用于返回屏幕上相邻像素之间值的变化量

我们先学习DDX和DDY函数

DDX和DDY函数工作原理

DDX和DDY函数示意图

当分别向右和向上移动一个像素时

比如,将世界坐标传递给一个DDX节点

就能得到向右移动一个像素时世界坐标的变化量

而将UV传递给一个DDY节点

就能得到向上移动一个像素时世界坐标的变化量

你基本上可以将任何变量传递给这些节点并得到有效的结果

这看起来有点神奇

那么它是怎么运作的呢?

片段着色器与GPU并行处理

GPU并行处理示意图

在渲染过程中有一个阶段称为片段阶段,如下图所示:

在这个阶段着色器计算要在屏幕上显示什么颜色

你通常可以认为片段函数在屏幕上的每个像素运行一次

但实际上GPU会同时并行执行四个片段函数

形成一个2x2的像素方块,如下图所示:

这些函数会保持同步运行

因此它们会同时执行相同的代码

这意味着渲染器可以随时获取所有变量的值

在这四个片段函数内部的所有时刻

每个函数处理相邻的像素

当你调用偏导数函数时

渲染器会对比两个相邻像素上变量的变化量

DDX和DDY具体计算方式

DDX和DDY计算图示(当黄色像素为1.0,黄色右侧像素为0.0时,DDX=-1.0)

DDX会返回右边像素的值减去左边像素值

DDY函数返回的是顶部像素值减去底部像素值的结果

需要注意的是这些函数只能在片段着色器阶段使用

你可以试着在Shader Graph中把它连接到顶点着色器阶段

你会发现系统根本不会允许你这样做

ShaderGraph内置了DDX和DDY节点,可用于片元着色器:

如果喜欢手写Shader代码,也可以调用DDX和DDY函数,他们内置于HLSL函数库中:

FWIDTH函数介绍

FWIDTH函数原理图

除了DDX和DDY,另一个常用的计算差值的函数是:FWidth

FWidth函数可以看作是DDX和DDY的结合体

FWidth计算由这两个函数组成的向量的长度

FWidth本质上是一个近似计算

不需要借助毕达哥拉斯定理

它直接对每个偏导数取绝对值后进行求和,这是我仿写的FWidth的实现:

实际上,FWidth作为原生函数内置于HLSL中

(所以无须重新实现,上面的仿写只是为了帮助大家理解)

遗憾的是Shader Graph并未提供专门的FWidth节点

但可以通过自定义函数来实现这一功能

作为替代Shader Graph提供了DDXY节点

这个节点省略了取绝对值的步骤

直接对DDX和DDY进行求和运算

偏导数函数主要用途

偏导数函数应用场景

好,这就是这些偏导数函数的精髓所在

那么它们到底有什么用呢?

它们最主要的用途是确定Mipmap的层级

上图为1级MipMap

上图为5级MipMap

上图为9级MipMap

你能想象到GPU如何利用DDX/DDY函数自动确定MipMap层级吗?

请关注我下期分享

MipMap层级确定的过程在纹理采样时会自动完成

接下来我们来学习这些函数在项目中的实际运用

重建面法线应用

对于普通球体模型,渲染结果通常是光滑球面,如下图:

那么如何渲染获得下图的平面球体呢?

面法线重建示意图

这就需要重建三角形面法线,并实现一个平面着色的Shader

之所以一般渲染的球体是光滑的,是因为:

  • 通常情况下顶点中包含的法线向量
  • 法线向量会在所有相邻面之间进行平均
  • 从而生成平滑的光照曲线

如果你想实现一个平面着色的Shader,就需要让法线指向它所在的三角面

那么你:

  • 首先要对顶点位置求偏导数
  • 然后计算偏导数的叉积

通过上述计算我们可以得到一个垂直于偏导数的向量

这两个偏导数都指向网格的某个面,从而获得平面法线,进而渲染出平面球体

抗锯齿技术应用

抗锯齿效果对比

此外你还可以利用偏导数来低成本地实现模型表面的抗锯齿效果

大家看到的这个着色器会根据UV坐标的U分量是否超过阈值来绘制不同颜色

如果你放大图像就会发现锯齿状的边缘

为了解决这个问题你需要将UV传递给FWidth

通过这种方式你可以得到一个像素范围内的近似UV变化

利用这个变化你可以在阈值两侧构建边界

接下来只需要根据UV在这些边界之间的位置来混合颜色

你可以使用Inverse Lerp和Saturate节点来进行混合

我还专门自定义了一个利用FWidth进行抗锯齿的节点

详细原理和用法可以关注我的分享

完成这些步骤后边缘会变得更加平滑(请与上图对比,或观看本文视频版本会更清晰)

你可以利用这个技术来制作一个漂亮且清晰的卡通着色器(如本节开头所示)

其他应用与总结

程序化形状应用

你也可以将它应用于程序化形状的生成

比如这个螺旋

需要注意的是这种抗锯齿技术的效果不如多采样抗锯齿那么出色

但它的速度要快得多

以上就是DDX、DDY和FWidth函数的全部内容

下期预告

下期视频中我将再次深入讲解MipMaps

看看这些函数如何影响MipMap的选择算法

如果喜欢我的短视频知识分享可以一键三连

更多技术干货也可以访问我的游戏开发网站

参考

  • 完整视频版本请访:ymck.top
  • 更多技术交流请加:alice17173
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐