cocos cretor shader effect-the book of shader-4.二维矩阵

2D Matrices(二维矩阵)

前面章节

  1. TheBookofShader开始
  2. Shaping functions(造型函数)
  3. Color(颜色)
  4. Shapes(形状)

平移

之前的章节我们学习了如何制作一些图形 - 而如何移动它们的技巧则是借助移动它们自身的参考坐标系。我们只需要给 st 变量加上一个包含每个片段的位置的向量。这样就移动了整个坐标系。

在这里插入图片描述

还是画着比较更容易解释,如上图所示:

  • 取消下面代码中的注释( color = vec3(st.x,st.y,0.0);),看下坐标空间是如何平移的。
// Author @patriciogv ( patriciogonzalezvivo.com ) - 2015

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform float u_time;

//生成一个长方形
float box(in vec2 _st, in vec2 _size){
    //这里得到盒子的点的坐标
    _size=vec2(0.5)-_size*0.5;
    //差值平滑,如果st小于_size,则返回0,如果大于_size+0.001,则返回1
    vec2 uv=smoothstep(_size,_size+vec2(0.001),_st);
    //
    uv*=smoothstep(_size,_size+vec2(0.001),vec2(1.0)-_st);
    //x,y的值都是0,1。都为0才是0,都为1才是1
    return uv.x*uv.y;
}

//生成横的长方形和竖的长方形
float cross(in vec2 _st, float _size){
    return  box(_st, vec2(_size,_size/4.)) +
            box(_st, vec2(_size/4.,_size));
}

void main(){
    vec2 st = gl_FragCoord.xy/u_resolution.xy;
    vec3 color = vec3(0.0);

    // To move the cross we move the space
    vec2 translate = vec2(cos(u_time),sin(u_time));
    st += translate*0.35;

    // Show the coordinates of the space on the background
    // color = vec3(st.x,st.y,0.0);

    // Add the shape on the foreground
    color += vec3(cross(st,0.25));

    gl_FragColor = vec4(color,1.0);
}


在这里插入图片描述

位移的代码主要是通过下面两句代码

 vec2 translate = vec2(cos(u_time),sin(u_time)); 
 st += translate*0.35;

我们根据时间来改变其位移,通过sin,cos获取从0-1的坐标范围。然后赋值给st,其实就是把我们生成的盒子的中心点改变,使其根据函数来变化其坐标从而达到绕着圆位移的作用,我们在第一句话加点参数

vec2 translate=vec2(cos(speedcc_time.x),sin(speedcc_time.x))*translateRadius;

其中speed是位移的速度,translateRadius就是围绕圆的半径

现在尝试下下面的练习:

  • 结合 u_time 和造型函数来移动十字,并试着让它有趣一点。找一个你觉得你感兴趣的某种运动形式,让这个十字也这样运动。记录“真实世界”的一些现象或许对你有所启发 — 可以是波的运动,摆动,弹球,汽车的加速运动,一辆自行车的刹车。

旋转

要移动物体,我们同样需要移动整个空间(坐标)系统。为此我们将使用一个矩阵。矩阵是一个通过行和列定义的一组数。用矩阵乘以一个向量是用一组精确的规则定义的,这样做是为了以一组特定的方式来改变向量的值。

在这里插入图片描述

GLSL本身支持2维,3维和4维方阵(mm矩阵):mat2 (2x2), mat3 (3x3) 和 mat4 (4x4)。GLSL同样支持矩阵相乘 ()和特殊矩阵函数([matrixCompMult()](…/glossary/?search=matrixCompMult))。

基于矩阵的特性,我们便有可能构造一个矩阵来产生特定的作用。比如我们可以用一个矩阵来平移一个向量:

在这里插入图片描述

更有趣的是,我们可以用矩阵来旋转坐标系统:

在这里插入图片描述

看下下面构成2维旋转的矩阵的代码。这个函数根据上面的公式,将二维向量绕 vec2(0.0) 点旋转。

mat2 rotate2d(float _angle){
    return mat2(cos(_angle),-sin(_angle),
                sin(_angle),cos(_angle));
}

上面是一个2d旋转的矩阵公式,我在这里就不详细展开来说了。

根据以往我们画形状的方式,这并不是我们想要的。我们的十字是画在画布中心的,对应于点 vec2(0.5) 。所以,再旋转坐标空间之前,我们需要先把图形移到中心点,坐标 vec2(0.0) ,再旋转坐标空间,最后在移动回原点。

在这里插入图片描述

就像下面的代码:

// Author @patriciogv ( patriciogonzalezvivo.com ) - 2015

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.14159265359

uniform vec2 u_resolution;
uniform float u_time;

