glPolygonOffset

glpolygonoffset.png

ポリゴンオフセットを有効にする方法3つ

glEnable()に次の引数を渡す
GL_POLYGON_OFFSET_FILL
GL_POLTGON_OFFSET_LINE
GL_POLYGON_OFFSET_POINT

さらに、glPolygonMode()も呼ばないといけません。
現在のポリゴンのラスター化手法を知らせるためです。
これら2つ、glEnable()とglPolygonMode()を呼んだ上で、glPolygonOffset()を呼びましょう。

いざ、glPolygonOffsetを使う

z値が全く同じで不自然な見た目になってしまうのを避けるために使用する。
デプス値をちょこっとずらすことが出来るのだ。

glPolygonOffset(factor,units)

奥行きのオフセットは次のように計算します

奥行きのオフセット=m*factor+r*units

  • m….その三角形の傾きの深さの最大値(ラスター化の過程で計算されます)
  • r….デプス値に差を作り出すことが出来る最小値。デプス値の解像度のようなもの。端末によって異なる値です。定数。
  • factorunitsは負の値でもokです

この奥行きのオフセットは、各フラグメントのデプス値に足し算されます。

使い方

たとえば、ポリゴンの縁に輪郭線を引くような場合は
ポリゴンを描く時に正の値を渡し(視点から見て奥に押し込む)
枠線を描く時に負の値を渡します。(視点の方向へ引き込む)

その三角形の奥行きの最大の傾きm

イメージとしては

そのポリゴンがニアークリッピング面やファークリッピング面と平行ならばm=0
そのポリゴンが、クリッピング面と平行ではなく傾いていたらm>0です。

実際は次のように計算されます

(1)
\begin{align} m=\sqrt{(\frac{\delta z}{\delta x^2}+\frac{\delta z}{\delta y^2})} \end{align}

要は長さみたいにしたいので、こうとも表現できます

(2)
\begin{align} m=max{|\frac{\delta z}{\delta x^2}|,|\frac{\delta z}{\delta y^2}|} \end{align}

三角形の傾きの項$\frac{\delta z}{\delta x^2}$$\frac{\delta z}{\delta y^2}$
三角形のラスタライズ処理中にOpenGLで自動的に計算してくれます。

デプス値に差を作り出すことが出来る最小値r

rは実装で定義される定数で、デプス値に差を作り出すことが出来る最小値を表します。

オフセットの値はどのぐらいがいいの?

ポリゴンの傾きの深さや、線の太さによりけりです。
傾きの深さが0の場合は

glPolygonOffset(0,1);

でokです。
つまり、奥行きの式が

奥行きのオフセット=m*factor+r*units

こうなる、ということです。

奥行きのオフセット=r

端末のデプス解像度がそのまま奥行きのオフセットになる、というわけですね。
奥行き度数を1ずらす、という感覚です。

傾きの深さが0以上の場合は

glPolygonOffset(0.751.0,??)

デプスバッファとglPolygonOffset

zファイティングを防ぐためには
glPolygonOffsetでちょっとずらした値をデプス値に与える必要がある。
なので、デプステストを使っている場合は要注意。
デプステスト無効状態で描かないといけない。
glPolygonOffset使った場合
デプスバッファには元のデプス値が記録される。

ポリゴンオフセットの有効・無効

glEnable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_POLYGON_OFFSET_FILL);

サンプルソースコードsnippet

z-fightingが起こるダメなコード glPolygonOffsetを使ってz-fightingが起こらない良いコード
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//頂点シェーダをロードする
//行列変換をする
//glVertexAttribPointerする
//小さい方(手前にしたい方)の四角形を描く
glDrawArrays(GL_TRIANGLE_FAN,0,4);
//depth funcを<=にする。次に描くポリゴンと全く平行な面を描くので
glDepthFunc(GL_LEQUAL);
//glVertexAttribPointerする
//大きい方(奥にしたい方)の四角形を描く
glDrawArrays(GL_TRIANGLE_FAN,0,4);
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
//頂点シェーダをロードする
//行列変換をする
//glVertexAttribPointerする
//小さい方(手前にしたい方)の四角形を描く
glDrawArrays(GL_TRIANGLE_FAN,0,4);
//depth funcを<=にする。次に描くポリゴンと全く平行な面を描くので
glDepthFunc(GL_LEQUAL);
 
const float polygonOffsetFactor=-1.0f;
const float polygonOffsetUnits=-2.0f;
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(polygonOffsetFactor,polygonOffsetUnits);
 
//glVertexAttribPointerする
//大きい方(奥にしたい方)の四角形を描く
glDrawArrays(GL_TRIANGLE_FAN,0,4);

outline stitching

サポートサイト Wikidot.com outlinestitching