Shader 動畫和 Canvas 動畫原理是同樣的,經過定時器循環渲染,並改變畫布中圖形的屬性來實現動畫。html
一些 Shader 編輯器都已經實現好了定時器的功能,同時會傳遞一些跟時間相關的值給到着色器代碼中,如 ShaderToy 中與時間相關的屬性是 iTime/iTimeDelta,gl-transition 中與時間相關的屬性是 progress。經過將着色器代碼中的變量與時間相結合,就可讓動畫產生。git
在以前的文章中講到了座標的運算,其中加減就是位移:github
那常規的位移動畫就不說,下面講些複雜的運動:app
st += vec(cos(u_time), sin(u_time))
就是圓周運動了:編輯器
旋轉能夠經過矩陣來輕鬆完成:函數
但你會發現,當咱們把矩陣和座標相乘,獲得的確實上面的圓周運動,這是由於旋轉座標在左下角,若是想旋轉矩形,則必須把中心點挪到矩形中心,或者換個說法,把矩形中心挪到左下角。post
封裝好的代碼:動畫
mat2 rotate2d(float _angle){
return mat2(cos(_angle),-sin(_angle),
sin(_angle),cos(_angle));
}
複製代碼
當咱們在非正方形的畫布中對材質進行旋轉的時候,會遇到一個難以避開的問題,就是拉伸問題。舉個例子,當畫布是矩形時,暴露了旋轉時拉伸的問題:ui
// 部分代碼
void main() {
vec2 st = textureCoordinate;
float ratio = inputImageTextureSize.x / inputImageTextureSize.y;
float animationTime = getAnimationTime();
float easingTime = animationTime;
float bigRotation = 30./180.*3.14159;
st = rotateUv(st, bigRotation*easingTime, vec2(.5, .5), 1.);
gl_FragColor = texture2D(inputImageTexture, st);
}
複製代碼
這篇文章也提到了這個問題,之因此會出現這個問題,是由於因爲寬高的比例不是 1:1,說明雖然 x 和 y 的座標都是 0~1,可是它們表示的長度是不同的,正由於這個長度不同,致使在旋轉的時候,像素點的運動並不符合畫布的比例: spa
而解決方案也比較簡單,咱們在旋轉的時候,對 y 軸進行畫布比例的拉伸便可:
void main() {
vec2 st = textureCoordinate;
float ratio = inputImageTextureSize.x / inputImageTextureSize.y;
float animationTime = getAnimationTime();
float easingTime = animationTime;
float bigRotation = 30./180.*3.14159;
st.y *= 1./ratio;
st = rotateUv(st, bigRotation*easingTime, vec2(.5, .5), 1.);
st.y *= ratio;
gl_FragColor = texture2D(inputImageTexture, st);
}
複製代碼
縮放就是座標的乘除運算,一樣也能夠經過矩形來實現:
同理,若是不對座標系進行轉換,縮放的中心仍是在左下角:
兩個動畫組合一塊兒:
封裝好的代碼:
mat2 scale(vec2 _scale){
return mat2(_scale.x,0.0,
0.0,_scale.y);
}
複製代碼
正弦餘弦是很是優美的動畫曲線,咱們在講函數可視化也展現過下面這張圖(圖片來源於bookofshader):
因此經過這張圖你應該知道正弦餘弦函數能夠作出什麼樣的效果了,咱們來試試:
這是笛卡爾座標系的運動,假設咱們把座標系變成極座標系,你們能腦補大概的效果了嗎?
假如我想作一個外向擴散的動畫,相似雷達那樣的效果呢?去掉 sin()
函數便可:
相關連接: