在 WebGL 着色器中获取准确的整数模
Get accurate integer modulo in WebGL shader
我想在 WebGL 片段着色器中获得 x
和 y
的准确 modulo。 x
和 y
是整数。
作图mod(x,y)
,我们得到以下信息:
实际用于生成红黑矩形的代码是:
gl_FragColor = vec4(mod(
float(int(v_texCoord[0]*15.))/15.,
float(int(v_texCoord[1]*15.))/15.
), 0, 0, 1);
其中 v_texCoord 是一个 vec2,范围从左上角的 0,0
到右下角的 1,1
。 float 和 int 的精度设置为 mediump。
阅读图表,我们发现虽然 mod(6,6)
是正确的 0
,但 mod(7,7)
实际上是 7
! 我该如何解决这个问题?
我尝试实现自己的 mod() 函数。但是,它有相同的错误,并生成相同的图形。
int func_mod(int x, int y) {
return int(float(x)-float(y)*floor(float(x)/float(y)));
}
在Javascript中,我可以调试它,该功能完美运行。然后我尝试了一种迭代方法,因为我担心我会发疯而且我也不相信浮点除法。
int iter_mod(int x, int y) {
x = int(abs(float(x))); y = int(abs(float(y)));
for(int i=0; i>-1; i++) {
if(x < y) break;
x = x - y;
}
return x;
}
这行得通,但我无法绘制它,因为它在我尝试时崩溃 linux 并在 ring 0 中出现错误。它适用于我需要的 spritesheet 计算,但我真的觉得这是一个不正确的解决方案。
(更新:它在我的 phone 上完美运行。现在不是我的代码错误,这只是我的问题...)
你不是 mod7 乘 7 你是 mod7/15 乘 7/15
尝试
gl_FragColor = vec4(mod(
floor(v_texCoord[0] * 15.),
floor(v_texCoord[1] * 15.)
) / 15., 0, 0, 1);
您可以在此处查看 2 个版本 运行
function render(num) {
var gl = document.getElementById("c" + num).getContext("webgl");
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var arrays = {
position: [-1, -1, 0, 1, -1, 0, -1, 1, 0, -1, 1, 0, 1, -1, 0, 1, 1, 0],
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
var uniforms = {
resolution: [gl.canvas.width, gl.canvas.height],
intMod: num == 1,
};
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, bufferInfo);
}
render(0)
render(1);
canvas { margin: 1em; height: 100px; width: 150px; }
div { display: inline-block; }
pre { text-align: center; }
<script src="https://twgljs.org/dist/3.x/twgl.min.js"></script>
<script id="vs" type="notjs">
attribute vec4 position;
void main() {
gl_Position = position;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
uniform vec2 resolution;
uniform bool intMod;
void main() {
vec2 v_texCoord = gl_FragCoord.xy / resolution.xy;
if (!intMod) {
gl_FragColor = vec4(mod(
float(int(v_texCoord[0]*15.))/15.,
float(int(v_texCoord[1]*15.))/15.
), 0, 0, 1);
} else {
gl_FragColor = vec4(mod(
floor(v_texCoord[0]*15.),
floor(v_texCoord[1]*15.)
)/15., 0, 0, 1);
}
}
</script>
<div><canvas id="c0"></canvas><pre>mod with fractions</pre></div>
<div><canvas id="c1"></canvas><pre>mod with ints</pre></div>
您还应注意,mod by 0 是未定义的,这意味着您将在不同的 GPU 上获得不同的结果
这是一个 GLSL 函数,它使用应为整数的(浮点)参数准确计算 MOD:
/**
* Returns accurate MOD when arguments are approximate integers.
*/
float modI(float a,float b) {
float m=a-floor((a+0.5)/b)*b;
return floor(m+0.5);
}
请注意,如果 a<0 且 b>0,则 return 值将 >=0,这与其他语言的 % 运算符不同。
请注意,自 webGL2 以来,我们现在有 int 操作,所以这个问题现在可以通过 x % y 轻松解决。
我想在 WebGL 片段着色器中获得 x
和 y
的准确 modulo。 x
和 y
是整数。
作图mod(x,y)
,我们得到以下信息:
实际用于生成红黑矩形的代码是:
gl_FragColor = vec4(mod(
float(int(v_texCoord[0]*15.))/15.,
float(int(v_texCoord[1]*15.))/15.
), 0, 0, 1);
其中 v_texCoord 是一个 vec2,范围从左上角的 0,0
到右下角的 1,1
。 float 和 int 的精度设置为 mediump。
阅读图表,我们发现虽然 mod(6,6)
是正确的 0
,但 mod(7,7)
实际上是 7
! 我该如何解决这个问题?
我尝试实现自己的 mod() 函数。但是,它有相同的错误,并生成相同的图形。
int func_mod(int x, int y) {
return int(float(x)-float(y)*floor(float(x)/float(y)));
}
在Javascript中,我可以调试它,该功能完美运行。然后我尝试了一种迭代方法,因为我担心我会发疯而且我也不相信浮点除法。
int iter_mod(int x, int y) {
x = int(abs(float(x))); y = int(abs(float(y)));
for(int i=0; i>-1; i++) {
if(x < y) break;
x = x - y;
}
return x;
}
这行得通,但我无法绘制它,因为它在我尝试时崩溃 linux 并在 ring 0 中出现错误。它适用于我需要的 spritesheet 计算,但我真的觉得这是一个不正确的解决方案。
(更新:它在我的 phone 上完美运行。现在不是我的代码错误,这只是我的问题...)
你不是 mod7 乘 7 你是 mod7/15 乘 7/15
尝试
gl_FragColor = vec4(mod(
floor(v_texCoord[0] * 15.),
floor(v_texCoord[1] * 15.)
) / 15., 0, 0, 1);
您可以在此处查看 2 个版本 运行
function render(num) {
var gl = document.getElementById("c" + num).getContext("webgl");
var programInfo = twgl.createProgramInfo(gl, ["vs", "fs"]);
var arrays = {
position: [-1, -1, 0, 1, -1, 0, -1, 1, 0, -1, 1, 0, 1, -1, 0, 1, 1, 0],
};
var bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
var uniforms = {
resolution: [gl.canvas.width, gl.canvas.height],
intMod: num == 1,
};
gl.useProgram(programInfo.program);
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
twgl.setUniforms(programInfo, uniforms);
twgl.drawBufferInfo(gl, bufferInfo);
}
render(0)
render(1);
canvas { margin: 1em; height: 100px; width: 150px; }
div { display: inline-block; }
pre { text-align: center; }
<script src="https://twgljs.org/dist/3.x/twgl.min.js"></script>
<script id="vs" type="notjs">
attribute vec4 position;
void main() {
gl_Position = position;
}
</script>
<script id="fs" type="notjs">
precision mediump float;
uniform vec2 resolution;
uniform bool intMod;
void main() {
vec2 v_texCoord = gl_FragCoord.xy / resolution.xy;
if (!intMod) {
gl_FragColor = vec4(mod(
float(int(v_texCoord[0]*15.))/15.,
float(int(v_texCoord[1]*15.))/15.
), 0, 0, 1);
} else {
gl_FragColor = vec4(mod(
floor(v_texCoord[0]*15.),
floor(v_texCoord[1]*15.)
)/15., 0, 0, 1);
}
}
</script>
<div><canvas id="c0"></canvas><pre>mod with fractions</pre></div>
<div><canvas id="c1"></canvas><pre>mod with ints</pre></div>
您还应注意,mod by 0 是未定义的,这意味着您将在不同的 GPU 上获得不同的结果
这是一个 GLSL 函数,它使用应为整数的(浮点)参数准确计算 MOD:
/**
* Returns accurate MOD when arguments are approximate integers.
*/
float modI(float a,float b) {
float m=a-floor((a+0.5)/b)*b;
return floor(m+0.5);
}
请注意,如果 a<0 且 b>0,则 return 值将 >=0,这与其他语言的 % 运算符不同。
请注意,自 webGL2 以来,我们现在有 int 操作,所以这个问题现在可以通过 x % y 轻松解决。