1

基本的な2Dピクセルシェーダーを作成しましたが、機能しないようです。エフェクトをアクティブにして描画すると、画面には何も描画されません。しかし、無効にすると、テクスチャが期待どおりに画面に描画されます。

私の目的は、画面に任意のテクスチャを描画し、このピクセルシェーダーに、範囲などのオーバーレイシステムで使用するために、ピクセルの円形の塊を「刻む」ことができるようにすることです。

これが私のピクセルシェーダーコードです:

sampler TextureSampler : register(s0);
//A list of positions for circles. They are specified in texture space rather than screen space.
float2 PositionData[64];
//A matching list of radiuses. These are specified in pixels, though.
float Radii[64];
//how much of the array is filled with data.
int DataSize;
//the size of the texture being drawn.
float2 TextureSize;

float4 RenderSolidCircles(float2 texCoord : TEXCOORD0) : COLOR
{
    float opacityAcc = 1;
    float2 screenSpaceTexCoord = texCoord * TextureSize;
    for (int i = 0; i < DataSize; i++)
    {
        float2 properPosCoordinate = PositionData[i] * TextureSize;
        float dist = length(screenSpaceTexCoord - properPosCoordinate) - Radii[i];
        if (dist < 0)
        {
            opacityAcc -= min(abs(dist), 1);
        }
    }
    opacityAcc = max(0, opacityAcc);
    float4 outPix = tex2D(TextureSampler, texCoord);
    outPix.a *= opacityAcc;
    return outPix;
}


technique SolidCircles
{
    pass P0
    {
        PixelShader = compile ps_3_0 RenderSolidCircles();
    }
}

float4 PassThrough(float2 texCoord : TEXCOORD0) : COLOR
{
    return tex2D(TextureSampler, texCoord);
}
technique PassThrough
{
    pass P0
    {
        PixelShader = compile ps_3_0 PassThrough();
    }
}

SolidCirclesテクニックのASMバージョンは次のとおりです。

//
// Generated by Microsoft (R) D3DX9 Shader Compiler 9.15.779.0000
//
// Parameters:
//
//   int DataSize;
//   float2 PositionData[64];
//   float Radii[64];
//   sampler2D TextureSampler;
//   float2 TextureSize;
//
//
// Registers:
//
//   Name           Reg   Size
//   -------------- ----- ----
//   PositionData   c0      64
//   Radii          c64     64
//   DataSize       c128     1
//   TextureSize    c129     1
//   TextureSampler s0       1
//
//
// Default values:
//snipped comments here

    ps_3_0
    def c130, 1, 0, -1, 2
    def c131, 3, 4, 5, 6
    def c132, 7, 8, 9, 10
    def c133, 11, 12, 13, 14
    def c134, 15, 16, 17, 18
    def c135, 19, 20, 21, 22
    def c136, 23, 24, 25, 26
    def c137, 27, 28, 29, 30
    def c138, 31, 32, 33, 34
    def c139, 35, 36, 37, 38
    def c140, 39, 40, 41, 42
    def c141, 43, 44, 45, 46
    def c142, 47, 48, 49, 50
    def c143, 51, 52, 53, 54
    def c144, 55, 56, 57, 58
    def c145, 59, 60, 61, 62
    def c146, 63, 0, 0, 0
    dcl_texcoord v0.xy  // texCoord<0,1>
    dcl_2d s0

#line 22 "C:\Users\RCIX\Documents\Visual Studio 2008\Projects\2DFXFilesTest\2DFXFilesTest\Content\OverlayFx.fx"
    mov r0.w, c130.x  // opacityAcc<0>
    mul r2.xy, v0, c129  // screenSpaceTexCoord<0,1>
    mov r5.w, -c128.x
    add r0.z, r5.w, c130.y
    cmp r12.w, r0.z, c130.y, c130.x
    mul r11.w, r12.w, c130.x
    if_ne r11.w, -r11.w
      mov r13.xy, c129  // ::TextureSize<0,1>
      mul r12.xy, r13, c0  // properPosCoordinate<0,1>
      mov r12.xy, -r12
      add r11.xy, r2, r12
      mul r16.xy, r11, r11
      add r11.z, r16.x, r16.y
      rsq r10.w, r11.z
      rcp r8.w, r10.w
      mov r9.w, -c64.x
      add r4.w, r8.w, r9.w  // dist<0>
      add r7.w, r4.w, c130.y
      cmp r6.w, r7.w, c130.y, c130.x
      mov r3.w, -r4.w
      mov r5.z, -r3.w
      add r1.w, r4.w, r5.z
      cmp r15.w, r1.w, r4.w, r3.w
      add r14.w, r15.w, c130.z
      cmp r2.w, r14.w, c130.x, r15.w
      mov r2.w, -r2.w
      add r13.w, r2.w, c130.x  // opacityAcc<0>
      mov r6.w, -r6.w
      cmp r0.w, r6.w, r0.w, r13.w  // opacityAcc<0>

#line 24
    endif

//snipped 63 blocks of unrolled loop code

#line 33
    mov r1.w, -r0.w
    add r15.w, r1.w, c130.y
    cmp r14.w, r15.w, c130.y, r0.w  // opacityAcc<0>
    texld r0, v0, s0  // outPix<0,1,2,3>
    mul r2.x, r14.w, r0.w  // outPix<3>
    mov oC0.xyz, r0  // ::RenderSolidCircles<0,1,2>
    mov oC0.w, r2.x  // ::RenderSolidCircles<3>

