我正在使用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。我解决了这个问题,你可以在视频中看到,因为场景的其余部分正在绘制。请注意,有些方面正在以某种方式被剔除,尽管我在主渲染状态下关闭了剔除。
自行运行,着色器具有相同的行为。其他着色器似乎没有干扰它。
我的问题是,什么可能导致四边形失真?我验证了我的转换矩阵,它们似乎是正确的。 失真的原因是什么?或者常见原因是什么?
答案 0 :(得分:0)
我终于有了解决方案! 问题出在RenderSceneGS几何着色器中。 矩阵应该以另一个顺序相乘,即
output.pos = mul( g_mWorldViewProj, float4(position,1.0));
我发现这很奇怪,因为与顶点着色器中的矩阵乘法相比,这个顺序实际上是颠倒的。我被告知这是由于矩阵如何存储在内存中,但是,我没有更多关于这个问题的性质的信息。