The Book of Shaders by Patricio Gonzalez Vivo & Jen Lowe

日本語 - 中文版 - 한국어 - Español - Français - Italiano - Deutsch - English


ハロー・ワールド!

新しいプログラミング言語を学ぶときはたいてい最初に「Hello World」を表示します。一行のシンプルなプログラムで新しい世界に高らかにご挨拶というわけです。

しかしGPUの世界で文字を書くのは第一歩にしてはかなりの大仕事です。代わりに鮮やかな色でこの熱意を表現することにしましょう。

もしこの本をブラウザーで読んでいるのであれば、上のサンプルコードをクリックして好きなところを編集することができます。GPUは変更した内容を反映してコードをコンパイルし、シェーダーを即座に置き換えます。試しに6行目の値を書き換えてみましょう。

一見シンプルなコードですが、ここから多くのことが読み取れます。

  1. C言語と同じように、シェーダー言語は結果として色を返すmain()関数を持っています。

  2. 最終的なピクセルの色は、予約語として確保されたグローバル変数、gl_FragColorに割り当てられます。

  3. このCによく似た言語には(gl_FragColorのような)組み込みの「変数」や「関数」、「型」があります。このサンプルでは浮動小数点精度を持つ4次元ベクトル vec4 型が使われています。またこの後、vec3vec2 のような型や、おなじみの floatintbool なども登場します。

  4. vec4型をよく見ると、4つの引数はそれぞれ赤(Red)、緑(Green)、青(Blue)、透過度(Alpha)の各チャンネルに対応していることが分かるでしょう。またこれらの値が正規化されている(normalized)、つまり 0.0 から 1.0 の値をとることも読み取れます。後ほど、値が正規化されていると変数間の写像に便利であることを学びます。

  5. プリプロセッサマクロが使えるのも、このサンプルから読み取れるもう一つの大事な「C言語的」特徴です。マクロはコンパイルの前に処理されます。マクロを使うとグローバル変数を定義(#define)したり、#ifdef#endif を使って場合分けを行うことができます。全てのマクロの命令はハッシュタグ(#)で始まります。コンパイルの直前には全ての #define の呼び出しが置き換えられ、#ifdef#ifndef といった条件文のチェックが行なわれます。上のサンプルでは、GL_ES が定義されているときにだけ2行目のコードを挿入します。GL_ES は多くの場合、モバイル機器やブラウザー上でコンパイルされたことを意味します。

  6. 浮動小数点型はシェーダーに不可欠で、その精度はとても重要な意味を持ちます。精度が低いとレンダリングが速くなる代わりに品質が下がります。もしこだわりたければ、GLSLでは浮動小数点を使うそれぞれの変数ごとに精度を指定できます。一行目の precision mediump float; は、全ての浮動小数点型の変数に中レベルの精度を指定しています。より低い精度(precision lowp float;)や高い精度(precision highp float;)を選ぶこともできます。

  7. 最後に、そしておそらく一番大切なことですが、GLSLの仕様では変数の自動的な型変換は保証されていません。どういうことでしょう。メーカーは色々な方法でグラフィックカードを高速化しようとしますが、同時に最低限の仕様を満たす必要があります。自動的な型変換はこの最低限の仕様には含まれていません。上のサンプルでは vec4 型は浮動小数点精度を持っているので、float 型の値が割り当てられることになっています。コードの一貫性を保ち、真っ白な画面で何時間もデバッグするのを避けるために、浮動小数点型の値には小数点(.)を使うことを習慣にしましょう。下記のようなコードはうまく動くとは限りません。

(訳注:gl_FragColorはGLSL1.3から非推奨になりました。以降のバージョンでは開発者が自由に名前をつけることができます。この本のサンプルは1.2以前のバージョンで書かれているため、gl_FragColorを出力用の変数として用います)

void main() {
    gl_FragColor = vec4(1,0,0,1);   // ERROR
}

さて、冒頭のサンプルで大事なことはほとんど説明しました。そろそろコードをクリックして、学んだことをひととおり試してみましょう。エラーが起きたときはプログラムがコンパイルに失敗し真っ白な画面が表示されます。

次のような例を試すと面白いでしょう。

vec4 red(){
    return vec4(1.0,0.0,0.0,1.0);
}
vec4 color = vec4(vec3(1.0,0.0,1.0),1.0);

この章のサンプルはさほど面白くはありませんが、キャンバス上のピクセルを全て同じ色に変える、最も基礎的な例です。この後に続く章ではピクセルの色を2種類の入力、空間(画面上のピクセルの位置)と時間(ページがロードされてから経過した秒数)を使って変化させる方法を学びます。