blog

OpenGL-ポリゴンオフセットとカラーブレンド

深度テストを使用することで、隠面消去の問題を解決できることを話しました。結果は完璧に見えますが、本当に深度テストに問題はないのでしょうか?もちろんそうではありません。では、テストの問題の深さについて見...

Feb 18, 2020 · 5 min. read
シェア

記事では、隠面消去問題を解決するために深度テストを使用することについてお話しました。結果は完璧に見えますが、本当に深さテストに問題はないのでしょうか?深さ検定の問題点を見てみましょう:

I. ディープ・テストの潜在的リスク:Zファイト(Zコンフリクト、ちらつき)

なぜZ-fighting:

これは、深度テストをオンにすると、OpenGL がモデルの不明瞭な部分を描画しなくなるためです。その結果、よりリアルな表示になりますが、非常に小さな奥行きの違いに対する奥行きバッファの精度の制限により、OpenGLが2つの奥行き値を正しく判断できないことがあり、奥行きテストの結果が予測できないことがあります。つまり、最初の2つのイメージはインターレースされています。

Zファイト現象は、同じ位置に現れたレイヤーの切り込み深さの精度が非常に低く見える場合に起こりやすい現象です。これは、2つのオブジェクトが近接しているため、誰がお金で誰が後ろなのか判断できず、表示が曖昧になることを示します。

解決方法Z-fighting

Zファイトを解決するために、OpenGLはポリゴンをオフセットする方法を提供しています。2つの形状の間に隙間がある場合、これは干渉がないことを意味するのでしょうか。これは、奥行きテストを実行する前に、立方体の奥行き値がわずかに増加していると解釈できます。重ね合わせた2つの図形の奥行き値は、描画する前に区別することができます。

  • 1.ポリゴンオフセットを有効にします:
/ポリゴンオフセットメソッドを有効にする
glEnable(GL_POLYGON_OFFSET_FILL)
//パラメータリスト:
GL_POLYGON_OFFSET_POINT 対応するラスタライズモード: GL_POINT 
GL_POLYGON_OFFSET_LINE 対応するラスタライズモード: GL_LINE
GL_POLYGON_OFFSET_FILL 対応するラスタライズモード: GL_FILL
  • オフセットを指定します:
void glPolygonOffset(Glfloat factor,Glfloat units);
フラグメント上のオフセットの合計を計算する式が使用される。:
Depth Offset = (DZ * factor) + (r * units); DZ:深度値
r:深度バッファを変化させる最小値。
負の値はZ値を近づけ、正の値はZ値を遠ざける。

係数と単位は通常-1に設定され、-1で十分です。

  • ポリゴンオフセットを閉じる
glDisable(GL_POLYGON_OFFSET_FILL)

なぜオフにしなければならないかというと、OpenGLは実行時に巨大なステートマシンなので、ポリゴンオフセットをオンにした後、オフセットを設定したらオフにしなければならないからです。そうしないと、後の描画に影響が出ます。

Z戦を防ぐには?

  • 2つのオブジェクトが近接しすぎないように、描画時に小さなオフセットを挿入します;
  • 作物表面近くを観察者から離す:作物内の精度が向上します;
  • より高いビット数のデプスバッファを使用:デプスバッファの精度を向上。

II.カラーミキシング

OpenGL でレンダリングするとき、色はカラーバッファに保存され、各セグメント の深度値も深度バッファに保存されます。深度バッファをオフにすると、新しい色は単にキャッシュ内の元の色を上書きし、深度バッファを再びオンにすると、新しい色が元の色に置き換わるのは、元の値よりも隣の切り抜き面に近い場合だけです。そのため、深度テストがオンになっている場合。しかし、重なっている2つのレイヤーのうち、1つは半透明です。 重なっているレイヤーのうち1つは半透明で、1つは非透明です。 単純に深度値を比較してオーバーレイを行うのではなく、2つのレイヤーを比較する必要があります。 代わりに、2 つのレイヤーの色をブレンドする必要があります。

コモンミックス

2つのレイヤーを単純に重ねたときのカラーブレンドに使用され、このブレンドは色の混合を解決しません。これは固定シェーダとプログラマブルシェーダの両方で使用できます。

固定カラーミキサー/プログラマブルカラーミキサー→スイッチモード使用→カラーミキシング

  • カラーミキシングを開始します:
glEnable(GL_BlEND);
  • カラーミキシングをオフにします:
glDisable(GL_BlEND);

ミキシングファクターを使用します:

シーンによっては、デフォルトのブレンディングモードがシステムのニーズを満たさないことがあり、望みの効果を得るためにブレンディング係数を手動で設定する必要があります。このようなブレンディングは、プログラマブルシェーダでのみ使用できます。

プログラマブルタッガー→ディスクタッガー→元の写真の色+薄い緑を処理→カラーミキシング計算を実行→方程式を適用

つのコンセプト:
  • ターゲットカラー:カラーバッファに保存されているカラー値;
  • Source: 現在のレンダリングコマンドの結果としてカラーバッファに入る色の値。

ブレンディング機能を有効にすると、ソースカラーとデスティネーションカラーの合成方法は、ブレンディング方法によって制御されます。デフォルトでは、ブレンド方法は以下のようになっています:

//Cfパラメータ・カラーの最終計算
//Csソースカラー
//Cdターゲットカラー
//Sソースブレンド係数
//Dオブジェクトのブレンド係数
Cf = (Cs * S) + (Cd * D) 
// 
glEnable(GL_BlEND);
//ブレンド係数を設定する--デフォルト値は GL_SRC_ALPHA   GL_ONE_MINUS_SRC_ALPHA
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
// 
glDisable(GL_BlEND);

ブレンド係数を設定するには、glBlendFun関数を使います。

void glBlendFunc(GLenum S,GLenum D)
S:ソース・ミキシング・ファクター
D: 客観的混合因子

#### 色のブレンド方法の変更:デフォルトのブレンド方法:

Cf = (Cs * S) + (Cd * D);

実際には、このハイブリッド方式とは別に、5つの異なる方式を選択することができます。

ブレンド法の関数glbBlendEquationを選択します:

void glbBlendEquation(GLenum mode);

glBlendFuncを使用してブレンド係数を設定できるだけでなく、より柔軟なオプションが利用可能です。

//strRGB: ソースカラーのブレンド係数 
//dstRGB: ターゲットカラーのブレンド係数 
//strAlpha: ソースカラーのアルファファクター 
//dstAlpha: ターゲットカラーのアルファ係数
void glBlendFuncSeparate(GLenum strRGB,GLenum dstRGB ,GLenum strAlpha,GLenum dstAlpha);

カラーミキシングのまとめ:

ブレンド機能は、不透明なオブジェクトの前に透明なオブジェクトを描画する効果を得るためによく使われます。逆に、上のイメージが不透明で下のイメージが完全に見えない場合は、カラーブレンドをオンにする必要はありません。

RenderSenceのカラーミキシングのオンとオフに使用される実際のコードです:

void RenderScene(void)
{
 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
 
 //1.ブレンディングを有効にする
 glEnable(GL_BLEND);
 //2.混合機能をオンにする 混合色係数を計算する
 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
 //色を定義する
 GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
 
 //3.シェーダマネージャを使う
 //*ユニットシェーダーを使う
 //パラメータ 1: 単純にデフォルトのデカルト座標系を使用し、すべてのセグメントに1つの色を適用する。GLT_SHADER_IDENTITY
 //パラメータ2:シェーダーの色
 shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
 //4.コンテナ・クラスが描画を開始する。
 squareBatch.Draw();
 
 //5.ブレンディングをオフにする
 glDisable(GL_BLEND);
 
 //同期された描画コマンド
 glutSwapBuffers();
}

Read next

ゴー・ディファーの使い方と落とし穴

この記事では、deferについての理解を、ある問題から別の問題へとリフレッシュしたいと思います。deferは、Go言語が提供するメカニズムで、遅延された呼び出しを登録することで、一部のリソースを確実に回収して解放します。 deferを使うことで、特にreturn文が多く、リソースがクローズされていないことや論理エラーによるものであることを忘れがちなシナリオにおいて、リソースのリークをある程度回避することができます。...

Feb 18, 2020 · 8 min read