使用GLSL可以制作出很多漂亮有趣的材质效果
首先要理解,GLSL管道是消耗的gpu,我们的材质文件处理的是每一个像素点的逻辑。如果图片是10px*10px像素,那么图像渲染的时候,会同时执行10*10=100个材质渲染。(具体基础知识都在百度里)
所以,我们在做效果的时候,思路要放在每一个像素的处理上,比如,把图像上的一个颜色像素从(x1,y1)移动到(x2,y2)的位置,实际上接下来就是在(x1,y1)的位置上渲染(x2,y2)的内容。而非css或者js里面的translate和moveTo()这么简单。
具体实现思路:(首先创建material和effect)并且绑定在元素上
图片的属性,习惯性的去掉packable的勾选
为了方便对比,我放了两个素材
我们要让丝带动起来,必不可少的需要一个时间变量cc_time
打开之前新建并且绑定好关系的sidai.effect文件,在顶点输入(vs)代码里面定义时间变量,并输出出去:
定义v_time将时间cc_time变量赋值给他,并且输出(out)出去。
在片段输出(fs)代码中,接收(in)顶点输出的时间变量,时间是动起来的最基本的因素了。
解决了动起来的问题,我们下面要根据管道渲染的思路,来考虑每一个像素点的渲染来实现位移。
如果丝带想要飘起来,首先我们需要一个把他变成弯曲形状的力,我们要将像素按照这个坐标来移动,将原本在(x,0)的像素,分别在x的时候,改变y的值,使其当前的y有正有负
代码里面的v_uv0只是当前像素的位置和。我们需要的是整个图像的所有像素位置(为的就是在x1和y1上渲染x2和y2的像素信息,v_uv0只是当前x1y1的)。只能从外面传入进来了。
传入纹理尺寸:
接收图像宽高:(fs)
使用texture方法来获取到图像的像素颜色信息(使得我在x1y1可以获得到图像的x2y2的信息),添加一个sin函数,就会变形了。
x轴不变,y轴发生形变
因为sin函数的结果永远会落在±1.0,所以振幅的大小只是倍数的问题了。
由于图像坐标系是0.0到1.0所以,sin(v_uv0)永远没办法超过1,所以,v_uv0要*10或者更多,这决定了曲线的(频率)。
现在的图像是静态的,为了使其动起来,我们会在x不变的情况上加入y高低的变化,所以依然,还是在sin里面(为了确保有规律的往复运动),加入v_time:
这里一定要是加减v_time,而不要乘除
我们来看一下加减和乘除的区别
基本成形,但是存在一个问题,一般丝带的一头是固定好的。
这个5.0就是振幅的变化,当前情况永远是在0*5到1*5的振幅运动,
我们希望在x=0的振幅几乎为0,在x=1的时候振幅最大,所以我们需要一个增长函数,正好v_uv的x轴变化给我们提供了0-1的一个数值。
所以最终公式为:
o *= texture(texture, v_uv0.xy+ vec2(0.0,sin(v_uv0.x*10.0-(v_time.x*3.0))*(v_uv0.x*8.0)/textureSize.y));
效果呈现:
源码整理:cocos版本2.4.3,参数自行调整
// 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 }
# 纹理尺寸
textureSize: {
value: [100.0, 100.0],
editor: {
tooltip: "纹理尺寸px(宽 x 高)"
}
}
}%
CCProgram vs %{
precision highp float;
#include
#include
in vec3 a_position;
in vec4 a_color;
out vec4 v_color;
#if USE_TEXTURE
in vec2 a_uv0;
out vec2 v_uv0;
#endif
out vec4 v_time;
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;
v_time = cc_time;
gl_Position = pos;
}
}%
CCProgram fs %{
precision highp float;
#include
#include
in vec4 v_color;
#if USE_TEXTURE
in vec2 v_uv0;
uniform sampler2D texture;
#endif
in vec4 v_time;
// 接收外部变量
uniform GaussianBlur {
// 纹理尺寸(宽 x 高)(px)
vec2 textureSize;
};
void main () {
vec4 o = vec4(1, 1, 1, 1);
ALPHA_TEST(o);
o *= texture(texture, v_uv0.xy+ vec2(0.0,sin(v_uv0.x*10.0-(v_time.x*3.0))*(v_uv0.x*8.0)/textureSize.y));
gl_FragColor = o;
}
}%