v7投稿 | 常见噪声函数原理及故障艺术应用

常见噪声函数原理及故障艺术应用

引言: 常常精妙于大自然的鬼斧神功,每个生命都独一无二,也基本无法找到实现其一模一样效果的函数,即使是形如噪声函数这样,能做出类似大理石、云朵一样的效果,但也无法精确描绘每个真实存在的云的形状。

噪声函数,也被称为随机函数或随机场,是一种创建复杂的随机模式的方法,可以用于纹理生成、景观模拟、云朵生成、湖面水波纹生成。具有一定的随机性,但也不是完全无规则,是一种伪随机形态函数。

噪声函数常见的生成步骤有

  1. 划分网格
  2. 顶点处生成随机值(或者为标量、或者为矢量)
  3. 根据周围几个顶点值通过插值计算混合值,得到当前位置的值

在这三个步骤中,如何划分网格、顶点如何生成随机值、插值计算算法、网格边缘处计算方式,这几个问题,存在不同的具体方案。因此,也细分多种噪声函数。

噪声种类

  • 值噪声(value noise)

    实现简单、能快速生成噪声。

    可以用值噪声进行入门,其步骤为

    (1)简单的划分网格可以通过uv * vec2(widthScale, heightScale)实现

    (2)找到当前的像素点所在的网格floor(uv)

    (3)通过左上、左下、右上、右下的网格顶点值(注:需要补充图TODO: ),计算对应的随机值

    (3)通过插值函数,进行平滑过渡
    image

    原理:划分网格后,在每个整数点生成随机标量值,然后使用插值方法在这些点之间创建平滑的过渡。

    // 随机函数得到随机值
    float random2(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(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
    }
    
    // value noise函数
    float noise(vec2 st) {
      vec2 i = floor(st);
      vec2 f = fract(st);
      
      vec2 u = f*f * (3.0 - 2.0 * f); // cubic函数,平滑过渡
      
      return mix(mix(random2(i + vec2(0.0, 0.0)),
      random2(i + vec2(1.0, 0.0)), u.x),
      mix(random2(i + vec2(0.0, 1.0)),
      random2(i + vec2(1.0, 1.0)), u.x), u.y);
    }
    

    效果
    image

    详细代码可见: https://github.com/ZhuangWeiMian/cocos_effect/tree/main/assets/noise/value_noise

  • 梯度噪声(gradient noise)

    在value noise的场景中,由于网格顶点生成随机值的部分,是标量的形式进行生成,没有方向性,因此会出现比较明显的网格状效果。在梯度噪声中,生成的随机值,是以梯度向量的方式生成,缓解了一部分的网格状效果。关键代码部分:

    // 生成具有x、y方向的二维随机值
    vec2 random2(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);
    }
    

    效果
    image

  • 柏林噪声(Perlin noise)(注解上原理文章)

    柏林噪声则是一种改进的梯度噪声,在原有基础上,增加了一些平滑过渡插值、八度音阶(叠加多个不同幅度、不同频率),增加了一定的复杂度,但是提供了更高维度的变换效果,更加自然、连续的噪声效果。
    效果
    image

    完整代码可见https://github.com/ZhuangWeiMian/cocos_effect/tree/main/assets/noise/perlin_noise

  • 简单x噪声(Simplex noise)(注解上原理文章)

    Simplex噪声则是在柏林噪声上更进一步优化, Simplex 噪声使用的是单纯形网格(在二维空间是等边三角形,在三维空间是四面体),单纯形的所有边的长度都是相等的,因此在任何方向上的距离都是相同的,不会出现像 Perlin 噪声 那样在对角线方向上的距离更远的问题。这就使得 Simplex噪声 在各个方向上的性质更为一致,各向异性更低。
    效果
    image

    完整代码可见https://github.com/ZhuangWeiMian/cocos_effect/tree/main/assets/noise/simplex_noise

  • 细胞噪声(Worley noise)

    Worley 噪声基于随机点的分布来生成噪声图案,它具有更自然、更有结构的特性。(因为看起来很像细胞,不喜欢所以不实现。image

常见故障艺术

故障艺术(Glitch Art)是赛博朋克风格中常见的艺术风格,通过分离变化图像中的颜色,进一步艺术加工,呈现不一样的风格。

常见的故障艺术类型,有四类,主要分为颜色分离、异常色块、uv纹理抖动、屏幕抖动。而在这几种类别中,又可以根据变换的图形差异,有新的小类展示

  • 颜色分离

    又称RGB分离,也称颜色偏离故障。一般会用不同的uv偏移值取色,一般是一个通道的uv不偏移,对另外两个通道uv进行偏移

    关键代码:

    // 分离参数,复杂可以根据时间变化、频率、幅度
    float splitAmout = 0.05;
    colorR = texture2D(texture, vec2(v_uv0.x + splitAmout, v_uv0.y));
    colorG = texture2D(texture,  vec2(v_uv0.x, v_uv0.y));
    colorB = texture2D(texture, vec2(v_uv0.x - splitAmout, v_uv0.y));
    
    vec3 colorFinal = mix(vec3(colorR.r, colorG.g, colorB.b), colorG.rgb, .2);
    

    原图
    image
    效果
    image

    复杂一点可以根据时间、叠加多个正弦函数、调整频率

     float splitAmout = (1.0 + sin(cc_time.x * 6.0)) * 0.5;
     splitAmout *= 1.0 + sin(cc_time.x * 16.0) * 0.5;
     splitAmout *= 1.0 + sin(cc_time.x * 19.0) * 0.5;
     splitAmout *= 1.0 + sin(cc_time.x * 27.0) * 0.5;
     splitAmout = pow(splitAmout, 10.0);
     splitAmout *= (0.05 * 10.0);
    
     colorR = texture2D(texture, vec2(v_uv0.x + splitAmout, v_uv0.y));
     colorG = texture2D(texture,  vec2(v_uv0.x, v_uv0.y));
     colorB = texture2D(texture, vec2(v_uv0.x - splitAmout, v_uv0.y));
    
     vec3 colorFinal = mix(vec3(colorR.r, colorG.g, colorB.b), colorG.rgb, .2);
    
    

    效果
    output
    完整代码:https://github.com/ZhuangWeiMian/cocos_effect/tree/main/assets/glitch_art/rgb_split

  • 异常色块

    这里主要是色块的生成,形如方块形状、长条形状则可以用floor函数生成,floor(uv.y * 10)这种可以把y轴划分为十份,然后色块随机设置透明度或者色值叠加

      float randomNoise(vec2 seed)
      {
        return mod(sin(dot(seed * floor(cc_time.x * 10.0), vec2(17.13, 3.71))) * 43758.5453123, 1.0);
      }
    
    	// 生成随机色块
      float noise = randomNoise(floor(st));
      // 加强强度
      float displaceNoise = pow(noise, 8.0) * pow(noise, 8.0);
    
      vec4 colorR = texture2D(texture, vec2(v_uv0.x + displaceNoise * 0.05 * randomNoise(7.0), v_uv0.y));
      vec4 colorG = texture2D(texture, vec2(v_uv0.x, v_uv0.y));
      vec4 colorB = texture2D(texture, vec2(v_uv0.x - displaceNoise * 0.05 * randomNoise(7.0), v_uv0.y));
    
    	gl_FragColor = vec4(colorR.r, colorG.g, colorB.b, 1.0);
    
    

    进一步,可以调整方块的大小,方块大小不一致,调整方块形状,比如圆形或者其他形状、或者是条形状。

    11

    // 生成随机色块 叠加不同形状的方形
      float noise1 = randomNoise(floor(st.xy * 5.0));
      float noise2 = randomNoise(floor(st.xy * 3.0));
      // 加强强度
      float displaceNoise1 = pow(noise1, 2.0);
      float displaceNoise2 = pow(noise2, 6.0);
      float displaceNoise = fract(displaceNoise1 * displaceNoise2 * 10.0);
    

    效果
    output

  • uv分层抖动

    在生成色块后,移动uv,使得图像呈现抖动效果,核心在于uv的变化

    vec2 st = v_uv0.xy * 1.0;
      
      float strength = .1;
      float splitNumber = 10.0;
      float pixelSizeX = .5;
      float speed = 50.0;
    
      // 划分变化区域 通过调整uv采样的位置 模拟了屏幕信号的块状抖动传输故障
      if (mod(st.y * splitNumber, 2.0) < 1.0)
      {
        st.x += pixelSizeX * cos(cc_time.x * speed) * strength;
      }
      
      vec4 colorG = texture2D(texture, vec2(st.x, st.y));
      
      gl_FragColor = vec4(colorG.r, colorG.g, colorG.b, 1.0);
    

    效果
    output
    完整代码:https://github.com/ZhuangWeiMian/cocos_effect/tree/main/assets/glitch_art/tile_jitter

    进一步,可以变化色块的大小,实现差异的色块大小

  • 扫描线&噪点故障

    实现上主要是通过对uv进行基于noise的抖动效果

    float jitter = randomNoise(st.y, cc_time.x) * 2.0 - 1.0;
    jitter *= step(scanLineJitterY, abs(jitter)) * clamp(sin(cc_time.x / 2.0) + sin(cc_time.x) + sin(cc_time.x / 4.0), 0.0, 1.0);
      
    vec4 colorG = texture2D(texture, mod(st + vec2(jitter, 0.0), 1.0));
    gl_FragColor = colorG;
    

    效果
    output
    完整代码: https://github.com/ZhuangWeiMian/cocos_effect/tree/main/assets/glitch_art/scan_line_jitter

    模拟噪点故障,在于用noise去扰动原先场景图的颜色值

      float speed = 2.0;
      
      vec4 colorG = texture2D(texture, st);
      float noiseX = randomNoise(cc_time.x * speed + st / vec2(-213, 5.53));
      float noiseY = randomNoise(cc_time.x * speed - st / vec2(213, - 5.53));
      float noiseZ = randomNoise(cc_time.x * speed + st / vec2(213, 5.53));
      
      colorG.rgb += 0.5 * vec3(noiseX, noiseY, noiseZ) - 0.25;
      
      gl_FragColor = vec4(colorG.r, colorG.g, colorG.b, 1.0);
    

    效果
    output
    完整代码: https://github.com/ZhuangWeiMian/cocos_effect/tree/main/assets/glitch_art/analog_noise

除了类似的故障艺术之外,同时也会有一些特殊类似图片消融、湖泊、水面、树叶、云朵的生成。同时在一些需要随机的场景中也能有比较好的表现。

25赞

赞保存了!!!

:cow: :beer:

牛皮plus

牛皮pro

牛皮pro max

mark。。。

mark!!!!!!

用牛牛给牛牛点赞,牛牛牛逼牛爆了

哈哈哈哈哈哈哈哈笑死我了

markkkkkkkkkkkkkkkkk!

小母牛坐飞机,牛逼上天了 :laughing: