GPU particles

Started by
38 comments, last by Telanor 10 years, 8 months ago
Well... I ported it over but I can't see any particles. The DX debug layer is giving me a warning when I try to run the VS graphics debugger:

Engine.Context.StreamOutput.SetTarget(streamToBuffer, 0);

D3D11 WARNING: ID3D11DeviceContext::Begin: Begin is being invoked on a Query, where the previous results have not been obtained with GetData. This is valid; but unusual. The previous results are being abandoned, and new Query results will be generated. [ EXECUTION WARNING #408: QUERY_BEGIN_ABANDONING_PREVIOUS_RESULTS]
I'm not even using queries. If I turn off the debug layer, it stops on the line above it:

Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(drawFromBuffer, ParticleVertex.SizeInBytes, 0));

"Additional information: External component has thrown an exception."

Full code:
[spoiler]
using Craft.Camera;
using Craft.Main;
using Craft.Misc;
using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Runtime.InteropServices;
using Buffer = SharpDX.Direct3D11.Buffer;
using MapFlags = SharpDX.Direct3D11.MapFlags;

namespace Craft.Game.Particles
{
	public struct ParticleVertex
	{
		public static readonly InputElement[] VertexDeclaration = new[]
		{
			new InputElement("POSITION", 0, Format.R32G32B32_Float, 0),
			new InputElement("NORMAL", 0, Format.R32G32B32_Float, 0),
			new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 0),
			new InputElement("TEXCOORD", 0, Format.R32G32_Float, 0),
			new InputElement("TEXCOORD", 1, Format.R32_UInt, 0),
			new InputElement("TEXCOORD", 2, Format.R32G32_Float, 0)
		};

		public static readonly int SizeInBytes = Marshal.SizeOf(typeof(ParticleVertex));

		public Vector3 Position;
		public Vector3 Velocity;
		public Vector4 Color;
		public Vector2 TimerLifetime;
		public uint Flags;
		public Vector2 SizeStartEnd;

