前言
皮皮最近接到了一個小需求:
??美術(shù)小姐姐:皮皮皮皮,你能不能做奶茶流济?
??我:锐锣??绳瘟?
??美術(shù)小姐姐:就是那種雕憔,奶茶的輪廓加上動態(tài)水波紋~
??我:嚇?biāo)牢疫€以為讓我做喝的奶茶...
??美術(shù)小姐姐:炒雞多圖片都需要這種效果,用動畫的話工作量太大了糖声!
??我:波浪效果是吧斤彼,小意思,一個月的奶茶就夠了蘸泻,或者掃碼提需求~
??美術(shù)小姐姐:皮琉苇???????
??我:卒~
俗話說:遇事不決,量子力學(xué)寫雖得兒悦施。
根據(jù)我多年喝奶茶的經(jīng)驗并扇,像這種效果用 Shader 做就再簡單不過了,最終的效果如下:
趁此機會抡诞,本篇文章就來與小伙伴們分享動態(tài)波浪 Shader 的原理和制作思路吧穷蛹。
要注意的是土陪,這是一篇偏入門的文章,寫得會相對比較詳細(xì)肴熏,盡量讓不懂 Shader 的小白也可以看懂鬼雀,這也是我寫文章的一貫風(fēng)格。
好了蛙吏,話不多說取刃,進入正題~
正文
??整體思路
看到波浪的表現(xiàn)特點我第一時間想到的就是正弦曲線(或者說是正弦波,又讓我想起了示波器)出刷。
??正弦曲線(Sinusoid)
正弦曲線是三角函數(shù)中的一種正弦(Sine)比例的曲線璧疗。正弦曲線表現(xiàn)為一條波浪線,形狀猶如海上完美的波浪馁龟。
標(biāo)準(zhǔn)的正弦函數(shù)公式為:
正弦函數(shù)屬于周期函數(shù)崩侠,其值域為 [-1, 1]
。
如下圖就是一個純正標(biāo)準(zhǔn)的正弦曲線:
而一般我們常用的正弦曲線公式為:
這條公式比標(biāo)準(zhǔn)公式多了幾個常數(shù)坷檩,含義如下:
-
A
:振幅(Amplitude)却音,曲線最高點與最低點的差值,表現(xiàn)為曲線的整體高度 -
ω
:角速度(Angular Velocity)矢炼,控制曲線的周期系瓢,表現(xiàn)為曲線的緊密程度 -
φ
:初相(Initial Phase),即當(dāng)x = 0
時的相位句灌,表現(xiàn)為曲線在坐標(biāo)系上的水平位置 -
k
:偏距(Offset)夷陋,表現(xiàn)為曲線在坐標(biāo)系上的垂直位置
相位(Phase):上方公式中的
ωx±φ
部分稱為相位,相位發(fā)生在周期性的運動之中胰锌,最直接的理解就是角度骗绕。
?稍加思索
有了公式之后,我們可以嘗試調(diào)整其中的常數(shù)來改變函數(shù)曲線的形態(tài)资昧。
在查看下方的示例時酬土,請嘗試將曲線形態(tài)的變化與圖中右上角公式的變化關(guān)聯(lián)起來。
改變曲線的高度
我們可以調(diào)整常數(shù) A
(振幅)來改變曲線的值域(值域為 [-A, A]
):
改變曲線的周期
我們可以調(diào)整常數(shù) ω
(角速度)來改變曲線的周期:
改變曲線的水平位置
我們可以調(diào)整常數(shù) φ
(初相)來改變曲線的水平位置:
多說一句
其實對于“曲線的水平位置”這個描述是不太準(zhǔn)確的格带,因為初相實際上改變的是當(dāng) x = 0
時的相位撤缴,也就直接影響函數(shù)曲線在 x = 0
處的位置。
所以說曲線的位置并沒有真正改變叽唱,而只是曲線的形態(tài)發(fā)生了改變屈呕。
但是由于正弦曲線的周期性特點,曲線的這種形態(tài)變化看起來像是曲線進行了位移尔觉。
改變曲線的垂直位置
我們可以調(diào)整常數(shù) k
(偏距)來改變曲線的垂直位置:
??動手實現(xiàn)
明白了正弦曲線的特性之后凉袱,接下來我們需要做的就是在代碼中運用正弦函數(shù)。
慢著!正弦曲線確實如海上完美的波浪般優(yōu)美专甩,但是正弦曲線是靜態(tài)的钟鸵,我們要的波浪是動態(tài)的啊涤躲!
??如何讓曲線動起來
別慌棺耍!還記得我們可以調(diào)整初相來改變曲線的“水平位置”嗎?
既然如此种樱,我們可以給初相加入時間因素蒙袍,使得 y 值可以隨著時間的增加發(fā)生周期性變化,看起來就像是曲線在進行“水平位移”嫩挤。
就像這樣:
得到新的公式
加入時間因素 t
后的曲線公式:
??On Shadertoy
小貼士:由于 GLSL ES 沒有辦法進行調(diào)試害幅,所以寫 Shader 時可以先在 Shadertoy 中編寫并在線預(yù)覽,顯著提高效率岂昭。
一切盡在注釋中以现,簡單詳細(xì)且直觀。
主函數(shù)代碼如下:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// 將像素坐標(biāo)歸一化(區(qū)間 [0.0, 1.0])
// iResolution 是 Shadertoy 提供的視口分辨率全局變量(類型:vec3)
vec2 uv = fragCoord / iResolution.xy;
// 振幅(控制波浪頂端和底端的高度)
float amplitude = 0.05;
// 角速度(控制波浪的周期)
float angularVelocity = 10.0;
// 頻率(控制波浪移動的速度)
float frequency = 10.0;
// 偏距(設(shè)為 0.5 使得波浪垂直居中于屏幕)
float offset = 0.5;
// 初相位(正值表現(xiàn)為向左移動约啊,負(fù)值則表現(xiàn)為向右移動)
// iTime 是 Shadertoy 提供的運行時間全局變量(類型:float)
float initialPhase = frequency * iTime;
// 代入正弦曲線公式計算 y 值
// y = Asin(ωx ± φt) + k
float y = amplitude * sin((angularVelocity * uv.x) + initialPhase) + offset;
// 區(qū)分 y 值上下部分邑遏,設(shè)置不同顏色
vec4 color = uv.y > y ? vec4(0.0, 0.0, 0.0, 1.0) : vec4(0.0, 0.7, 0.9, 1.0);
// 輸出到屏幕
fragColor = color;
}
預(yù)覽效果如下(??是不是有內(nèi)味兒了):
??On Cocos Creator
我們主要關(guān)注片段著色器部分,這里就不展示整個 Effect 文件的代碼了恰矩,直接上傳送門吧记盒。
Effect 文件:https://gitee.com/ifaswind/eazax-ccc/blob/master/resources/effects/eazax-sine-wave.effect
代碼核心其實就是套用了公式,我們代碼注釋一起看吧外傅。
一切盡在注釋中纪吮,簡單詳細(xì)且直觀。
片段著色器代碼如下:
CCProgram fs %{
precision highp float;
// 引入 Cocos Creator 內(nèi)置的全部變量
#include <cc-global>
// 頂點顏色(來自頂點著色器)
in vec4 v_color;
// UV 坐標(biāo)(來自頂點著色器)
in vec2 v_uv0;
// 紋理
uniform sampler2D texture;
// 自定義屬性
uniform Properties {
float amplitude; // 振幅
float angularVelocity; // 角速度
float frequency; // 頻率
float offset; // 偏距
};
void main () {
// 保存頂點顏色
vec4 color = v_color;
// 疊加紋理顏色
color *= texture(texture, v_uv0);
// 直接丟棄原本就透明的像素
if (color.a == 0.0) discard;
// 初相位(正值表現(xiàn)為向左移動栏豺,負(fù)值則表現(xiàn)為向右移動)
// cc_time 是 Cocos Creator 提供的運行時間全局變量(類型:vec4)
float initiaPhase = frequency * cc_time.x;
// 代入正弦曲線公式計算 y 值
// y = Asin(ωx ± φt) + k
float y = amplitude * sin(angularVelocity * v_uv0.x + initiaPhase) + offset;
// 丟棄 y 值以上的像素(左上角為原點 [0.0, 0.0])
if (v_uv0.y < y) discard;
// 輸出顏色
gl_FragColor = color;
}
}%
運行效果如下:
使用 cc.tween
動態(tài)改變高度(偏距)實現(xiàn)波浪進度條:
cc.tween(this.sineWave)
.to(3, { height: 1 })
.to(0.5, { amplitude: 0 })
.start();
在線預(yù)覽:https://ifaswind.gitee.io/eazax-cases?case=sineWave
SineWave 組件:https://gitee.com/ifaswind/eazax-ccc/blob/master/components/effects/SineWave.ts
專題
《一起學(xué) Shader》這個專題斷更了一段時間彬碱,很對不起小伙伴們,是時候續(xù)上了??
《Shader 入門:GLSL ES(數(shù)據(jù)類型)》
傳送門
更多分享
《Cocos Creator 性能優(yōu)化:DrawCall》
《在 Cocos Creator 里畫個炫酷的雷達(dá)圖》
公眾號
??菜鳥小棧
??我是陳皮皮,這是我的個人公眾號晚胡,專注但不僅限于游戲開發(fā)灵奖、前端和后端技術(shù)記錄與分享。
??每一篇原創(chuàng)都非常用心估盘,你的關(guān)注就是我原創(chuàng)的動力瓷患!
Input and output.