CSS Shaders はじめの 8歩目、ピクセルごとに異なる色

Posted :

GraphicalWeb Advent Calendar 2012 の 13日目の記事です。

前回の記事では、fragment shader を利用しピクセルに色をつける方法を試しました。すべてのピクセルに対し同じ色を指定しただけでした。今回は、頂点ごとに異なる色をつける方法を少し試してみます。

まず、vertex shader では、頂点ごとに異なる a_position や a_meshCoord などの attribute 変数を利用することができました。しかし fragment shader では attribute 変数は利用できません。頂点ごとに異なる情報を fragment shader に渡したい場合には、vertex shader を経由して、そこから fragment shader に変数を渡すことになります。

vertex shader から fragment shader に変数を渡すときには、varying 変数を利用します。

uniform 変数|CSS から vertex shader と fragment shader に固定の情報を渡す
attribute 変数|CSS から頂点ごとに異なる情報を vertex shader に渡す
varying 変数|vertex shader から頂点ごとに異なる情報を fragment shader に渡す

varying 変数を試すために次の簡単なサンプルを用意してみました。

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 );

    // a_position を v_color に代入して fragment shader に渡す
    v_color = a_position;
    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;
}

すると vertex shader では座標として利用されていた vec4 が fragment shader でそのまま色へ利用されます。

ここまでの状態の demo(2012年 12月現在では CSS Shader を有効にした Chrome 25以降である必要があります。)

vec4 が色として利用される場合は vec4( red, green, blue, alpha ) なので、キャプチャー上では

  • 左上の座標は x = 0, y = 0, z = 0 で vec4( 0.0, 0.0, 0.0, 1.0 ) なので不透明の黒
  • 右上の座標は x = 1, y = 0, z = 0 で vec4( 1.0, 0.0, 0.0, 1.0 ) なので不透明の赤
  • 左下の座標は x = 0, y = 1, z = 0 で vec4( 0.0, 1.0, 0.0, 1.0 ) なので不透明の緑

となっているのが確認できます。