2016年5月27日金曜日

Three.jsでオブジェクト単位でフィルタをかける

Three.jsではポストプロセスを使うとフィルタをかけることができるが、シーン全体に適用されてしまうので、オブジェクト単位でフィルタをかけたいときには使えない。そこで、GLSLを使用してオブジェクト単位でフィルタをかける。

GLSLはシェーダーをカスタマイズするための言語。ここでは詳しく触れない(詳しく説明できるだけの知識はない)ので、詳細はWebグラフィックをハックする(最終回)を参照。GLSLには「頂点シェーダー」と「フラグメントシェーダー」があり、それぞれ頂点座標の計算とピクセル単位の描画色の計算を行う。要は、頂点シェーダーでオブジェクトの形状を変化させ、フラグメントシェーダーでオブジェクトの色を変化させることができる。

今回やりたいことは、Three.jsのポストプロセスでフィルタをかけるでやったことを、オブジェクト単位でできるようにすることなので、変化させるのは色だけ。つまり、フラグメントシェーダーをいじってフィルタをかける。ぼかしフィルターとしてボックスフィルター使う。以下はその手順。

1.頂点シェーダーの記述
GLSLはHTMLに<script>~</script>で囲んで記述する。頂点座標を変化させない場合でも、頂点シェーダーの記述は必要。GLSLには組み込み変数があり、頂点シェーダーではgl_Position(頂点座標)という組み込み変数に値を入れる必要がある。

※座標変換をしているだけで、頂点位置が変化しているわけではない。

2.ボックスフィルター
ボックスフィルターとは、ざっくりとした言い方をすると、あるピクセルとその周辺値の平均値をあるピクセルの値とするフィルター。例えば、あるピクセルとそれに縦横斜めに隣接する8個のピクセルの計9個の値を足して9で割る。この計算をフラグメントシェーダーで行う。

3.フラグメントシェーダーの記述
フラグメントシェーダーではgl_FragColor(描画色)という組み込み変数に値を入れる必要がある。

本来なら画像の解像度に合わせてratioの値を調整したり、計算するピクセルが画像の端の場合にどの値で計算するかなどを考慮する必要があるが、ここでは省略。それでもそれなりに画像はぼけてみえる。

4.マテリアルの作成
GLSLを使用するにはマテリアルの作成にTHREE.ShaderMaterialを使う。
// テクスチャの作成
var texture = new THREE.TextureLoader().load( '../image/persimmon.jpg' );

// マテリアルの作成
// uniforms: シェーダーに渡す変数を指定(ここではテクスチャを指定)
// vertexShader: 頂点シェーダーを指定
// fragmentShader: フラグメントシェーダーを指定
var material = new THREE.ShaderMaterial( {
uniforms: {
texture:   { type: 't', value: texture }
},
vertexShader:   document.getElementById( 'vshader' ).textContent,
fragmentShader: document.getElementById( 'fshader' ).textContent
});

あとは通常のThree.jsの記述と同じ。

結果は以下の通り。

オリジナル

ボックスフィルター


0 件のコメント:

コメントを投稿