整数、bool値uniform

intとbool

 一応intとboolのuniformの取り扱い方も説明します。要するに1234のiとivです。しかしやることはfとfvの代わりに整数を使うだけです。ちなみに32bitの整数です。つまり-2,147,483,648 から 2,147,483,647 までですね。boolはもう言ってしまうとiやivを援用します。つまり0と1を使うんですが、true/falseで代用できるしその方が自然なのでそれを使えばいいでしょう。これで一通りuniformについて説明し終えることになります...行列以外。
 もちろんWebGL2になってuintとか追加されたんですが、ここまでの内容を応用すれば簡単なので、あとはもう行列しかやる予定はないです。興味がある場合は、独自に調べてください。 \[ 1+2=3.~~4+5=9.~~11+13=24.~~\int_0^1 xdx = \frac{1}{2}. \]  これは特に意味は無くて、次の記事でKaTeXを使うと思うので、テストです。

コード全文

作品13のリンク

プログラムの解説

 intとboolのuniformを扱っています。キャンバスは384x384とし、32x32に区切っています(32の倍数でないと具合が悪いので)。32bitの整数値を32bitで表現して色付けて表しています。内部でuintに変換するだけなので簡単です。下24個は固定ですが上8個をコンフィグでいじれます。あんま範囲が広いとバグるので抑えてあります。内容は以上です。
 上8個は色を変えてあります。一応、uintの扱いについて言及します。

  vec2 p = uPoints[gl_VertexID];
  vUv = (p + 1.0) * 0.5;
  // 左上が(0,0)となるように調整
  vUv.y = 1.0 - vUv.y;
  // さらに32x32に落とす
  vUv *= 32.0;

 以上のように、バーテックスシェーダでは位置情報を左上が0,0となるように32x32で正規化しています。位置は正方形です。vec2のuniformで指定します。次にフラグメントシェーダ:

void main(){
  int bitIndex = int(vUv.x);
  if (uInvert) { bitIndex = 31 - bitIndex; }
  int intIndex = int(vUv.y);
  float factor = fract(vUv.y);
  uint ui = uint(uInts[intIndex]);
  // 1もuint化しないといけないんだよ...
  uint bit = (ui >> bitIndex) & uint(1);
  vec3 col = vec3(factor);
  if(vUv.y < 8.0){
    col = col + vec3(0.0, 0.5, 1.0) - col * vec3(0.0, 0.5, 1.0);
  }
  fragColor = vec4(col*float(bit), 1.0);
}

 まず横の情報をint化、縦の情報もint化します。縦の情報は配列のindexとして使います。整数が得られたらuint化します。これのbitを取得するんですが、ポイントはuintはuint同士でしか演算できないことです。定数の1はconst int扱いなのでここにあるようにuint化しないと演算できません。bitずらしは負の数でも問題ないようです。注意点は以上です。

uniform[1234]i[v]

 あとはもうあんま話すことが無いですね...基本は終わっているので。一応、いつものようにnameを取得すると次のようになっています:

uPoints[0], uInvert, uInts[0]

 あとはこれらに従って、uniformの1234のiまたはivで、今までと同じように登録するだけです。fがiになるだけで全部一緒です。なので解説することがありません。取得ですが、getUniformで同じように取得できます。この場合intなら整数のNumber, ivec[234]ならInt32Arrayが返ります。ただ真偽値のuniformの場合、これはbool,bvec[234]で指定するんですが、この場合は真偽値、もしくはその配列が返ります。ちょっと補足しますね。

bool uniformの登録

 真偽値のセットにはiやivを使います:

gl.uniform1i(uniforms.uInvert.location, config.invert);

 マナーとしては真偽値を使うんでしょうが、iやivなので0や1の方が自然なのか...?でもgetUniformで真偽値が返るのですから、よほどのことが無い限りは素直に真偽値を使うべきでしょう。ちなみにp5は0や1に変換しているそうです。まあ、好きにやりましょう。
 一応このブール値はどっちから並べるかを指定しています。チェックすると逆順で並びます。特に有用性があるわけではありません。

intの精度について

 シェーダーにも追記したんですが、今さっき引っかかったので、一応自戒を込めて補足します。
 先ほど、フラグメントシェーダーに次の一行を追加しました。

precision highp int; // これが無いとスマホの見た目がおかしくなる

 今回のコードでは、フラグメントシェーダー内では32bitの整数を扱っていることが前提です。にも関わらず、私のスマホの見た目はこんな感じでした:

mediump int

 これはどういうことかというと、16bitの整数になってしまっているんですね。-32768~32767です。フラグメントシェーダーが扱える整数の範囲は処理系依存なので、このようなことが起きるようです。なおこの現象を再現しようと思って、私の富士通のノートパソコンでフラグメントシェーダにmediump intを明示したところ、何も問題は起きず、highp intで処理されました。どうやら精度の高い方が採用されるようです。
 そんなわけで、highp intを明示したところ、問題は解消しました。こういうところがWebGLの難しい所です。指定した精度と仕様上の精度では精度の高い方が採用されるので、低い精度を指定したところであまり意味は無いようです。素直にhighpを指定した方がよさそうです。
 私は、よほどのことが無い限りは、スマホでもきちんと動くコードを書くように心がけています。TLにたまたま流れてきたコードの作品サイトに飛んだら処理が重すぎて死んだ...みたいな経験をたくさんしてきたので、作品を見る人に不快な思いをさせたくないわけです。

 まあいいですね。次の記事では行列を取り扱う予定です。