河面水流的效果
又名,噪声图的花式用法
- 抄自哪里的呢?网上看别的人游戏有一个,就搞了搞试试,还凑合
- 开始吧,弄个干净的shader,然后布个游戏场景
主场景图
这张图是反转y轴,放在下方做水面用的
场景摆一下,
NewSprite 缩放是-0.55 ,负数是为了反转y轴做镜像效果,0.55是因为?不可描述,总之水面的纹理是要y轴压缩的。。
NewSprite 用上我们新建的干净的shader和材质,shader删掉片元着色器我们不准备用的代码,老规矩,从一张黑图开始
precision highp float;
#include <alpha-test>
#include <texture>
#include <cc-global>
in vec4 v_color;
#if USE_TEXTURE
in vec2 v_uv0;
uniform sampler2D texture;
#endif
void main () {
vec3 color = vec3(0.);
// 弄个t接收cc_time.x, *= 0.6是因为正常速太快,变慢点 备用
float t = cc_time.x * 0.6;
gl_FragColor = vec4(color,1.);
}
- 噪声图
// 文件开头修改加入texture2的声明
properties:
texture: { value: white }
// 添加下面的行 本行注释删掉,写在这里只是为了标识这是添加的
texture2: { value: white }
....
....
// 片元着色器修改成下面这样:
.....
uniform sampler2D texture;
// 添加下面的行
uniform sampler2D texture2;
void main () {
vec3 color = vec3(0.);
// 弄个t接收cc_time.x, *= 0.6是因为正常速太快,变慢点
float t = cc_time.x * 0.6;
// 对噪声图取样x通道,显示在屏幕上
color += texture2D(texture2,v_uv0).x;
gl_FragColor = vec4(color,1.);
}
然后打开点击材质,把噪声图拖拽到材质面板中的texture2中。
看下现在的样子
- 好,现在要用这个噪声图干嘛呢?做水波荡漾
取噪声图的xy两个通道,作为对场景图取样所用uv的偏移值,会出来什么效果呢?
片元着色器main函数改成下面这样
void main () {
vec3 color = vec3(0.);
// 弄个t接收cc_time.x, *= 0.6是因为正常速太快,变慢点
float t = cc_time.x * 0.6;
// + t * vec2(.5,.1)
vec2 off1 = texture2D(texture2,v_uv0).xy;
// 偏移值缩放0.1倍,不然波纹太过分了
off1 *= .1;
color += texture2D(texture,off1 + v_uv0).xyz;
gl_FragColor = vec4(color,1.);
}
可以看到,画面明显的扭曲了,但是现在还是静态的,需要加入时间参数让这个扭曲动起来
偏移值的0.1的缩放值还是太大,下面用0.01的试试
void main () {
vec3 color = vec3(0.);
// 弄个t接收cc_time.x, *= 0.6是因为正常速太快,变慢点
float t = cc_time.x * 0.6;
// v_uv0 + t * vec2(.5,.1) 这里的t是上面的时间,会持续增大的一个数值
// vec2(.5,.1) 是我随便写的一个方向向量,方向*时间 作为uv的偏移
// 噪声图设置 WrapMode = Repeat 否则偏移值超过vec2(1.,1.)之后就取不到值了,要改成repeat才可以取值
vec2 off1 = texture2D(texture2,v_uv0 + t * vec2(.5,.1)).xy;
// 偏移值缩放0.1倍,不然波纹太过分了
off1 *= .01;
color += texture2D(texture,off1 + v_uv0).xyz;
gl_FragColor = vec4(color,1.);
}
水面波动已经明显了。
- 水面的明暗变化,镜头越近颜色越暗
其实就是屏幕越往下变颜色越黑了。。
color += texture2D(texture,off1 + v_uv0).xyz;
// 参数0-1是正好 从黑到白的,用-.5->1.3这个范围,色值就是不太黑到不太白,免得颜色太极端
color *= smoothstep(-.5,1.3,v_uv0.y) - .3;
- 添加一些水面的浮沫
开头为啥说是噪声图的花式运用呢,因为这里又要用噪声图了。
对噪声图再来一次取值,前面讲的那一堆可以留下别管,也可以先删掉,单独看这一段。最后上个完全的代码吧
// baseuv做变换对噪声图取值
vec2 baseuv = v_uv0;
// 让噪声图x轴重复四次,y轴重复三次
vec2 scale = vec2(4.,3.);
baseuv = baseuv * scale;
float c1 = texture2D(texture2,baseuv).x;
color = vec3(c1);
gl_FragColor = vec4(color,1.);
海浪呢,不太对呢,怎么从这个海浪变换一个浮沫的效果出来呢?
float c1 = texture2D(texture2,baseuv).x;
// 加这一行
c1 = smoothstep(0.23,0.,c1);
color = vec3(c1);
啥原理呢,上面那个大浪啊,值0-1的,用smoothstep对大浪做个变换,只留下0-0.23的色值,大于0.23的都变成了纯黑色。
大概画一个函数曲线
c1值输入函数曲线后,0-0.23范围输出了0->1的值,越黑的地方越亮,亮的就变黑色了,就是上面图的效果了。
- 浮沫漂流起来
先做个思考,整体往左飘是不是有点太单调太假了,我还做shader干嘛呢,直接做个静态图往左移不就好了吗
不行,要做分行速度差。
分20行吧,每行做移动速度不同的漂流
float random (vec2 st) {
return fract(sin(dot(st.xy,
vec2(12.9898,78.233)))*
43758.5453123);
}
......
上面的函数加在main函数外面
下面的东西是main里面的
......
// 白沫的uv 所以取名mouv!
vec2 mouv = v_uv0;
// 做y轴分行,原理见彩虹那篇帖子
mouv.y *= 20.;
// n3就是行id 取名无力
float n3 = floor(mouv.y);
// n4就是用行id随机一个对应的随机值出来,每行一个随机值作为行的运动速度
// 所以对于y轴在同一行(注意上面*=20,所以共20行),我们这里计算出一个改行的运动速度,放在这备用
float n4 = random(vec2(n3,n3)) + .3;
// baseuv做变换对噪声图取值
vec2 baseuv = v_uv0;
// 让噪声图x轴重复四次,y轴重复三次
vec2 scale = vec2(4.,3.);
baseuv = baseuv * scale;
// 取值用的uv加上向左的移动 t是上面用过的那个cc_time.x哈,*0.1不然太快了
// n4是上面计算好的速度哈
baseuv.x += t * .1 * n4;
float c1 = texture2D(texture2,baseuv).x;
c1 = smoothstep(0.23,0.,c1);
color = vec3(c1);
- 用前面做出来的荡漾的水面加上下面的浮沫出来就是最终效果,贴代码吧
// 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 }
texture2: { value: white }
alphaThreshold: { value: 0.5 }
}%
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-global>
in vec4 v_color;
in vec2 v_uv0;
uniform sampler2D texture;
uniform sampler2D texture2;
float random (vec2 st) {
return fract(sin(dot(st.xy,
vec2(12.9898,78.233)))*
43758.5453123);
}
void main () {
vec3 color = vec3(0.);
// 弄个t接收cc_time.x, *= 0.6是因为正常速太快,变慢点
float t = cc_time.x * 0.6;
// v_uv0 + t * vec2(.5,.1) 这里的t是上面的时间,会持续增大的一个数值
// vec2(.5,.1) 是我随便写的一个方向向量,方向*时间 作为uv的偏移
// 噪声图设置 WrapMode = Repeat 否则偏移值超过vec2(1.,1.)之后就取不到值了,要改成repeat才可以取值
vec2 off1 = texture2D(texture2,v_uv0 + t * vec2(.5,.1)).xy;
// 偏移值缩放0.1倍,不然波纹太过分了
off1 *= .01;
color += texture2D(texture,off1 + v_uv0).xyz;
// 参数0-1是正好 从黑到白的,用-.5->1.3这个范围,色值就是不太黑到不太白,免得颜色太极端
color *= smoothstep(-.5,1.3,v_uv0.y) - .3;
// 白沫的uv 所以取名mouv!
vec2 mouv = v_uv0;
// 做y轴分行,原理见彩虹那篇帖子
mouv.y *= 20.;
// n3就是行id 取名无力
float n3 = floor(mouv.y);
// n4就是用行id随机一个对应的随机值出来,每行一个随机值作为行的运动速度
// 所以对于y轴在同一行(注意上面*=20,所以共20行),我们这里计算出一个改行的运动速度,放在这备用
float n4 = random(vec2(n3,n3)) + .3;
// baseuv做变换对噪声图取值
vec2 baseuv = v_uv0;
// 让噪声图x轴重复四次,y轴重复三次
vec2 scale = vec2(4.,3.);
baseuv = baseuv * scale;
// 取值用的uv加上向左的移动 t是上面用过的那个cc_time.x哈,*0.1不然太快了
// n4是上面计算好的速度哈
baseuv.x += t * .1 * n4;
float c1 = texture2D(texture2,baseuv).x;
c1 = smoothstep(0.23,0.,c1);
color += vec3(c1);
gl_FragColor = vec4(color,1.);
}
}%
- 后话
代码里的运动用的移动速度为了做gif看起来明显我调大了,各位自己搞的时候自己调调速度,挑一个自己满意的出来。
前面提到的一些分行 噪声的知识在下面链接
公众号,欢迎关注