言語設定

シェーダー入門

シェーダーは、グラフィックス処理ユニット(GPU)上で実行される特別なプログラムで、驚くべきことができます。GPU を利用して多くのピクセルを一度に処理し、ノイズ生成、ぼかしのようなフィルターの適用、 ポリゴンのシェーディングなどの特定のタスクに特に適していて高速です。シェーダープログラミングは最初はやりがいがありますが、p5.js の 2D 描画とは異なるアプローチが必要です。このドキュメントでは、シェーダープログラミングの基本を説明し、他のリソースについて紹介します。

セットアップ

p5.js はシェーダーを扱うのに適したツールです。なぜなら、WebGL のセットアップの多くを処理してくれるため、シェーダーコード自体に集中できます。 シェーダーを始める前に、キャンバスを p5.js の WebGL モデルを使ってセットアップする必要があります。


      ...
      function setup() {
        createCanvas(windowWidth, windowHeight, WEBGL);
      }
      ..
      

シェーダープログラムは、頂点シェーダーフラグメントシェーダーの2つの部分で構成されています。頂点シェーダーは画面上に描画される 3D ジオメトリの位置を影響させ、フラグメントシェーダーはカラー出力を影響させる役割を担っています。これらは別々のファイルに格納され、loadShader() を使って p5.js にロードされます。シェーダーがロードされると、draw() の中で使うことができます。以下の例は、p5.js で基本的なシェーダーをセットアップする方法を示しています。


let myShader;

function preload() {
  // load each shader file (don't worry, we will come back to these!)
  myShader = loadShader('shader.vert', 'shader.frag');
}

function setup() {
  // the canvas has to be created with WEBGL mode
  createCanvas(windowWidth, windowHeight, WEBGL);
  describe('a simple shader example that outputs the color red')
}

function draw() {
  // shader() sets the active shader, which will be applied to what is drawn next
  shader(myShader);
  // apply the shader to a rectangle taking up the full canvas
  rect(0,0,width,height);
}
      

シェーディング言語(GLSL)

ここで、シェーダーファイルに実際に何を書くのか疑問に思うかもしれません! シェーダーファイルは、グラフィックスライブラリシェーディング言語(GLSL)で書かれており、 慣れ親しんでいるものとはかなり異なる構文や構造を持っています。GLSL は C 言語に似た構文を持っており、JavaScript には存在しないいくつかの概念が含まれています。

まず、シェーディング言語は型について非常に厳格です。 作成する変数は、格納されているデータの種類でラベル付けする必要があります。以下は、一般的な型のリストです:


vec2(x,y)     // 2つの浮動小数点数のベクトル
vec3(r,g,b)   // 3つの浮動小数点数のベクトル
vec4(r,g,b,a) // 4つの浮動小数点数のベクトル
float         // 小数点のある数
int           // 小数点のない整数
sampler2D     // テクスチャへの参照

      

一般的に、シェーディング言語は JavaScript よりもはるかに厳格です。たとえば、セミコロンがないとエラーメッセージが表示されます。 また、浮動小数点数や整数など、異なるタイプの数値を相互に使用することはできません。

まず、基本的な頂点シェーダーを見てみましょう:


attribute vec3 aPosition;

void main() {
  vec4 positionVec4 = vec4(aPosition, 1.0);
  positionVec4.xy = positionVec4.xy * 2.0 - 1.0;
  gl_Position = positionVec4;
}

この頂点シェーダーは、属性(attribute)で始まります。これは、p5.js がシェーダーと頂点位置情報を共有するために使用します。この属性は、vec3 であり、x、y、および z の値を含んでいます。属性は、頂点シェーダーでのみ使用される特別な変数タイプであり、通常は p5.js によって提供されます。rect()vertex() などの p5.js メソッドを使用すると、p5.js は自動的に頂点情報をシェーダーに渡します。

すべての頂点シェーダーには、頂点の位置を決めるための関数 main() が必要です。 この例では、頂点シェーダーが頂点の位置を変更して、シェーダーの出力が全体のスケッチを占めるようにします。最後に main() の中で、gl_Position に値を割り当てます。

まだ十分に理解できなくても心配しないでください。 頂点シェーダーは重要な役割を果たしますが、フラグメントシェーダーで作成したものがジオメトリ上で適切に表示されるようにするだけで、 多くのプロジェクトで同じ頂点シェーダーを再利用することができます。 一方、フラグメントシェーダーはシェーダーの色出力を担当し、シェーダープログラミングの大部分を行います。 以下は、赤色を表示するだけの非常にシンプルなフラグメントシェーダーです:


precision mediump float;

void main() {
  vec4 myColor = vec4(1.0, 0.0, 0.0, 1.0);
  gl_FragColor = myColor;
}

フラグメントシェーダーは、float の 'precision' を指定する行で始まります。この値は、lowpmediumphighp のいずれかになりますが、通常は mediump を使用し、特定の状況では highp を使用することがあります。

precision mediump float;

そして、頂点シェーダーと同様に、フラグメントシェーダーにも main() 関数が必要ですが、gl_Position ではなく、gl_FragColor に色を割り当てます。


...
vec4 myColor = vec4(1.0, 0.0, 0.0, 1.0);
gl_FragColor = myColor;
...

変数 myColorvec4 として定義されており、4つの値を格納します。色を扱っているので、それらの4つの値は赤、緑、青、アルファです。シェーダーでは、スケッチで使用される0 から255の色を使用せず、0.0から1.0の間の値を使用します。