// approximately 1866 instruction slots used (1 texture, 1865 arithmetic)

これが私のゲームクラスの描画関数の関連部分です。

GraphicsDevice.Clear(Color.CornflowerBlue);
overlayEffect.Parameters["PositionData"].SetValue(Positions.ToArray());
overlayEffect.Parameters["Radii"].SetValue(Radii.ToArray());
overlayEffect.Parameters["DataSize"].SetValue(64);
overlayEffect.Parameters["TextureSize"].SetValue(new Vector2(500));

spriteBatch.Begin(SpriteBlendMode.AlphaBlend,
    SpriteSortMode.Immediate,
    SaveStateMode.None);

overlayEffect.Begin();
overlayEffect.CurrentTechnique.Passes[0].Begin();

spriteBatch.Draw(pixTex, new Rectangle(0, 0, 500, 500), Color.White);
spriteBatch.End();

overlayEffect.CurrentTechnique.Passes[0].End();
overlayEffect.End();

base.Draw(gameTime);

最後に、位置と半径のリストを作成する私の関数は次のとおりです。

private void RebuildPositionsList()
{
    spriteBatch = new SpriteBatch(GraphicsDevice);
    Positions = new List<Vector2>();
    Radii = new List<float>();
    for (int i = 0; i < 64; i++)
    {
        Positions.Add(
            new Vector2(
                (float)r.NextDouble(),
                (float)r.NextDouble())
                );
        Radii.Add(((float)r.NextDouble() * 100) + 40);
    }
}

私のテクスチャを作る線:

pixTex = new Texture2D(GraphicsDevice, 1, 1);
pixTex.SetData<Color>(new Color[] { new Color(0f, 0f, 0f, 1f) });

PositionsおよびRadiiは、それぞれサイズ64のベクトルとフロートのリストです。pixTexは1ピクセルの黒一色のテクスチャです。

シェーダーが機能しないのはなぜですか?

4

3 に答える 3

2

したがって、この回答に対するコメントでは、ここでのさらに別の問題は、XNA3.1のスプライトバッチの頂点シェーダーがvs_1_1であるということであると判断されました。また、厳密に言えば、SM3.0頂点シェーダーまたはピクセルシェーダーを異なるバージョンのシェーダーと混合することはできません。実際には、ほとんどのカードで問題を解決できるようですが、RCIXのカード(Radeon HD 4850)では問題が解決しないようです。

(これが、DirectXデバッグランタイム(SDKから)を用意しておく価値がある理由です。このようなことについて警告が表示されます。DebugViewを使用してその出力を表示できます。)

この問題にはいくつかの解決策があります。

1)はるかに簡単な解決策は、XNA 4.0にアップグレードすることです(欠点は、重大な変更と、現在ベータ版のみであるという事実です)。このバージョンのXNAでは、SpriteBatchに独自の頂点シェーダーを簡単に指定できます。

2) XNA 3.1のSpriteBatchでカスタム頂点シェーダーを使用できますが、それほど簡単ではありません。開始点としては、XNAで使用される頂点シェーダーのソースコードが適しています(XNA 4.0まで、上記を参照)。

3)最後に:おそらく、シェーダーにps_2_0を使用させることができますか?テクスチャごとに64個のカットアウトが本当に必要ですか?

于 2010-07-24T02:23:15.103 に答える
1

電話をかける前に、を呼び出すeffect.End()必要がありますspriteBatch.End()

この理由(およびXNA 4.0で「修正」されているという事実)は、ShawnHargreavesのブログのこの記事で説明されています。(このエントリも読む価値があるかもしれません。)

基本的に(XNA 3.1SpriteSortMode.Immediateの場合):予想されるほど即時ではありません。エフェクトを終了する前にspriteBatch.End()、スプライトの最後のバッチを実際にGPUにプッシュするために呼び出す必要があります。

スプライトエフェクトのサンプルは、スプライトにエフェクトを正しく適用する方法を示しています。

于 2010-07-21T06:40:07.363 に答える
1

OK、まず最初に、他の回答の2つの修正を適用する必要があります(効果を終了する前にバッチを終了し、(コメントから)使用しますSpriteBlendMode.AlphaBlend)。

今-シェーダーの問題。それは実際に機能していますが、おそらくあなたが期待する方法ではありません。スプライトが描画される画面空間の座標(幅= 500、高さ= 500)と、ピクセルシェーダーが機能するテクスチャ空間の座標(幅= 1、高さ= 1)を混同しているようです。

したがって、まず最初に、スプライトに穴を開けるときは、次のようにテクスチャ空間で穴を開ける必要があります。

Positions.Add(new Vector2(0.5f, 0.5f));
Radii.Add(0.25f);

Positions.Add(new Vector2(0.25f, 0.25f));
Radii.Add(0.1f);

そして第二に、アンチエイリアシングの試みのように見えるのは、カットアウトがフェードアウトになっていることです。画面に描画されるテクスチャのサイズを考慮する必要があります。最も簡単な修正は、次の行を変更することです。

opacityAcc -= min(abs(dist), 1);

これに:

opacityAcc -= min(abs(dist * 500), 1);

もちろん、これはスプライトが500x500で描画されることを前提としています。実際の値をシェーダーパラメーターとして渡す必要があります。

スプライトを非正方形で描画する場合は、座標系を「整列」させるために少し余分な計算を行う必要があります。それは演習として残しておきます。

于 2010-07-22T06:28:25.073 に答える