gl_PointCoord 的确切坐标?

exact coordinates of gl_PointCoord?

在一个顶点中,我给 pointSize 一个大于 1 的值。比如说 15。 在片段中,我想在 15x15 正方形内选择一个点:

vec2 sprite = gl_PointCoord;  
if (sprite.s == (9. )/15.0 ) discard ;  
gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);

但是当 Size 不是 2 的幂时,这不起作用。

(如果大小为 16,那么 (sprite.s == a/16。)其中 a 在 1..16 中:完美!)

是一种实现我的目的的方法,其中大小不是 2 的幂?

编辑:我知道纹理大小的解决方案:PointSize * PointSize

gl_FragColor = texture2D(tex, gl_PointCoord);

但这不适合动态变化

编辑 7 月 26 日:

首先我不明白为什么使用 webgl2 而不是 webgl 在浮点纹理中更容易阅读。就我而言,我做了一个 ext = gl.getExtension ("OES_texture_float"); gl.readpixel 使用相同的语法。

然后,可以肯定的是,我并没有完全理解,但我尝试了解决方案 s = 0.25 和 s = 0.75 以正确居中的 2x2 像素,但这似乎不起作用。 另一方面,值:0.5 和 1.0 给我一个正确的显示(参见 fiddle1)

(fiddle 1) https://jsfiddle.net/3u26rpf0/274/

事实上,为了准确显示任何大小的顶点(比如 SIZE),我使用以下公式:

float size = 13.0;  
float nby = floor ((size) /2.0);  
float nbx = floor ((size-1.0) /2.0);  
// 
// <nby> pixels CENTER <nbx> pixels 
//
// if size is odd nbx == nby
// if size is even nbx == nby +1

vec2 off = 2. * vec2 (nbx, nby) / canvasSize;  
vec2 p = -1. + (2. * (a_position.xy * size) + 1.) / canvasSize + off; 

gl_Position vec4 = (p, 0.0,1.0);  
gl_PointSize = size;

https://jsfiddle.net/3u26rpf0/275/

使用浮点数检查精确值通常不是一个好主意。检查范围

sprite.s > ??? && sprite.s < ???

或者更好的是考虑使用遮罩纹理或比硬编码 if 语句更灵活的东西。

否则在 WebGL 中像素由它们的中心引用。因此,如果您在像素边界上绘制一个 2x2 点,那么这些应该是 gl_PointCoord.

.s
+-----+-----+
| .25 | .75 |
|     |     |
+-----+-----+
| .25 | .75 |
|     |     |
+-----+-----+

如果您将其画出像素边界,则视情况而定

++=====++=====++======++
||     ||     ||      ||
||  +------+------+   ||
||  |      |      |   ||
++==|      |      |===++
||  |      |      |   ||
||  +------+------+   ||
||  |      |      |   ||
++==|      |      |===++
||  |      |      |   ||
||  +------+------+   ||
||     ||     ||      ||
++=====++=====++======++

它仍然只会绘制 4 个像素(最接近点所在位置的 4 个像素),但它会选择不同的 gl_PointCoords,就好像它可以在小数像素上绘制一样。如果我们偏移 gl_Position 所以我们的点超过 0.25 个像素,它仍然绘制与像素对齐时完全相同的 4 个像素,因为 0.25 的偏移量不足以将它从绘制相同的 4 个像素移开,我们可以猜测它是将 gl_PointCoord 偏移 -.25 像素(在我们的例子中,这是一个 2x2 点,偏移量为 .125,所以 (.25 - -.125) = .125 和 (.75 - .125) = . 675.

我们可以通过使用 WebGL2 将它们写入浮点纹理来测试 WebGL 使用的是什么(因为在 WebGL2 中读取浮点像素更容易)

function main() {
  const gl = document.createElement("canvas").getContext("webgl2");
  if (!gl) {
    return alert("need WebGL2");
  }
  const ext = gl.getExtension("EXT_color_buffer_float");
  if (!ext) {
    return alert("need EXT_color_buffer_float");
  }
  
  const vs = `
  uniform vec4 position;
  void main() {
    gl_PointSize = 2.0;
    gl_Position = position;
  }
  `;
  
  const fs = `
  precision mediump float;
  void main() {
    gl_FragColor = vec4(gl_PointCoord.xy, 0, 1);
  }
  `;
  
  const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
  const width = 2;
  const height = 2;

  // creates a 2x2 float texture and attaches it to a framebuffer
  const fbi = twgl.createFramebufferInfo(gl, [
    { internalFormat: gl.RGBA32F, minMag: gl.NEAREST, },
  ], width, height);

  // binds the framebuffer and set the viewport
  twgl.bindFramebufferInfo(gl, fbi);
  
  gl.useProgram(programInfo.program);
  
  test([0, 0, 0, 1]);
  test([.25, .25, 0, 1]);
  
  function test(position) {
    twgl.setUniforms(programInfo, {position});
    gl.drawArrays(gl.POINTS, 0, 1);

    const pixels = new Float32Array(width * height * 4);
    gl.readPixels(0, 0, 2, 2, gl.RGBA, gl.FLOAT, pixels);
    
    console.log('gl_PointCoord.s at position:', position.join(', '));
    for (y = 0; y < height; ++y) {
      const s = [];
      for (x = 0; x < width; ++x) {
        s.push(pixels[(y * height + x) * 4]);
      }
      console.log(`y${y}:`, s.join(', '));
    }
  }
}
main();
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>

gl_PointCoord 的公式在 the spec section 3.3

因此,对于一个 2 像素宽度的点,在距 0 像素边界 0.25 像素处绘制一个点

drawing a 2x2 at .25,.25 (slightly off center)
// first pixel

// this value is constant for all pixels. It is the unmodified
// **WINDOW** coordinate of the **vertex** (not the pixel)
xw = 1.25

// this is the integer pixel coordinate
xf = 0

// gl_PointSize
size = 2

s = 1 / 2 + (xf + 1 / 2 -  xw)  / size
s = .5    + (0  + .5    - 1.25) / 2
s = .5    + (-.75)              / 2
s = .5    + (-.375)
s = .125

这是我从上面的示例 运行 中得到的值。

xw 顶点 的 window x 坐标。换句话说 xw 是基于我们将 gl_Position 设置为 so

xw = (gl_Position.x / gl_Position.w * .5 + .5) * canvas.width

或更具体地说

xw = (gl_Position.x / gl_Position.w * .5 + .5) * viewportWidth + viewportX

其中 viewportXviewportWidth 设置为 gl.viewport(x, y, width, height) 并且默认为与 canvas 相同的大小。