Question

I am trying to write a compact and simple noise function with a strictly FP16 limit. This is with what I came out so far, but I think somewhere on the operation the number gets too small for fract or sin, since in the GPU I must write this for these are within the FP16 limits. Any ideas on what am I doing wrong? BY the way, I cannot use a time variables, neither sample noise textures. The function I need to get right must be compact, small and self-sufficient, and produce a simple grainy noise effect. Note: The next algorithm works fine in any desktop GPU card, but fails completely on the "MALI 400 MP" GPU, since this one has a FP16 limitation on float values.

vec3 noise(vec3 color)
{
    float variation = length(color);
    float dot_product = dot(variation, -0.577350269);
    float sin_result = sin(dot_product) * 1.19245;
    float random = fract(sin_result);
    return color + vec3(random);
}

If any one can recommend any other random function for GLSL-ES but strictly with a FP16 limit, would also be great. I know about other random implementations such as simplex noise, but these are too large and slow for what I need to do. So Perlin and Simplex noise algorithms are not an option.

Était-ce utile?

La solution 3

Although is an old question I eventually found the solution long ago. Next the script so anyone can use it. As seed you should pass a dynamic or random value which you may pass to the shader as an attribute.

float getNoise(vec2 seed)
{
    vec2 theta_factor_a = vec2(0.9898, 0.233);
    vec2 theta_factor_b = vec2(12.0, 78.0);
    
    float theta_a = dot(seed.xy, theta_factor_a);
    float theta_b = dot(seed.xy, theta_factor_b);
    float theta_c = dot(seed.yx, theta_factor_a);
    float theta_d = dot(seed.yx, theta_factor_b);
    
    float value = cos(theta_a) * sin(theta_b) + sin(theta_c) * cos(theta_d);
    float temp = mod(197.0 * value, 1.0) + value;
    float part_a = mod(220.0 * temp, 1.0) + temp;
    float part_b = value * 0.5453;
    float part_c = cos(theta_a + theta_b) * 0.43758;

    return fract(part_a + part_b + part_c);
}

Autres conseils

These are the ones that I use but I don't know if either works in a FP16 limit:

// source: http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/
highp float rand(vec2 co)
{
      highp float a = 12.9898;
      highp float b = 78.233;
      highp float c = 43758.5453;
      highp float dt= dot(co.xy ,vec2(a,b));
      highp float sn= mod(dt,3.14);
      return fract(sin(sn) * c);
}

 float rand2(vec2 co)
{
      return fract(sin(dot(co.xy,vec2(12.9898,78.233))) * 43758.5453);
}

I didn't create either of these. The link to the original author is above. I actually use rand2 and didn't have the issue mentioned on that blog. To make a greyscale noise do something like:

float randColor = rand(v_position);
gl_FragColor = vec4(randColor);

To do a full color noise it would take 3 times longer and you'd do:

gl_FragColor = vec4(rand(v_position), rand(v_position), rand(v_position), 1.0);

To add noise to whatever you're drawing you could:

float randColor = rand(v_position) * .1;  // to add 10% noise
gl_FragColor = vec4(gl_FragColor.r + randColor, gl_FragColor.g + randColor, gl_FragColor.b + randColor, 1.0);

By the way, this is slow. On an iPhone5 this works fine with no major slowdown. But on a 4S it dropped by fps down to 30. If I removed adding the noise it raised it to 60. So beware.

Would a hash function suffice? Pearson hashing was designed for 8-bit registers back in the days of yore and is fantastically simple: you hardcode a 256-byte lookup table (or if that's out of the question, a simple-but-nonlinear permutation of some kind) which we'll call T. For each byte of the input, you XOR it with the hash so far and then look up the value to get a new hash.

In your case, let R, G and B be your input bytes. Then the hashes could be

  • Rnoise = T[R^T[G^T[B]]]
  • Gnoise = T[G^T[B^T[R]]]
  • Bnoise = T[B^T[R^T[G]]]

E: To be clear, this won't produce a random output because there's no randomness in your input. But I think it mimics what your code is trying to do.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top