使用片段着色器在2D多边形上绘制边框 [英] Drawing a border on a 2d polygon with a fragment shader

查看:119
本文介绍了使用片段着色器在2D多边形上绘制边框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些简单的多边形(少于20个顶点)使用GL_TRIANGLES和平坦的颜色(二维模拟)在一个简单的xy平面上平坦化.

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.

我想为这些多边形添加可变厚度的边框和不同的颜色.我已经使用相同的顶点和glLineWidth/GL_LINE_LOOP实现了某些功能,该方法可以正常工作,但又是另一次渲染,并重复了所有顶点转换.

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.

我认为我应该可以使用gl_FragCoord以及顶点数据和/或纹理坐标在片段着色器中执行此操作,但是我不确定,我的幼稚尝试显然是不正确的.

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.

我想像下面的事情.

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是错误的方法-我应该使用某种纹理映射吗?

The part I'm trying to figure out is the distance_from_edge function - how can that be calculated? Is using gl_FragCoord the wrong approach - should I be using some kind of texture mapping?

作为一个实验,我尝试将顶点转换为具有比例的像素空间,然后计算该像素与gl_FragCoord之间的距离(以像素为单位),但得出的结果我并不十分了解.另外,我需要到 edge 的距离,而不是顶点,但是我不确定如何获得该距离.

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. Plus I need the distance to the edge, not the vertex, but I'm not sure how to get that.

有什么想法吗?

根据尼科尔的回答,我的问题变成:

based on Nicol's response, my question becomes:

假设我有一个三角形,其中3个角顶点标记为边缘顶点,中间一个顶点标记为非边缘(因此总共渲染了3个三角形),那么如何在片段着色器中插值以绘制边框给定厚度的?我假设我将边缘标志以及所需的线宽传递给了片段着色器,并且它进行了一些插值计算以找出边缘而非边缘顶点之间的距离,并根据需要将颜色阈值设置为边框/填充?

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? 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.

您可以将每个顶点的重心坐标视为与相对边缘的距离.在下图中,顶点P0的相对边缘为e1,其距离由h1表示;其重心坐标为<0.0, h1, 0.0>.在栅格化过程中生成片段时,GPU可能会在内部使用此坐标空间为三角形内插顶点属性,从而可以根据三角形内的位置快速对每个顶点属性进行加权.

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; its barycentric coordinate is <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.

下面是两个教程,解释了如何执行此操作,通常这是用于渲染线框覆盖图的,因此您可能会更好地进行搜索.出于您的目的,由于这实际上是线框渲染的一种专门技术(此外,您还希望丢弃不属于外部多边形边缘的线),因此您将需要标识边缘顶点并执行其他处理.

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.

例如,如果一个顶点不是外边缘的一部分,那么您将需要为其指定一个重心坐标,例如< 1,100,0>以及所连接的顶点<< 0,100,1>和内部边缘将被忽略(假设它是与指定为< 0,1,0>的顶点相对的边,如下图所示).这个想法是,您永远不希望沿该边缘的点在0.0左右的任何位置进行插值(或您将阴影作为边框的一部分使用的阈值),从而使其在三角形方向上与三角形的中心极距.相反的顶点将解决此问题.

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). 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.

没有几何着色器(对OpenGL ES友好):

如果您能够修改顶点数据以保存重心坐标,则这里有一个链接说明如何执行此操作.它具有更高的存储和预处理要求(尤其是不再可能在相邻边之间共享顶点,因为您需要每个三角形都由三个顶点组成,每个顶点具有不同的输入重心坐标-这就是为什么几何着色器是理想的解决方案).但是,它将比需要几何体着色器的更通用解决方案在更多的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友好):

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.

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

此解决方案的理论基础可以在此处找到(由Internet Archive Wayback Machine提供):

The theoretical basis for this solution can be found here (courtesy of the Internet Archive Wayback Machine):

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

这篇关于使用片段着色器在2D多边形上绘制边框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