这一篇也要从创建一个新的effect开始,先改一下
先把CCProgram fs{}改成截图的样
从纯白色的图开始,做下面的效果。
所以这个效果到底叫啥,为啥想不起来在哪见过的。蓝瘦。
shader的随机函数
先上一个随机函数,用 o.xyz = vec3(hashOld12(uv));
,用uv生成一个随机值并填入gl_FragColor.rgb生成看一下,一个无规则的噪声图。用这个函数的功能就是从uv生成随机数 但是这是用数学计算出的伪随机数,效果是对不同uv出来的值是随机的,但是对固定uv随机,每次随机的结果也是固定的。
原理参考:随机数生成
float hashOld12(vec2 p)
{
return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453);
}
上正文
屏幕分格
float drawLayer(float scale,vec2 uv)
{
// 注释设 scale为10的情况
// 输出值
float co = 0.;
// 拷贝一份uv用,不修改原uv
vec2 uv1 = uv;
// uv值范围从 0-1变为 0-scale scale值为10就是0-10范围
uv1 *= scale;
// floor向下取整,计算出格子所在下标,
// 10*10的格子,如果uv是 0.2345,0.2345,uv1就是2.345,2.345
// 取整后 即为该uv所在格子下表,2,2
// 0.2 <= uv < 0.3 该范围内所有uv坐标,处理后hv均为 2,2
vec2 hv = floor(uv1);
// fr是 fract对数字取小数部分, 0.2345,0.2345 -> uv1 2.345,2.345 -> 0.345,0.345
// 如 0.2 <= uv < 0.3 处理后就是一个范围 0-1的范围
vec2 fr = fract(uv1);
// 用fr.x+fr.y作为输出看一下结果
co += fr.x + fr.y;
return co;
}
把处理后的坐标反映到颜色上可以直观的看到处理后的数值,图片已经成功分成了10*10的格子
下面,就可以用 像素点计算出来的 分格后的 下表和在格内的坐标来对每个格子画圆看一下。
每个格子内画圆
vec2 hv = floor(uv1);
vec2 fr = fract(uv1);
// 画圆,用fr(即格内坐标)和 0.5,0.5的点的距离作为颜色值,circle范围0-0.5
float circle = distance(fr,vec2(.5));
// 上面的结果是距离值计算出来的,有明暗变化,用step把圆内都变成纯白色
float radius = 0.4; // 半径
circle = step(radius,circle);
// 1. - circle 翻转色值,使距离圆心越近颜色越亮
circle = 1. - circle;
co += circle;
co += drawGird(fr);
return co;
圆太规律了,要加点变化
随机函数终于用上了。
// 用hv引入随机的半径 因为一格内hv相同,随机值结果也就是半径值相等
float radius = hashOld12(hv);
大小差异太大了。
调一下,
// radius 0-1 映射到 0.1-0.4的范围
radius = radius * 0.3 + 0.1;
每个格里都有,太规整了,去掉一半圆吧
// 半径*10取整,对2取余,舍弃一半的圆
float f1 = mod(floor(radius * 10.),2.);
radius *= f1;
还是太整齐了
用hv.y做个随机,给该行的uv1.x做个差值吧
vec2 hvtemp = floor(uv1);
float n = hashOld12(vec2(hvtemp.y));
uv1.x += n;
// floor向下取整,计算出格子所在下标,
// 10*10的格子,如果uv是 0.2345,0.2345,uv1就是2.345,2.345
// 取整后 即为该uv所在格子下表,2,2
// 0.2 <= uv < 0.3 该范围内所有uv坐标,处理后hv均为 2,2
vec2 hv = floor(uv1);
// fr是 fract对数字取小数部分, 0.2345,0.2345 -> uv1 2.345,2.345 -> 0.345,0.345
// 如 0.2 <= uv < 0.3 处理后就是一个范围 0-1的范围
vec2 fr = fract(uv1);
差不多了,在多个随机亮度
......
float radius = hashOld12(hv);
// 亮度 用这个初始随机值做亮度用
float strength = radius;
......
circle = 1. - circle;
circle *= strength;
......
从creator传入参数
传入几个颜色看一下
colorLeft: { value: [1.,1.,1.,1.],editor: { type: "color"}}
colorRight: { value: [1.,1.,1.,1.],editor: { type: "color"}}
color1: { value: [1.,1.,1.,1.],editor: { type: "color"}}
color2: { value: [1.,1.,1.,1.],editor: { type: "color"}}
color3: { value: [1.,1.,1.,1.],editor: { type: "color"}}
一定要注意缩进,这个格式的文件格式很严格
加入这两块地方,片元着色器就可以访问这一堆变量了,从材质面板也可以编辑这一堆变量的值了。
加个背景色 在多家几层颜色
void main () {
vec2 uv = vec2(v_uv0.x,v_uv0.y);
vec3 co = vec3(0.);
// 加个背景色
co += mix(colorLeft,colorRight,uv.y).xyz;
vec4 carr[3];
carr[0] = color1;
carr[1] = color2;
carr[2] = color3;
for(int i = 0;i < 3;i++ ){
float idx = float(i);
// 用循环下表做一个递增的层半径
float p1 = idx * 5. + 3.;
// 给每一层做一个随机运动方向 也就是一个速度向量
vec2 uvoff = vec2(hashOld12(vec2(p1)),hashOld12(vec2(p1 * 10.0)));
// 速度*时间 = 偏移距离 让该层随时间运动 可以注释掉 *u_time 就不会运动了
uvoff = uvoff *u_time * .1;
vec2 p2 = vec2(uv.x,uv.y) + uvoff;
// p1 半径, p2 供计算的uv值
float layer = drawLayer(p1,p2);
co += layer * carr[i].xyz;
}
gl_FragColor = vec4(co,1.);
}
每一层都很亮,要做出远暗进亮怎么办?
让层亮度和格子大小成正比比例
// 让层亮度和格子大小成正比比例 (scale是uv的缩放数,越大 格子就越小)
// * 9 是因为有些暗,变亮点,这个值可以随便调调
strength *= 1. / scale * 9.;
circle *= strength;
现在,可以运行起来看一看了,
动态给shader传入参数 u_time
sp.getMaterial(0).effect.setProperty('u_time',this._utime);
this._utime自己用update累加一下哈 我的是每帧 += 0.01;
用js脚本实时修改shader的u_time的值,这时画面上的圆圈应该都能动起来了。
圆圈优化
//circle = step(radius,circle); 这一行注释掉,用下一行。这时模糊圆圈边缘的函数,0.02*scale就是模糊的宽度,这个系数也可以自己调整到喜欢的数值,
// 这个系数和strength乘的系数调整个不同的值,组合起来效果也大不一样。
circle = smoothstep(radius - .02 * scale,radius,circle);
我的审美也就止步于此了。。