GPU particles

Started by
38 comments, last by Telanor 10 years, 8 months ago

Yeah call stack is useless indeed. But the explanations might help. So the thing runs you just can't debug it with the graphics debugger. (Lapse on my part, you did mention it already, I just didn't understand it fails with the debugger only). Welcome to the club: If memory serves, I could never debug StreamOut with PIX either.

That leaves only one thing: Debug yourself. Setup a staging buffer, use context.CopyResource to copy the stream out buffer to the stage after the update and context.Map the stage to read it back. Then inspect it or log it. To make it easier modify the system to use only one particle (one that never dies e.g.). Or draw a small mesh you know that draws at said position. That should cover the update part. It's a bit involved, but that's about what I can come up with (other than using a different tool that hopefully works).

You said you use CPU-particles now, so I assume you can draw them. Do you use the drawing technique from the sample (meaning: a quad expansion geometry shader) or something else ?

Advertisement

I have search disable rasterization you said that is SetPixelShader(NULL) in shader.Second make both the depthState and StencilState disable! I want konw is the right way to realize you said like this?
Now I have success with your help.. I am very thanks to you! you are great...But I doubt is the right way to do like this

You're welcome. Looks like the sample, so yeah, I think it's fine. Not sure if I understand your question (you might try google translate - no offense intended). Disabling depth write is ok. To correctly occlude particles you need to draw your other stuff first and the draw the particles with depth test only.

@Telanor:
I just have a gut feeling here. I suspect sort of a race condition or something with the static initialization. Does the sample work at all ? Could you try a non-static version ? I'm shooting in the dark: Do you have more - useful - information about that crash ? Call stack ? D3D debug log ?

Oh! you understand me!biggrin.png ....you are friendly!!..Is that you say draw other stuff first and draw the particles depth Test with only read and not write ? I have been doing this for a long time? Is that right?

Yeah call stack is useless indeed. But the explanations might help. So the thing runs you just can't debug it with the graphics debugger. (Lapse on my part, you did mention it already, I just didn't understand it fails with the debugger only). Welcome to the club: If memory serves, I could never debug StreamOut with PIX either.

That leaves only one thing: Debug yourself. Setup a staging buffer, use context.CopyResource to copy the stream out buffer to the stage after the update and context.Map the stage to read it back. Then inspect it or log it. To make it easier modify the system to use only one particle (one that never dies e.g.). Or draw a small mesh you know that draws at said position. That should cover the update part. It's a bit involved, but that's about what I can come up with (other than using a different tool that hopefully works).

You said you use CPU-particles now, so I assume you can draw them. Do you use the drawing technique from the sample (meaning: a quad expansion geometry shader) or something else ?


Well its not that I can't debug the streamout, I can't debug anything in my entire project because the particle system just kills the debugger. Of course I can disable it for debugging other systems, but I just wanted to point out that its not specifically when inspecting the particle system, the entire snapshot fails. More importantly, the debugger actually works just fine when run on the sample. I will give the manual debugging idea a try, but there's a lot of things that could be wrong that will be hard to spot without a proper debugger.

And yes, my CPU particles draw just fine. I'm not using any of the code/shaders from them for this though, I'm using the same drawing code/shader from the sample.

I've compared my code with what GuoLei posted and its pretty much identical, especially the part that's crashing for me, so I'm really not sure what's wrong with it. As a random though, I wonder if this has anything to do with the fact that my project is using DX11.1? Also here is my shader code, though I doubt the issue is coming from there:


//
// Particle effect using geometry shader and stream out
// 2013 Christoph Romstoeck (lwm)
//

Texture2D<float4> Texture;

SamplerState linearSampler
{
	AddressU = CLAMP;
	AddressV = CLAMP;
	Filter = MIN_MAG_MIP_LINEAR;
};

#define FLAG_CONSTRAINED 1
#define FLAG_FAST_FADE 2

cbuffer EveryFrame : register(b0)
{
	float4x4	View;
	float4x4	Projection;
	float4x4	LookAt;
	float3	CamDir;
	float	Time;
	float3	Gravity;
};

struct ParticleVertex
{
	float3 Position : POSITION;
	float3 Velocity : NORMAL;
	float4 Color : COLOR;
	float2 TimerLifetime : TEXCOORD0;
	uint Flags : TEXCOORD1;
	float2 SizeStartEnd : TEXCOORD2;
};

struct ParticleVertexGsUpdateOut
{
	float4 Position : SV_POSITION;
	float3 Velocity : NORMAL;
	float4 Color : COLOR;
	float2 TimerLifetime : TEXCOORD0;
	uint Flags : TEXCOORD1;
	float2 SizeStartEnd : TEXCOORD2;
};

