gl_PointCoord的确切坐标?

时间:2018-07-23 13:26:59

标签: glsl webgl

在一个顶点中,我给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使用相同的语法。

然后,可以肯定的是我什么都不懂,但是我尝试对正确居中的2x2像素尝试s = 0.25和s = 0.75的解决方案,但这似乎不起作用。 另一方面,值0.5和1.0为我提供了正确的显示(请参见小提琴1)

(小提琴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/

1 个答案:

答案 0 :(得分:1)

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

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

或者更好地考虑使用蒙版纹理或比硬编码的if语句更灵活的东西。

否则,在WebGL中,像素由其中心引用。因此,如果您在像素边界上绘制2x2点,则这些值应为.s的{​​{1}}值。

gl_PointCoord

如果您将其画出像素边界,则取决于情况

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

它仍将仅绘制4个像素(最接近该点所在的4个像素),但它将选择不同的gl_PointCoords,就好像它可以绘制小数像素一样。如果我们使++=====++=====++======++ || || || || || +------+------+ || || | | | || ++==| | |===++ || | | | || || +------+------+ || || | | | || ++==| | |===++ || | | | || || +------+------+ || || || || || ++=====++=====++======++ 偏移,使得我们的点超出了0.25像素,则它仍将与像素对齐时绘制完全相同的4像素,因为偏移量.25不足以将其移出绘制相同的4像素,因此我们可以猜测是将gl_Position偏移-.25像素(在我们的示例中是2x2点,偏移量是.125,因此(.25--.125)= .125和(.75-.125)=。 675。

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

gl_PointCoord
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>的公式位于the spec section 3.3

gl_PointCoord formula

因此,从2个像素宽度的点开始,一个点从0个像素边界上绘制了0.25个像素

gl_PointCoord

这是我从上面的示例中获得的值。

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 顶点的窗口x坐标。换句话说,xw是基于我们将xw设置为如此的

gl_Position

或更具体地说

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

xw = (gl_Position.x / gl_Position.w * .5 + .5) * viewportWidth + viewportX viewportX设置为viewportWidth的情况下,默认大小与画布相同。