在最后我们将一起实现如下图水面波动的效果,不过阅读完本文,也将了解到这一思路的其他用法
本篇默认读者本已经能读懂基本的glsl语言,语法不再做过多解释,如果有不理解可以翻看之前的文章有详细讲解
用shader制作马赛克
这是上帝的杰作:10行代码搞定“热成像”
几款2077风格的shader
如何扭曲图片
如何扭曲图片?方法多种多样,但偏移是其中比较常用也极其便宜的方式。比如可以让小骑士左侧身体偏移20%:
void main() {
if(st.x>0.5 ){
st.y+=0.2;
}
vec4 color = texture2D (u_image0, st);
gl_FragColor = vec4(color.rgb, 1.0);
}
st是一张(0.0)->(1,1)的二维平面,让其中右侧区域的像素点都读取其上方0.2位置处的像素信息,就实现了平移掉过,这种线性的平移我们在几款2077风格的shader一文中已经领教,但用它模拟扭曲是有点为难胖虎了。所以我们给他来点非线形的偏移:
#define PI 3.14//圆周率
#define E 2.71828//自然对数的底
.....
float Distribution(float x){
float a = 1.0/(4.0*PI*PI);
float b = pow(E,-(x-0.5)*(x-0.5)/0.04);
return a*b;
}
void main() {
st.y = mod(st.y+ 10.0*Distribution(st.x),1.0); // mod保证画面连续
vec4 color = texture2D (u_image0, st);
gl_FragColor = vec4(color.rgb, 1.0);
}
这里我们在x=0.5处添加了一个正太分布的偏移:
由正太分布的性质可以知道,越接近x=0.5偏移量越大,越接近1和0偏移越小。在一些需要实现非平面镜的场景中,这个shader可以结合鱼眼及其他扭曲一起实现一些鬼魅的效果。
意外的涂鸦效果
如果叠加一个正太方程就能实现扭曲,那么叠加一个波动方程可以实现怎样的效果?这里简单选取一个正弦波:
void main() {
vec2 offset = vec2(0.0);
offset.x = sin(st.x * 14.0) * .2;
offset.y = sin(st.y * 14.0) * .2;
vec4 color = texture2D(u_image0, uv+offset);
gl_FragColor = vec4(color.rgb, 1.0);
}
这里设置一个偏移量offset,由于需要在画面中出现连续的波峰和波谷,需要将函数的频率提高,同时我们不想让offset取值偏移到屏幕之外,所以控制了振幅,该选什么呢?就暂定0.2吧,然后:
克苏鲁降临了。
这是因为此时振幅还是过大,频率快可以在画面中出现多层次扭曲,振幅小意味着每次的波动是轻微的。可以做以下调整:
offset.x = sin(st.x * 14.0) * .02;
offset.y = sin(st.y * 14.0) * .02;
或者使用一个mix函数来实现:
vec2 coord = mix(st,st+offset, 0.01);
vec4 color = texture2D(u_image0, st+offset);
此时出现的效果就是:
这里控制下振幅就实现了一种常见的2D效果doodle(涂鸦):
这里我封装了一个函数来实现周期性的涂鸦效果,这在effect等动画工具中也是很常见的:
vec2 doodle(vec2 st, float speed, float amount) {
....
_Speed = (floor(u_time * 1.040 * _Speed) / _Speed) * _Speed;
...
vec2 offset = vec2(0.0);
offset.x = sin((st.x * _Amount + _Speed));
offset.y = cos((st.y * _Amount + _Speed));
...
}
其中_Speed是一个阶梯状函数,这是常见的用来实现跨度式变化的函数:
speed控制变化的快慢,amount控制振幅的大小,越大图像越夸张,推荐speed在(1,5)之间,amount则选择(5,15)
水面波动效果
最后可能观众老爷也猜到了,其实我们只要把阶梯函数去掉就能够实现,让speed呈现线形变化就能实现本文开头例子中的波动效果了。
_Speed = u_time; // 简单粗暴!!!
其实这个波动效果已经足够用了,但有一点太过规律了,如果需要提升的话,我们还需要再添加一些渐变的随机,这部分就留给读者盆友们自行思考了。
至于这个一鱼两吃的效果有什么应用,也留给读者盆友们吧。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。