「通常の」ブレンドモードとOpenGLのトラブル


8

OpenGLブレンド関数を期待どおりに(または賢明な画像編集プログラムから)期待どおりに機能させるのに苦労しました。例として、次の2つの画像を使用してブレンドします(白い背景では見づらいので、色がラベル付けされます)。

合成する画像

テスト画像

これは私が起こると期待していることです(そしてpaint.netで何が起こるか):

期待される結果

Paint.Net画像テスト

明らかに、openglのデフォルトのブレンド関数は、次のようになります(非常に間違っています)。

glBlendFunc(GL_SRC_ALPHA、GL_ONE_MINUS_SRC_ALPHA)

OpenGLノーマルブレンディングテスト

たくさんのテストの後、これは私が「良い」ブレンド関数を作成するために得ることができる最も近いものです:

glBlendFuncSeparate(GL_SRC_ALPHA、GL_ONE_MINUS_SRC_ALPHA、GL_ONE、GL_ONE_MINUS_SRC_ALPHA)

OpenGLカスタムブレンドテスト

ただし、元の予想結果を振り返ると、一部の色が本来よりも少し暗くなっていることがわかります(中央左部分)。具体的には、それらは(.5アルファのため)カラー値の半分に事前に乗算されており、これを行わない関数を作成することはできません(ほとんど見えない赤い透明部分で奇妙な混合の問題を引き起こすことなしに)。

誰かがこの問題の解決策を知っていますか?ソースであらかじめ乗算されたアルファを使用する必要がありました(ゲームで使用するすべての色をあらかじめ乗算された色に変換するか、各シェーダーに何かを書き込むために追加の作業が必要なため、これを行いたくありません)。 :

glBlendFuncSeparate(GL_ONE、GL_ONE_MINUS_SRC_ALPHA、GL_ONE、GL_ONE_MINUS_SRC_ALPHA)事前乗算なし)

OpenGLカスタムブレンドテスト

明らかにそれも間違っていますが、これが実際に私がこれまでに得た唯一の正しい結果です。

glBlendFuncSeparate(GL_ONE、GL_ONE_MINUS_SRC_ALPHA、GL_ONE、GL_ONE_MINUS_SRC_ALPHA)(事前乗算された入力)

OpenGLカスタムブレンドテスト

唯一の問題は、それを画面に表示するための事前乗算をどのようにして取り除くのですか?ブレンドするものごとに追加のレンダーサイクルが必要になる可能性があり、この問題には複雑すぎるように思われるので、私はまだ答えを探しています(OpenGLは非常に広く使用されているため、これについて何かを見つけることができないのは興味深いことです)他の誰かがこの問題に遭遇したと思います)。

出典:

オンラインブレンド機能検査- http://www.andersriggelsen.dk/glblendfunc.php
下層イメージ- http://i.stack.imgur.com/XjLNW.png
トップレイヤーイメージ- のhttp://i.stack.imgur .com / 9CN6w.png


すべてのスクリーンショットは、Anders RiggelsenのオンラインVisual glBlendFunc + glBlendEquation Toolから取得したものです。将来、そのようなことは助けを求めるときに言及するのに役立つでしょう。
Trevor Powell

@TrevorPowell Dang何かを言うのを忘れていることはわかっていました(本当にそれを一番下に置くつもりでした)。どちらの方法でも、ブレンドモードを簡単にテストするために使用していたものですが、他のOpenGLの種類では標準である必要があります(他の人がそれを使用したいと思っている場合でも)。
レモンドロップ

回答:


5

最初の例(glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA))では、上に描画される画像(「前景」の画像)のアルファに基づいて色をブレンドするように指示しています。したがって、画像の左下隅にある前景色(38,50,168)と背景色(38,50,168)を50%ブレンドすると、驚くことなく、まったく同じ色になり(38,50,168)ます。なぜなら、そのクロスブレンドはまさにあなたがOpenGLに行うように言ったものだからです。

「期待される」画像から判断すると、2つの色の間でクロスブレンドを行う必要はありません。前景色を、フルカラーの背景色の上に重ね合わせて、それらの間でクロスブレンドしないでください。

これを行うには、glBlendFuncSeparateを使用し(背景の色をアルファとは異なる方法で処理するため)、ブレンド操作中に背景のアルファ値を100%として処理するように指定します。

ワーキング

見やすくするために、出力される最終的なRGB値を次に示します。 RGB

そして、これが出力される最終的な透明度の値です。 アルファ

(その「100%」透明領域は実際には99.7%透明としてラベル付けされるべきであり、右下の「50%」領域は49.7%透明としてラベル付けされるべきです。どちらも最初の画像の右側にある赤みがかったビットのためです。また、不透明度ではなく「透明度」を使用して数値をリストするのは申し訳ありません。おそらく少し混乱します。)

特定の問題がある場合は、正しくない値を生成しているRGBまたはアルファイメージの領域を指摘してください。


ソースのアルファ係数もGL_ONE同様にすべきではありませんか?それ以外の場合は、アルファ式のようになりますdest_alpha = src_alpha * src_alpha + 1 * dest_alpha
bcrist

さて、左中央の部分がまだ本来よりもずっと暗いのを見ると、レイヤーを反転させると次のようになります:i.imgur.com/rigBNz6.png(ほとんど見えない赤は、それ
レモンドロップ

に対して50%でブレンドしています(0,0,0)。うちもちろん、それはあなたが反対50%でそれをブレンドするときよりも暗いです(255,255,255)
Trevor Powell

@TrevorPowellアルファが0の場合、それはまったく問題になりませんか?私が求めている方程式のようです:finalAlpha = srcAlpha + destAlpha * (1 - srcAlpha)そして、カラー計算finalColor = ((srcColor * srcAlpha) + (destColor * destAlpha * (1 - srcAlpha))) / finalAlphaColor * Alphaビットは、事前に乗算された値を出力することによってシェーダーで実行できますが、事前乗算を取り除くためにfinalAlphaで除算する方法はありません。(ここから撮影)
レモンドロップ

0

レイヤーのようなオーバーラップするフレームバッファーオブジェクトのセットをレンダリングしたいときも、まったく同じ問題がありました。問題は、Open GLブレンディング関数が線形であり、宛先の背景が不透明な場合に機能することです。ただし、2つの透明なレイヤーをブレンドする実際のブレンド方程式は線形方程式ではなく、除算部分が含まれています。

out_color = {src_color * src_alpha + dest_color * dest_alpha *(1-src_alpha)} / out_alpha

現在のOpengGL実装でこれを行うことは可能ではないと思います。したがって、回避策として、ピクセルシェーダーを使用して各ピクセルの出力を手動で計算する必要がありました。


ええ、私がやったことは、いくつかの回避策を実行するのではなく、テクスチャのアルファを事前に乗算するだけでした。いくつかのライブラリを使用すると簡単にできます(ロード時にテクスチャを事前に乗算するだけです)
Lemon Drop
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.