mat2 rotate2d(float _angle){
    return mat2(cos(_angle),-sin(_angle),
                sin(_angle),cos(_angle));
}

float box(in vec2 _st, in vec2 _size){
    _size = vec2(0.5) - _size*0.5;
    vec2 uv = smoothstep(_size,
                        _size+vec2(0.001),
                        _st);
    uv *= smoothstep(_size,
                    _size+vec2(0.001),
                    vec2(1.0)-_st);
    return uv.x*uv.y;
}

float cross(in vec2 _st, float _size){
    return  box(_st, vec2(_size,_size/4.)) +
            box(_st, vec2(_size/4.,_size));
}

void main(){
    vec2 st = gl_FragCoord.xy/u_resolution.xy;
    vec3 color = vec3(0.0);

    // move space from the center to the vec2(0.0)
    st -= vec2(0.5);
    // rotate the space
    st = rotate2d( sin(u_time)*PI ) * st;
    // move it back to the original place
    st += vec2(0.5);

    // Show the coordinates of the space on the background
    // color = vec3(st.x,st.y,0.0);

    // Add the shape on the foreground
    color += vec3(cross(st,0.4));

    gl_FragColor = vec4(color,1.0);
}

我们可以把旋转的代码与位移结合起来,在cocos上的代码就是如此:
coffeescript

vec2 translate=vec2(cos(speed*cc_time.x),sin(speed*cc_time.x))*translateRadius;
st+=translate;

     st-=vec2(.5);
    st=rotate2d(sin(cc_time.x)*PI)*st;
    st+=vec2(.5); 

    _color = vec3(st.x,st.y,0.0);
    float t=cross2(st,0.2);
    _color+=vec3(t);

    gl_FragColor = vec4(_color,1.);

在这里插入图片描述

缩放

我们看到了如何用矩阵平移和旋转物体。(或者更准确的说,如何通过变换坐标系统来旋转和移动物体。)如果你用过3D建模软件或者 Processing中的 pushmatrix 和 popmatrix 函数,你会知道矩阵也可以被用来缩放物体的大小。

在这里插入图片描述

根据上面的公式,我们知道如何构造一个2D缩放矩阵:

mat2 scale(vec2 _scale){
    return mat2(_scale.x,0.0,
                0.0,_scale.y);
}

// Author @patriciogv ( patriciogonzalezvivo.com ) - 2015

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.14159265359

uniform vec2 u_resolution;
uniform float u_time;

mat2 scale(vec2 _scale){
    return mat2(_scale.x,0.0,
                0.0,_scale.y);
}

float box(in vec2 _st, in vec2 _size){
    _size = vec2(0.5) - _size*0.5;
    vec2 uv = smoothstep(_size,
                        _size+vec2(0.001),
                        _st);
    uv *= smoothstep(_size,
                    _size+vec2(0.001),
                    vec2(1.0)-_st);
    return uv.x*uv.y;
}

float cross(in vec2 _st, float _size){
    return  box(_st, vec2(_size,_size/4.)) +
            box(_st, vec2(_size/4.,_size));
}

void main(){
    vec2 st = gl_FragCoord.xy/u_resolution.xy;
    vec3 color = vec3(0.0);

    st -= vec2(0.5);
    st = scale( vec2(sin(u_time)+1.0) ) * st;
    st += vec2(0.5);

    // Show the coordinates of the space on the background
    // color = vec3(st.x,st.y,0.0);

    // Add the shape on the foreground
    color += vec3(cross(st,0.2));

    gl_FragColor = vec4(color,1.0);
}

同样的,我们把位移旋转和缩放的效果放在一起,看下其效果

    /**********位移操作*******/
    vec2 translate=vec2(cos(speed*cc_time.x),sin(speed*cc_time.x))*translateRadius;
    st+=translate;

 /**********旋转缩放操作*******/
     st-=vec2(.5);
    st=rotate2d(sin(cc_time.x)*PI)*st;
    st=scale(vec2(sin(cc_time.x)+1.))*st;
    st+=vec2(.5); 

    _color = vec3(st.x,st.y,0.0);
    float t=cross2(st,0.2);
    _color+=vec3(t);

    gl_FragColor = vec4(_color,1.);

在这里插入图片描述

Other uses for matrices: YUV color 矩阵的其他应用:YUV 颜色

YUV 是个用来模拟照片和视频的编码的色彩空间。这个色彩空间考虑人类的感知,减少色度的带宽。

下面的代码展现一种利用GLSL中的矩阵操作来切换颜色模式的有趣可能。

// Author @patriciogv - 2015
// http://patriciogonzalezvivo.com
#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform float u_time;

// YUV to RGB matrix
mat3 yuv2rgb = mat3(1.0, 0.0, 1.13983,
                    1.0, -0.39465, -0.58060,
                    1.0, 2.03211, 0.0);

