[WebGL] 浮動小数点テクスチャの扱いでハマった件

  • 8
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

必要な拡張機能それで合ってますか?

最近、WebGLで遅延シェーディングしたりすると、モバイルでG-Bufferが描かれないなんてことがあった。
いや、でもOES_texture_floatは確かに正常にgetExtensionできる。

CPUで書き込み、GPUで読み出すというケース

あくまで、GPU側ではRenderTargetとして使わず、tetxture2Dで読み出すと言う場合には確かにOES_texture_floatのみで問題ない。
ただし、フィルタにLINEARをかけるのであれば、OES_texture_float_linearが必要だ。

half floatテクスチャを用いたい場合は、OES_texture_half_float,OES_texture_half_float_linearをそれぞれ用いれば良い。

ここまでは常識的な範囲だろう。

GPU側で書き込みが必要なケース

シャドウマップのための深度を記録する目的や、遅延シェーディングで法線情報を記録しようとしたりして浮動小数点テクスチャが必要になると、FrameBufferに対して浮動小数点テクスチャを登録して、そこに対して利用する。つまりは、RenderTargetとして利用する場合は、少し様子が異なる。

実は、GPU側からの書き出しでは、OES_texture_floatだけでは足りない。
加えて、WEBGL_color_buffer_floatが必要となる。特に、モバイル環境では、OES_texture_floatはサポートしているが、WEBGL_color_buffer_floatはサポートしていないなどあり色々めんどくさい。

さらにめんどくさいのは、これが一筋縄にgetExtensionすればいいんだろ。というわけにもいかないというところだ。

実はこのWEBGL_color_buffer_float、ブラウザがサポートしていてもgetExtensionでnullが返ってくることがある。
だから、別に今まで動いてたって人がいたとしたら、getExtensionしなくても使えたっていうわけだ。

じゃあ、どうやって使用可否を判断するかというと、試しにFrameBufferとくっつけてみるしかない。

let isSupported;
    if (gl.getExtension("WEBGL_color_buffer_float") === null) {
      const fbo = gl.createFramebuffer();
      const tex = gl.createTexture();
      gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
      gl.bindTexture(gl.TEXTURE_2D, tex);
      gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.FLOAT, null);
      gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
      if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !== gl.FRAMEBUFFER_COMPLETE) {
        isSupported = false;
      } else {
        isSupported = true;
      }
      gl.deleteTexture(tex);
      gl.deleteFramebuffer(fbo);
    } else {
      isSupported = true;
    }

CPU側で読み込みたいってケース

readPixelsを使ってfloat値を読み込みたいって場合は、さらに注意が必要。
これはそれ用の仕様があるわけでもなく、なぜかWEBGL_color_buffer_floatがサポートされていれば、FLOATかつ、RGBAの読み込みができるようになっている。