Drawing a grid in a WebGL fragment shader
fragment-shader, shader, webgl
Solution
I believe I've found an acceptable solution.
Using the following vertices (drawn in a triangle strip):
[ 1.0 1.0 0.0
-1.0 1.0 0.0
1.0 -1.0 0.0
-1.0 -1.0 0.0]
Vertex shader:
attribute vec4 aVertexPosition;
void main(void) {
gl_Position = aVertexPosition;
}
Fragment Shader:
precision mediump float;
uniform float vpw; // Width, in pixels
uniform float vph; // Height, in pixels
uniform vec2 offset; // e.g. [-0.023500000000000434 0.9794000000000017], currently the same as the x/y offset in the mvMatrix
uniform vec2 pitch; // e.g. [50 50]
void main() {
float lX = gl_FragCoord.x / vpw;
float lY = gl_FragCoord.y / vph;
float scaleFactor = 10000.0;
float offX = (scaleFactor * offset[0]) + gl_FragCoord.x;
float offY = (scaleFactor * offset[1]) + (1.0 - gl_FragCoord.y);
if (int(mod(offX, pitch[0])) == 0 ||
int(mod(offY, pitch[1])) == 0) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 0.5);
} else {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}
}
Gives results (depending on the pitch and offset) like:
Problem
I'm working on porting a ZUI from SVG over to WebGL for a few reasons, and I'd like to render a grid using a fragment shader. Here's the basic effect I'm going for https://dl.dropboxusercontent.com/u/412963/steel/restel_2.mp4 I'd like to have a triangle that has thin, 1px lines every 10 units, and a thicker 2px line every 100 units (the units here being arbitrary but consistent with world-space, not screen-space). Here's what I have so far, without the secondary thicker lines like in the video (note that this is literally a copy from my open buffer, and obviously isn't right): Vertex Shader: ``` attribute vec3 aVertexPosition; uniform mat4 uMVMatrix; uniform mat4 uPMatrix; varying float vX; varying float vY; void main(void) { vX = aVertexPosition.x; vY = aVertexPosition.y; gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); } ``` Fragment Shader: ``` precision mediump float; uniform vec2 resolution; uniform float uZoomFactor; varying float vX; varying float vY; void main(void) { float distance = gl_FragCoord.z / gl_FragCoord.w; float fuzz = 1.0 / distance; float minorLineFreq; if (distance > 10.0) { minorLineFreq = 1.0; } else if (distance > 5.0) { minorLineFreq = 1.0; } else { minorLineFreq = 0.10; } float xd = mod(vX, minorLineFreq) * 88.1; float yd = mod(vY, minorLineFreq) * 88.1; if (xd < fuzz) { gl_FragColor = vec4(0.0,0.0,0.0,1.0); } else if (yd < fuzz) { gl_FragColor = vec4(0.0,0.0,0.0,1.0); } else { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); } } ``` It produces approximately the right image at a certain distance (but notice the banding effect where there's 2px lines instead of 1px): Grid with banding Zoomed in grid with unwanted thicker lines So, how can I get a consistent grid, with 1px thick lines at every distance, all inside of a WebGL fragment shader?