5

私は非常に単純な CCScene を持っており、以下を含む CCLayer は 1 つだけです。

  1. 標準描画モードの背景用 CCSprite
  2. CCRenderTexture を使用してペイント ブラシを描画し、そのスプライトを背景スプライトの上のルート CCLayer にアタッチします。
_bgSprite = [CCSprite spriteWithFile:backgroundPath];
_renderTexture = [CCRenderTexture renderTextureWithWidth:self.contentSize.width 高さ:self.contentSize.height];
[_renderTexture.sprite setBlendFunc:(ccBlendFunc){GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA}];
[self addChild:_bgSprite z:-100];
[self addChild:_renderTexture];

ブラシ レンダリング コード:

[_renderTexture begin];
glBlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ONE); // 1.
// calculate vertices code,etc...
glDrawArrays(GL_TRIANGLES, 0, (GLsizei)count);
[_renderTexture end];

ユーザーが最初の色付きブラシでブラシをかけると、期待どおりに背景とブレンドされます。しかし、前のブラシの上に別の色でブラッシングを続けると、うまくいきません (2 つのブラシが重なり合うと、ソフト アルファ エッジの不透明度が失われます)。

ここに画像の説明を入力

多くのブレンドオプションを試しましたが、どういうわけか正しいものを見つけることができません.

CCRenderTexture が期待どおりに (以前に描画されたコンテンツと) ブレンドされないという特別な点はありますか?

ブラッシングに使用する私のフラグメント シェーダーは、テクスチャーの入力カラー アルファを保持するためにマイナーな変更を加えた単なる標準的なテクスチャー シェーダーです。

ボイドメイン()
{
    gl_FragColor = texture2D(u_texture, v_texCoord);
    gl_FragColor.a = v_fragmentColor.a;
}

更新 - ほぼ完璧な解決策: jozxyqk

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                        GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

レンダリング コードで ( と の代わり// 1.

[_renderTexture.sprite setBlendFunc:(ccBlendFunc){GL_ONE, GL_ONE_MINUS_SRC_ALPHA}];

これはうまく機能し、私が望むものを与えてくれます...

ここに画像の説明を入力

...ただし、_rederTexture が完全に不透明な場合のみ。

の不透明度を_rendertexture.sprite下げると、予想どおりにブラシがフェードアウトするのではなく、明るくなります。

ここに画像の説明を入力

親テクスチャが完全に不透明なときにブラシのアルファが背景と正しくブレンドされるのに、不透明度が下がるとバナナになるのはなぜですか? ブラシを背景と正しくブレンドするにはどうすればよいですか?

4

1 に答える 1

9

編集

合成ブラシ→レイヤー→背景

OK、何が起こっているのかというglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)と、ブラシ ストロークをブラシ テクスチャにブレンドする作業ですが、結果として得られるテクスチャのアルファ値が間違っています。追加された各フラグメントは、1. そのアルファを最終的なアルファ値に追加する必要があります。相互作用のために正確にその量の光を削除する必要があります。2. 前のアルファを残りの分だけスケーリングします。前のサーフェスは前の値だけ光を減らしますが、新しい表面が追加され、削減する光が少なくなります。それが理にかなっているかどうかはわかりませんが、これにつながります...

glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                    GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

これで、ブラシ テクスチャのカラー チャネルには、背景とブレンドされる (事前にアルファが乗算された) 全体の色が含まれ、アルファ チャネルはウェイト (または色が背景を覆い隠す量) を提供します。色はアルファで事前に乗算されているため、デフォルトの RenderTexture ブレンドは再びGL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHAアルファでスケーリングされ、全体的な色が暗くなります。Cocos2D で設定する必要がある次の関数を使用して、ブラシ テクスチャを背景とブレンドする必要があります。

glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);

うまくいけば、これは可能です。ブレンドするブラシ テクスチャを設定する可能性を管理する方法についてはあまり考えていませんがGL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA、アルファを分割/正規化するために浮動小数点テクスチャや追加のパスが必要になる場合があります。

または、描画する前に背景をレンダー テクスチャにスプラットし、レイヤーをブレンドせずにそのままにしておきます。

これは私のために働いた:

glDisable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);

fbo.bind();
glClear(GL_COLOR_BUFFER_BIT);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,
                    GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
drawTexture(brush1);
drawTexture(brush2);
fbo.unbind();

drawTexture(grassTex); //tex alpha is 1.0, so blending doesn't affect background
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
drawTexture(fbo.getColour(0)); //blend in the brush layer

GL での小さなテスト

ブラシレイヤーの不透明度

を使用GL_ONE, GL_ONE_MINUS_SRC_ALPHAすると、レイヤー ブレンディングでのライブラリの不透明度の実装で問題が発生します。これは、色がアルファで乗算されていることを前提としているためです。値を小さくするopacityと、ブレンド中にブラシ レイヤーのアルファが縮小されます。GL_ONE_MINUS_SRC_ALPHA次に、背景色の量を増やしますGL_ONEが、ブラシ レイヤーの合計が 100% になり、画像が過飽和になります。

最も簡単な解決策は、グローバル レイヤーの不透明度によって色を縮小する方法を自分で見つけて、引き続き使用することGL_ONE, GL_ONE_MINUS_SRC_ALPHAです。

  • ライブラリがサポートしている場合、実際に使用GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_ALPHAすることが答えになるかもしれませんが、明らかにそうではありません。
  • 固定パイプライン レンダリングを使用して color: をスケーリングすることもできますglColor4f(opacity, opacity, opacity, opacity)が、これには 2 番目のレンダー ターゲットが必要であり、上記のコードと同様に手動でブレンドを行う必要があります。ここでは、背景用に 1 回、ブラシ レイヤー用に 2 回フル スクリーン クワッドを描画します。
  • ブレンドを手動で行っている場合は、glColorメソッドの代わりにフラグメント シェーダーを使用する方がより堅牢です。これにより、特に 0 から 1 の範囲外の分割と一時変数が関係する場合に、より複雑なブレンド関数を使用したい場合に、はるかに優れた制御が可能になります。 gl_FragColour = texture(brushTexture, coord) * layerOpacity;

編集終了


標準のアルファブレンディング関数はglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);であり、GL の「初期」/デフォルト関数とはまったく異なります。

glBlendFuncSeparate で行うようにアルファ値を合計すると、アルファが過飽和になり、下の色が完全に置き換えられます。彩度のブレンドはまともな結果をもたらすかもしれません: glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE). サポートされている場合は、 glBlendEquationSeparateと MAX ブレンディングを試してみる価値があるかもしれません。MAX を使用する利点は、線画コードからオーバーラップするアーティファクト (ハード トライアングル ビット) を減らすことです。たとえば、色を置き換えますが、合計アルファ値 X に達するまでのみです。編集: どちらの場合も、各ストロークの後にブレンドとクリアが必要になります

レンダー テクスチャを背景にブレンドすることが実際に機能しているとしか思えません。(現在のレイヤー値ではありません)

余談ですが、ほとんど無関係ですが、アルファ/不透明度の代わりに透過率の値を保持する「Under Blending」もあります (ここから)。

glBlendEquation(GL_FUNC_ADD); 
glBlendFuncSeparate(GL_DST_ALPHA, GL_ONE, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); 
于 2013-09-11T09:16:02.693 に答える