【WebGL】GLSLの曲者varyingとuniformとは?その挙動の説明と使い方について

2023年11月30日WebGL & Three.js

WebGL(GLSL)において、データを受け渡しする方法には3つあります。

  • attribute
  • varying
  • uniform

その中でもvaryingは特にわかりにくいです。
varyingの挙動が理解できればほぼわかったと言えるというくらい重要なものです。

attributeについては、attributeと頂点シェーダについてをご確認ください。

varyingとは?

varyingとは、頂点シェーダからフラグメントシェーダへの値の受け渡しをするデータのことです。
JavaScriptから頂点シェーダへは、attributeが渡されますが、頂点シェーダからフラグメントシェーダへは、このvaryingが渡されます。
attributeとは?と不明な場合は、上の頂点シェーダのリンクを確認してみてください。

varyは英語で「変化する」を意味する単語です。
特徴としては、ユーザーで定義が可能で、
頂点間のフラグメントは線形補間された値が渡る点です。

varyingのメリット

スムーズなグラデーションができる

このvaryingのおかげで、頂点間のフラグメントは線形補間されるため、
フラグメントシェーダでの色がスムーズになり、グラデーションも綺麗に表現することができます。
WebGLを使ったカラフルなグラデーションのサンプルデモはこちらで確認できます。

光の反射を計算できる

頂点の法線をフラグメントに渡すことで、光の反射を計算できます。
物体の明るさを光を考慮して決められるということです。

物体に画像や動画を貼り付けられる

varyingのuv座標を使用することで、物体に画像や動画を貼り付けて表現することができます。

varyingを実装段階で覚えておきたいこと

頂点シェーダからフラグメントシェーダへは、このvaryingが渡されます。
つまり、頂点の位置はそれぞれ決定された後にvaryingが渡されるということです。

頂点シェーダでたとえば以下のコードを指定します。

attribute vec3 position; //positionはそれぞれの頂点で異なる値を保持
varying vec3 vertexPosition; //フラグメントに渡すvertexPositionを宣言
vertexPosition = position; //頂点ごとに代入

positionはそれぞれの頂点で異なる値を保持します。
フラグメントに渡すvertexPositionを宣言します。
そして、頂点ごとにvertexPositionをpositionに代入します。

フラグメントシェーダでは以下のようなコードになります。

varying vec3 vertexPosition;

こうすることでvertexPositionに値が渡ってくるのですが、このときの値は、各フラグメントで異なります。
各フラグメントに、線形補間された値が渡ってきます。

uniformとは

uniformとは、頂点シェーダとフラグメントシェーダに一様な(uniformな)値を渡すものです。
同じデータといってもいいかもしれません。
varyingと同じく、ユーザーで定義が可能です。
異なる点として、varyingのように線形補間などはなく、全部の頂点と全部のフラグメントで一様な値を渡します。

用途としては、経過時間を使ったアニメーションだったり、
クリックされたときに状態変化させるアニメーションのことに使います。

uniformの使い方

uniformの使い方はほぼvaryingと同じで、以下のように定義して、javaScriptなどからWebGLに値を渡すことができます。

// 頂点シェーダ
uniform float u1;
void main() {
  position += u1;
  gl_Position = ...
}
// フラグメントシェーダ
uniform float u1;
void main() {
  gl_FragColor = ...
}