CSS Shaders はじめの 10歩目、アニメーション
Posted :
GraphicalWeb Advent Calendar 2012 の 15日目の記事です。
前回までの記事で vertex shader による変換と fragment shader による色の使い方をひと通り見てきました。今回は、これに動きを加えます。
順をおってみて行きましょう。まず前回の状態の HTML, CSS, Shader 2種を用意します。
手順 1
HTML と CSS
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CSS Shaders!</title>
<style>
.sample {
width:500px;
background: url( bg.png );
-webkit-filter: custom(
url( shader.vs ) mix( url( shader.fs ) ),
32 32,
u_transform perspective( 1000 ) rotateX( 45deg )
);
}
</style>
</head>
<body>
<div class="sample">
<p>CSS Shader!! シィーエスエス シェーダー!! </p>
<img src="nyantocat.gif" alt="">
<p>the Nyantocat by Cameron McEfee</p>
</div>
</body>
</html>
vertex shader
precision mediump float;
attribute vec4 a_position;
attribute vec2 a_meshCoord;
uniform mat4 u_projectionMatrix;
uniform mat4 u_transform;
// fragment shader に渡すために varying 変数を宣言
varying vec4 v_color;
void main() {
float z = sin( a_meshCoord.x * 3.1415) * 100.0;
vec4 pos = vec4( a_position.xy, z, a_position.w );
// z の高さ ( 0 ~ 100 ) に応じて、透明度の異なる黒を fragment shader に送る
v_color = vec4( 0.0, 0.0, 0.0, min( 0.75, 1.0 - ( z / 100.0 ) ) );
gl_Position = u_projectionMatrix * u_transform * pos;
}
fragment shader
precision mediump float;
// vertex shader から受け取るために varying 変数を宣言
varying vec4 v_color;
void main() {
css_MixColor = v_color;
}
ここまでの状態の demo(2012年 12月現在では CSS Shader を有効にした Chrome 25以降である必要があります。)
手順 2、filter プロパティーの値に引数を追加
custom 関数の引数に「u_time という名前の変数、値は 0」を追加しました。
CSS
.sample {
width:500px;
background: url( bg.png );
-webkit-filter: custom(
url( shader.vs ) mix( url( shader.fs ) ),
32 32,
u_transform perspective( 1000 ) rotateX( 45deg ),
u_time 0
);
}
手順 3、vertex shader で引数を利用
CSS から渡された u_time を float 型として宣言し、さらに変換時の z 座標に影響を与えるようにします。こうすることで、 CSS から渡される u_time の値が変わるたびにメッシュの z 座標を変えることができます。
vertex shader
precision mediump float;
attribute vec4 a_position;
attribute vec2 a_meshCoord;
uniform mat4 u_projectionMatrix;
uniform mat4 u_transform;
// u_time を float として宣言
uniform float u_time;
varying vec4 v_color;
void main() {
// u_time の値が sin 波に影響を与えるようにする
float z = sin( a_meshCoord.x * 3.1415 + u_time ) * 100.0;
vec4 pos = vec4( a_position.xy, z, a_position.w );
v_color = vec4( 0.0, 0.0, 0.0, min( 0.75, 1.0 - ( z / 100.0 ) ) );
gl_Position = u_projectionMatrix * u_transform * pos;
}
手順 4 : CSS にアクションを追加
ここでは transition プロパティーを追加し、合わせて :hover 時のスタイルを追加しました。:hover 時には、u_time の値が 12 に設定されていることにも注目してください。
CSS 全体は次のようになっています。
CSS
.sample {
width:500px;
background: url( bg.png );
-webkit-filter: custom(
url( shader.vs ) mix( url( shader.fs ) multiply ),
32 32,
u_transform perspective( 1000 ) rotateX( 45deg ),
u_time 0
);
-webkit-transition: -webkit-filter ease-in-out 2s;
}
.sample:hover {
width:500px;
background: url( bg.png );
-webkit-filter: custom(
url( shader.vs ) mix( url( shader.fs ) multiply ),
32 32,
u_transform perspective( 1000 ) rotateX( 45deg ),
u_time 12
);
}
これにより、:hover することにより u_time の値が変化し、そこには CSS transitions が効いているため、CSS Shader により変換されるメッシュがアニメーションします。
ここまでの状態の demo(2012年 12月現在では CSS Shader を有効にした Chrome 25以降である必要があります。)