问题
I am struggling to get the next simple algorithm working in the Samsung Galaxy SIII
float rand(vec2 co)
{
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
....
vec3 color = texture2D(u_texture, v_texcoord);
gl_FragColor.rgb = color + vec3(rand(gl_FragCoord.xy + time / 1000.0));
....
The code generates perfectly the expected noise in Samsung Galaxy S1 and Google Nexus S. But it fails completely in the new smartphone which uses ARM's Mali-400/MP4.
Anyone can spot anything wrong with this algorithm? Or maybe understand why could it fail?
回答1:
Your problem likely comes from taking the sin
of a big number. The result of this depends on the exact implementation of sin
, which is not available. Obviously the sin
function used by the Mali chip has more predictable results with big numbers than the others.
It seems to me that you should use an actual noise function, not this thing. At least it will have predictable results across hardware.
回答2:
A bit of discussion of this issue on the ARM forums: http://forums.arm.com/index.php?/topic/16364-random-number-with-mali-400-mp/.
The problem is because of FP16 precision in fragment shaders on the Mali GPU. Basically, there are no fractional bits left by the time fract
is invoked (because the multipliers are so large), so you don't get any "noise" back at all. If you make the constants smaller, you'll start getting non-zero values back, but they won't be noisy. (I'm not entirely sure how the values were picked, and its not clear where this algorithm came from).
Technically this noise algorithm is relying on higher (medium? high?) precision floating point operations, which are optional in fragment shaders. According to this other post you can check the platform's supported precision in fragment shaders by checking for the "OES_fragment_precision_high" extension in glGetString(GL_EXTENSIONS)
.
The webgl-noise project in Nicol's answer doesn't seem as susceptible to floating-point truncation issues (it seems to keep things in a tighter bound). However, it has a period of around 300, and it generates more "structured" noise than the "white" (or "pink") noise you currently get. Its an excellent library, though, so its worth working into your code even if its not a drop-in replacement.
回答3:
Use Gold Noise, a uniform normalized distribution. It is designed specifically to run at low precision (lowp
). It also accepts a seed (eg. time).
float gold_noise(in vec2 xy, in float seed){
return fract(tan(distance(xy*PHI, xy)*seed)*xy.x);
}
来源:https://stackoverflow.com/questions/11293628/noise-algorithm-fails-in-samsung-galaxy-siii-gles