Ryan Peschel
Ryan Peschel

Reputation: 11828

How to prevent flickering when drawing a grid with WebGL?

I'm drawing a 2D grid in world coordinates in WebGL that a character can move over. For example, there may be a grid at position 2000, 2000 in the world, and it is 4000x4000 in dimensions. Here is what it looks like:

enter image description here

Basically the issue that I see is that individual lines either render, or don't, which causes a jarring flickering effect. It's even more noticeable at higher zoom levels, because it flashes between a 1px line and a 0px line.

My shader code to draw the grid is very simple:

in vec2 v_world;

vec3 fgColor = vec3(0.675);

vec2 gap = vec2(100);

void main() {
  int x = int(mod(v_world.x, gap.x));
  int y = int(mod(v_world.y, gap.y));

  if (x == 0 || y == 0) {
    outputColor = vec4(fgColor, 1);
  } else {
    discard;
  }
}

What is causing this? And is there a way to fix it?

Upvotes: 1

Views: 401

Answers (1)

Blindy
Blindy

Reputation: 67417

Just because you cast the result to an integer, it doesn't mean that you can use floating point operations (at an undefined precision) and expect them to be strictly equal to a specific value. You're going to have to work a lot harder to make this work as you'd expect.

Also you don't show the rest of your setup, but multisampling for example makes this problem worse, since you start running into sub-pixel issues (if you aren't already, you really don't show much of anything -- I can easily imagine a world in which you add fractions of pixels to v_world). Remember that what v_world probably is is an interpolated UV coordinate between 0 and 1, multiplied by your canvas size, so precision loss alone can explain this.

The easiest way by far to draw your grid is to use a vertex buffer and build the lines yourself, then translate them in place modulo your gap. One draw call per frame, no buffer updates and absolutely no branches in your shaders.

Upvotes: 2

Related Questions