はじめに
本記事はShader言語初学者向けとなっています。
初学者向けではありますがプログラミングの基礎は理解されていることが望ましいです。
GLSL Sandboxとは?
GLSL SandboxとはWeb上でGLSLをコーディング、実行することができるサービスです。
また作成した作品を公開・共有することが可能です。
今回はこのGLSL Sandboxを利用してフラグメントシェーダで遊んでみましょう。
Hello GLSL World!
早速ですが作品を作っていきましょう。Galleryの左上の Create new effect!から作成することができます。
ページが遷移するとこのような画面になっています。
main関数が実際にフラグメントシェーダとして処理される部分になります。
すでにコードが書かれているのでまずはざっくりと消してしまい、main関数を以下のように変更してみましょう。
void main ( void ) {
gl_FragColor = vec4(1,1,1,1);
}
するとこのように画面全体が真っ白で表示されます。
このことから gl_FragColor に色情報を vec4 型で与えることで色を表示できることがわかります。
vec4型でそれぞれ RGBAの順番で色情報を持っているため、
void main( void ) {
gl_FragColor = vec4(1,0,0,1);
}
このようにすることで真っ白だった画面が真っ赤になります。
このようにmain関数内でgl_FragColorの色情報を操作していくことでエフェクトを作成していきます。
GLSL Sandboxで定義されているもの
様々な表現をする上で必要となるデータがglsl Sandboxでは定義されています。
実際にコードを書いていく前に確認しておきましょう。
- float time
時間が定義されています。時間経過によるアニメーションなどに利用することができます。
- vec2 mouse
マウスの座標が0~1の範囲で定義されています。マウスの位置によって光原や視線の移動に利用されます。
- vec2 resolution
現在のレンダーターゲットの解像度が定義されています。UV値の取得などに利用されます。
- sampler2D backbuffer;
前フレームの描画情報が定義されています。
UV情報を利用する
このままでは画面全体を単色で塗ることしかできないので、画面の中の位置情報であるUV情報を取得してみましょう。
void main( void ) {
vec2 position = ( gl_FragCoord.xy / resolution.xy );
gl_FragColor = vec4( position.x );
}
gl_FragCoord.xy / resolution.xy を計算しています。gl_FragCoordには処理しようとしているピクセル (GLSLでは本当はピクセルではなくフラグメントという概念ですがここではピクセルとしておきます)の座標が入っているため、画面の解像度で割ることで0~1の範囲に変換することができます。
UV座標の取得ができたので、今回はそのままその値を色情報として表示しています。UV情報を格納したpositionのxをそのまま出力しているため、右に行くにつれて白くなっていることがわかります。
しかし、このままでは後ほど出てくる距離関数というものを扱う際に都合の悪い点が出てきます。それを回避するために画面の中心を0とした値を取得できるように変更しましよう。
void main( void ) {
vec2 position = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
gl_FragColor = vec4(position.x , -position.x,0,1);
}
gl_FragCoordの値を2倍にしたのちに解像度で除算することで範囲を -resolution ~ resolution の値にすることができました。その後に画面の中短辺の長さで除算することで画面の短辺の値を-1~1に変換しています。
position.xが正の値であれば赤に、負であれば緑になるように出力すると
このようになりました。この結果からも画面の中心に-1~1の範囲で値が取得できるようになったことが分かるはずです。
形を描画する
では続けて具体的な形状を描画していきましょう。まずは単純な円を表示してみます。高校数学の数学Ⅱにおける軌跡と領域の単元を思い出してみましょう。特定の領域は不等式で表すことができると学習したはずです。円の領域であれば
x2+y2≦r2
で表されます。
この数式をそのままコードにしてみましょう。
void main( void ) {
vec2 position = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
vec4 col = vec4(0);
if(pow(position.x,2.0) + pow(position.y,2.0) <= 1.0){
col = vec4(1);
}
gl_FragColor = col;
}
このように円が表示されました。
しかし、単純な円の表示でも少し複雑なコードとなるためより複雑な形状を表現しようとするとより困難になることが想像できます。
そこで先ほど少し出てきた距離関数というものが役に立ちます。今回の円を例にすると原点を中心として1未満の距離の領域と定義することができます。これをコードで表現すると length(position) < 1 となることが予想できます。これを少し改良し
void main( void ) {
vec2 position = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
vec4 col = vec4(0);
gl_FragColor = vec4(ceil(1.0-length(position)));
}
このように単純な処理で円を描画することができました。また、距離関数を変更することで
このような図形を表示することも可能です。
最後に
GLSL Sandboxに投稿されている様々な作品も今回扱った距離関数を複数組み合わせて表現しているものが多くあります。ただ今回の内容は2D的な表現のみであり、他の作品のような表現をするためにはレイマーチンという技法を知る必要があります。距離関数は特にレイマーチンとの組み合わせで威力を発揮するものなので知っておいて損はないでしょう。レイマーチンに関しては後日扱うとして、今回の記事がGlsl Sandboxで遊ぶきっかけに、コードで表現出来る世界の足がかりとなれば幸いです。