关于webgl:如何实现水面波动一种代码实现两种效果shader-奇技淫巧

51次阅读

共计 1890 个字符,预计需要花费 5 分钟才能阅读完成。

在最初咱们将一起实现如下图水面稳定的成果,不过浏览完本文,也将理解到这一思路的其余用法

本篇默认读者本曾经能读懂根本的 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; // 简略粗犷!!!

其实这个稳定成果曾经足够用了,但有一点太过法则了,如果须要晋升的话,咱们还须要再增加一些突变的随机,这部分就留给读者盆友们自行思考了。

至于这个一鱼两吃的成果有什么利用,也留给读者盆友们吧。

正文完
 0