CSS Shadersについて調べてみる

3Dの座標変換やある程度の動作原理を勉強したので、
今度はCSS Shadersの勉強に挑戦。
色々情報を貯めていきます。

##demo
* [CSS ShaderでGoogle Mapを地球儀風にしてみる - jsdo.it](http://jsdo.it/edo_m18/iErn)
* [CSS ShaderでMax OSXのジニーエフェクト - jsdo.it](http://jsdo.it/edo_m18/mTzT)

## Links

* [CSS Shaders はじめの 2歩目、custom() で何が行われるのか](http://yomotsu.net/blog/2012/12/07/cssshaders2.html)

* [CSS Filter Lab](http://html.adobe.com/webstandards/csscustomfilters/cssfilterlab/)

* [[Adobe] CSS Custom Filters](http://html.adobe.com/jp/webstandards/csscustomfilters/)

* [CSS Custom Filters](http://adobe.github.com/web-platform/samples/css-customfilters/)

* [Introducing CSS shaders: Cinematic effects for the web](http://www.adobe.com/devnet/html5/articles/css-shaders.html)

* [[W3C] CSS shaders](https://dvcs.w3.org/hg/FXTF/raw-file/tip/custom/index.html)



## CSS Shaderの動作原理など

![custom()](http://f.cl.ly/items/380b3p3i3R2e1n0o2O3c/Figure%203.%20The%20CSS%20shaders%20processing%20model..png)

Vertex shader(以下、VS)でmeshを生成し、それにより分割。
さらにFragument shader(Pixel shader)によって変形後の色を決定する、という流れらしい。
↑はその過程の図。

VS内のa_positionなどは決められた変数名。
main関数内で呼ばれ、vertex meshで分割された各座標それぞれに対して実行される。（つまり、それぞれの頂点に対してどういう処理を行うか、がmain関数の意味）

------

CSSでの指定（filter: custom()）方法。

```css
custom(url('wobble.vs')                               /* wobble effect */
           mix(url('color-swipe.fs') normal source-atop), /* swipe effect */
           40 40,                                         /* mesh lines/cols */
           amplitude 60,                                  /* wobble strength */
           amount 0.0);                                   /* effect amount */
```

ちなみに上記例のamplitudeやamountは決められたものではなく、各シェーダ内で使用される変数名に値を渡すことを意味する。
つまり、ここの名前と値は任意のものとなる。（hoge 30.0、とかもOK）

さらに嬉しいことに、変換行列はCSS3のtransformと同じ書式で指定できる。例えば、

```css
-webkit-filter:
	custom(
		url(vertexshader.vs) mix(url(fragmentshader.fs) normal source-atop),
		30 30,
		transform rotateX(45deg) translateY(300px)
	);
```

などとすると、rotateXとtranslateYを掛けあわせた変換行列がシェーダ側に渡る。
受け取り方はuniform変数のmat4型として受け取ればいい。

```glsl
//uniform変数のmat4型でCSS3の変換行列を受け取れる。
uniform mat4 transform;
```

使い方は通常のmat4型と同様になる。

---

###Vertex shader（サンプル）

```glsl:vertexshader.vs
precision mediump float; // Required.

// ===== Built-in Per-vertex Attributes =====
attribute vec3 a_position; // The vertex's coordinates.
attribute vec2 a_texCoord; // The vertex's texture coordinate.

// ===== Built-in Parameters =====
// Uniform parameters are available to shaders and have the
// same value for each vertex and fragment.
uniform mat4 u_projectionMatrix; // The projection matrix.

// ===== CSS Parameters =====
uniform float amplitude;
uniform float amount;

// ===== Varyings =====
// Varying are set in the vertex shader and available in the
// fragment shader.
// A fragment's value for a varying is a weighted average based
// on its distance from the three vertices surrounding it.
varying vec2 v_texCoord;

// ===== Constants ======
const float rotate = 20.0;
const float PI = 3.1415926;

// ===== Helper Functions ======
mat4 rotateX(float a) {...}
mat4 rotateY(float a) {...}
mat4 rotateZ(float a) {...}

// ===== Shader Entry Point ===== //
void main()
{
    v_texCoord = a_texCoord.xy;
    vec4 pos = vec4(a_position, 1.0);

    float r = 1.0 - abs((amount - 0.5) / 0.5);
    float a = r * rotate * PI / 180.0;
    mat4 rotX = rotateX(a);
    mat4 rotY = rotateY(a / 4.0);
    mat4 rotZ = rotateZ(a / 8.0);

    float dx = 0.01 * cos(3.0 * PI * (pos.x + amount)) * r;
    float dy = 0.01 * cos(3.0 * PI * (pos.y + amount)) * r;
    float dz = 0.1 * cos(3.0 * PI * (pos.x + pos.y + amount)) * r;

    pos.x += dx;
    pos.y += dy;
    pos.z += dz;

    gl_Position = u_projectionMatrix * rotZ * rotY * rotX * pos;
}
```

### Fragment shader（サンプル）

```glsl:fragmentshader.fs
precision mediump float; // Required.
// ===== CSS Parameters =====
uniform float amplitude; // Unused in the fragment shader.
uniform float amount;
// ===== Varyings ======
varying vec2 v_texCoord;
// ===== Constants ======
const vec3 scanlineColor = vec3(1.0, 1.0, 1.0);
const float gradientHeight = 0.1;
const mat4 grayscaleMatrix = mat4(
    …
);
// ==== Shader Entry Point =====
void main()
{
    // The scanline goes from the bottom of the element (1.0) to
    // just above the top of the element (-gradientHeight).
    // This makes sure the gradient is out of view at amount = 1.0.
    float scanlineTravelDistance = 1.0 + gradientHeight;
    // Scale amount from [0,1] to [0,scanlineTravelDistance].
    float scanlineAmount = amount * scanlineTravelDistance;
    // Make the scanline start at the bottom and progress upward.
    // Its position goes from [1.0, -gradientHeight].
    float scanlinePosition = 1.0 - scanlineAmount;
    if (v_texCoord.y < scanlinePosition) {
        // Make the element grayscale above the scanline.
        css_ColorMatrix = grayscaleMatrix;
    } else {
        // Apply a gradient below the scanline.
        float distanceFromScanline = v_texCoord.y - scanlinePosition;
        float gradientStrength = (gradientHeight - min(distanceFromScanline, gradientHeight)) / gradientHeight;
        css_MixColor = vec4(scanlineColor, gradientStrength);
    }
}
```

##CSS Shaderに暗黙的に渡される変数

※「説明」部分は、[W3Cの草案](https://dvcs.w3.org/hg/FXTF/raw-file/tip/custom/index.html)を独自で訳したものです。

###attribute変数

| 変数種 | 型 | 変数名 | 説明 |
|:-----------:|:------------:|:------------:|:------|
|attribute | vec4 | a_position |[filter region](https://dvcs.w3.org/hg/FXTF/raw-file/tip/custom/index.html#filter-region)の頂点座標。<br />座標は、[-0.5, 0.5]の間でx, y, z軸ともに正規化されます。|
|attribute | vec2 | a_texCoord |頂点のテクスチャ座標。<br />座標は、両方の軸で[0, 1]の間となります。|
|attribute | vec2 | a_meshCoord |[mesh box](https://dvcs.w3.org/hg/FXTF/raw-file/tip/custom/index.html#mesh-box)の頂点座標。<br />座標は、両方の軸で[0, 1]の間となります。|
|attribute | vec3 | a_triangleCoord |xとyの値は、shader meshの現在の「タイル」の座標を提供します。<br />例えば、(0, 0)はメッシュ内のタイルの右上を表します。<br />xとyの値は、それぞれ [0, mesh columns] と [0, mesh rows] の間になります。<br />z座標は、下図に表されるように計算されます。<br />z座標の値は、それぞれの頂点と対応する三角形によって提供されます。<br />例えば、上の三角形の右下の頂点は`2`に、下の三角形の右下は`4`となるでしょう。![a_triangleCoord sample](https://dvcs.w3.org/hg/FXTF/raw-file/tip/custom/images/a_triangleCoord.z.png)|

###uniform変数

| 変数種 | 型 | 変数名 | 説明 |
|:-----------:|:------------:|:------------:|:------|
|uniform   | mat4 | u_projectionMatrix |現在のテクスチャ座標空間先のプロジェクションマトリクス。<br />注: モデル変形マトリクスプロパティセットは、シェーダーに渡されません。<br />フィルターをかけられた描画要素に適用されます。|
|uniform   | sampler2D | u_texture |入力テクスチャ。<br />フィルターマージンとして透明のマージンも含まれます。(※セキュリティ的な問題でアクセスできないかも？)|
|uniform| sampler2D  | u_contentTexture |フィルターをかけられた描画要素のテクスチャ。<br />もしフィルターがフィルター連鎖の最初だった場合、このテクスチャは`u_texture` uniform変数と同等となります。<br />しかしもし、それらが先行フィルターだった場合はこれはオリジナルのフィルターされた描画要素として提供されます。<br />一方、`u_texture`はフィルター連鎖（あるいはグラフ）の最初の先行フィルターとして出力されます。|
|uniform   | vec2 | u_textureSize |入力テクスチャのサイズ。<br />フィルターマージンを含む。|
|uniform   | vec4 | u_meshBox |フィルターボックス座標系内のmesh boxの位置とサイズ。<br />例えば、もしmesh boxがフィルターボックスなら、値は(-0.5, -0.5, 1, 1)となるでしょう。|
|uniform   | vec2 | u_tileSize |頂点と同じ座標空間における現在のメッシュタイルのサイズ。|
|uniform   | vec2 | u_meshSize |タイルの面で現在のメッシュのサイズ。<br />x座標は行の数値を、y座標は列の数値を提供します。|

###特殊変数

使ってみて使える、みたいな感じなのでとりあえずメモ程度。（ちゃんと調べてません）

|対象シェーダ| 型 | 変数名 | 説明 |
|:----------------|:------------:|:------------:|:------|
|Vertex|vec4|gl_Position|頂点位置をWebGLに伝える変数|
|Fragment|vec4|gl_FragCoord|現在計算中のフラグメントの座標|