OpenGL Shader-彩噪效果实现

884 阅读2分钟

「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战

了解噪声图生成逻辑之后,若需要实现彩噪图该怎么做呢?对于如何实现彩噪效果原理方法介绍好像是很少的。在shaderToy上发现了一个生成彩噪demo地址,在该demo中实现了生成随机彩噪的方法。

彩噪效果

如上所述该demo由音频文件数据作为二维向量输入点,其数据可以当做随机数来使用。但当实际过程中若直接使用uv作为二维向量输入点时会发现最终效果并不是彩噪效果。

float value = 1.0;
const float PHI = 1.61803398874989484820459; // Φ = Golden Ratio 

float gold_noise(in vec2 xy, in float seed)
{
    return fract(tan(distance(xy*PHI, xy)*seed)*xy.x);
}

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    vec4 noise = vec4(gold_noise(uv, fract(value)+1.0), // r
                gold_noise(uv, fract(value)+2.0), // g
                gold_noise(uv, fract(value)+3.0), // b
                1.0); 
    gl_FragColor = noise;
}

image.png

因为输入uv并不是随机数的原因导致最终呈现效果上看是有规律的结果。这里就需要用到噪点随机函数公式来完成uv向量值的随机性。因此又需要使用到random函数来实现效果。

vec2 random(vec2 st){
    st = vec2( dot(st,vec2(127.1,311.7)),
              dot(st,vec2(269.5,183.3)) );
    return -1.0 + 2.0*fract(sin(st)*43758.5453123);
}
vec2 randomVec2 = random(uv);
vec4 noise = vec4(gold_noise(uv, fract(value)+1.0), // r
            gold_noise(uv, fract(value)+2.0), // g
            gold_noise(uv, fract(value)+3.0), // b
            1.0); 
gl_FragColor = noise;

image.png 最终成像上就完成了彩噪显示,然后可以加上纹理图像后就达到特效叠加的效果了。

原图彩噪叠加
image.pngimage.png

扩展

除了上述的彩噪效果之外再结合对于随机数加强会得出不一样的彩噪结果。

vec2 randomVec2 = random(uv) * random(uv);vec2 randomVec2 = sqrt(random(uv));
image.pngimage.png

此外彩噪算法还有其他函数公式可以实现,当然最终效果也会有所差异。

  • 彩噪②
vec4 noise(vec4 v){
    // ensure reasonable range
    v = fract(v) + fract(v*1e4) + fract(v*1e-4);
    // seed
    v += vec4(0.12345, 0.6789, 0.314159, 0.271828);
    // more iterations => more random
    v = fract(v*dot(v, v)*123.456);
    v = fract(v*dot(v, v)*123.456);
    return v;
}

void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    gl_FragColor = noise(vec4(gl_FragCoord.xy, 1.0, 0.0));;
}
  • 彩噪③
vec2 hash( vec2 p ) // replace this by something better
{
    p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) );
    return -1.0 + 2.0*fract(sin(p)*43758.5453123);
}

float noise( in vec2 p ,in float seed)
{
    const float K1 = 0.366025404; // (sqrt(3)-1)/2;
    const float K2 = 0.211324865; // (3-sqrt(3))/6;

    vec2  i = floor( p + (p.x+p.y)*K1 );
    vec2  a = p - i + (i.x+i.y)*K2;
    float m = step(a.y,a.x); 
    vec2  o = vec2(m,1.0-m);
    vec2  b = a - o + K2;
    vec2  c = a - 1.0 + 2.0*K2;
    vec3  h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );
    vec3  n = h*h*h*h*vec3( dot(a,hash((i+0.0) * seed)), dot(b,hash((i+o)* seed)), dot(c,hash((i+1.0)*  seed)));
    return dot( n, vec3(70.0) );
}


void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    float r = noise( 200.0 *uv ,fract(iTime)+1.0) * 0.5 + 0.5;
    float g = noise( 200.0 *uv ,fract(iTime)+2.0) * 0.5 + 0.5;
    float b = noise( 200.0 *uv ,fract(iTime)+3.0) * 0.5 + 0.5;
    gl_FragColor = vec4( r, g, b, 1.0 );
}
彩噪②彩噪③
image.pngimage.png

总结

彩噪效果是噪点图的衍生,现有随机函数实现噪点图的生成,再赋予噪点图色值来实现了彩噪效果。对于基础原理和底层数学公式为何可以实现这样的效果还需要细细分析和挖掘。