		public ParticleVertex(Vector3 position, Vector3 velocity, Vector4 color, Vector2 timerLifetime, uint flags, Vector2 sizeStartEnd) : this()
		{
			Position = position;
			Velocity = velocity;
			Color = color;
			TimerLifetime = timerLifetime;
			Flags = flags;
			SizeStartEnd = sizeStartEnd;
		}
	}

	public static class GPUParticles
	{
		private const int MaxParticles = 1048576;
		private const int MaxNew = 128;

		[Flags]
		enum ParticleFlags
		{
			Constrained = 1,
			FastFade = 2
		}

		private static Buffer spawnBuffer;
		private static Buffer drawFromBuffer;
		private static Buffer streamToBuffer;

		private static Effect effect;
		private static EffectPass updatePass;
		private static EffectPass renderPass;
		private static InputLayout layout;

		private static EffectMatrixVariable evView;
		private static EffectMatrixVariable evProjection;
		private static EffectMatrixVariable evLookAt;
		private static EffectScalarVariable evTime;
		private static EffectVectorVariable evCamDir;
		private static EffectVectorVariable evGravity;
		private static EffectShaderResourceVariable evTexture;
		private static ParticleVertex[] newParticles;
		private static int numNew;

		internal static void Initialize()
		{
			newParticles = new ParticleVertex[MaxNew];

			effect = ContentLoader.LoadEffect(@"Content\Effects\GPUParticles.fxo");
			updatePass = effect.GetTechniqueByName("UpdateTeq").GetPassByIndex(0);
			renderPass = effect.GetTechniqueByName("RenderTeq").GetPassByIndex(0);
			layout = ContentLoader.CreateInputLayout(updatePass, ParticleVertex.VertexDeclaration);

			spawnBuffer = new Buffer(Engine.Device, new BufferDescription(ParticleVertex.SizeInBytes * MaxNew, ResourceUsage.Dynamic, BindFlags.VertexBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, 0));
			drawFromBuffer = new Buffer(Engine.Device, new BufferDescription(ParticleVertex.SizeInBytes * MaxParticles, ResourceUsage.Default, BindFlags.VertexBuffer | BindFlags.StreamOutput, CpuAccessFlags.None, ResourceOptionFlags.None, 0));
			streamToBuffer = new Buffer(Engine.Device, new BufferDescription(ParticleVertex.SizeInBytes * MaxParticles, ResourceUsage.Default, BindFlags.VertexBuffer | BindFlags.StreamOutput, CpuAccessFlags.None, ResourceOptionFlags.None, 0));

			evView = effect.GetVariableByName("View").AsMatrix();
			evProjection = effect.GetVariableByName("Projection").AsMatrix();
			evLookAt = effect.GetVariableByName("LookAt").AsMatrix();
			evTime = effect.GetVariableByName("Time").AsScalar();
			evCamDir = effect.GetVariableByName("CamDir").AsVector();
			evGravity = effect.GetVariableByName("Gravity").AsVector();
			evTexture = effect.GetVariableByName("Texture").AsShaderResource();

			evTexture.SetResource(ContentLoader.LoadTexture(@"Content\Textures\particles\sparkle.png"));
		}

		public static void Spawn(Vector3 position, Vector3 velocity, Color color, float sizeStart, float sizeEnd, float lifetime, bool constrained, bool fastFade)
		{
			// discard particle if buffer is full
			if (numNew >= MaxNew)
				return;

			// create particle struct
			var v = new ParticleVertex(position, velocity, color.ToVector4(), new Vector2(0, lifetime), 0, new Vector2(sizeStart, sizeEnd));

			// set the particle's flags
			if (constrained) v.Flags |= (uint) ParticleFlags.Constrained;
			if (fastFade) v.Flags |= (uint) ParticleFlags.FastFade;

			// append to buffer
			newParticles[numNew++] = v;
		}

		internal static void Draw(ICamera camera)
		{
			var cameraForward = camera.Forward;
			var lookAtMatrix = Matrix.Billboard(Vector3.Zero, -cameraForward, Vector3.UnitY, cameraForward);

			evView.SetMatrix(camera.View);
			evProjection.SetMatrix(camera.Projection);
			evLookAt.SetMatrix(lookAtMatrix);
			evTime.Set((float) Core.GameTime.TotalGameTime.TotalSeconds);
			evCamDir.Set(cameraForward);
			evGravity.Set(9.81f);

			Advance();
			Render();
		}

		private static void Advance()
		{
			// Use particleDrawFrom as input and stream output to particleStreamTo
			Engine.Context.InputAssembler.InputLayout = layout;
			Engine.Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.PointList;
			Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(drawFromBuffer, ParticleVertex.SizeInBytes, 0));
			Engine.Context.StreamOutput.SetTarget(streamToBuffer, 0);

			updatePass.Apply(Engine.Context);

			// Update particles on the gpu
			Engine.Context.DrawAuto();

			// See if we have any newly-spawned particles waiting
			if (numNew > 0)
			{
				// Copy new particles to vertex buffer and draw them to append them to stream output target
				DataStream stream;
				Engine.Context.MapSubresource(spawnBuffer, MapMode.WriteDiscard, MapFlags.None, out stream);
				stream.WriteRange(newParticles);
				Engine.Context.UnmapSubresource(spawnBuffer, 0);

				Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(spawnBuffer, ParticleVertex.SizeInBytes, 0));
				Engine.Context.Draw(numNew, 0);
				numNew = 0;
			}

			Engine.Context.StreamOutput.SetTargets(null);

			// Swap vertex buffers
			Utilities.Swap(ref drawFromBuffer, ref streamToBuffer);
		}

		private static void Render()
		{
			// Since we just swapped the vertex buffers, particleDrawFrom contains the current state
			Engine.Context.OutputMerger.SetBlendState(DeviceStates.BlendStateAdditive);
			Engine.Context.OutputMerger.SetDepthStencilState(DeviceStates.DepthStencilStateNone);
			Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(drawFromBuffer, ParticleVertex.SizeInBytes, 0));

			renderPass.Apply(Engine.Context);
			Engine.Context.DrawAuto();

			Engine.Context.GeometryShader.Set(null);
		}

		internal static void Shutdown()
		{
			spawnBuffer.Dispose();
			drawFromBuffer.Dispose();
			streamToBuffer.Dispose();
		}
	}
}
[/spoiler]
Advertisement

Is there some official information about the point->quat expansion special-case handling?

