在WebGL着色器中获取准确的整数模 [英] Get accurate integer modulo in WebGL shader
问题描述
我想在WebGL片段着色器中获得x
和y
的准确模. x
和y
是整数.
I want to get an accurate modulo of x
and y
in a WebGL fragment shader. x
and y
are integers.
绘制mod(x,y)
,我们得到以下信息:
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);
其中v_texCoord是一个vec2,范围从左上角的0,0
到右下角的1,1
.将float和int的精度都设置为mediump.
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.
阅读图表,我们看到尽管mod(6,6)
正确地是0
,但是mod(7,7)
实际上是7
! 我该如何解决?
Reading the chart, we see that although mod(6,6)
is correctly 0
, mod(7,7)
is actually 7
! How do I fix this?
我试图实现自己的mod()函数.但是,它具有相同的错误,并生成相同的图.
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)));
}
在Java脚本中,我可以对其进行调试,该功能可以完美运行.然后,我尝试了一种迭代方法,因为我担心自己会发疯,而且我也不信任浮点除法.
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;
}
这行得通,但是我无法用图形表示出来,因为当我尝试使用ring 0时,它使linux崩溃并出现错误.对于我需要的Spritesheet计算来说,它工作得很好,但我真的觉得这是不正确的解决方案.
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…)
推荐答案
您不是将7乘7乘以7/15乘7/15乘以
You're not modding 7 by 7 you're modding 7/15ths by 7/15ths
尝试
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>
您还应该注意,mod by 0是未定义的,这意味着您将在不同的GPU上获得不同的结果
You should also note that mod by 0 is undefined meaning you'll get different results on different GPUs
这篇关于在WebGL着色器中获取准确的整数模的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!