3Dの座標変換やある程度の動作原理を勉強したので、
今度はCSS Shadersの勉強に挑戦。
色々情報を貯めていきます。
##demo
Links
CSS Shaderの動作原理など
Vertex shader(以下、VS)でmeshを生成し、それにより分割。
さらにFragument shader(Pixel shader)によって変形後の色を決定する、という流れらしい。
↑はその過程の図。
VS内のa_positionなどは決められた変数名。
main関数内で呼ばれ、vertex meshで分割された各座標それぞれに対して実行される。(つまり、それぞれの頂点に対してどういう処理を行うか、がmain関数の意味)
CSSでの指定(filter: custom())方法。
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と同じ書式で指定できる。例えば、
-webkit-filter:
custom(
url(vertexshader.vs) mix(url(fragmentshader.fs) normal source-atop),
30 30,
transform rotateX(45deg) translateY(300px)
);
などとすると、rotateXとtranslateYを掛けあわせた変換行列がシェーダ側に渡る。
受け取り方はuniform変数のmat4型として受け取ればいい。
//uniform変数のmat4型でCSS3の変換行列を受け取れる。
uniform mat4 transform;
使い方は通常のmat4型と同様になる。
###Vertex shader(サンプル)
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(サンプル)
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の草案を独自で訳したものです。
###attribute変数
変数種 | 型 | 変数名 | 説明 |
---|---|---|---|
attribute | vec4 | a_position |
filter regionの頂点座標。 座標は、[-0.5, 0.5]の間でx, y, z軸ともに正規化されます。 |
attribute | vec2 | a_texCoord | 頂点のテクスチャ座標。 座標は、両方の軸で[0, 1]の間となります。 |
attribute | vec2 | a_meshCoord |
mesh boxの頂点座標。 座標は、両方の軸で[0, 1]の間となります。 |
attribute | vec3 | a_triangleCoord | xとyの値は、shader meshの現在の「タイル」の座標を提供します。 例えば、(0, 0)はメッシュ内のタイルの右上を表します。 xとyの値は、それぞれ [0, mesh columns] と [0, mesh rows] の間になります。 z座標は、下図に表されるように計算されます。 z座標の値は、それぞれの頂点と対応する三角形によって提供されます。 例えば、上の三角形の右下の頂点は 2 に、下の三角形の右下は4 となるでしょう。
|
###uniform変数
変数種 | 型 | 変数名 | 説明 |
---|---|---|---|
uniform | mat4 | u_projectionMatrix | 現在のテクスチャ座標空間先のプロジェクションマトリクス。 注: モデル変形マトリクスプロパティセットは、シェーダーに渡されません。 フィルターをかけられた描画要素に適用されます。 |
uniform | sampler2D | u_texture | 入力テクスチャ。 フィルターマージンとして透明のマージンも含まれます。(※セキュリティ的な問題でアクセスできないかも?) |
uniform | sampler2D | u_contentTexture | フィルターをかけられた描画要素のテクスチャ。 もしフィルターがフィルター連鎖の最初だった場合、このテクスチャは u_texture uniform変数と同等となります。しかしもし、それらが先行フィルターだった場合はこれはオリジナルのフィルターされた描画要素として提供されます。 一方、 u_texture はフィルター連鎖(あるいはグラフ)の最初の先行フィルターとして出力されます。 |
uniform | vec2 | u_textureSize | 入力テクスチャのサイズ。 フィルターマージンを含む。 |
uniform | vec4 | u_meshBox | フィルターボックス座標系内のmesh boxの位置とサイズ。 例えば、もしmesh boxがフィルターボックスなら、値は(-0.5, -0.5, 1, 1)となるでしょう。 |
uniform | vec2 | u_tileSize | 頂点と同じ座標空間における現在のメッシュタイルのサイズ。 |
uniform | vec2 | u_meshSize | タイルの面で現在のメッシュのサイズ。 x座標は行の数値を、y座標は列の数値を提供します。 |
###特殊変数
使ってみて使える、みたいな感じなのでとりあえずメモ程度。(ちゃんと調べてません)
対象シェーダ | 型 | 変数名 | 説明 |
---|---|---|---|
Vertex | vec4 | gl_Position | 頂点位置をWebGLに伝える変数 |
Fragment | vec4 | gl_FragCoord | 現在計算中のフラグメントの座標 |