p5.js shader スタート 6 シェーダーの重要な概念

本稿は「Important shader concepts」ページを翻訳したものです。

シェーダーの重要な概念

このページにはシェーダーの使用を開始するに当たって”知っておく必要のある”情報が多く含まれています。みなさんはここから、p5サンプルに飛び込んでいく準備を整えるのです。

0と1の間の空間

シェーダーを記述するときに必要な事柄は全部、0と1の間の空間に存在します。どういうことだ?と思われるかもしれませんが、これにより計算が信じられないほど速くなり処理も容易になるので、実際のところ実に賢い方法です。次のグラデーションシェーダーの例でも分かるように(これはすでにfill()の機能を超えています)、

  • カラーはRGBで定義されるが、カラー値は0-255ではなく0-1の範囲で変化する
    • したがって青は(0, 0, 255)でなく(0.0, 0.0, 1.0)になる
    • オレンジは(255, 128, 0)でなく(1.0, 0.5, 0.0)になる
  • キャンバスのピクセルの位置は0-1の間で定義される
    • したがって、スケッチでの位置 x = 0, y = 0 つまり (0, 0)は、シェーダーでは (0.0, 0.0)になる
    • スケッチでの位置 x = width, y = height つまり (width, height)は、シェーダーでは(1.0, 1.0)になる

これはどういうことかというと、シェーダーに関する限りキャンバスは、左下隅の(0.0, 0.0)から右上隅の(1.0, 1.0)に変化する1のサイズを持っているということです。これは、左上隅が(0,0)で右下隅が(width,height)であるp5キャンバスとは正反対なので、注意してください。

次のサンプルでは、マウスを動かすと、カーソルのピクセル位置(白いボックス)と正規化された(0から1の間)位置が表示されます。

浮動小数点数値が重要

すべてが0と1の間で定義されるので、点も含めてつねに浮動小数点数値全部を記述します。青なら(0,0,1)でなく(0.0, 0.0, 1.0)と書きます。グラフィックカードはこれについて程度の差はあれ気難しく、そういうカードの場合、シェーダーは実行されません。

変数の作成と変更

GLSL(われわれが扱うシェーダー言語)は強く型付けされる言語であることを覚えておく必要があります。これは、扱うすべての変数の型(int,float,vec2など)を定義しなければいけないということです。ただlet myVariableと言うだけで変数が作成でき、保持しているデータからどの型かを理解するJavaScriptとは大きく異なります。これはまた、変数が保持するデータ型を、JavaScriptのようにその場で変更したり、floatを期待する関数にintは渡せないということでもあります。

最初は、全部の変数にvec2 positionやfloat scaleといった型指定をしなくてはいけないことに混乱するでしょうが、やがて慣れます。

ベクトルの驚異

ここまでで、シェーダーではベクトル(vec3やvec4など)を多く使っていることに気づかれたでしょう。ベクトルは、変数に2つ以上の数値を保持させたいときに使用します。変数に1つの数値のみ保持したい場合にはfloatかintを使用し、それ以外の場合には、vec2やvec3、vec4を使用します。2,3,4の数字は使用するパラメータの量です。

ベクトルは、数学では位置や方向に使用されますが、シェーダーランドではカラーの保持にも使用されます。

// カラーや位置の操作に使用できるスカラー
float scalar = 5.2;             
// キャンバスのセンター(width/2, height/2)
vec2 position = vec2(0.5, 0.5);       
// R = 0, G = 0.5, B = 1.0
vec3 color = vec3(0.0, 0.5, 1.0);
// 半透明 A = 0.5 の青
vec4 colorWithAlpha = vec4(0.0, 0.0, 1.0, 0.5);

変数をこのように作成できることのメリットは、成分に簡単にアクセスできることです。カラーの各成分には、color.rやcolor.g、color.bのようにしてアクセスできます。

// R = 0, G = 0.5, B = 1.0
vec3 color = vec3(0.0, 0.5, 1.0);     

float redComponent = color.r;	// R = 0
float greenComponent = color.g; // G = 0.5
float blueComponent = color.r;  // B = 1.0

color.rgbと書くと、3つ全部が得られます。color.xyzと書くことすらできます。シェーダーはそれがカラーの数値なのか、位置の数値なのかは知らず、ベクトルの成分にアクセスしていることを知っているだけです。しかし変数がカラーの場合には.rgbaと書き、位置の場合には.xyzwと書くのがよいプラクティスです。

成分にアクセスする”ドット”の方法はSwizzling(スウィズリング)と呼ばれます。

vec3 color = vec3(0.0, 0.5, 1.0);	// R = 0, G = 0.5, B = 1.0

vec3 colorCopy1 = color.rgb;		// R = 0, G = 0.5, B = 1.0
vec3 colorCopy2 = color.xyz;		// R = 0, G = 0.5, B = 1.0

変更も簡単です。

vec3 color = vec3(0.0, 0.5, 1.0);	// R = 0, G = 0.5, B = 1.0

// R成分を新しい値に設定する
color.r = 0.833;             
vec3 newColor = color;            	// R = 0.833, G = 0.5, B = 1.0
関数の作成

.vertや.fragファイルでは関数の作成も容易ですが、関数が返す型(たとえばvec3)を定義する必要があります。

以下は、.fragファイルに記述できる関数の例です。

// 渡されたrgb値を0と1の間に変換する関数
vec3 rgb(float r, float g, float b){
  return vec3(r / 255.0, g / 255.0, b / 255.0);
}

void main() {
  // 赤
  vec3 color = rgb(255.0, 0.0, 0.0)
  gl_FragColor = vec4(color, 1.0);
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA