如何在 glsl 中复制 photoshop bevel/emboss 边框效果

How to replicate the photoshop bevel/emboss border effect in glsl

我一直在寻找一些关于如何使用 GLSL 着色器复制 photoshop 斜角效果的信息。

我找到了一些示例着色器,但我似乎无法理解它。我偶然发现了这个问题 https://dsp.stackexchange.com/questions/530/bitmap-alpha-bevel-algorithm, 达到了预期的结果,但我不知道如何将其转换为着色器。

如有任何建议,我们将不胜感激。

首先,我会警告你,这可能很难适应着色器,具体取决于你的 GPU 和所需的质量,但你可以试一试。

我将这个问题分成两个单独的问题:

    1. 找到最近的洞的距离和方向。
    1. 阴影像素基于 distance/direction。

广告。 1.

您想找到最近的像素,其 alpha 值低于某个阈值。你测试你的着色器开始的像素,然后你测试它的邻居(3x3 网格,没有中心),然后他们的邻居(5x5)等等......你继续这个直到你找到一个像素或者你超过了大小你的斜面。

这是棘手的部分。没有太多的数学运算,但是你有很多纹理读取和 if-else GPU 不喜欢的。当您增加边框大小时,性能会下降得非常快。 GPU 在执行着色器时似乎具有某种 'timeout' 功能,因此如果花费太长时间,即使是完美运行的着色器也可能会被悄无声息地杀死。这些限制可能因 GPU and/or 驱动程序而异,因此很难说在您的机器上运行的代码是否也可以在另一台机器上运行。这很难确定,但可以做到。

广告。 2.

有了距离和方向,你就快完成了。如果距离大于边框大小,那么当前像素不是边框,否则你将你的方向与一些 light-dir 进行比较(它在你的示例中是左上角)并决定边框应该更亮还是更暗。 您也可以使用距离来影响 light/dark 强度,这样您就可以获得圆滑的斜坡而不是平坦的斜坡。

所有这些只是最简单的方法。您可以尝试将其拆分为渲染通道、进行一些预计算、缩小纹理、使用 mip-maps 作为四叉树等来加速代码。

编辑您的评论:

只要你不打算修改每帧的数据,你可以预计算很多。

假设您有一个纹理,其中的孔是白色的,其余部分是黑色的,您想要柔化此图像。您编写了一个着色器,对当前像素进行采样(我们称之为 pix)并对它的 8 个相邻像素进行采样并对它们进行平均(我们称之为 avg),然后您调用:

result = max( pix, avg );

这样您将在周围涂上白色,但绝不会使已经是白色的像素变暗。你 运行 这个着色器连续几次以获得更大的涂抹。现在,如果你反转颜色,你会得到类似距离值的东西,对吧:) ?

(不用反转也可以,你用alpha通道和min代替max,我只是觉得这样更容易描述)

此涂片的形状将取决于 avg 值的样本模式。我告诉过你采用 3x3 网格,但你可以在这里试验并使用更多圆形。

这个距离值的渐变会给你一个方向。

您可以更进一步并预先计算您的着色数据。您可以使用要为每个像素添加或减去的值来计算纹理。将此纹理打包到 0-255 范围内。然后,在渲染过程中,您将对该纹理进行采样,从中减去 0.5(移动到 [-0.5,0.5] 范围)并添加到您的源纹理。