1

ParticleGS DirectX10 サンプルを基に、DirectX 11 でジオメトリ シェーダー ベースのパーティクル システムを構築しています。

サンプル コードを使用して好みに合わせて変更すると、単一のクワッド (基本的には、常に自分自身を再作成する 1 つのパーティクル) を描画できます。

これは私のシェーダーコードです:

//Single particle stream-out shader which uses ping-pong buffers.
//Based on DirectX sample ParticlesGS

struct VSParticleIn
{
    float3 pos              : POSITION;         
    float3 vel              : NORMAL;           
    float  Timer            : TIMER;            
    uint   Type             : TYPE;     //Only one type for the moment.         
};

struct VSParticleDrawOut
{
    float3 pos : POSITION;
    float4 color : COLOR0;
    float radius : RADIUS;
};

struct PSSceneIn
{
    float4 pos : SV_Position;
    float2 tex : TEXTURE0;
    float4 color : COLOR0;
};

cbuffer cbRenderParticle
{
    float4x4 g_mWorldViewProj;
    float4x4 g_mInvView;
};

cbuffer cbAdvanceParticle
{
    float g_fGlobalTime;
    float g_fElapsedTime;
    float4 g_vFrameGravity;
    float g_fSecondsPerFirework = 1.0;
};

cbuffer cbImmutable
{
    float3 g_positions[4] =
    {
        float3( -1, 1, 0 ),
        float3( 1, 1, 0 ),
        float3( -1, -1, 0 ),
        float3( 1, -1, 0 ),
    };
    float2 g_texcoords[4] = 
    { 
        float2(0,1), 
        float2(1,1),
        float2(0,0),
        float2(1,0),
    };
};

Texture2D g_txDiffuse;
SamplerState g_samLinear
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Clamp;
    AddressV = Clamp;
};

Texture1D g_txRandom;
SamplerState g_samPoint
{
    Filter = MIN_MAG_MIP_POINT;
    AddressU = Wrap;
};

RasterizerState mainState {
    FillMode = Solid;
    CullMode = None;
    FrontCounterClockwise = false;
};

BlendState AdditiveBlending
{
    AlphaToCoverageEnable = FALSE;
    BlendEnable[0] = TRUE;
    SrcBlend = SRC_ALPHA;
    DestBlend = ONE;
    BlendOp = ADD;
    SrcBlendAlpha = ZERO;
    DestBlendAlpha = ZERO;
    BlendOpAlpha = ADD;
    RenderTargetWriteMask[0] = 0x0F;
};

BlendState NoBlending
{
    AlphaToCoverageEnable = FALSE;
    BlendEnable[0] = FALSE;
};

DepthStencilState DisableDepth
{
    DepthEnable = FALSE;
    DepthWriteMask = ZERO;
};

DepthStencilState DSSLess
{
    DepthEnable = TRUE;
    DepthWriteMask = ALL;
    StencilEnable = TRUE;
    StencilReadMask = 0;
    StencilWriteMask = 0;

    FrontFaceStencilFunc = ALWAYS;
    FrontFaceStencilDepthFail = INVERT;
    FrontFaceStencilPass = KEEP;
    FrontFaceStencilFail = KEEP;

    BackFaceStencilFunc = ALWAYS;
    BackFaceStencilDepthFail = INVERT;
    BackFaceStencilPass = KEEP;
    BackFaceStencilFail = KEEP;

    DepthFunc = LESS;
};

VSParticleDrawOut RenderSceneVS(VSParticleIn input)
{
    VSParticleDrawOut output = (VSParticleDrawOut)0;
    output.pos = input.pos;
    output.radius = 3;
    output.color = float4(1,1,1,1);
    return output;
}

VSParticleIn PassthroughVS(VSParticleIn input)
{
    return input;
}

float3 RandomDir(float fOffset)
{
    float tCoord = (g_fGlobalTime + fOffset) / 300.0;
    return g_txRandom.SampleLevel( g_samPoint, tCoord, 0 );
}


[maxvertexcount(128)]
void AdvanceParticlesGS(point VSParticleIn input[1], inout PointStream<VSParticleIn> ParticleOutputStream)
{
    //Just keeps emitting itself.
    ParticleOutputStream.Append( input[0] );
}


[maxvertexcount(4)]
void RenderSceneGS(point VSParticleDrawOut input[1], inout TriangleStream<PSSceneIn> SpriteStream)
{
    PSSceneIn output;

    for(int i=0; i<4; i++)
    {
        float3 position = g_positions[i]*input[0].radius;
        //position = mul( position, g_mInvView ) + input[0].pos;
        output.pos = mul( float4(position,1.0), g_mWorldViewProj );

        output.color = input[0].color;
        output.tex = g_texcoords[i];
        SpriteStream.Append(output);
    }
    SpriteStream.RestartStrip();
}

float4 RenderScenePS(PSSceneIn input) : SV_Target
{   
    return g_txDiffuse.Sample( g_samLinear, input.tex ) * input.color;
}

technique10 RenderParticles
{
    pass p0
    {
        SetVertexShader( CompileShader( vs_4_0, RenderSceneVS() ) );
        SetGeometryShader( CompileShader( gs_4_0, RenderSceneGS() ) );
        SetPixelShader( CompileShader( ps_4_0, RenderScenePS() ) );

        SetBlendState( AdditiveBlending, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xFFFFFFFF );
        SetRasterizerState( mainState );
        SetDepthStencilState( DSSLess, 0 );
    }  
}


GeometryShader gsStreamOut = ConstructGSWithSO( CompileShader( gs_4_0, AdvanceParticlesGS() ), "POSITION.xyz; NORMAL.xyz; TIMER.x; TYPE.x" );
technique10 AdvanceParticles
{
    pass p0
    {
        SetVertexShader( CompileShader( vs_4_0, PassthroughVS() ) );
        SetGeometryShader( gsStreamOut );
        SetPixelShader( NULL );

        SetRasterizerState( mainState );
        SetDepthStencilState(DisableDepth, 0);
    }  
}

しかし、私がかつて抱えていた問題に似た問題に気付きました:レンダリングされた形状が歪んでいます。ここに何が起こっているかを紹介するビデオがあります。http://youtu.be/6NY_hxjMfwY

現在、いくつかの効果を一緒に使用するときにこの問題が発生していましたが、他の効果のためにジオメトリ シェーダーを明示的に null に設定する必要があることに気付きました。ビデオでわかるように、シーンの残りの部分が適切に描画されているため、この問題を解決しました。メインのレンダリング状態でカリングをオフにしましたが、何らかの理由で一部の側面がカリングされていることに注意してください。

単独で実行すると、シェーダーは同じ動作をします。他のシェーダーは干渉しないようです。

私の質問は、クワッドの歪みの原因は何ですか? 変換行列を確認しましたが、正しいようです。歪みの原因は何ですか?または一般的な原因は何ですか?

4

1 に答える 1

0

私はついに解決策を手に入れました!問題は RenderSceneGS ジオメトリ シェーダーにあります。行列は、別の順序で乗算する必要があります。

output.pos = mul( g_mWorldViewProj, float4(position,1.0));

この順序は、頂点シェーダーの行列乗算と比較して実際には逆であるため、これは奇妙に感じます。これは、行列がメモリに保存される方法が原因であると言われていますが、この問題の性質についてこれ以上の情報はありません。

于 2012-12-11T16:57:38.067 に答える