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以降である必要があります。)