// RGB to YUV matrix
mat3 rgb2yuv = mat3(0.2126, 0.7152, 0.0722,
                    -0.09991, -0.33609, 0.43600,
                    0.615, -0.5586, -0.05639);

void main(){
    vec2 st = gl_FragCoord.xy/u_resolution;
    vec3 color = vec3(0.0);

    // UV values goes from -1 to 1
    // So we need to remap st (0.0 to 1.0)
    st -= 0.5;  // becomes -0.5 to 0.5
    st *= 2.0;  // becomes -1.0 to 1.0

    // we pass st as the y & z values of
    // a three dimensional vector to be
    // properly multiply by a 3x3 matrix
    color = yuv2rgb * vec3(0.5, st.x, st.y);

    gl_FragColor = vec4(color,1.0);
}

正如你所见,我们用对向量乘以矩阵的方式对待色彩。用这种方式,我们“移动”这些值。

这章我们学习如何运用矩阵变换来移动,旋转和缩放向量。除了之前章节学的图形,这些变换是创作的基础。在接下来的章节我们会应用我们所学的制作漂亮的程序纹理。你会发现编程的重复性和多样性是种令人兴奋的实践。

源代码:

// Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.  

CCEffect %{
  techniques:
  - passes:
    - vert: vs
      frag: fs
      blendState:
        targets:
        - blend: true
      rasterizerState:
        cullMode: none
      properties:
        texture: { value: white }
        alphaThreshold: { value: 0.5 }
        translateRadius: {value: 0.5 }
        speed: {value: 1.0}
}%


CCProgram vs %{
  precision highp float;

  #include <cc-global>
  #include <cc-local>

  in vec3 a_position;
  in vec4 a_color;
  out vec4 v_color;

  #if USE_TEXTURE
  in vec2 a_uv0;
  out vec2 v_uv0;
  #endif

  void main () {
    vec4 pos = vec4(a_position, 1);

    #if CC_USE_MODEL
    pos = cc_matViewProj * cc_matWorld * pos;
    #else
    pos = cc_matViewProj * pos;
    #endif

    #if USE_TEXTURE
    v_uv0 = a_uv0;
    #endif

    v_color = a_color;

    gl_Position = pos;
  }
}%


CCProgram fs %{
  precision highp float;
  
  #include <alpha-test>
  #include <texture>
  #include <cc-local>
  #include <cc-global>

  in vec4 v_color;

  #if USE_TEXTURE
  in vec2 v_uv0;
  uniform sampler2D texture;
  #endif

  uniform ScriptVal{
    float translateRadius;
    float speed;
  };

  float PI=3.1415726;

  mat2 scale(vec2 _scale)
  {
    return mat2(_scale.x,0.,0.,_scale.y);
  }

   mat2 rotate2d(float angle)
  {
    return mat2(cos(angle),-sin(angle),sin(angle),cos(angle));
  }


  float box(vec2 _st,vec2 _size)
  {
    //这里得到盒子的点的坐标
    _size=vec2(0.5)-_size*0.5;
    //差值平滑,如果st小于_size,则返回0,如果大于_size+0.001,则返回1
    vec2 uv=smoothstep(_size,_size+vec2(0.001),_st);
    //
    uv*=smoothstep(_size,_size+vec2(0.001),vec2(1.0)-_st);
    //x,y的值都是0,1。都为0才是0,都为1才是1
    return uv.x*uv.y;
  }

  float cross1(vec2 _st,float _size)
  {
    return box(_st,vec2(_size,_size/4.));
  }

  float cross2(vec2 _st,float _size)
  {
    return box(_st,vec2(_size,_size/4.))+box(_st,vec2(_size/4.,_size));
  }


  void main () {
    vec4 o = vec4(1, 1, 1, 1);
    #if USE_TEXTURE
      CCTexture(texture, v_uv0, o);
    #endif
    o *= v_color;
    ALPHA_TEST(o);
    vec2 st=v_uv0;
    vec3 _color=vec3(0.5);

    vec2 translate=vec2(cos(speed*cc_time.x),sin(speed*cc_time.x))*translateRadius;
  //   translate=vec2(abs(cos(2.*cc_time.x)),abs(sin(2.*cc_time.x)));
    st+=translate;

     st-=vec2(.5);
    st=rotate2d(sin(cc_time.x)*PI)*st;
    st=scale(vec2(sin(cc_time.x)+1.))*st;
    st+=vec2(.5); 

    _color = vec3(st.x,st.y,0.0);
    float t=cross2(st,0.2);
    _color+=vec3(t);

    gl_FragColor = vec4(_color,1.);
  }
}%

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值