必要な拡張機能それで合ってますか?
最近、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の読み込みができるようになっている。