C-WebGL: Depthの互換問題
Unityだと踏まないと思ってたのに。。
Depthの座標系がOpenGLとそれ以外で違う問題
OpenGL(= WebGL)では、ラスタライザは ( -1 , 1) のデプス値を出力してこれを glDepthRangef
の設定値でマップして出力する。
Vulkanは、ラスタライザは ( 0 , 1) のデプス値を出力できる。このため、OpenGLでは処理できた負値のデプス値はクリップされてしまう。
この違いを吸収する必要がある。
RenderDocで問題を確認する
描画されるはずのものが描画されなかったりといった変な描画一般には、Pixel Historyが役に立つ。
"Depth Clipped" と表示されているので、描画されない理由はクリッピングであることがわかる。 (gl_Position
も実際に z
が負値になっている)
Depth Clampingで正常に動作することを確認する
DirectXでは、 (0,1) に収まらないdepthはクランプされる。この動作自体はVulkanでも(拡張で?)使えるのでこれを有効にして絵が出ることを確認する。
結果、描画はちゃんと出るので、depthさえ変換すれば正常に動作すると期待できると言える。
ANGLE先輩の意見を聞く
C-WebGLはANGLE + Vulkanの組合せでも動作する。というわけで同じプログラムをANGLEで動かしてVulkanのシェーダを観察できる。
ANGLE先輩曰く:
gl_Position = vec4(gl_Position.xy, (gl_Position.z + gl_Position.w) * 0.5, gl_Position.w);
普通だな!クリップ座標での z
が区間 [-w, w]
なのを [0,-w]
に補正するには、
-
w
を足してz + w
=[0, 2w]
- 2で割って
(z + w) * 0.5
=[0, w]
よって、バーテックスシェーダの main
の末尾に上記の式を挿入すれば良い。
パッチ候補の作成
ANGLEそのままの
vec4(gl_Position.xy, (gl_Position.z + gl_Position.w) * 0.5, gl_Position.w);
では、パッチの長さが長くなってしまう。
/* ★ この命令列をmainに挿入 */
%32 = OpLoad %v4float %gl_Position
%33 = OpVectorShuffle %v2float %32 %32 0 1
%37 = OpAccessChain %_ptr_Output_float %gl_Position %uint_2
%38 = OpLoad %float %37
%40 = OpAccessChain %_ptr_Output_float %gl_Position %uint_3
%41 = OpLoad %float %40
%42 = OpFAdd %float %38 %41
%44 = OpFMul %float %42 %float_0_5
%45 = OpAccessChain %_ptr_Output_float %gl_Position %uint_3
%46 = OpLoad %float %45
%47 = OpCompositeExtract %float %33 0
%48 = OpCompositeExtract %float %33 1
%49 = OpCompositeConstruct %v4float %47 %48 %44 %46
OpStore %gl_Position %49
OpReturn
OpFunctionEnd
というわけで、ちょっとシンプルに z
のみの書き換えとして、
gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;
/* ★ この命令列をmainに挿入 */
%35 = OpAccessChain %_ptr_Output_float %gl_Position %uint_2
%36 = OpLoad %float %35
%38 = OpAccessChain %_ptr_Output_float %gl_Position %uint_3
%39 = OpLoad %float %38
%40 = OpFAdd %float %36 %39
%42 = OpFMul %float %40 %float_0_5
%43 = OpAccessChain %_ptr_Output_float %gl_Position %uint_2
OpStore %43 %42
OpReturn
OpFunctionEnd
また、 実際には main
自体をリプレースする必要がある 。現状のパッチでやっているようなUBOのロードと一緒に専用のFunctionを出力してしまう方が簡単で、スッキリするはず。
追加が必要な定義
-
float32
型(たぶん事前に存在するのでチェックしておく) -
Output
なfloat32
ポインタ - 新規に追加する
main
- 新規に追加する
main
の Block用のLabel
- 定数
2
- 定数
3
- 定数
0.5
名前も cwgl_entrypoint
とかに変えちゃうか。(Vulkanではエントリポイントの名前は自由に設定できる)
実装した