http://directtovideo.wordpress.com/2009/10/06/a-thoroughly-modern-particle-system/

Quite good reading about gpu particle systems using just dx9.

Just creating lot of particles is fun but not that usefull. Making particles look good and fitting for scene you usually want shading/shadowing match the rest of the scene. Also you want simulate some collisions and maybe even particle to particle forces. Also some sorting is must for good looking alpha blending.

http://directtovideo.wordpress.com/2009/10/06/a-thoroughly-modern-particle-system/

Quite good reading about gpu particle systems using just dx9.

Just creating lot of particles is fun but not that usefull. Making particles look good and fitting for scene you usually want shading/shadowing match the rest of the scene. Also you want simulate some collisions and maybe even particle to particle forces. Also some sorting is must for good looking alpha blending.

For particle lighting, I generate a volume texture mapped to the camera projection with lighting information in each voxel (I use HL2 basis) which I can then sample with a few texture fetches in my particle PS to resolve reasonably accurate lighting. When I have too much overdraw/particles, I revert to just sampling a fixed approximated lighting value instead of resolving directional lighting. Works well, and is really quite fast, once you pay the cost to generate the map. (atm takes 2-3 ms in cs with 500 lights visible). Maybe it would be possible to move the generation to CPU while the gbuffer / whatnot is being rendered?

Well... I ported it over but I can't see any particles. The DX debug layer is giving me a warning when I try to run the VS graphics debugger:


Engine.Context.StreamOutput.SetTarget(streamToBuffer, 0);

D3D11 WARNING: ID3D11DeviceContext::Begin: Begin is being invoked on a Query, where the previous results have not been obtained with GetData. This is valid; but unusual. The previous results are being abandoned, and new Query results will be generated. [ EXECUTION WARNING #408: QUERY_BEGIN_ABANDONING_PREVIOUS_RESULTS]
I'm not even using queries. If I turn off the debug layer, it stops on the line above it:


Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(drawFromBuffer, ParticleVertex.SizeInBytes, 0));

"Additional information: External component has thrown an exception."
Full code:
[spoiler]

using Craft.Camera;
using Craft.Main;
using Craft.Misc;
using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Runtime.InteropServices;
using Buffer = SharpDX.Direct3D11.Buffer;
using MapFlags = SharpDX.Direct3D11.MapFlags;

namespace Craft.Game.Particles
{
	public struct ParticleVertex
	{
		public static readonly InputElement[] VertexDeclaration = new[]
		{
			new InputElement("POSITION", 0, Format.R32G32B32_Float, 0),
			new InputElement("NORMAL", 0, Format.R32G32B32_Float, 0),
			new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 0),
			new InputElement("TEXCOORD", 0, Format.R32G32_Float, 0),
			new InputElement("TEXCOORD", 1, Format.R32_UInt, 0),
			new InputElement("TEXCOORD", 2, Format.R32G32_Float, 0)
		};

		public static readonly int SizeInBytes = Marshal.SizeOf(typeof(ParticleVertex));

		public Vector3 Position;
		public Vector3 Velocity;
		public Vector4 Color;
		public Vector2 TimerLifetime;
		public uint Flags;
		public Vector2 SizeStartEnd;