struct ParticleVertexGsOut
{
	float4 Position : SV_POSITION;
	float4 Color : COLOR;
	float2 TexCoord : TEXCOORD0;
	float4 PositionVS : TEXCOORD1;
};

// ===

// Vertex shader has no work to do.
// Simply pass vertex on to the next stage.
ParticleVertex VS_Passthrough(ParticleVertex v)
{
	return v;
}

// Geometry shader to update one particle.
[maxvertexcount(1)]
void GS_Update(point ParticleVertex vertex[1], inout PointStream<ParticleVertexGsUpdateOut> stream) {

	ParticleVertex input = vertex[0];	

	// Calculate new age of the particle.
	float newTimer = input.TimerLifetime.x + Time;

	// If the particle is older than its lifetime, don't do anything.
	if(newTimer > input.TimerLifetime.y)
		return;

	// Calculate new position by adding the particle's velocity.
	float3 newPosition = input.Position + input.Velocity * Time;

	// Calculate new velocity by adding the world's gravity.
	float3 newVelocity = input.Velocity + Gravity * Time;

	ParticleVertexGsUpdateOut output;
	output.Position = float4(newPosition, 1);
	output.Velocity = newVelocity;
	output.Color = input.Color;
	output.TimerLifetime.x = newTimer;
	output.TimerLifetime.y = input.TimerLifetime.y;
	output.Flags = input.Flags;
	output.SizeStartEnd = input.SizeStartEnd;

	// Append updated particle to output stream.
	stream.Append(output);
}

GeometryShader pGSComp = CompileShader(gs_4_0, GS_Update());
GeometryShader pGSwSO = ConstructGSWithSO(pGSComp, "SV_POSITION.xyz; NORMAL.xyz; COLOR.xyzw; TEXCOORD0.xy; TEXCOORD1.x; TEXCOORD2.xy");

technique11 UpdateTeq
{
	pass Pass1
	{
		SetVertexShader(CompileShader(vs_4_0, VS_Passthrough()));
		SetGeometryShader(pGSwSO);
		SetPixelShader(NULL);
	}
}

// ===============================================

// Geometry shader to expand the vertex into a quad.
[maxvertexcount(4)]
void GS_Render(point ParticleVertex inputArray[1], inout TriangleStream<ParticleVertexGsOut> stream)
{

	ParticleVertex input = inputArray[0];	

	// Calculate the particles age in [0..1]
	float age = input.TimerLifetime.x / input.TimerLifetime.y;

	ParticleVertexGsOut v;

	// Determine the particle's color based on its age.
	v.Color = input.Color;
	bool fastFade = (input.Flags & FLAG_FAST_FADE) > 0;
	if (fastFade)
		v.Color.a *= (-(256 * 256) * pow(age - 0.5f, 16) + 1);
	else
		v.Color.a *= (-4 * (age - 0.5f) * (age - 0.5f) + 1);

	// Calculate the particle's current size
	float2 size = lerp(input.SizeStartEnd.x, input.SizeStartEnd.y, age);	

	// Check if one of the quad's axes should be constrained to the particle's velocity.
	bool constrained = (input.Flags & FLAG_CONSTRAINED) > 0;
	float3 right, up;

	if(constrained)
	{
		right = normalize(input.Velocity);
		up = cross(CamDir, right) * size.y;
		right *= size.x;
	}
	else
	{
		float2 xr = float4(size.x, 0, 0, 1);
		float2 yr = float4(0, size.y, 0, 1);

		right = mul(xr, LookAt).xyz;
		up = mul(yr, LookAt).xyz;
	}

	// Create and append four vertices to form a quad.
	float4 positionWS = float4(input.Position + right + up, 1.f);
	v.PositionVS = mul(positionWS, View);
	v.Position = mul(v.PositionVS, Projection);
	v.TexCoord = float2(1, 1);
	stream.Append(v);

	positionWS = float4(input.Position - right + up, 1.f);
	v.PositionVS = mul(positionWS, View);
	v.Position = mul(v.PositionVS, Projection);
	v.TexCoord = float2(0, 1);
	stream.Append(v);

	positionWS = float4(input.Position + right - up, 1.f);
	v.PositionVS = mul(positionWS, View);
	v.Position = mul(v.PositionVS, Projection);
	v.TexCoord = float2(1, 0);
	stream.Append(v);

	positionWS = float4(input.Position - right - up, 1.f);
	v.PositionVS = mul(positionWS, View);
	v.Position = mul(v.PositionVS, Projection);
	v.TexCoord = float2(0, 0);
	stream.Append(v);

	stream.RestartStrip();
}

