【问题标题】:GLSL-ES Random grainy noise with FP16 limit具有 FP16 限制的 GLSL-ES 随机粒状噪声
【发布时间】:2012-11-12 11:58:03
【问题描述】:

我正在尝试编写一个具有严格 FP16 限制的紧凑而简单的噪声函数。 这是我到目前为止所得出的结论,但我认为在操作的某个地方,对于 fractsin,这个数字太小了,因为在 GPU 中我必须为这些都在 FP16 限制内。关于我做错了什么的任何想法?顺便说一句,我不能使用时间变量,也不能采样噪声纹理。我需要正确的功能必须紧凑、小巧且自给自足,并产生简单的颗粒状噪音效果。 注意:下一个算法在任何桌面 GPU 卡上都可以正常工作,但在“MALI 400 MP”GPU 上完全失败,因为这个算法对浮点值有 FP16 限制。

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 限制,那也很好。我知道其他随机实现,例如单纯形噪声,但这些对于我需要做的事情来说太大而且太慢了。所以 PerlinSimplex 噪声算法不是一种选择。

【问题讨论】:

  • 通过向颜色添加一个作为颜色函数的值,相同的“噪声”值被添加​​到具有相同颜色的所有片段。因为对象通常具有颜色渐变,所以您会在对象上出现条带。您可以通过将 dot 函数中的常量更改为更大的值来了解我的意思。
  • 这个帖子random number with mali 400 mp有帮助吗?
  • 没有多大意义,有了这个接口并且没有能力在函数内部引入随机性,一个由单一颜色组成的色块永远不会产生实际的噪声,因为无论做什么计算,由于输入永远不会改变,因此返回值仍将保持不变。该函数应该有一个额外的参数,一个索引,坐标等等。
  • Anttii,颜色参数是有助于产生噪声的参数,就像单个片段像素颜色一样,因此通过长度(颜色)可以生成随机噪声,因为每个像素都是不同的.除了具有 FP16 的 GPU 之外,该算法在所有 GPU 上都能完美运行
  • 恐怕要对真正的噪音进行编码,需要一些静态变量,这些变量在片段中是不允许的。 (uniform 或 in 不可用,因为它们不能为下一个片段更改和/或保留)所以唯一的方法是将失真作为片段位置、颜色或纹理坐标的函数,但这不是噪声:(。

标签: algorithm random shader 16-bit glsles


【解决方案1】:

虽然这是一个老问题,但我很久以前就找到了解决方案。接下来是脚本,以便任何人都可以使用它。作为种子,您应该传递一个动态或随机值,您可以将其作为属性传递给着色器。

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

【讨论】:

    【解决方案2】:

    这些是我使用的,但我不知道它们是否适用于 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。所以要小心。

    【讨论】:

    • 问题在于使用 sin(),它在 ES2 中非常非常依赖于实现。它在 IOS 上可能工作正常,但他的 Maali 显然做得不同。
    • 我认为使用纹理作为查找表将是下一个最佳选择。但我想那也已经结束了。
    【解决方案3】:

    散列函数就足够了吗? Pearson hashing 在过去是为 8 位寄存器设计的,并且非常简单:你硬编码一个 256 字节的查找表(或者,如果这是不可能的,某种简单但非线性的排列),它我们将调用 T。对于输入的每个字节,您将它与到目前为止的哈希值进行异或,然后查找该值以获得新的哈希值。

    在您的情况下,让 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:需要明确的是,这不会产生随机输出,因为您的输入没有随机性。但我认为它模仿了你的代码试图做的事情。

    【讨论】:

    • 不幸的是,openGL ES 没有整数数学,因此没有异或。与 cpus 相比,任何 lut 都非常昂贵。
    猜你喜欢
    • 2012-05-15
    • 1970-01-01
    • 2020-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-11
    • 2011-06-20
    • 1970-01-01
    相关资源
    最近更新 更多