		public ParticleVertex(Vector3 position, Vector3 velocity, Vector4 color, Vector2 timerLifetime, uint flags, Vector2 sizeStartEnd) : this()
		{
			Position = position;
			Velocity = velocity;
			Color = color;
			TimerLifetime = timerLifetime;
			Flags = flags;
			SizeStartEnd = sizeStartEnd;
		}
	}

	public static class GPUParticles
	{
		private const int MaxParticles = 1048576;
		private const int MaxNew = 128;

		[Flags]
		enum ParticleFlags
		{
			Constrained = 1,
			FastFade = 2
		}

		private static Buffer spawnBuffer;
		private static Buffer drawFromBuffer;
		private static Buffer streamToBuffer;

		private static Effect effect;
		private static EffectPass updatePass;
		private static EffectPass renderPass;
		private static InputLayout layout;

		private static EffectMatrixVariable evView;
		private static EffectMatrixVariable evProjection;
		private static EffectMatrixVariable evLookAt;
		private static EffectScalarVariable evTime;
		private static EffectVectorVariable evCamDir;
		private static EffectVectorVariable evGravity;
		private static EffectShaderResourceVariable evTexture;
		private static ParticleVertex[] newParticles;
		private static int numNew;

		internal static void Initialize()
		{
			newParticles = new ParticleVertex[MaxNew];

			effect = ContentLoader.LoadEffect(@"Content\Effects\GPUParticles.fxo");
			updatePass = effect.GetTechniqueByName("UpdateTeq").GetPassByIndex(0);
			renderPass = effect.GetTechniqueByName("RenderTeq").GetPassByIndex(0);
			layout = ContentLoader.CreateInputLayout(updatePass, ParticleVertex.VertexDeclaration);

			spawnBuffer = new Buffer(Engine.Device, new BufferDescription(ParticleVertex.SizeInBytes * MaxNew, ResourceUsage.Dynamic, BindFlags.VertexBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, 0));
			drawFromBuffer = new Buffer(Engine.Device, new BufferDescription(ParticleVertex.SizeInBytes * MaxParticles, ResourceUsage.Default, BindFlags.VertexBuffer | BindFlags.StreamOutput, CpuAccessFlags.None, ResourceOptionFlags.None, 0));
			streamToBuffer = new Buffer(Engine.Device, new BufferDescription(ParticleVertex.SizeInBytes * MaxParticles, ResourceUsage.Default, BindFlags.VertexBuffer | BindFlags.StreamOutput, CpuAccessFlags.None, ResourceOptionFlags.None, 0));

			evView = effect.GetVariableByName("View").AsMatrix();
			evProjection = effect.GetVariableByName("Projection").AsMatrix();
			evLookAt = effect.GetVariableByName("LookAt").AsMatrix();
			evTime = effect.GetVariableByName("Time").AsScalar();
			evCamDir = effect.GetVariableByName("CamDir").AsVector();
			evGravity = effect.GetVariableByName("Gravity").AsVector();
			evTexture = effect.GetVariableByName("Texture").AsShaderResource();

			evTexture.SetResource(ContentLoader.LoadTexture(@"Content\Textures\particles\sparkle.png"));
		}

		public static void Spawn(Vector3 position, Vector3 velocity, Color color, float sizeStart, float sizeEnd, float lifetime, bool constrained, bool fastFade)
		{
			// discard particle if buffer is full
			if (numNew >= MaxNew)
				return;

			// create particle struct
			var v = new ParticleVertex(position, velocity, color.ToVector4(), new Vector2(0, lifetime), 0, new Vector2(sizeStart, sizeEnd));

			// set the particle's flags
			if (constrained) v.Flags |= (uint) ParticleFlags.Constrained;
			if (fastFade) v.Flags |= (uint) ParticleFlags.FastFade;

			// append to buffer
			newParticles[numNew++] = v;
		}

		internal static void Draw(ICamera camera)
		{
			var cameraForward = camera.Forward;
			var lookAtMatrix = Matrix.Billboard(Vector3.Zero, -cameraForward, Vector3.UnitY, cameraForward);

			evView.SetMatrix(camera.View);
			evProjection.SetMatrix(camera.Projection);
			evLookAt.SetMatrix(lookAtMatrix);
			evTime.Set((float) Core.GameTime.TotalGameTime.TotalSeconds);
			evCamDir.Set(cameraForward);
			evGravity.Set(9.81f);

			Advance();
			Render();
		}

		private static void Advance()
		{
			// Use particleDrawFrom as input and stream output to particleStreamTo
			Engine.Context.InputAssembler.InputLayout = layout;
			Engine.Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.PointList;
			Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(drawFromBuffer, ParticleVertex.SizeInBytes, 0));
			Engine.Context.StreamOutput.SetTarget(streamToBuffer, 0);

			updatePass.Apply(Engine.Context);

			// Update particles on the gpu
			Engine.Context.DrawAuto();

			// See if we have any newly-spawned particles waiting
			if (numNew > 0)
			{
				// Copy new particles to vertex buffer and draw them to append them to stream output target
				DataStream stream;
				Engine.Context.MapSubresource(spawnBuffer, MapMode.WriteDiscard, MapFlags.None, out stream);
				stream.WriteRange(newParticles);
				Engine.Context.UnmapSubresource(spawnBuffer, 0);

				Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(spawnBuffer, ParticleVertex.SizeInBytes, 0));
				Engine.Context.Draw(numNew, 0);
				numNew = 0;
			}

			Engine.Context.StreamOutput.SetTargets(null);

			// Swap vertex buffers
			Utilities.Swap(ref drawFromBuffer, ref streamToBuffer);
		}

		private static void Render()
		{
			// Since we just swapped the vertex buffers, particleDrawFrom contains the current state
			Engine.Context.OutputMerger.SetBlendState(DeviceStates.BlendStateAdditive);
			Engine.Context.OutputMerger.SetDepthStencilState(DeviceStates.DepthStencilStateNone);
			Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(drawFromBuffer, ParticleVertex.SizeInBytes, 0));

			renderPass.Apply(Engine.Context);
			Engine.Context.DrawAuto();

			Engine.Context.GeometryShader.Set(null);
		}

		internal static void Shutdown()
		{
			spawnBuffer.Dispose();
			drawFromBuffer.Dispose();
			streamToBuffer.Dispose();
		}
	}
}
[/spoiler]

I'm currently having this exact same issue in my SlimDX code. Did you ever find a solution to that problem?

A few day ago, I created a little GPU particle sample for SharpDX. The buffers start off completely empty. To spawn new particles, I copy them to a third vertex buffer. After the pass to update the particles from last frame, I just "draw" the third buffer to append the new particles to the buffer for the current frame as well.

Any properties that are "sufficiently random" like the particle's color or various flags, I put directly into the vertex. I didn't include this in the sample to avoid bloating it, but to handle properties that a lot of particles share, every particle also has a type ID that indexes into an array of particle types in the geometry shader.

Hello! I have see your sample ! It's very Good But I use SharpDX11 to do this, not Tookit! The Shader your sample can't recognize about

"StreamOutput = "SV_POSITION.xyz; NORMAL.xyz; COLOR.xyzw; TEXCOORD0.xy; TEXCOORD1.x; TEXCOORD2.xy";

StreamOutputRasterizedStream = 0;"

I can't find right way to express this in Shader model5.0 of Technique11!

Oh! Sorry ! My English is bad! hople you can understand me! if you can help me I am Very thanks to you!

Well... I ported it over but I can't see any particles. The DX debug layer is giving me a warning when I try to run the VS graphics debugger:


Engine.Context.StreamOutput.SetTarget(streamToBuffer, 0);

D3D11 WARNING: ID3D11DeviceContext::Begin: Begin is being invoked on a Query, where the previous results have not been obtained with GetData. This is valid; but unusual. The previous results are being abandoned, and new Query results will be generated. [ EXECUTION WARNING #408: QUERY_BEGIN_ABANDONING_PREVIOUS_RESULTS]
I'm not even using queries. If I turn off the debug layer, it stops on the line above it:


Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(drawFromBuffer, ParticleVertex.SizeInBytes, 0));

"Additional information: External component has thrown an exception."
Full code:
[spoiler]

using Craft.Camera;
using Craft.Main;
using Craft.Misc;
using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using System;
using System.Runtime.InteropServices;
using Buffer = SharpDX.Direct3D11.Buffer;
using MapFlags = SharpDX.Direct3D11.MapFlags;

namespace Craft.Game.Particles
{
	public struct ParticleVertex
	{
		public static readonly InputElement[] VertexDeclaration = new[]
		{
			new InputElement("POSITION", 0, Format.R32G32B32_Float, 0),
			new InputElement("NORMAL", 0, Format.R32G32B32_Float, 0),
			new InputElement("COLOR", 0, Format.R32G32B32A32_Float, 0),
			new InputElement("TEXCOORD", 0, Format.R32G32_Float, 0),
			new InputElement("TEXCOORD", 1, Format.R32_UInt, 0),
			new InputElement("TEXCOORD", 2, Format.R32G32_Float, 0)
		};

		public static readonly int SizeInBytes = Marshal.SizeOf(typeof(ParticleVertex));

		public Vector3 Position;
		public Vector3 Velocity;
		public Vector4 Color;
		public Vector2 TimerLifetime;
		public uint Flags;
		public Vector2 SizeStartEnd;

