如何在 glsl 中复制 Photoshop 斜面/浮雕边框效果

Posted

技术标签:

【中文标题】如何在 glsl 中复制 Photoshop 斜面/浮雕边框效果【英文标题】:How to replicate the photoshop bevel/emboss border effect in glsl 【发布时间】:2018-11-18 18:02:24 【问题描述】:

我一直在尝试查找有关如何使用 GLSL 着色器复制 Photoshop 斜角效果的信息。

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

任何建议将不胜感激。

【问题讨论】:

【参考方案1】:

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

我会把这个问题分成两个独立的:

    查找到最近孔的距离和方向。
    根据距离/方向对像素进行着色。

广告。 1.

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

这是棘手的部分。没有太多的数学运算,但你有很多纹理读取和 GPU 不喜欢的if-else。当您增加边框大小时,性能会迅速下降。在执行着色器时,GPU 似乎具有某种“超时”功能,因此即使运行完美的着色器也可能会在执行时间过长时被静默杀死。这些限制可能在 GPU 和/或驱动程序之间有所不同,因此很难说在您的机器上运行的代码是否可以在另一台机器上运行。这很难确定,但可以做到。

广告。 2.

有了距离和方向,你就差不多完成了。如果距离大于边框大小,则当前像素不是边框,否则您将您的方向与一些浅色方向(在您的示例中位于左上角)进行比较,并决定边框应该更亮还是更暗。 您还可以使用距离来影响明暗强度,这样您就可以得到圆形斜坡而不是平坦斜坡。

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

编辑您的评论:

只要您不打算修改每帧的数据,您就可以进行大量预计算。

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

result = max( pix, avg );

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

(不用倒置也可以,你用alpha频道和min代替max,我只是觉得这种方式更容易描述)。

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

这个距离值的梯度会给你一个方向。

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

【讨论】:

感谢您的回答。到目前为止,我只是使用了单独的纹理,并应用了 PS 浮雕效果,并使用默认着色器渲染它们。但是,假设我使用了您建议的这种方法。您指出性能可能是一个问题(让我们忽略超时/机器问题)。您认为使用着色器仅将一组纹理渲染到屏幕外缓冲区然后重用该缓冲区是一个可行的选择吗? (假设渲染的缓冲区没有改变)。还是在 CPU 上进行常规编程是更好的选择?

以上是关于如何在 glsl 中复制 Photoshop 斜面/浮雕边框效果的主要内容,如果未能解决你的问题,请参考以下文章

glsl 着色器 - 颜色混合,正常模式(如在 Photoshop 中)

如何绕过 glsl 统一数组大小限制? [复制]

Unity中,3D角色的移动(斜面上)、跳跃、冲刺

GLSL语法以及如何与程序链接

ShaderJoy —— 漫画 sketch 效果GLSL

arcmap如何计算斜面积