// Simple pixel shader to render the particles.
float4 PS_Render(ParticleVertexGsOut input) : SV_Target
{
	float4 tex = Texture.Sample(linearSampler, input.TexCoord);

	return tex * input.Color;
}

technique11 RenderTeq
{
	pass Pass1
	{
		SetVertexShader(CompileShader(vs_4_0, VS_Passthrough()));
		SetGeometryShader(CompileShader(gs_4_0, GS_Render()));
		SetPixelShader(CompileShader(ps_4_0, PS_Render()));
	}
}

@Guo-Leo: Well, yes, more or less. The sample uses additive blending, that's about the simplest one with respect to depth. E.g. for alpha-blended partcicles one needs them to draw them back to front (farthest first), so you have to sort them according to distance. There's also so-called soft particles (google it). I recently stumbled upon this blog post which is a quite interesting read.

@Telanor: I'm really sorry to tell you I'm out of clues or helpful suggestions. I'm still using VS 2010, vanilla D3D11 and PIX. Yesterday I heard from NightCreature about the inconveniences of the graphics debugger. Your suspicion about D3D11.1 might as well be true.

Looking at your shader I have one final thought though: This looks like you're using the D3DX effect system (technique11, not the SharpDX effect system). Is it ?. When I played with alternative tools, or sometimes even with PIX, I had troubles. I also wonder how well it behaves with the newer runtimes. Try using bare shaders for a change. Good luck.

I may give that a try but I'm not so sure it'll help. I've been using the effects system for all my shaders so far with no problem. When I get a chance I'll set up the particle system in a separate project and switch between DX11 and 11.1 and see if that makes any difference. Thanks for trying though unbird, I appreciate it.

@Guo-Leo: Well, yes, more or less. The sample uses additive blending, that's about the simplest one with respect to depth. E.g. for alpha-blended partcicles one needs them to draw them back to front (farthest first), so you have to sort them according to distance. There's also so-called soft particles (google it). I recently stumbled upon this blog post which is a quite interesting read.

@Telanor: I'm really sorry to tell you I'm out of clues or helpful suggestions. I'm still using VS 2010, vanilla D3D11 and PIX. Yesterday I heard from NightCreature about the inconveniences of the graphics debugger. Your suspicion about D3D11.1 might as well be true.

Looking at your shader I have one final thought though: This looks like you're using the D3DX effect system (technique11, not the SharpDX effect system). Is it ?. When I played with alternative tools, or sometimes even with PIX, I had troubles. I also wonder how well it behaves with the newer runtimes. Try using bare shaders for a change. Good luck.

Thank you for your guidance? you are great! Thank you Very much! I will go on study with your guidance.

I just want to make a clarification:


Also, on the topic of gpu particles, I've seen some systems that use directcompute instead. Am I correct in assuming that only works on feature level 11 and up?
No. GPU particles have been around for a while, they are viable on anything that is Shader Model 3.0 and later - google "Lutz Latta" and "Building a million particle system". More advanced hardware makes everything much more streamlined and eventually takes it to be viable on a meaningful installed base.

Previously "Krohm"

Also, on the topic of gpu particles, I've seen some systems that use directcompute instead. Am I correct in assuming that only works on feature level 11 and up?


No, you can use compute shaders with feature level 10.x (cs_4_0) with a couple of restrictions. Also, so called Append/Consume buffers are restricted to shader model 5 which would be nice for particles (see the Hieroglyph engine particle sample).

Edit: Oh, well, that was actually an old question and has sort of been answered already. I really should stop doing this echoing thing wink.png
So I went and rebuilt the sample in a stand-alone project using plain sharpdx without the toolkit. It runs fine and the graphics debugger works. I tested with both DX11 and DX11.1, no problems. So I guess there's some kind of strange issue occurring elsewhere in my project which is somehow breaking the particle code. I guess the only thing I can do is turn off systems and see if it starts working.
More updates:

While setting up the stand-alone project, I had to set the gravity/deltaTime to 0 because otherwise the particles randomly flew off the screen at insane speeds. Turns out I forgot the gravity parameter was a Vector3 and was passing just a float. For some reason, SharpDX has a Set(float dataRef) overload which was being called. So the particles now render correctly in my main project (yay!).

I also went through and commented out all the other draw calls but the VS debugger *still* crashes instantly on start up, so I really have no idea what its problem is. Nvida Nsight now supports DX11.1 and runs but says it can't find debug info for the shaders (it is there) so I can't debug with that either. I guess I'll just have to use the separate project if I ever need to debug the particles.

This topic is closed to new replies.

Advertisement