		public ParticleVertex(Vector3 position, Vector3 velocity, Vector4 color, Vector2 timerLifetime, uint flags, Vector2 sizeStartEnd) : this()
		{
			Position = position;
			Velocity = velocity;
			Color = color;
			TimerLifetime = timerLifetime;
			Flags = flags;
			SizeStartEnd = sizeStartEnd;
		}
	}

	public static class GPUParticles
	{
		private const int MaxParticles = 1048576;
		private const int MaxNew = 128;

		[Flags]
		enum ParticleFlags
		{
			Constrained = 1,
			FastFade = 2
		}

		private static Buffer spawnBuffer;
		private static Buffer drawFromBuffer;
		private static Buffer streamToBuffer;

		private static Effect effect;
		private static EffectPass updatePass;
		private static EffectPass renderPass;
		private static InputLayout layout;

		private static EffectMatrixVariable evView;
		private static EffectMatrixVariable evProjection;
		private static EffectMatrixVariable evLookAt;
		private static EffectScalarVariable evTime;
		private static EffectVectorVariable evCamDir;
		private static EffectVectorVariable evGravity;
		private static EffectShaderResourceVariable evTexture;
		private static ParticleVertex[] newParticles;
		private static int numNew;

		internal static void Initialize()
		{
			newParticles = new ParticleVertex[MaxNew];

			effect = ContentLoader.LoadEffect(@"Content\Effects\GPUParticles.fxo");
			updatePass = effect.GetTechniqueByName("UpdateTeq").GetPassByIndex(0);
			renderPass = effect.GetTechniqueByName("RenderTeq").GetPassByIndex(0);
			layout = ContentLoader.CreateInputLayout(updatePass, ParticleVertex.VertexDeclaration);

			spawnBuffer = new Buffer(Engine.Device, new BufferDescription(ParticleVertex.SizeInBytes * MaxNew, ResourceUsage.Dynamic, BindFlags.VertexBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, 0));
			drawFromBuffer = new Buffer(Engine.Device, new BufferDescription(ParticleVertex.SizeInBytes * MaxParticles, ResourceUsage.Default, BindFlags.VertexBuffer | BindFlags.StreamOutput, CpuAccessFlags.None, ResourceOptionFlags.None, 0));
			streamToBuffer = new Buffer(Engine.Device, new BufferDescription(ParticleVertex.SizeInBytes * MaxParticles, ResourceUsage.Default, BindFlags.VertexBuffer | BindFlags.StreamOutput, CpuAccessFlags.None, ResourceOptionFlags.None, 0));

			evView = effect.GetVariableByName("View").AsMatrix();
			evProjection = effect.GetVariableByName("Projection").AsMatrix();
			evLookAt = effect.GetVariableByName("LookAt").AsMatrix();
			evTime = effect.GetVariableByName("Time").AsScalar();
			evCamDir = effect.GetVariableByName("CamDir").AsVector();
			evGravity = effect.GetVariableByName("Gravity").AsVector();
			evTexture = effect.GetVariableByName("Texture").AsShaderResource();

			evTexture.SetResource(ContentLoader.LoadTexture(@"Content\Textures\particles\sparkle.png"));
		}

		public static void Spawn(Vector3 position, Vector3 velocity, Color color, float sizeStart, float sizeEnd, float lifetime, bool constrained, bool fastFade)
		{
			// discard particle if buffer is full
			if (numNew >= MaxNew)
				return;

			// create particle struct
			var v = new ParticleVertex(position, velocity, color.ToVector4(), new Vector2(0, lifetime), 0, new Vector2(sizeStart, sizeEnd));

			// set the particle's flags
			if (constrained) v.Flags |= (uint) ParticleFlags.Constrained;
			if (fastFade) v.Flags |= (uint) ParticleFlags.FastFade;

			// append to buffer
			newParticles[numNew++] = v;
		}

		internal static void Draw(ICamera camera)
		{
			var cameraForward = camera.Forward;
			var lookAtMatrix = Matrix.Billboard(Vector3.Zero, -cameraForward, Vector3.UnitY, cameraForward);

			evView.SetMatrix(camera.View);
			evProjection.SetMatrix(camera.Projection);
			evLookAt.SetMatrix(lookAtMatrix);
			evTime.Set((float) Core.GameTime.TotalGameTime.TotalSeconds);
			evCamDir.Set(cameraForward);
			evGravity.Set(9.81f);

			Advance();
			Render();
		}

