在WebGL片段着色器中绘制网格

5

我正在将一个基于SVG的ZUI移植到WebGL,出于几个原因,我想使用片段着色器渲染网格。

这是我要实现的基本效果:https://dl.dropboxusercontent.com/u/412963/steel/restel_2.mp4

我想要一个三角形,每10个单位有细1px线条,每100个单位有粗2px线条(这里的单位是任意的,但与世界空间一致,而不是屏幕空间)。

以下是我目前的进展,没有像视频中那样的次要粗线条(请注意,这只是从我的开放缓存中复制,并且显然不正确):

顶点着色器:

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);
}

片元着色器:

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);
  }
}

它在某个距离上产生了大致正确的图像(但请注意带状效应,在其中有2px线条而不是1px):
带有带状效应的网格 Grid with banding 不受欢迎的更粗线条的放大网格 Zoomed in grid with unwanted thicker lines 那么,我怎样才能获得一个一致的网格,每个距离都有1像素厚的线条,都位于WebGL片段着色器内部?

为什么不使用纹理来解决这种问题呢?它们比编写片段着色器要容易得多。 - Dragan Okanovic
2个回答

11

我相信我已经找到了一个可接受的解决方案。

使用以下顶点(以三角形带的方式绘制):

[ 1.0  1.0  0.0
 -1.0  1.0  0.0
  1.0 -1.0  0.0
 -1.0 -1.0  0.0]

顶点着色器:

attribute vec4 aVertexPosition;

void main(void) {
  gl_Position = aVertexPosition;
}

片元着色器:

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);
  }
}

根据音高和偏移量,产生如下结果:

示例网格输出


在这里测试这种东西很有趣这里。左上角的数字设置分辨率。 - gman

4

gl_FragCoord 已经按照渲染目标的分辨率进行了缩放。因此,您只需简单地:

precision mediump float;

vec4 color = vec4(1.);
vec2 pitch  = vec2(50., 50.);

void main() {    
    if (mod(gl_FragCoord.x, pitch[0]) < 1. ||
        mod(gl_FragCoord.y, pitch[1]) < 1.) {
        gl_FragColor = color;
    } else {
        gl_FragColor = vec4(0.);
    }
}

https://glslsandbox.com/e#74754.0


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接