水波擴散是一個比較好看的交互效果,特別是在某些以水爲故事發生場景的遊戲中,擴散的水波會讓場景更加栩栩如生web

實現思路
若是水波靜止,咱們看到的實際上是像素點圍繞着某個中心點的拉伸效果,咱們只需讓每一個像素點疊加上它和中心點的向量差,就可以呈現出畫面上的全部像素圍繞中心點的拉伸感。canvas
void main() {
vec2 uv = normalize(vec2(0.5, 0.5) - v_uv0) * 0.2 + v_uv0;
gl_FragColor = texture(texture, uv);
}

這個時候若是咱們加上時間參數,咱們就能夠獲得一個往外不停井噴的「黑洞」:微信
void main() {
vec2 uv = normalize(vec2(0.5, 0.5) - v_uv0) * 0.2 * cc_time.x + v_uv0;
gl_FragColor = texture(texture, uv);
}

可是水波往外擴散是呼吸燈式的一波波往外涌,並且不是這種無盡式的一直把東西往外掏的感受,因此咱們要給cc_time.x
加上一個週期性的變化,讓它能表現出這種週期性的往外擴散的感受。app
void main() {
vec2 uv = normalize(vec2(0.5, 0.5) - v_uv0) * 0.2 * sin(cc_time.x) + v_uv0;
gl_FragColor = texture(texture, uv);
}

這種呼吸燈式的涌動其實和咱們的最終效果有很大區別,由於它永遠在循環涌動,可是咱們的水波是從中心擴散出去以後,中間部分就再也不動了的,怎麼讓中間的像素再也不屢次涌動呢?若是把一圈水波比做圓,那水波的擴散行爲其實就是這個圓的半徑在不斷的增大,圓外面的波紋有效,圓裏面的波紋靜止。所以咱們能夠多加一個距離取樣,像素離擴散中心的距離大於半徑才保留不然丟棄,而這個半徑從零開始逐漸增大。async
void main() {
vec2 distance_vec = vec2(0.5, 0.5) - v_uv0;
float sin_factor = sin(cc_time.x) * 0.2;
float wave_radius = 0.3;
float distance = sqrt(distance_vec.x * distance_vec.x + distance_vec.y * distance_vec.y);
// 其中waveOffset是隨時間增加的,經過外部傳入
float dis_factor = clamp(wave_radius - abs(distance - wave_offset), 0.0, 1.0);
vec2 uv = v_uv0 + normalize(distance_vec) * sin_factor * dis_factor;
gl_FragColor = texture(texture, uv);
}

接下來的就是參數的調試,主要是三角函數的採樣那裏,咱們但願水波可以產生多個波動,因此咱們須要乘上必定的倍數,讓函數的做用範圍足夠大,纔能有足夠多的波峯谷底。另外就是sin函數的輸出值域在(-1, 1)
之間,因此咱們的輸出也須要縮小必定的倍數,才能讓函數的峯值變化處於一個合理的範圍。編輯器
void main() {
vec2 distance_vec = center - v_uv0;
distance_vec = distance_vec * vec2(canvas_size.x / canvas_size.y, 1.0);
float distance = sqrt(distance_vec.x * distance_vec.x + distance_vec.y * distance_vec.y);
// distance小於1,可是咱們但願能有多個波峯波谷,因此在sin的內部乘上一個比較大的倍數
// sin函數的值在-1到1之間,咱們但願偏移值很小,因此輸出的時候須要縮小必定的倍數倍
float sin_factor = sin(distance * 100.0 + cc_time.x) * 0.05;
float discard_factor = clamp(wave_radius - abs(wave_offset - distance), 0.0, 1.0);
// 計算總的uv的偏移值
vec2 offset = normalize(distance_vec) * sin_factor * discard_factor;
vec2 uv = offset + v_uv0;
gl_FragColor = texture(texture, uv);
}

效果預覽
源碼獲取請點擊查看原文,長按二維碼查看效果👇函數

我是異名,你的閱讀是個人動力ui
放大鏡效果 微信小遊戲首包超出4M以後 spa
本文分享自微信公衆號 - 異名(async-code)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。