问题描述
我想在WebGL片段着色器中获得x和y的精确模量. 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.精度设置为浮点和int.
的中等阅读图表,我们看到,尽管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; }
这起作用了,但是我无法绘制它,因为当我尝试时,它会在环0中带有错误的Linux.它适用于我需要的SpriteSheet计算,但我真的觉得这是一个不正确的解决方案.
(更新:它在我的手机上完美工作.现在不是我的代码,这只是我的问题……)
推荐答案
您不是修改7乘7,您是7/15 by 7/15ths
尝试
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函数,可以用(float)参数准确地计算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,则返回值将为> = 0,与其他语言的%运算符不同.
其他推荐答案
请注意,由于WebGL2,我们现在有int操作,因此现在通过x%y.
问题描述
I want to get an accurate modulo of x and y in a WebGL fragment shader. x and y are integers.
Graphing mod(x,y), we get the following:
The actual code used to generate the red-and-black rectangle is:
gl_FragColor = vec4(mod( float(int(v_texCoord[0]*15.))/15., float(int(v_texCoord[1]*15.))/15. ), 0, 0, 1);
Where v_texCoord is a vec2 ranging from 0,0 at the top-left to 1,1 at the bottom-right. Precision is set to mediump for both float and int.
Reading the chart, we see that although mod(6,6) is correctly 0, mod(7,7) is actually 7! How do I fix this?
I tried to implement my own mod() function. However, it has the same errors, and produces the same graph.
int func_mod(int x, int y) { return int(float(x)-float(y)*floor(float(x)/float(y))); }
In Javascript, where I can debug it, the function works perfectly. I then tried an iterative approach, because I was worried I was going insane and I didn't trust the floating-point division anyway.
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; }
This worked, but I can't graph it because it crashes linux with an error in ring 0 when I try. It works fine for the spritesheet calculations I need it for, but I really feel it's an incorrect solution.
(Update: It works perfectly on my phone. It's not my code in error now, it's just my problem…)
推荐答案
You're not modding 7 by 7 you're modding 7/15ths by 7/15ths
Try
gl_FragColor = vec4(mod( floor(v_texCoord[0] * 15.), floor(v_texCoord[1] * 15.) ) / 15., 0, 0, 1);
You can see the 2 versions running here
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>
You should also note that mod by 0 is undefined meaning you'll get different results on different GPUs
其他推荐答案
Here is a GLSL function that calculates MOD accurately with (float) parameters that should be integers:
/** * 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); }
Please note, if a<0 and b>0 then the return value will be >=0, unlike other languages' % operator.
其他推荐答案
Note that since webGL2, we now have int operations so this problem is now trivially solve by x % y .