Ideally, what I'd like to do is draw a single quad and have GLSL handle the creation of the actual gridlines.
In my attempt so far the vertex shader:
#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);
}
The model matrix scales the quad up by some large number, like 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);
}
I've tried using both the Texture coords and the world space positions for this. Both result in the same affect which looks fine at some angles, but at others it starts looking horrid.
I thought maybe I could scale the alpha depending on the distance, so that my grid fades away into nothing, but the problem is that you can see in the second image, from the center of the screen, you can see that even those lines are being rendered with gaps through them (the point of the grid is to give a visual frame of reference around the origin).
Is there a simpler way to do this?
Screenshots as requested:
I settled on the either of the above (doesn't really matter which) and simply lowered the alpha as a function of distance from the origin. This serves my purpose though it isn't the question I asked.
this the code for render the grid: glEnable(GL_DEPTH_TEST); glBindVertexArray(vao); glDrawElements(GL_LINES, lenght, GL_UNSIGNED_INT, NULL); glBindVertexArray(0); glDisable(GL_DEPTH_TEST); c++ opengl.
fwidth — return the sum of the absolute value of derivatives in x and y.
GLSL is executed directly by the graphics pipeline. There are several kinds of shaders, but two are commonly used to create graphics on the web: Vertex Shaders and Fragment (Pixel) Shaders. Vertex Shaders transform shape positions into 3D drawing coordinates.
A simple case of aliasing. Just like with polygon rendering, your fragment shader is run once per pixel. Colour is computed for a single central coordinate only and is not representative of the true colour.
Mipmapping already does this for textures. Create a grid texture with just a few lines and map it so it repeats for your really large quad (make sure to set GL_REPEAT
). Set up the correct mipmap filtering parameters for the texture and call glGenerateMipmap
. When you call texture2D()
/texture()
in the fragment shader OpenGL automatically calculates which level of the mipmap to use based off the texture coordinate delta between the adjacent pixels. Finally, set up anisotropic filtering for an even more amazing looking grid.
If you want a grid to be truly "infinite", I've seen some ocean renderers connect the edges of the grid to the horizon with vertical geometry. If you have enough grid before them, you could possibly get away with setting them to one flat colour - the colour at the top level of your mipmap.
Examples (relating to comments):
1024x2 GL_LINES drawn from a VBO
45fps (drawn 100 times for benchmark at HD res)
See the comments regarding multisampling to address GL_LINES aliasing.
A 32^2 texture mapped to a quad with mipmapping
954fps (drawn 100 times for benchmark at HD res)
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);
you can see that even those lines are being rendered with gaps through them
Oh, of course we can. And this is because you've offended CG 101. (No offense :)
)
We use GL_LINES
for a reason; drawing gapless lines on a computer screen isn't trivial (albeit solved). I'm talking about something like this. What you did does computations on floating-point numbers and will amount to sub-pixel lines being drawn (i.e., gaps).
My suggestion would be to scrap this GLSL code and generate the lines as regular vertices. It's going to be probably faster, and you'll get proper results.
You'll also be able to get the "fade in the distance" effect you want using regular fog computations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With