		private static void Advance()
		{
			// Use particleDrawFrom as input and stream output to particleStreamTo
			Engine.Context.InputAssembler.InputLayout = layout;
			Engine.Context.InputAssembler.PrimitiveTopology = PrimitiveTopology.PointList;
			Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(drawFromBuffer, ParticleVertex.SizeInBytes, 0));
			Engine.Context.StreamOutput.SetTarget(streamToBuffer, 0);

			updatePass.Apply(Engine.Context);

			// Update particles on the gpu
			Engine.Context.DrawAuto();

			// See if we have any newly-spawned particles waiting
			if (numNew > 0)
			{
				// Copy new particles to vertex buffer and draw them to append them to stream output target
				DataStream stream;
				Engine.Context.MapSubresource(spawnBuffer, MapMode.WriteDiscard, MapFlags.None, out stream);
				stream.WriteRange(newParticles);
				Engine.Context.UnmapSubresource(spawnBuffer, 0);

				Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(spawnBuffer, ParticleVertex.SizeInBytes, 0));
				Engine.Context.Draw(numNew, 0);
				numNew = 0;
			}

			Engine.Context.StreamOutput.SetTargets(null);

			// Swap vertex buffers
			Utilities.Swap(ref drawFromBuffer, ref streamToBuffer);
		}

		private static void Render()
		{
			// Since we just swapped the vertex buffers, particleDrawFrom contains the current state
			Engine.Context.OutputMerger.SetBlendState(DeviceStates.BlendStateAdditive);
			Engine.Context.OutputMerger.SetDepthStencilState(DeviceStates.DepthStencilStateNone);
			Engine.Context.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(drawFromBuffer, ParticleVertex.SizeInBytes, 0));

			renderPass.Apply(Engine.Context);
			Engine.Context.DrawAuto();

			Engine.Context.GeometryShader.Set(null);
		}

		internal static void Shutdown()
		{
			spawnBuffer.Dispose();
			drawFromBuffer.Dispose();
			streamToBuffer.Dispose();
		}
	}
}
[/spoiler]

Do you solve your problem! I have use your code in another XOBOX forum The same you say I can't see any partile If you solve the problem please Hlep I will very thanks to you! Sorry My english is very bad! hople you can understand me!

I can't find right way to express this in Shader model5.0 of Technique11!

Here is MSDN's description of the Stream Out Syntax. You might also want to take a look at the ParticlesGS sample from the DirectX SDK.

current project: Roa

I can't find right way to express this in Shader model5.0 of Technique11!

Here is MSDN's description of the Stream Out Syntax. You might also want to take a look at the ParticlesGS sample from the DirectX SDK.

Yes I has see it But it does't work

The modified code is?

GeometryShader pGSComp = CompileShader(gs_5_0, GS_Update());
GeometryShader gsStreamOut = ConstructGSWithSO( pGSComp, "0:SV_POSITION.xyz;1:NORMAL.xyz;2:COLOR.xyzw;3:TEXCOORD0.xy;4:TEXCOORD1.x;5:TEXCOORD2.xy;",NULL,NULL,0);
technique11 UpdateTeq
{
pass Pass0
{
SetVertexShader( CompileShader( vs_5_0, VS_Passthrough() ) );
SetGeometryShader(gsStreamOut);
SetPixelShader( NULL);
}
}
It senms to right ! but VS Prompt Me!
D:\Coding\???\ResourceEditer(2013.07.15DX11????)\ResourceEditer\ResourceEditer\bin\Debug\MoonLight.Material.ParticleEffect.fx(91,31): error X3000: parameter count mismatch (ConstructGSWithSO)
I don't konw why! because MSDN write like this!! Oh ! I am very happy you can reply Me!

I can't find right way to express this in Shader model5.0 of Technique11!

Here is MSDN's description of the Stream Out Syntax. You might also want to take a look at the ParticlesGS sample from the DirectX SDK.

I use the same modified code in your sample It also can't work! I feel it's a simle error ! But I has solve it for 2 days...Now,Still failed!

This topic is closed to new replies.

Advertisement