1

我正在使用 ParticleGS DirectX10 示例,在 DirectX 11 中构建基于几何着色器的粒子系统。

使用示例代码并根据自己的喜好进行更改,我可以绘制一个四边形(本质上是一个不断重新创建自身的粒子)。

这是我的着色器代码:

//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 回答