LoginSignup
4
3

More than 5 years have passed since last update.

WebGL2でIntegerテクスチャへの書き込み&読み込み

Posted at

WebGL2でIntegerテクスチャに書き込みと読み込みを行う方法です。

サンプルをGithubに置いておいたので、この記事では要点だけを解説します。
aadebdeb/Sample_WebGL2_IntegerTexture: Sample of writing & reading integer texture in WebGL2

まずはIntegerテクスチャの作成を行います。
texImage2Dでフォーマットを指定します。このメソッドの引数であるinternalformatformat, typeは適切な組み合わせを選択する必要があります。今回はinternalformatをRGBA32I、formatをRGBA_INTEGER, typeをINTにして4つの値を格納できるようにします。組み合わせはこの記事が参考になります。

格納する値が1つでいい場合はinternalformatformatをそれぞれR32IRED_INTEGERに、2つの場合はRG32IRG_INTEGERを選択するといいでしょう。また小さい値しか格納しないのであればRGBA8IRGB16Iも使用できます。

また、Integerテクスチャを使用する場合はフィルタリングの方法をNEARESTにするよう必要があります。

function createTexture(gl, sizeX, sizeY) {
  const texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, texture);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32I, sizeX, sizeY, 0, gl.RGBA_INTEGER, gl.INT, null);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
  gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
  gl.bindTexture(gl.TEXTURE_2D, null);
  return texture;
}

次に作成したIntegerテクスチャに値を書き込む方法です。
通常のオフスクリーンレンダリングと同じように作成したテクスチャを紐づけたフレームバッファに以下のようなフラグメントシェーダーでレンダリングを行います。out修飾子がついた変数の型がテクスチャの型と同じになるようにivec4にしています。

#version 300 es

precision highp float;

out ivec4 value;

void main(void) {
  ivec2 coord = ivec2(gl_FragCoord.xy);
  value = ivec4((coord.x + coord.y + ivec3(0, 2, 4)) % 8, 0);
}

最後にIntegerテクスチャの読み込みです。Integerテクスチャにはsampler2Dではなくisampler2Dを利用します。またprecision highp isampler2D;のようにisampler2Dの精度を指定する必要もあります。

#version 300 es

precision highp float;
precision highp isampler2D;

out vec4 color;

uniform isampler2D tex;
uniform vec2 resolution;

void main(void) {
  vec2 uv = gl_FragCoord.xy / resolution;
  ivec3 v = texture(tex, uv).rgb;
  color = vec4(vec3(v) / 8.0, 1.0);
}

符号なし整数のテクスチャへの書き込み&読み込みも同様に行います。

テクスチャ作成時にはinternalformatにはRGBA32UIのようにUが付き、typeUNSIGNED_INTになります。

gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA32UI, sizeX, sizeY, 0, gl.RGBA_INTEGER, gl.UNSIGNED_INT, null);

テクスチャ書き込み時には出力先の変数の型がuvec4になります。

#version 300 es

precision highp float;

out uvec4 value;

void main(void) {
ivec2 coord = ivec2(gl_FragCoord.xy);
value = uvec4((coord.x + coord.y + ivec3(0, 2, 4)) % 8, 0);
}

テクスチャ読み込み時にはisampler2Dではなくusampler2Dを利用します。

#version 300 es

precision highp float;
precision highp usampler2D;

out vec4 color;

uniform usampler2D tex;
uniform vec2 resolution;

void main(void) {
vec2 uv = gl_FragCoord.xy / resolution;
uvec3 v = texture(tex, uv).rgb;
color = vec4(vec3(v) / 8.0, 1.0);
}

最後に注意事項について書いておきます。

RGB32Iのように3変数の値を格納するテクスチャへの書き込みはできません。書き込もうとすると以下のような警告が出ます。

[.WebGL-00000219F401A920]GL ERROR :GL_INVALID_FRAMEBUFFER_OPERATION : glDrawElements: framebuffer incomplete

また、Integerテクスチャの読み込み時にisampler2Dsampler2Dではなくsampler2Dを使うと、エラーにはなりませんがサンプルした値が0になります。

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3