2013-08-03 46 views
17

我有一些简单的多边形(少于20个顶点)在简单的xy平面上使用GL_TRIANGLES和平面颜色进行2D模拟。使用片段着色器在2D多边形上绘制边框

我想为这些多边形添加可变厚度和不同颜色的边框。我有使用相同的顶点和glLineWidth/GL_LINE_LOOP实现的东西,它可以工作,但是是另一个渲染过程并重复所有的顶点变换。

我想我应该可以在片段着色器中使用gl_FragCoord和顶点数据和/或纹理坐标来做到这一点,但我不确定,而且我的天真尝试显然不正确。

我想像下面这样。

uniform vec2 scale; // viewport h/w 
uniform float line_width; 
uniform vec4 fill_color; 
uniform vec4 border_color; 

varying vec4 vertex; // in world coords 

void main() 
{ 
    if (distance_from_edge(gl_FragCoord, vertex, scale) < line_width) 
    { 
     // we're close to the edge the polygon, so we're the border. 
     gl_FragColor = border_color; 
    } 
    else 
    { 
     gl_FragColor = fill_color; 
    } 
} 

我试图找出的部分是distance_from_edge函数 - 如何计算?正在使用gl_FragCoord错误的方法 - 我应该使用某种纹理映射吗?

作为一个实验,我试着用顶点将顶点转换为像素空间,然后计算像素与gl_FragCoord之间的距离,但这给出了我不太明白的奇怪结果。另外我需要的距离边缘,而不是顶点,但我不知道如何得到这一点。

任何想法?

编辑:基于尼科尔的反应,我的问题是:

假设我有一个标记为边缘顶点3角落顶点的三角形,并在中间一个顶点标为未EDGE(3个三角形所以呈现总计),那么如何在片段着色器中插入以绘制给定厚度的边界?我假设我将边缘标志传递给了片段着色器,以及所需的线条粗细,并且它会执行一些插值计算来计算边缘与不是边缘顶点之间的距离,并将颜色阈值限制为边框/填充?

+1

'gl_FragCoord'将是大规模对你无益。这只是告诉你片段在屏幕上的位置;它没有说明碎片相对于三角形的位置。顶点位置同样会大量无益。您将需要顶点着色器/用户提供的数据的帮助,该数据根据顶点是否是顶点将顶点的值放入顶点,然后插值。这意味着你无法检测到单个三角形的边缘;您必须将三角形分成几个三角形,以便区分内部顶点和边缘顶点。 –

+0

谢谢,我怀疑我错过了一些东西。所以如果我有一个带有3个顶点的三角形标记为边缘顶点,并且中间的一个不是(用四个三角形渲染),那么如何内插到边界的给定线宽? – bloodearnest

回答

23

所有你需要的是重心坐标,因为你正在处理三角形。为三角形的每个顶点分配一个标识,然后在顶点和片段阶段之间使用硬件的内置插值来计算片段着色器中每个顶点的相对距离。

您可以将每个顶点的重心坐标视为与相对边缘的距离。在下图中,顶点P0的相对边是e1,它的距离用h1表示;其重心坐标是<0.0, h1, 0.0>。当光栅化过程中生成片段时,GPU可以在内部使用该坐标空间来内插三角形的顶点属性,这使得基于三角形内的位置对每个顶点属性进行快速加权。

Diagram illustrating the calculation of distance from each edge

下面是两个教程,解释如何做到这一点,这通常是指用于渲染线框覆盖,所以你可能有更好的运气寻找那个。出于您的目的,由于这实际上是线框渲染的专门化(除了您想要排除不属于外部多边形边线的线),您将需要识别边顶点并执行其他处理。例如,如果顶点不是外部边缘的一部分,那么您将需要为其分配类似于< 1,100,0>和连接顶点< 0,100,1>的重心坐标,并且内部边缘将会被忽略(假定它是一个与指定的顶点< 0,1,0>相反的边,如下图所示)。这个想法是,你永远不需要沿着这条边的一个点插入任何接近0.0的位置(或者你用来为边界的一部分着色一个片段的任何阈值),使它离三角形的中心非常远离方向对面的顶点将解决这个问题。

Diagram showing how to exclude interior edges

无几何着色器(OpenGL ES的友好):

这里的解释如何做到这一点,如果你可以修改你的顶点数据保持重心坐标的链接。它具有较高的存储和预处理要求(特别是,在相邻边之间共享顶点可能不再可行,因为您需要每个三角形由三个顶点组成,每个顶点具有不同的输入重心坐标 - 这就是为什么几何着色器是理想的解决方案)但是,它将运行在比更常见的需要几何着色器的解决方案更多的OpenGL ES类硬件上。

http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/

随着几何着色器(的OpenGL ES型):

或者,您可以使用几何着色器计算在看到了在渲染时每个三角形的重心坐标本教程。很可能在OpenGL ES中,您将无法访问几何着色器,因此可能会忽略它。

http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_10.html http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_11.html

该解决方案的理论基础可以在这里找到(互联网档案Wayback机器提供):

http://web.archive.org/web/ */http://cgg-journal.com/2008-2/06/index.html

+0

谢谢,这让我走在正确的道路上。我已经实现了非几何着色器线框,并且它工作得很好。现在我只需要添加额外的非周长顶点并适当标记。我已经在我自己的实验中部分地沿着这条路线走下去了,但是有1个坐标,而不是3个。 – bloodearnest

+3

理论基础链接已关闭,此处为[替代链接(web档案)](https://web.archive。组织/网络/ 20130607004602/HTTP://cgg-journal.com/2008-2/06/index.html)。来自同一家伙的另一篇论文:[隐藏线移除的抗锯齿线框图的两种方法](http:// orbit.dtu。dk/fedora/objects/orbit:55459/datastreams/file_3735323/content) – fedab

+0

不幸的是,这种技术会导致边界接近顶点的工件。内部三角形边缘可以“切断”边界部分:http://imgur.com/Btl6h2Y。 – John