如何在GLSL中渲染一个无限的2D网格?

21

理想情况下,我想做的是绘制一个矩形,让GLSL处理实际网格线的创建。

到目前为止,我的尝试中顶点着色器:

#version 400

layout (location = 0) in vec4 in_position;
layout (location = 2) in vec3 in_UV;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

smooth out vec3 ex_UV;
smooth out vec3 ex_originalPosition;

void main()
{
    gl_Position = projection * view * model * in_position;

    ex_UV = in_UV;
    ex_originalPosition = vec3(in_position.xyz);
}

模型矩阵将四边形进行放大,例如10,000倍。

#version 400

layout (location = 0) out vec4 color;

smooth in vec3 ex_UV;
smooth in vec3 ex_originalPosition;

uniform vec4 lineColor;

void main(void)
{
    if(fract(ex_UV.x / 0.001f) < 0.01f || fract(ex_UV.y / 0.001f) < 0.01f)
        color = lineColor;
    else
        color = vec4(0);
}

我尝试过使用纹理坐标和世界空间位置。两者的效果都相同,某些角度看起来很好,但在其他角度看起来很糟糕。

图片描述

图片描述

我想也许可以根据距离缩放透明度,使得网格渐渐消失,但问题在于,就像第二张图片中所显示的那样,从屏幕中心开始,即使是那些线条也会呈现出间隙(网格的目的是为原点提供视觉参考框架)。

有没有更简单的方法呢?

编辑

如要求所示的屏幕截图:

VBO 线段与 x8 多重采样帧缓冲区

图片描述

VBO 线段与 x8 多重采样帧缓冲区和 glEnable(GL_LINE_SMOOTH)

图片描述

最终选择

我选择了其中任一(不太重要),并根据距离原点的距离简单降低了透明度。虽然这符合我的目的,但并不是我问的问题。 图片描述


我很想看到使用GL_LINES和多重采样的结果。你能发布一张截图作为更新吗? - jozxyqk
结果基本上与您的问题完全相同。不过最后我发现我实际上并不需要一个无限平面,所以我使用了一个更小的四边形,其alpha值从原点开始呈圆形渐变。虽然我认为您的答案对于我所提出的实际问题是正确的,但这个方法已经满足了我的需求。 - NeomerArcana
2个回答

22
一个简单的镜像案例。就像多边形渲染一样,每个像素都会运行一次片段着色器。颜色仅计算单个中心坐标,并不能代表真实颜色。

enter image description here

  1. 您可以创建一个多采样FBO并启用超级采样。但这很昂贵。
  2. 您可以在片段着色器中精确地计算每个像素下的线区域和空网格区域的面积,然后相应地上色。考虑到这是一个均匀网格,这可能是可能的,但数学可能仍然变得非常复杂。
  3. mipmapping 已经为纹理完成了此操作。创建一个只有几条线的网格纹理,并将其映射到重复你的非常大的四边形(请确保设置 GL_REPEAT )。为纹理设置正确的mipmap过滤参数并调用 glGenerateMipmap。当您在片段着色器中调用texture2D() / texture()时,OpenGL会根据相邻像素之间的纹理坐标差异自动计算使用哪个mipmap级别。最后,设置各向异性过滤以获得更惊人的网格外观。

    enter image description here

如果您希望网格真正“无限”,我已经看过一些海洋渲染器将网格边缘连接到地平线,并使用垂直几何形状。如果您有足够的网格在它们之前,可能可以将它们设置为一个平面颜色-您mipmap的顶层颜色。


示例(有关评论):

从VBO绘制的1024x2 GL_LINES
enter image description here
45fps(以HD分辨率为基准画了100次)

请参阅有关多重采样以解决GL_LINES镜像的注释。

映射到具有mipmapping的四边形的32^2纹理
enter image description here
954fps(以HD分辨率为基准画了100次)

Image img;
int w = 128;
int h = 128;
img.resize(w, h, 1);
for (int j = 0; j < h; ++j)
    for (int i = 0; i < w; ++i)
        img.data[j*w + i] = (i < w / 16 || j < h / 16 ? 255 : 0);

tex = img.upload();

glBindTexture(GL_TEXTURE_2D, tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);

...

//for the quick and dirty, immediate mode
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
glBegin(GL_QUADS);
glTexCoord2f(0,       0); glVertex3f(0, 0, 0);
glTexCoord2f(1024,    0); glVertex3f(1, 0, 0);
glTexCoord2f(1024, 1024); glVertex3f(1, 0, 1);
glTexCoord2f(0,    1024); glVertex3f(0, 0, 1);
glEnd();
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);

2
纹理并不能保证线条无缝。此外,您引入了许多不必要的片段处理和采样,在线条方法中只运行实际对线条有贡献的片段。目标只是绘制一个2D网格,而对我来说,您所有的方法都是巨大的过度设计。 - Bartek Banachewicz
1
对于您提出的第一个问题,他特别提供了应用纹理以实现抗锯齿线条的技巧,并比较了朴素地给四边形贴图和优雅地进行贴图的效果。对于第二个问题,我们仍需要引用哪种技术更快的资料。 - Blarglenarf
有趣的性能结果。现在我可以毫不犹豫地点赞了 :) - Bartek Banachewicz

1
你可以看到,即使是那些线条也存在间隙。

当然了,我们能看到。这是因为你得罪了CG 101。(不要介意 :)

我们使用GL_LINES有一个原因;在计算机屏幕上绘制无间隙的线条并不容易(虽然已经解决了)。我指的是像这样的东西。你所做的是对浮点数进行计算,这将导致子像素线被绘制(即间隙)。

我的建议是放弃这个GLSL代码,使用常规顶点生成线条。这可能会更快,并且您将获得正确的结果。

您还可以使用常规雾计算来实现您想要的“渐隐效果”。


@NeomerArcana 如果你真的想在着色器中实现它(你可以闻到空气中的味道:D),那么我会绘制一个四边形并将其细分为所需的密度。同样,这将利用事先制作的硬件支持来承受这样的负载。除此之外,你可以在几何着色器中修剪原始图形,因此将每个三角形缩小为线条应该是可以的。只需使用“layout(triangles) in; layout(lines) out;”即可。 - Bartek Banachewicz
@NeomerArcana 只是想澄清一下,我打算使用镶嵌着色器;在几何着色器中每个三角形输出一行是可以的。但如果每个三角形输出成千上万行,那就不行了! - Bartek Banachewicz
公正的说,我还没有对其进行基准测试,所以我只能说我怀疑它会慢得多。OP想要一个看起来流畅的网格。按照当前答案描述的方式绘制没有任何抗锯齿处理的线条原语将无法给他们想要的结果。 - jozxyqk
是的,理想情况下,它们应该是漂亮的并且抗锯齿的。 - NeomerArcana
2
似乎并不重要,我正在使用多采样缓冲区,到目前为止GL_LINES渲染得非常好,并且具有抗锯齿效果。 - NeomerArcana
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接