頂点シェーダーとフラグメントシェーダーが用意できたら、これらを別々のファイル(shader.vert と shader.frag)に保存し、loadShader() を使用してスケッチに読み込むことができます。

Uniforms: スケッチからシェーダーへのデータの受け渡し

このようなシンプルなシェーダーは、それ自体で役立つことがありますが、p5.js スケッチからシェーダーに変数を伝達する必要がある場合もあります。 ここでユニフォームが登場します。ユニフォームは、スケッチからシェーダーに送信できる特殊な変数です。 これにより、シェーダーをより制御できるようになります。例えば、p5.js のメソッド millis() を使用して「time」ユニフォームをスケッチに渡し、動きを導入することができます。シェーダーでは、ユニフォームはファイルの先頭、main() の外部で定義されます。 次のフラグメントシェーダーでは、スケッチから色を変更できるようにするためのカラーユニフォーム、myColor を作成しています。


precision mediump float;

uniform vec3 myColor;

void main() {
  // the color we have passed in as a uniform is assigned to the pixel
  gl_FragColor = vec4(myColor, 1.0);
}
      

p5.js スケッチに戻ると、この色は setUniform() を使って送信できるようになります。


...
function draw() {
  shader(myShader);
  // setUniform can then be used to pass data to our shader variable, myColor
  myShader.setUniform('myColor', [1.0,0.0,0.0]); // send red as a uniform
  // apply the shader to a rectangle taking up the full canvas
  rect(0,0,width,height);
}
...
      

また、ジオメトリに関する特定のデータをスケッチと頂点シェーダー間で共有するために通常使用される属性や、 頂点シェーダーとフラグメントシェーダー間でデータを共有するバリング変数があります。 これにより、フラグメントシェーダー内で位置やその他のジオメトリデータを使用することができます。


// (thank you to Adam Ferriss for the foundation of these example shaders)
// position information that is used with gl_Position
attribute vec3 aPosition;

// texture coordinates 
attribute vec2 aTexCoord;

// the varying variable will pass the texture coordinate to our fragment shader
varying vec2 vTexCoord;

void main() {
  // assign attribute to varying, so it can be used in the fragment
  vTexCoord = aTexCoord;

  vec4 positionVec4 = vec4(aPosition, 1.0);
  positionVec4.xy = positionVec4.xy * 2.0 - 1.0;
  gl_Position = positionVec4;
}

これでテクスチャ座標属性がバリング変数に割り当てられているため、フラグメントシェーダーでテクスチャ座標を使用できます。 以下の例では、テクスチャ座標の青とマゼンタの可視化が表示されます。


precision mediump float;

varying vec2 vTexCoord;

void main() {
  // now because of the varying vTexCoord, we can access the current texture coordinate
  vec2 uv = vTexCoord;
  
  // and now these coordinates are assigned to the color output of the shader
  gl_FragColor = vec4(uv,1.0,1.0);
}
an illustration showing UV coordinates, the x axis in red, and the y axis in blue.
p5.js は多くの属性とユニフォームを処理してくれます。p5.js がシェーダーに送信するすべての属性のリストをこちらで確認できます

結論

これらのスキルを持っていれば、基本的なシェーダーを作成することができますが、シェーダープログラミングは非常に深いものであり、 このチュートリアルを超える多くのシェーダートピックがあります。p5.js のシェーダーは、視覚的な効果やエフェクト、さらには 3D ジオメトリにマップされるテクスチャを作成するための強力なツールになり得ます。

シェーダーについてもっと学びたいですか?これらのウェブサイトをチェックしてみてください!

  • The Book of Shaders、Patricio Gonzalez Vivo と Jen Lowe によるシェーダーガイド。
  • P5.js shaders、Casey Conchinha と Louise Lessél によるシェーダーガイド。
  • Shadertoy、ブラウザエディタで書かれたシェーダーの大規模なオンラインコレクション。
  • p5jsShaderExamples、Adam Ferriss によるリソースコレクション。

その他のチュートリアル

このチュートリアルは、p5.js で WebGL を使用する基本についてのシリーズの一部です。以下の他のチュートリアルをすべてチェックしてください。

用語集

シェーダー

多くの視覚効果やフィルタを効率的に生成できる特殊なグラフィックカードプログラム。

GLSL

Graphics Library Shader Language(GLSL)は、シェーダーを記述するために使用されるプログラミング言語。

Uniform

スケッチからシェーダーに渡される変数。

ベクター

色、位置などを表すために、通常は2、3、または4の数値を格納するデータ型。

Float

小数点を持つことができる浮動小数点数を格納するデータ型。

Int

小数点のない整数を格納するデータ型。

サンプラー

シェーダーに渡されるテクスチャを表すデータ型。

属性(Attribute)

p5.js スケッチで生成され、頂点シェーダーで利用可能な GLSL 変数。ほとんどの場合、p5.js によって提供されます。

テクスチャ

シェーダープログラムに渡される画像。

タイプ

データの特性を示すラベル。例えば、int、float、vector など。

頂点シェーダー

シェーダープログラムの一部で、3D 空間でのジオメトリの位置を決定する役割を担っています。

フラグメントシェーダー

シェーダープログラムの一部で、シェーダーが出力する各ピクセルの色と外観を決定する役割を担っています。