2022/09/23(金) [n年前の日記]
#1 [python] OpenGLのGL_ALPHA_TESTについて動作を調べてた
Python + PyOpenGL を使ってOpenGLを勉強しているところ。ポリゴンに貼ったテクスチャ画像の透明部分について、妙な描画結果になることに気づいてしまって、そのあたりを少し調べてた。
環境は、Windows10 x64 21H2 + Python 3.9.13 + PyOpenGL 3.1.6。GPU/ビデオカードは、NVIDIA GeForce GTX 1060 6GB。
実験に使った画像は以下。
_img_rgba2.png
実験に使ったソースは以下。
_06_draw_billboard_alpha_test_2.py
さて。アルファチャンネルを持ったテクスチャ画像をそのまま描画すると、以下のように、アレな見た目になってしまう。画面の右側は期待していた見た目になっているけれど、左側は、透明になってほしい部分の後ろにあるはずの色がちゃんと出てこない…。
ボールの向こう側にもボールがあるのだから、本来、透明部分には、奥側にあるボールの赤い色がそのまま出てほしいわけだけど…。実際は奥側のボールを素通りして、背景相当の緑の床が表示されてしまっている。
これはデプスバッファを使って描画する際に起きてしまう問題で、「一番手前にあるポリゴンの色だけをそこに描画すれば隠面消去ってできるよね」という考え方で描画するものだから、その奥にあるポリゴンの色は無視されて、こんな状態になってしまう、らしい。
GL_ALPHA_TEST を有効にすると、多少は改善されるけど。しかし、これもまだまだ問題が…。
この場合、アルファチャンネルの値を見て、0.1 より上か下かで、不透明もしくは透明に2値化してくれるはずだけど…。やはり奥側にあるボールの色が反映されず、床が見えてしまっている。
色々試してみたけれど、結局のところ、こういったテクスチャ画像を貼るポリゴンについては、奥行き情報でソートして、奥側から手前に向かって描画しないと解決しないようだなと分かってきた。その分、処理負荷が増えるだろうから、あまりやりたくはないのだけど…。
あるいは、テクスチャ画像そのものに対して、事前にアルファチャンネルを2値化しておくことでも解決できるだろうなと。実際、上記のボール群も、アルファチャンネルを2値化している下半分については、見た目で特に問題は無いわけで。もっとも、縁の部分でジャギが目立つだろうし、ぼんやり重ねた感じの表現ができなくなるから、見た目の品質は落ちてしまうのだろうけど、処理負荷については、おそらく軽く済むだろう…。
つまるところ、処理負荷を増やして見た目の品質を向上させるか、見た目を犠牲にして処理を軽くするか、トレードオフなのかもしれないなと…。
余談。このあたりの問題は、 _「opengl transparent artifacts」 や _「Order independent Transparency」 (OIT) でググるとそれらしいページが出てくる模様、とメモ。
環境は、Windows10 x64 21H2 + Python 3.9.13 + PyOpenGL 3.1.6。GPU/ビデオカードは、NVIDIA GeForce GTX 1060 6GB。
実験に使った画像は以下。
- 赤いボールの上半分をぼかしてある。(アルファチャンネルが0 - 255まで滑らかに変化)
- 下半分のアルファチャンネルを2値化してある。(0 か 255になっている)
実験に使ったソースは以下。
_06_draw_billboard_alpha_test_2.py
- a, d key : カメラ位置の回転
- w, s key : カメラの高さを変更
- z key : ビルボードのソートの ON/OFF
- x key : GL_ALPHA_TEST の ON/OFF
さて。アルファチャンネルを持ったテクスチャ画像をそのまま描画すると、以下のように、アレな見た目になってしまう。画面の右側は期待していた見た目になっているけれど、左側は、透明になってほしい部分の後ろにあるはずの色がちゃんと出てこない…。
ボールの向こう側にもボールがあるのだから、本来、透明部分には、奥側にあるボールの赤い色がそのまま出てほしいわけだけど…。実際は奥側のボールを素通りして、背景相当の緑の床が表示されてしまっている。
これはデプスバッファを使って描画する際に起きてしまう問題で、「一番手前にあるポリゴンの色だけをそこに描画すれば隠面消去ってできるよね」という考え方で描画するものだから、その奥にあるポリゴンの色は無視されて、こんな状態になってしまう、らしい。
- 右側が正しく描画されているのは、たまたま、奥から手前へ向かって各ポリゴンを描画しているから。
- 左側がおかしなことになっているのは、不幸なことに(?)、手前から奥に向かって各ポリゴンを描画しているから。
GL_ALPHA_TEST を有効にすると、多少は改善されるけど。しかし、これもまだまだ問題が…。
glEnable(GL_ALPHA_TEST) glAlphaFunc(GL_GREATER, 0.1)
この場合、アルファチャンネルの値を見て、0.1 より上か下かで、不透明もしくは透明に2値化してくれるはずだけど…。やはり奥側にあるボールの色が反映されず、床が見えてしまっている。
色々試してみたけれど、結局のところ、こういったテクスチャ画像を貼るポリゴンについては、奥行き情報でソートして、奥側から手前に向かって描画しないと解決しないようだなと分かってきた。その分、処理負荷が増えるだろうから、あまりやりたくはないのだけど…。
あるいは、テクスチャ画像そのものに対して、事前にアルファチャンネルを2値化しておくことでも解決できるだろうなと。実際、上記のボール群も、アルファチャンネルを2値化している下半分については、見た目で特に問題は無いわけで。もっとも、縁の部分でジャギが目立つだろうし、ぼんやり重ねた感じの表現ができなくなるから、見た目の品質は落ちてしまうのだろうけど、処理負荷については、おそらく軽く済むだろう…。
つまるところ、処理負荷を増やして見た目の品質を向上させるか、見た目を犠牲にして処理を軽くするか、トレードオフなのかもしれないなと…。
余談。このあたりの問題は、 _「opengl transparent artifacts」 や _「Order independent Transparency」 (OIT) でググるとそれらしいページが出てくる模様、とメモ。
[ ツッコむ ]
以上です。