I am working from the ParticleGS DirectX10 sample, to build a geometry shader based particle system in DirectX 11.
Using the sample code, and changing it to my liking, I am able to draw a single quad (which is essentially one particle constantly recreating itself).
This is my shader code:
//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);
}
}
However, I noticed a problem which was similar to one I once had: the rendered shape is distorted. Here is a video showcasing what is happening. http://youtu.be/6NY_hxjMfwY
Now, I used to have this issue when using several effects together, when I realised that I needed to explicitly set the geometry shader to null for the other effects. I solved this problem, as you can see in the video, as the rest of the scene is drawing properly. Note that some sides are being culled somehow, although I turned off culling in my main render state.
Run on its own, the shader has the same behaviour. Other shaders do not seem interfere with it.
My question is, what could cause the distortion of the quad? I verified my transformation matrices, and they seem to be correct. What could be the cause of the distortion? Or what are the common causes?
I finally have the solution!
The problem lies within the RenderSceneGS geometry shader.
The matrix should be multiplied in the other order, which is
I find this strange, since this order is actually reversed compared to matrix multiplication in the vertex shader. I have been told that this is due to how the matrices are stored in memory, however, I do not have much more information on about the nature of this issue.