简体   繁体   English

使用片段着色器在2d多边形上绘制边框

[英]Drawing a border on a 2d polygon with a fragment shader

I have some simple polygons (fewer than 20 vertices) rendering flat on a simple xy plane, using GL_TRIANGLES and a flat color, a 2d simulation. 我有一些简单的多边形(少于20个顶点)在一个简单的xy平面上渲染平面,使用GL_TRIANGLES和一个平面颜色,一个2d模拟。

I would like to add a border of variable thickness and a different color to these polygons. 我想为这些多边形添加可变厚度和不同颜色的边框。 I have something implemented using the same vertices and glLineWidth/GL_LINE_LOOP, which works, but is another rendering pass and repeats all the vertex transforms. 我有一些使用相同顶点和glLineWidth / GL_LINE_LOOP实现的东西,它起作用,但是是另一个渲染过程并重复所有顶点变换。

I think I should be able to do this in the fragment shader using gl_FragCoord and the vertex data and/or texture coordinates, but I'm not sure, and my naive attempts have been obviously incorrect. 我想我应该能够使用gl_FragCoord和顶点数据和/或纹理坐标在片段着色器中完成此操作,但我不确定,我的天真尝试显然是不正确的。

I imagine something like the following. 我想象下面的东西。

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;
    }
}

The part I'm trying to figure out is the distance_from_edge function - how can that be calculated? 我想弄清楚的部分是distance_from_edge函数 - 如何计算? Is using gl_FragCoord the wrong approach - should I be using some kind of texture mapping? 使用gl_FragCoord是错误的方法 - 我应该使用某种纹理映射吗?

As an experiment I tried converting the vertex to pixel space with the scale, and then calculate the distance between that and gl_FragCoord in pixels, but that give strange results that I didn't really understand. 作为一个实验,我尝试用缩放将顶点转换为像素空间,然后以像素为单位计算它与gl_FragCoord之间的距离,但这会产生我并不真正理解的奇怪结果。 Plus I need the distance to the edge , not the vertex, but I'm not sure how to get that. 另外我需要到边缘的距离,而不是顶点,但我不知道如何得到它。

Any ideas? 有任何想法吗?

EDIT: based on Nicol's response, my question becomes: 编辑:根据尼科尔的回应,我的问题变成:

Assuming I have a triangle with 3 corner vertices marked as edge vertices, and one vertex in the middle marked as not edge (so rendered with 3 triangles in total), then how do I interpolate in the fragment shader to draw a border of a given thickness? 假设我有一个三角形,其中3个角顶点标记为边缘顶点,并且中间的一个顶点标记为非边缘(因此总共渲染了3个三角形),那么如何在片段着色器中插值以绘制给定边框厚度? I am assuming I pass the edge flag to the fragment shader, as well as the desired line thickness, and it does some interpolation calculation to figure out the distance between the edge and not edge vertices, and thresholds the color as border/fill as appropriate? 我假设我将边缘标志传递给片段着色器,以及所需的线条粗细,并进行一些插值计算以计算边缘与非边缘顶点之间的距离,并将颜色阈值设置为适当的边界/填充?

All you need are the barycentric coordinates, since you are dealing with triangles. 所有你需要的是重心坐标,因为你正在处理三角形。 Assign each vertex of the triangle an identity, and then use the hardware's built-in interpolation between the vertex and fragment stages to figure out the relative distance from each of the vertices in your fragment shader. 为三角形的每个顶点分配一个标识,然后使用硬件在顶点和片段阶段之间的内置插值来计算片段着色器中每个顶点的相对距离。

You can think of the barycentric coordinates for each vertex as the distance from the opposite edge. 您可以将每个顶点的重心坐标视为距相对边缘的距离。 In the diagram below, vertex P0's opposite edge is e1, and its distance is represented by h1; 在下图中,顶点P0的相对边是e1,它的距离用h1表示; its barycentric coordinate is <0.0, h1, 0.0> . 其重心坐标<0.0, h1, 0.0> GPUs may use this coordinate space internally to interpolate vertex attributes for triangles when fragments are generated during rasterization, it makes quick work of weighting per-vertex properties based on location within a triangle. 当在光栅化期间生成片段时,GPU可以在内部使用此坐标空间来插入三角形的顶点属性,它可以基于三角形内的位置快速加工每顶点属性。

图解说明了从每个边缘计算距离

Below are two tutorials that explain how to do this, typically this is used for rendering a wireframe overlay so you might have better luck searching for that. 下面是两个教程,解释了如何执行此操作,通常这用于渲染线框覆盖,以便您可以更好地搜索它。 For your purposes, since this is effectively a specialization of wireframe rendering (with the addition that you want to throw out lines that do not belong to exterior polygon edges), you will need to identify edge vertices and perform additional processing. 出于您的目的,由于这实际上是线框渲染的特化(除了您想要抛出不属于外部多边形边的线),您还需要识别边缘顶点并执行其他处理。

For instance, if a vertex is not part of an exterior edge, then you will want to assign it a barycentric coordinate of something like <1,100,0> and the connected vertex <0,100,1> and the interior edge will be ignored (assuming it is an edge opposite the vertex designated <0,1,0>, as seen in the diagram below). 例如,如果顶点不是外边缘的一部分,那么你需要为它分配一个像<1,100,0>和连接顶点<0,100,1>之类的重心坐标,并忽略内边缘(假设它是一个与指定<0,1,0>的顶点相对的边,如下图所示。 The idea is that you never want a point along this edge to interpolate anywhere near 0.0 (or whatever your threshold you use for shading a fragment as part of the border), making it extremely distant from the center of the triangle in the direction of the opposite vertex will solve this. 这个想法是你永远不希望沿着这个边缘的点插值到0.0附近的任何位置(或者你用来将一个片段作为边界的一部分着色的任何阈值),使它与三角形的中心相距极远。相反的顶点将解决这个问题。

该图显示了如何排除内部边缘

Without Geometry Shaders (OpenGL ES friendly): 没有几何着色器(OpenGL ES友好):

Here's a link explaining how to do this, if you are able to modify your vertex data to hold the barycentric coordinates. 这是一个解释如何执行此操作的链接,如果您能够修改顶点数据以保持重心坐标。 It has higher storage and pre-processing requirements (in particular, sharing of vertices between adjacent edges may no longer be possible since you need each triangle to consist of three vertices that each have a different input barycentric coordinate - which is why geometry shaders are a desirable solution). 它具有更高的存储和预处理要求(特别是,相邻边缘之间的顶点共享可能不再可能,因为您需要每个三角形由三个顶点组成,每个顶点具有不同的输入重心坐标 - 这就是为什么几何着色器是一个理想的解决方案) However, it will run on a lot more OpenGL ES class hardware than more general solutions that require geometry shaders. 但是,它将运行在比需要几何着色器的更通用解决方案更多的OpenGL ES类硬件上。

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

With Geometry Shaders ( Not OpenGL ES friendly): 使用几何着色器( OpenGL ES友好):

Alternatively, you can use a geometry shader to compute the barycentric coordinates for each triangle at render-time as seen in this tutorial. 或者,您可以使用几何着色器在渲染时计算每个三角形的重心坐标,如本教程中所示。 Chances are in OpenGL ES you will not have access to geometry shaders, so this can probably be ignored. 有可能在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 http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_10.html http://strattonbrazil.blogspot.com/2011/09/single-pass-wireframe-rendering_11.html

The theoretical basis for this solution can be found here (courtesy of the Internet Archive Wayback Machine): 这个解决方案的理论基础可以在这里找到(由Internet Archive Wayback Machine提供):

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM