love2d--glsl03噪声

由于一些glsl的教程都是3d的,而love是2d的,所以之后以示例为主,我会收集

一些love的shader,分类讲解。

此文简译自love2d社区博客,这里略去作者的自我介绍。

像素着色器入门

示例1:

--屏幕大小是512x512
function love.load()
    screen = love.graphics.newShader([[
        vec4 effect(vec4 colour, Image image, vec2 local, vec2 screen)
        {
            //红绿颜色分量按纹理坐标比例缩放 
            vec4 screen_colour = vec4(screen.x / 512.0,
                                      screen.y / 512.0,
                                      0.0,
                                      1.0);
 
            return screen_colour;
        }
    ]])
 
    texture = love.graphics.newShader([[
        vec4 effect(vec4 colour, Image image, vec2 local, vec2 screen)
        {
            //红绿颜色分量随纹理坐标缩放
            vec4 coord_colour = vec4(local.x, local.y, 0.0, 1.0);
            //使用纹理中合适的像素
            vec4 image_colour = Texel(image, local);
            // 混合两种颜色
            return mix(coord_colour, image_colour, 0.5);
        }
    ]])
 
    image = love.graphics.newImage("love-logo.png")
end
 
function love.draw()
    love.graphics.setShader(screen)
    --下面绘制了三个三角形
    love.graphics.polygon("fill", 0, 0, 0, 512, 512, 0)
    love.graphics.polygon("fill", 256, 256, 256, 512, 512, 256)
    love.graphics.polygon("fill", 384, 384, 384, 512, 512, 384)
 
    love.graphics.setShader(texture)
    love.graphics.draw(image, 256, 256, 0.5, 3, 3, 44.5, 44.5)
end

左边:像素着色器通过改变纹理坐标让纹理更多彩;x越靠近1,颜色越红;y越靠近

1,颜色越绿。右边:三角形的颜色由屏幕坐标确定,x越靠近屏幕宽,颜色越红;y

越靠近屏幕高颜色越绿(注意屏幕坐标y轴向上)

简单来说,像素效果是绘制时选择多边形每个像素的颜色和透明度的函数(当你绘制图像

时,实际上在绘制一个矩形,它每个像素的颜色和透明度已从图像数据里确定,这和绘制

颜色一样)。当前绘制的颜色、 屏幕像素的坐标、love程序本身都可以影响绘制效果; 如

果正在绘制Sprite,那么全部的图像数据以及像素纹理坐标都是可用的。

噪声简介

噪声是不可预测的数据,并在计算机图形学中用于生成类似自然的结构、 模式和纹理。通

过引入噪声,你可以创建没有明显重复的视觉效果或几何图案,也不需要预设的的纹理和

图片 ;也很容易产生动画效果。(附百度百科

在计算机图形学里最受欢迎的噪声是Perlin;它还常用于地形生成中,因为它可以产生随机

小山的外观。另一个是Worley 噪声,也被称为蜂窝噪声,因为它可以产生类单元格的外观。

    

左:统一值(值均匀)噪声        中: Perlin梯度噪声                   右:Worley 梯度噪声

在像素处理器里使用噪声

在love像素着色器里使用噪声并不难,网上有许多glsl的噪声例子,但我为你已经收集了大量

的例子。噪声通常以向量作输入因子;通常在空间维度,但你可以放任何你喜欢的东西,通过

添加额外的时间维,你可以创造非常好玩的动画。

--屏幕大小是512x512
function love.load()
  --[[
    -- 读入shader文件 原作是读文件,我这里直接放到字符串里
    local perlin = love.filesystem.read("perlin2d.glsl")
    ]]
    local perlin =[[
        //
    // GLSL textureless classic 2D noise "cnoise",
    // with an RSL-style periodic variant "pnoise".
    // Author:  Stefan Gustavson (stefan.gustavson@liu.se)
    // Version: 2011-08-22
    //
    // Many thanks to Ian McEwan of Ashima Arts for the
    // ideas for permutation and gradient selection.
    //
    // Copyright (c) 2011 Stefan Gustavson. All rights reserved.
    // Distributed under the MIT license. See LICENSE file.
    // https://github.com/ashima/webgl-noise
    //
    //看到不认识的函数请查看glsl 1.2版手册的62页
    
    //向量不能直接取余,这里定义了一个取余函数
    vec4 mod289(vec4 x)
    {
      return x - floor(x * (1.0 / 289.0)) * 289.0;
    }
    //下面的一些运算都是向量运算,为什么这么计算,就只有
    //查看相关的图形学了
    vec4 permute(vec4 x)
    {
      return mod289(((x*34.0)+1.0)*x);
    }

    vec4 taylorInvSqrt(vec4 r)
    {
      return 1.79284291400159 - 0.85373472095314 * r;
    }

    vec2 fade(vec2 t) {
      return t*t*t*(t*(t*6.0-15.0)+10.0);
    }

    // 经典perlin噪声
    float perlin2d(vec2 P)
    {
      vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0);
      vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0);
      Pi = mod289(Pi); // To avoid truncation effects in permutation
      vec4 ix = Pi.xzxz;
      vec4 iy = Pi.yyww;
      vec4 fx = Pf.xzxz;
      vec4 fy = Pf.yyww;

      vec4 i = permute(permute(ix) + iy);

      vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ;
      vec4 gy = abs(gx) - 0.5 ;
      vec4 tx = floor(gx + 0.5);
      gx = gx - tx;

      vec2 g00 = vec2(gx.x,gy.x);
      vec2 g10 = vec2(gx.y,gy.y);
      vec2 g01 = vec2(gx.z,gy.z);
      vec2 g11 = vec2(gx.w,gy.w);

      vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));
      g00 *= norm.x;  
      g01 *= norm.y;  
      g10 *= norm.z;  
      g11 *= norm.w;  

      float n00 = dot(g00, vec2(fx.x, fy.x));
      float n10 = dot(g10, vec2(fx.y, fy.y));
      float n01 = dot(g01, vec2(fx.z, fy.z));
      float n11 = dot(g11, vec2(fx.w, fy.w));

      vec2 fade_xy = fade(Pf.xy);
      vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
      float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
      return 2.3 * n_xy;
    }

    // 经典perlin噪声,周期变化
    float perlin2d_periodic(vec2 P, vec2 rep)
    {
      vec4 Pi = floor(P.xyxy) + vec4(0.0, 0.0, 1.0, 1.0);
      vec4 Pf = fract(P.xyxy) - vec4(0.0, 0.0, 1.0, 1.0);
      Pi = mod(Pi, rep.xyxy); // To create noise with explicit period
      Pi = mod289(Pi);        // To avoid truncation effects in permutation
      vec4 ix = Pi.xzxz;
      vec4 iy = Pi.yyww;
      vec4 fx = Pf.xzxz;
      vec4 fy = Pf.yyww;

      vec4 i = permute(permute(ix) + iy);

      vec4 gx = fract(i * (1.0 / 41.0)) * 2.0 - 1.0 ;
      vec4 gy = abs(gx) - 0.5 ;
      vec4 tx = floor(gx + 0.5);
      gx = gx - tx;

      vec2 g00 = vec2(gx.x,gy.x);
      vec2 g10 = vec2(gx.y,gy.y);
      vec2 g01 = vec2(gx.z,gy.z);
      vec2 g11 = vec2(gx.w,gy.w);

      vec4 norm = taylorInvSqrt(vec4(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));
      g00 *= norm.x;  
      g01 *= norm.y;  
      g10 *= norm.z;  
      g11 *= norm.w;  

      float n00 = dot(g00, vec2(fx.x, fy.x));
      float n10 = dot(g10, vec2(fx.y, fy.y));
      float n01 = dot(g01, vec2(fx.z, fy.z));
      float n11 = dot(g11, vec2(fx.w, fy.w));

      vec2 fade_xy = fade(Pf.xy);
      vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade_xy.x);
      float n_xy = mix(n_x.x, n_x.y, fade_xy.y);
      return 2.3 * n_xy;
    }

    
    
    ]]
    --把噪声函数和effect函数组合起来
    noise = love.graphics.newShader(perlin .. [[
        vec4 effect(vec4 colour, Image image, vec2 local, vec2 screen)
        {
            // 缩放屏幕坐标作为perlin噪声的参数
            number noise = perlin2d(screen / 128.0);
 
            // 噪声范围-1--1,修正它为0--1
            noise = noise * 0.5 + 0.5;
 
            return vec4(noise, noise, noise, 1.0);
        }
    ]])
end
 
function love.draw()
    love.graphics.setShader(noise)
    love.graphics.rectangle("fill", 0, 0, 512, 512)
end

尝试更多趣事

人们长期使用梯度噪声创造有趣的效果,网上又丰富的示例。我把收集了一些有趣的例子,你

可以快速的开始玩转。操作说明,用鼠标滚轮缩放、 按住右键平移,空格下一个效果, enter 键

模板开关。

  

左边:使用饱和 Worley噪音创建蓝色水波效果(在时间维中动画效果看起来很大) 。中间:绘制

模板多边形里的效果。右边:通过不断地添加缩放的 Perlin噪声可以创建烟熏效果。这种分形噪

声经常用于生成地形,因为它看起来类自然。底部:我在开发的游戏中,结合了前两种技术。

结论

像素效果不是太难学,噪声很容易产生详细而有趣的效果; 真正的难处是找到使用它的新方式。我

的噪声浏览器方便观察修改后的效果,你可以修改它来看可以得到什么。

注:非常感谢作者的辛勤劳动,前面的代码都可以用love2d 0.9运行,最后的“噪声浏览器",代码太多

我没修改,压缩包里已经附带了love 0.8版本。我的感觉shader不难,但用shader创造有趣的效果,需

要很多图形学和数学知识。对于我等小菜咋办,只有多多收集大神的shader了,在此上稍加修改,最好看

图形学和相关的数学知识。

此文所有代码下载地址,网盘

原文地址:https://www.cnblogs.com/xdao/p/love2d_shader03.html