如何在OpenGL中制作好看的cel着色线?

时间:2014-07-14 13:21:38

标签: c++ opengl 3d shader

我试图通过在线框模式下渲染背面来制作墨迹线(轮廓和内联),如下所示:http://en.wikipedia.org/wiki/Cel_shading

线宽为1的结果足够好了:

good

但是,当我设置较粗的线宽(> 3)时,会发生这种情况:

bad

OpenGL渲染线条作为四边形,导致边缘之间出现空白,并在旋转模型时产生弹出效果。此外,启用多重采样时会出现这些奇怪的尖边:

horrible

我尝试通过将顶点渲染为平滑点来修复空白区域问题,但我找不到合适的方法来正确进行深度无关混合。

是否可以改进此方法以显示漂亮的粗线或我必须依赖着色器?如果是这样,哪种方法首选?

我目前的代码:

glCullFace(GL_FRONT);
glColor3f(0,0,0);
glLineWidth(outlineWidth);
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glEnable(GL_POLYGON_OFFSET_LINE);
glPolygonOffset(1,1);
//draw model with GL_TRIANGLES (yeah, I know...)
glDisable(GL_POLYGON_OFFSET_LINE);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glCullFace(GL_BACK);

1 个答案:

答案 0 :(得分:1)

我认为没有着色器就没有简单的方法来实现你的目标。通常对于抗锯齿线,您可以使用glEnable(GL_LINE_SMOOTH)和glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST)(需要在前一个回复中提到的混合启用),但这不会呈现好的线条上限。

您有两种选择:

  1. 使用基于图像的后处理方法,并使用例如Sobel Filter对深度缓冲区进行边缘检测。为此,您需要在纹理中存储深度缓冲区的线性化版本,并将滤镜实现为片段着色器。
  2. 另一种方法是使用网格数据结构,您可以从中分别提取和渲染所有可见边。这个方法的一个很好的教程可以在http://prideout.net/blog/?p=54找到。
  3. 这两种解决方案都比上面几条OpenGL线要复杂得多。