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;
使用浮点数检查精确值通常不是一个好主意。检查范围
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
其中 viewportX
和 viewportWidth
设置为 gl.viewport(x, y, width, height)
并且默认为与 canvas 相同的大小。
在一个顶点中,我给 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;
使用浮点数检查精确值通常不是一个好主意。检查范围
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
其中 viewportX
和 viewportWidth
设置为 gl.viewport(x, y, width, height)
并且默认为与 canvas 相同的大小。