GLSL-ES Случайный зернистый шум с пределом FP16

Я пытаюсь написать компактную и простую функцию шума со строго FP16. Это то, с чем я вышел, но я думаю, что где-то на операции число становится слишком маленьким для фракции или sin, так как в GPU я должен написать это для они находятся в пределах FP16. Любые идеи о том, что я делаю неправильно? Кстати, я не могу использовать переменные времени, ни текстуры шума образца. Функция, которую мне нужно получить, должна быть компактной, маленькой и самодостаточной, а также создавать простой эффект зернистого шума. Примечание. Следующий алгоритм отлично работает на любой графической карте настольного компьютера, но полностью не работает на графическом процессоре " MALI 400 MP", поскольку у этого есть ограничение FP16 на значения float.

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);
}

Если кто-то может рекомендовать любую другую случайную функцию для GLSL-ES, но строго с лимитом FP16, также будет замечательно. Я знаю о других случайных реализациях, таких как симплекс-шум, но они слишком велики и медленны для того, что мне нужно делать. Таким образом, Perlin и Симплексные алгоритмы шума не являются опцией.

Ответ 1

Это те, которые я использую, но я не знаю, работает ли это в пределе FP16:

// 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);
}

Я не создал ни одного из них. Ссылка на оригинал автора выше. Я действительно использую rand2 и не имел проблемы, упомянутой в этом блоге. Чтобы сделать шум в оттенках серого, сделайте что-то вроде:

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

Чтобы сделать полный цветовой шум, потребуется 3 раза дольше, и вы сделали бы:

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

Чтобы добавить шум к тому, что вы рисуете, вы можете:

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);

Кстати, это медленно. На iPhone5 это отлично работает без серьезного замедления. Но на 4S он упал на fps до 30. Если я удаляю добавление шума, он поднимает его до 60. Так что будьте осторожны.

Ответ 2

Будет ли хеш-функция достаточной? хеширование Pearson было разработано для 8-битных регистров в дни yore и фантастично просто: вы жестко указываете 256-байтную таблицу поиска (или если это не может быть и речи, простая, но нелинейная перестановка какой-то), которую мы будем называть T. Для каждого байта ввода вы XOR это с хешем до сих пор, а затем посмотрите на значение, чтобы получить новый хеш.

В вашем случае пусть R, G и B будут вашими входными байтами. Тогда хеши могут быть

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

E: Чтобы быть ясным, это не приведет к случайному выходу, потому что на вашем входе нет случайности. Но я думаю, что он имитирует то, что ваш код пытается сделать.