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

时间:2015-06-15 10:22:36

标签: opengl glsl

理想情况下,我想要做的是绘制一个四边形并让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);
}

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

enter image description here

enter image description here

我想也许我可以根据距离缩放alpha,这样我的网格就会消失,但问题是你可以在第二张图片中看到,从屏幕中心,你可以看到它甚至这些线条通过它们的间隙进行渲染(网格的点是在原点周围给出一个可视的参照系)。

有更简单的方法吗?

修改

根据要求截图:

带有x8多重采样帧缓冲区的VBO行

enter image description here

带有x8多重采样帧缓冲区和glEnable(GL_LINE_SMOOTH)的VBO行

enter image description here

我决定

我确定了上述任何一个(并不重要)并简单地将alpha降低为与原点距离的函数。这符合我的目的,虽然这不是我问的问题。 enter image description here

2 个答案:

答案 0 :(得分:19)

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

enter image description here

  1. 您可以创建多重采样FBO并启用超级采样。但那很贵。
  2. 您可以在数学上精确计算每个像素下的线区域和空网格区域的数量,然后在片段着色器中相应地着色它们。鉴于它是一个统一的网格,这可能属于可能的范围,但数学可能仍然相当复杂。
  3. Mipmapping 已针对纹理执行此操作。创建一个只有几行的网格纹理并对其进行映射,以便为您真正大的四边形重复(确保设置GL_REPEAT)。为纹理设置正确的mipmap过滤参数并调用glGenerateMipmap。当您在片段着色器中调用texture2D() / texture()时,OpenGL会根据相邻像素之间的纹理坐标增量自动计算要使用的mipmap的哪个级别。最后,为更加惊人的网格设置各向异性过滤。

    enter image description here

  4. 如果你想要一个网格真正无限的&#34;,我已经看到一些海洋渲染器将网格的边缘连接到具有垂直几何的地平线。如果你之前有足够的网格,你可能会把它们设置成一种平面颜色 - 你的mipmap顶层的颜色。

    示例(与评论有关):

    从VBO中提取的1024x2 GL_LINES
    enter image description here
    45fps(在HD res基准上绘制100次)

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

    32 ^ 2纹理映射到四边形与mipmapping
    enter image description here
    954fps(在HD res基准上绘制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);
    

答案 1 :(得分:1)

  

你可以看到,甚至那些线条都是通过它们的间隙渲染的

哦,我们当然可以。这是因为你冒犯了CG 101.(没有冒犯:)

我们使用GL_LINES是有原因的;在计算机屏幕上绘制无缝线条并非易事(虽然已经解决)。我在谈论something like this。你做了什么对浮点数进行计算,并且相当于绘制了子像素线(即间隙)。

我的建议是废弃这个GLSL代码并将这些行生成为常规顶点。它可能会更快,你会得到适当的结果。

您还可以使用常规雾计算获得所需的“淡入距离”效果。