5

Photoshop フィルター乗算を Direct3D で複製しようとしています。私はさまざまなレンダリング状態について読んでグーグルで調べてきましたが、効果はほとんど機能しています。問題は、テクスチャのアルファ値を無視していることです。

状況を説明する画像は次のとおりです。

http://www.kloonigames.com/petri/stackoverflow_doesnt_allow_.jpg

これに対する 1 つの解決策を見つけました。それは、画像を透明度なしで白い背景で保存することでした。しかし、私はこの解決策に満足していません。問題は、本当にアルファ値を使用する必要があることです。画像を徐々にフェードアウトさせたい。ブレンドモードがアルファ値を無視している場合、これを行うことはできません。

問題は、画像をアルファでレンダリングする方法です。

ブレンドモードのコードは次のとおりです。

dev->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);

編集により SetTextureStageState が追加されました

dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
dev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
dev->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
dev->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
4

4 に答える 4

5

ピクセル シェーダーでアルファを事前に乗算するか、事前に乗算されたアルファを含むテクスチャを使用することで、この効果を 1 ステップで実現できます。

たとえば、シェーダーに 3 つのブレンド操作があり、それぞれでアルファを考慮したい場合などです。

Blend = ( src.rgb * src.a ) + ( dest.rgb * (1-src.a) )
Add = ( src.rgb * src.a ) + ( dest.rgb )
Multiply = (src.rgb * dest.rgb * src.a) + (dest.rgb * (1-src.a) )

ソース カラーに対して 2 つの操作があるため、1 つのパスでは乗算が不可能であることがわかります。ただし、シェーダーでアルファを事前に乗算すると、ブレンド操作からアルファ コンポーネントを抽出でき、同じシェーダーで 3 つの操作すべてをブレンドすることが可能になります。

ピクセル シェーダーでは、アルファを手動で事前乗算できます。または、DirectXTex texconv などのツールを使用してテクスチャを変更します。

return float4(color.rgb*color.a, color.a);

操作は次のようになります。

Blend = ( src.rgb ) + ( dest.rgb * (1-src.a) )
Add = ( src.rgb ) + ( dest.rgb )
Multiply = ( src.rgb * dest.rgb ) + (dest.rgb * (1-src.a) )
于 2014-10-16T22:40:20.730 に答える
1

あなたが望むように聞こえます:

dst.rgb = (src.a * src.rgb) * ((1 - src.a) * dst.rgb)

これを行うには D3DRS_BLENDOP を使用しますが、残念ながら D3DBLENDOP_MULTIPLY はありません。この操作はフラグメントシェーダーなしでは不可能だと思います。

于 2009-10-23T15:12:38.077 に答える
0
dev->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_DESTCOLOR);
dev->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

トリックを行います。ただし、拡散頂点カラーの「アルファ」は使用できなくなりました。頂点の色に低いアルファを設定すると、オーバーレイ ピクセルが実際に明るくなります。

于 2016-08-30T12:44:02.373 に答える
0

OK、これはあなたが思うほど単純ではありません。これには Effect と 2 つの renderTargets を使用します...これを行うために 1 つのレンダー パスを使用するのは面白いですが、うまくいきません。Photoshop にはレイヤーがあり、各レイヤーにはアルファ チャネルがあります。ところで、あなたが作っているアプリの種類を知っておくとよいでしょう。

したがって、最初に D3D で、ウィンドウと同じサイズの 2 つの RGBA_32bit renderTargets を作成し、それらをクリアして白にします。スワップ用に (new RenderTarget[2];) のように配列にします。

次に、ブレンド状態を (AlphaFunc=Add、Src=SrcAlpha、Dst=InvSrcAlpha) に設定します。最初の円では、renderTarget[1] をテクスチャ/サンプラーの入力ソースとして使用して、renderTarget[0] に描画します。円の色を受け取り、renderTarget[1] のサンプラーの色で乗算する Effect を使用して円をレンダリングします。円 1 を描画した後、単純なインデックス付けによって renderTarget[0] を renderTarget[1] と交換します。したがって、renderTarget[1] が描画先になり、renderTarget[0] がサンプリング元になります。次に、円 2 などの描画プロセスを繰り返します。

円を描画した後、最後に描画された renderTarget を backBuffer にコピーして、シーンを表示します。

これは、論理的にどのように行うかの例です。コーディングのリファレンスが必要な場合は、 http://www.codesampler.com/が適しています。

void TestLayering()
{
bool rtIndex = false;
RenderTarget* renderTarget = new RenderTarget[2];
Effect effect = new Effect("multiplyEffect.fx");
effect.Enable();
BlendingFunc = Add;
BlendingSource = SrcAlpha;
BlendingDest = InvSrcAlpha;

for(int i = 0; i != circleCount; ++i)
{
  renderTarget[rtIndex].EnableAsRenderTarget();
  renderTarget[!rtIndex].EnableAsSampler();
  circle[i].Draw();
  rtIndex = !rtIndex;
}

//Use D3D9's StretchRect for this...
backBuffer.CopyFromSurface(renderTarget[rtIndex]);
}

//Here is the effects pixel shader
float4 PS_Main(InStruct In) : COLOR
{
float4 backGround = tex2D(someSampler, In.UV);
return circleColor * backGround;
}
于 2011-03-04T21:09:30.720 に答える