1

I've been toying around with an infinite grid using shaders in OpenGL 4.5, following this tutorial here. Since the tutorial was written for Vulkan and a higher version of GLSL (I'm using 450 core), I had to move the vertices out of the vertex shader and into the application code. I'm rendering the quad using an element buffer, so my vertices ended up looking like this:

std::vector<glm::vec3> points{glm::vec3{-1, -1, 0},
                              glm::vec3{1, -1, 0},
                              glm::vec3{1, 1, 0},
                              glm::vec3{-1, 1, 0}};

std::vector<GLuint> indices{0, 1, 2, 2, 3, 0};

// Render like this:
glBindVertexArray(m_vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

I've managed to get the grid fully working, but it has two issues that I can't figure out:

  1. Objects that are drawn on top of the grid are getting clipped as the horizon moves up. This feels like z-fighting, but I'm not 100% sure why this would happen, seeing how the cube is being rendered after the grid.
  2. The underside of the grid is completely solid. This one also confuses me, because based on the fragment shader, the spaces in between the grid lines should be fully transparent... and yet they appear to be completely solid.

Here are some sample images of what is happening: enter image description here See that the cube is sliced in half. If I move the camera down, the rest of the cube will slowly appear. Conversely, if I move the camera up, the cube eventually disappears completely.

enter image description here This is the underside of the grid. I should be able to see the cube through the grid, but the grid behaves like a solid object.

Does anyone have any ideas of what I'm doing wrong? Should I be enabling something in the application? For reference, I currently have this enabled:

glEnable(GL_MULTISAMPLE);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
genpfault
  • 51,148
  • 11
  • 85
  • 139
Mauricio
  • 123
  • 5
  • We're going to need more information to debug that, namely model / view / projection matrix and shaders. I've had similar problems in the past caused by some matrices multiplied in the wrong order, or that were transposed when they should not have been. – Erel Jun 28 '22 at 18:53
  • *"the spaces in between the grid lines should be fully transparent"* -Why? Because of the alpha channel and blending? This only works if the depth test is disabled. – Rabbid76 Jun 28 '22 at 18:53
  • @Erel Model matrix is identity. View is computed with glm::lookat, and the projection matrix is a perspective matrix computed with glm::perspective. I can post the vertex/fragment shader code if it makes things easier. – Mauricio Jun 28 '22 at 18:59
  • @Rabbid76 that would solve the issue for the underside of the grid, but not while the camera is above the grid. In this case, the grid is drawn on top of the cube, which shouldn't be happening either. – Mauricio Jun 28 '22 at 19:03
  • To solve the problem, **enable** the depth test, but change the drawing order, draw the objects first and draw the grid at the end. – Rabbid76 Jun 28 '22 at 19:04
  • I did, but I may have replied out of order. Leaving GL_DEPTH_TEST enabled and switching the order so the cube is rendered before the grid fixes the issue of the object not being visible while the camera is **beneath** the grid. If the camera is above the grid, it is now drawn on top of the cube. – Mauricio Jun 28 '22 at 19:08
  • Yes the grid is drawn on top of the cube, if the grid is closer to the camera than the cube, it's because of the depth test. Closer objects win against more distant objects. But you should see the cube through the grid when blending is enabled. – Rabbid76 Jun 28 '22 at 19:12
  • Ah! I knew it was something silly like that. I can just switch the order if the camera goes beneath the y-plane. Thanks @Rabbid76. Do you want to post an answer so I can accept it? Or should I answer the question? – Mauricio Jun 28 '22 at 19:17
  • btw, I followed the same tutorial using OpenGL 4.6 and I draw the grid completely from the shader, all I had to do is replace `gl_VertexIndex` with `gl_VertexID` and write out the multiplication with `float(t > 0)`, that cast is supposed to evaluate to `0.0` or `1.0` but it didn't work for me – BETSCH Mar 23 '23 at 11:26

2 Answers2

2

Blending only works when the Depth Test is disabled or the objects are drawn from back to front. When the depth test is enabled (with its default function GL_LESS) closer objects win against more distant objects. Even if a fragment's alpha channel is 0, the fragment affects the depth buffer and the depth test. Thus, a more distant fragment is discarded if a closer, transparent fragment was previously drawn.
You only have one object with transparent fragments, the grid. To solve your problem, just draw the grid after the cube:

  • enable depth test
  • draw solid objects (cube)
  • enable blending
  • draw grid
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
1

I've discovered what the problem was. I also followed the tutorial and I had a similar problem. The problem is with the gl_FragDepth. The way OpenGL test the depth is by having values between -1 and 1, whereas DirectX 12 does it between 0 and 1. The algorithm is based in the idea of the depth range between 0 and 1. In order to fix this, you can change the computation for the fragment depth like this:

// gl_FragDepth = computeDepth(fragPos3D);
gl_FragDepth = ((gl_DepthRange.diff * computeDepth(fragPos3D)) +
                gl_DepthRange.near + gl_DepthRange.far) / 2.0;

Please look at this article for more information.