カスタム フィルタ(CSS シェーダー)の概要

カスタム フィルタ(従来は CSS シェーダーと呼ばれていたもの)を使用すると、WebGL のシェーダーの機能を DOM コンテンツで使用できます。現在の実装で使用されるシェーダーは WebGL のシェーダーとほぼ同じであるため、一歩引いて 3D の用語とグラフィック パイプラインを少し理解する必要があります。

LondonJS に最近配信したプレゼンテーションの録画を添付します。この動画では、知っておくべき 3D 用語の概要、変数の種類、カスタム フィルタの使い方などを順を追って説明します。また、スライドを入手して、自分でデモを試すこともできます。

シェーダーの概要

以前、シェーダーの概要でシェーダーの概要と、WebGL の観点からシェーダーの使用方法についてわかりやすく説明しました。カスタム フィルタのコンセプトと言語の多くは、既存の WebGL シェーダーの用語に依存しているため、シェーダーを扱ったことがない場合は、この先に進む前に必ずお読みください。

では、カスタム フィルタを有効にして、さらに学習を進めましょう。

カスタム フィルタの有効化

カスタム フィルタは、Chrome と Canary 版、Chrome for Android で利用できます。about:flags にアクセスして「CSS Shaders」を検索し、有効にしてからブラウザを再起動するだけです。これで準備完了です。

構文

カスタム フィルタは、blursepia など、DOM 要素にすでに適用できる一連のフィルタを拡張したものです。エリック ビデルマンが作成したプレイグラウンド ツールをぜひご確認ください。

カスタム フィルタを DOM 要素に適用するには、次の構文を使用します。

.customShader {
    -webkit-filter:

    custom(
        url(vertexshader.vert)
        mix(url(fragment.frag) normal source-atop),

    /* Row, columns - the vertices are made automatically */
    4 5,

    /* We set uniforms; we can't set attributes */
    time 0)
}

ここから、頂点シェーダーとフラグメント シェーダー、DOM 要素に分割する行と列の数、通過するユニフォームを宣言していることがわかります。

最後に、ブレンドモード(normal)と複合モード(source-atop)とともに、フラグメント シェーダーの周囲に mix() 関数を使用します。フラグメント シェーダー自体を見て、mix() 関数が必要な理由を確認しましょう。

Pixel Push

WebGL のシェーダーを使い慣れている方なら、カスタム フィルタでは状況が若干異なることにお気づきでしょうか。1 つは、フラグメント シェーダーがピクセルを塗りつぶすために使用するテクスチャは作成しません。その代わりに、フィルタが適用された DOM コンテンツは、自動的にテクスチャにマッピングされます。これは、次の 2 つのことを意味します。

  1. セキュリティ上の理由から、DOM のテクスチャの個々のピクセルの色の値をクエリすることはできません
  2. (少なくとも現在の実装では)最終的なピクセルの色を自身で設定することはありません。つまり、gl_FragColor は使用できません。ここでは、DOM コンテンツをレンダリングすることを想定し、css_ColorMatrixcss_MixColor を通じてそのピクセルを間接的に操作します。

フラグメント シェーダーの Hello World は次のようになります。

void main() {
    css_ColorMatrix = mat4(1.0, 0.0, 0.0, 0.0,
                            0.0, 1.0, 0.0, 0.0,
                            0.0, 0.0, 1.0, 0.0,
                            0.0, 0.0, 0.0, 1.0);

    css_MixColor = vec4(0.0, 0.0, 0.0, 0.0);

    // umm, where did gl_FragColor go?
}

DOM コンテンツの各ピクセルには css_ColorMatrix が乗算されます。上記のケースでは、単位行列としては何もせず、RGBA 値は一切変更しません。たとえば、赤色の値のみを残したい場合は、次のように css_ColorMatrix を使用します。

// keep only red and alpha
css_ColorMatrix = mat4(1.0, 0.0, 0.0, 0.0,
                        0.0, 0.0, 0.0, 0.0,
                        0.0, 0.0, 0.0, 0.0,
                        0.0, 0.0, 0.0, 1.0);

4D(RGBA)ピクセル値に行列を乗算すると、反対側から操作されたピクセル値が得られます。この例では、緑と青の成分がゼロで設定されます。

css_MixColor は主に、DOM コンテンツと混同するベースカラーとして使用されます。このミキシングは、アート パッケージでおなじみのブレンド モード(オーバーレイ、画面、カラー回避、ハードライトなど)で行えます。

この 2 つの変数でピクセルを操作する方法はたくさんあります。ブレンド モードと複合モードの相互作用については、フィルタ エフェクトの仕様をご確認ください。

頂点の作成

WebGL では、メッシュの 3D 点の作成はすべて Google が行いますが、カスタム フィルタでは必要な行数と列数を指定するだけで、ブラウザが自動的に DOM コンテンツを複数の三角形に分割します。

頂点の作成
行と列に分割された画像

これらの各頂点は、操作のために頂点シェーダーに渡されるため、必要に応じて 3D 空間内での移動を開始できます。あと少しで、素晴らしいエフェクトを編み出すことができます。

アコーディオン効果
アコーディオン効果で歪んだ画像

シェーダーを使用したアニメーション

シェーダーにアニメーションを組み込むことで、シェーダーを楽しく魅力的なものにできます。これを行うには、CSS で遷移(またはアニメーション)を使用してユニフォームの値を更新します。

.shader {
    /* transition on the filter property */
    -webkit-transition: -webkit-filter 2500ms ease-out;

    -webkit-filter: custom(
    url(vshader.vert)
    mix(url(fshader.frag) normal source-atop),
    1 1,
    time 0);
}

    .shader:hover {
    -webkit-filter: custom(
    url(vshader.vert)
    mix(url(fshader.frag) normal source-atop),
    1 1,
    time 1);
}

上記のコードで注目すべき点は、遷移中に時間が 0 から 1 に緩和される点です。シェーダー内でユニフォーム time を宣言し、その現在の値を使用できます。

    uniform float time;

uniform mat4 u_projectionMatrix;
attribute vec4 a_position;

void main() {
    // copy a_position to position - attributes are read only!
    vec4 position = a_position;

    // use our time uniform from the CSS declaration
    position.x += time;

    gl_Position = u_projectionMatrix * position;
}

今すぐプレイ

カスタム フィルタは遊ぶのにとても便利ですが、カスタム フィルタがないと作成できない効果の高い効果もあります(場合によっては作成できないこともあります)。まだ始まったばかりで、状況はかなり変化していますが、これらを追加すると、プロジェクトにちょっとした華やかさが加わるでしょう。ぜひ試してみてください。

参考情報