我想加载任意网格并沿边缘绘制粗黑线,以获得类似卡通般的阴影。
我通过使用模板缓冲区设法在对象周围绘制了黑色轮廓。您可以在此处看到结果:



但是缺少的是对象本身的黑线。我考虑过检查法线不连续性:检查相邻像素是否具有与当前像素不同的法向向量。如果是,则找到边缘。不幸的是,无论是在OpenGL中还是在GLSL顶点/片段着色器中,我都不知道如何实现这种方法。

我很高兴为这种方法或任何其他有关边缘的方法提供帮助检测。

编辑:我的网格没有使用任何纹理。

太精确了,我想创建一个看起来尽可能像的CAD / CAM解决方案这项(摘自Top Solid https://www.youtube.com/watch?v=-qTJZtYUDB4):



评论

我相信您需要更详细地定义“边缘”。它与简单的线框有何不同?在cifz答案中,对屏幕空间后处理有很好的描述,但是根据您的问题很难确定它是否适用。

好吧,用边缘表示形成实体的“折痕”和“脊”。线框将显示所有三角形的面,这不是我想要的。

好的,正是我要的:-)我将从那些折痕和山脊生成线框。棘手的部分仍然是确定折痕/隆起是什么。你有什么想法吗?

cad程序通常不会使用着色器执行此操作。相反,他们从模型中知道了硬边,并在该信息的网格形式顶部绘制了一条线。

joojaa您是否有关于此技术的更多信息?如果是双曲面自由曲面,该怎么办?我也不确定当圆锥或圆柱体被自由形式的东西切割/修剪时会发生什么。 stackoverflow.com/questions/43795262/…

#1 楼

通常,边缘检测归结为检测具有高梯度值的图像区域。

在我们的例子中,我们可以粗略地将渐变视为图像函数的导数,因此,渐变的幅度为您提供了有关图像局部变化的信息(关于相邻像素/纹理元素) )。现在,正如您所说的,边缘是不连续的指示,因此,既然我们定义了渐变,就很清楚此信息就是我们所需要的。一旦找到图像的梯度,只需对它应用阈值即可获得二进制值的边缘/非边缘。

您如何找到这个梯度确实是您要的问题,我尚未回答:)

很多方法!这里有几个:)

内置着色器功能

hlsl和glsl都提供派生功能。在GLSL中,您可以使用dFdx和dFdy分别为您提供x和y方向上的渐变信息。通常,这些函数以2x2的片段块为单位进行评估。
除非您对单个方向感兴趣,否则,最好的一种紧凑方法是获得紧凑的结果,该结果表明该区域中梯度的强度是fwidth,其他什么都没有但是dFdy和dFdy的绝对值之和。您可能会对整体图像而不是特定通道的边缘感兴趣,因此您可能希望将图像功能转换为亮度。考虑到这一点,在边缘检测方面,着色器可能包括以下内容:

  float luminance = dot(yourFinalColour,vec3(0.2126, 0.7152, 0.0722));
  float gradient = fwidth(luminance );
  float isEdge = gradient > threshold;


阈值较高时,您会发现较粗糙的边缘,并且可能反之,如果错过一些阈值,您可能会检测到虚假边缘。您必须尝试找到最适合您需求的阈值。

这些功能起作用的原因值得一提,但我现在没有时间,我很可能稍后再更新此答案:)

屏幕空间文章-处理

您可能会比这更奇特,现在图像处理中的边缘检测领域非常广阔。我可以根据您的需求援引您数十种检测边缘检测的好方法,但是现在让我们保持简单吧,如果您有兴趣的话,我可以为您提供更多选择!

所以这个想法很相似与上面的方法不同,如果需要,您可以查看更广泛的邻域,并在环绕样本上使用一组权重。通常,您使用内核对图像进行卷积,从而为您提供良好的渐变信息。常见的选择是Sobel内核



分别为您提供x和y方向上的渐变:

q 431。 br />您可以从渐变中获得单个值,例如$ GradientMagnitude = \ sqrt {(Gradient_x)^ 2 +(Gradient_y)^ 2} $

然后您可以像我一样用阈值上面提到过。

您可以看到,该内核为中央像素赋予了更多权重,因此有效地计算了梯度+一点平滑度,这在传统上是有帮助的(通常将图像进行高斯模糊处理以消除小边缘) )。

上面的方法很好用,但是如果您不喜欢平滑,则可以使用Prewitt内核:


q4312010我很着急,很快就会写出正确格式的文本而不是图像!)

确实有很多内核和技术可以以图像处理方式而不是实时图形来发现边缘检测,因此我排除了更多复杂的方法(双关语不是故意的),因为使用dFdx / y函数可能会很好。

评论


$ \ begingroup $
cifz的解释非常好,但是如果在特定情况下看不到渐变怎么办?例如,立方体的背面没有光源,因此看不到渐变。然后,您描述的这种基于图像的边缘检测过程将无法正常工作,对吗?
$ \ endgroup $
– enne87
16年5月18日在7:31

$ \ begingroup $
如果使用延迟渲染器,则可以执行此操作,但是可以在普通缓冲区上执行一次,也可以再次执行该操作。如果您具有预通过,则可以将算法应用于深度。仍然您是对的,屏幕空间方法可能并非在所有情况下都是理想的:)哪种解决方案可行,很大程度上取决于您为此效果准备的预算以及场景的复杂程度。
$ \ endgroup $
–cifz
16年5月19日在7:24



$ \ begingroup $
如果这对于您的游戏而言确实很重要,则非常简单但可能会增加负担,那就是为每个顶点(加载时离线)在您的相邻法线上计算一个梯度,并将此因子作为附加的顶点属性传递。
$ \ endgroup $
–cifz
16年5月19日在7:40

$ \ begingroup $
再次挂起cifz寻求帮助。好吧,我想要实现的是开发一个类似于以下内容的CAD / CAM解决方案:youtube.com/watch?v=-qTJZtYUDB4而且我真的很想知道他们如何管理它来渲染所有黑色边缘,折痕和山脊。 cifz,您认为作为图形编程专家,他们通过使用您的一种屏幕空间方法实现了这种外观吗?还是通过计算相邻法线的梯度?我真的很想知道如何做到这一点。再次感谢!
$ \ endgroup $
– enne87
16年5月19日在9:01

$ \ begingroup $
无需支付任何费用,只需开始在线阅读一些教程,购买一些书并努力学习即可:)最后,这将是非常有益的!
$ \ endgroup $
–cifz
16年5月20日在13:41

#2 楼

以防万一其他人也需要检测边缘:
这是一篇很好的文章,介绍了如何显示线框,而本文介绍了如何仅显示边缘。