整数、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を使うと思うので、テストです。
コード全文
プログラムの解説
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の整数を扱っていることが前提です。にも関わらず、私のスマホの見た目はこんな感じでした:

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