几何着色器失真

时间:2012-12-08 20:45:05

标签: geometry directx shader hlsl

我正在使用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。我解决了这个问题,你可以在视频中看到,因为场景的其余部分正在绘制。请注意,有些方面正在以某种方式被剔除,尽管我在主渲染状态下关闭了剔除。

自行运行,着色器具有相同的行为。其他着色器似乎没有干扰它。

我的问题是,什么可能导致四边形失真?我验证了我的转换矩阵,它们似乎是正确的。 失真的原因是什么?或者常见原因是什么?

1 个答案:

答案 0 :(得分:0)

我终于有了解决方案! 问题出在RenderSceneGS几何着色器中。 矩阵应该以另一个顺序相乘,即

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

我发现这很奇怪,因为与顶点着色器中的矩阵乘法相比,这个顺序实际上是颠倒的。我被告知这是由于矩阵如何存储在内存中,但是,我没有更多关于这个问题的性质的信息。