Jump to content

  • Log In with Google      Sign In   
  • Create Account

GPU particles


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
39 replies to this topic

#21 Telanor   Members   -  Reputation: 1358

Like
0Likes
Like

Posted 20 July 2013 - 03:07 PM

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


No I never found a solution. The error makes no sense to me and I can't find any info about it on google, so I'm stuck with CPU particles for the time being.

Sponsor:

#22 GuoLei007   Members   -  Reputation: 118

Like
0Likes
Like

Posted 20 July 2013 - 03:46 PM

 

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


No I never found a solution. The error makes no sense to me and I can't find any info about it on google, so I'm stuck with CPU particles for the time being.

 

Oh! I am  very  sad  to  hear  this.....  we  both  use  sharpdx11.......I also  can't  find  any info  about  this!!  



#23 unbird   Crossbones+   -  Reputation: 6010

Like
0Likes
Like

Posted 22 July 2013 - 05:50 AM

The info is in the MSDN doc, you're just misreading the compiler error. Admittedly, setting up SO in the effect file is a little cryptic.
 

parameter count mismatch (ConstructGSWithSO)

There are up to four streams from your geometry shader you can select from, not just three. You're missing a NULL.

Also, if I get the sample right, it uses one output stream only, so you can omit the (optional) buffer index altogether (an index of >3 e.g. doesn't make sense anyway, you only got 4 output streams).

This should work (at least it compiles)

GeometryShader gsStreamOut = ConstructGSWithSO( pGSComp, "SV_POSITION.xyz;NORMAL.xyz;COLOR.xyzw;TEXCOORD0.xy;TEXCOORD1.x;TEXCOORD2.xy;",NULL,NULL,NULL,-1);
Note the -1 at the end. This is actually D3D11_SO_NO_RASTERIZED_STREAM, since you don't need rasterization for the particle update. Not sure this will work, try 0 first instead (PixelShader is NULL anyway).

#24 GuoLei007   Members   -  Reputation: 118

Like
0Likes
Like

Posted 24 July 2013 - 04:35 AM

The info is in the MSDN doc, you're just misreading the compiler error. Admittedly, setting up SO in the effect file is a little cryptic.
 

parameter count mismatch (ConstructGSWithSO)

There are up to four streams from your geometry shader you can select from, not just three. You're missing a NULL.

Also, if I get the sample right, it uses one output stream only, so you can omit the (optional) buffer index altogether (an index of >3 e.g. doesn't make sense anyway, you only got 4 output streams).

This should work (at least it compiles)

GeometryShader gsStreamOut = ConstructGSWithSO( pGSComp, "SV_POSITION.xyz;NORMAL.xyz;COLOR.xyzw;TEXCOORD0.xy;TEXCOORD1.x;TEXCOORD2.xy;",NULL,NULL,NULL,-1);
Note the -1 at the end. This is actually D3D11_SO_NO_RASTERIZED_STREAM, since you don't need rasterization for the particle update. Not sure this will work, try 0 first instead (PixelShader is NULL anyway).

 

Tanks!  I have  write that like  you  said  But  sitll  failed!  I  find the  particle  but it only  one pixel!  I don't know  why   Can you analysis  it by your Experience! 

Attached Thumbnails

  • QQ截图20130724182905.png


#25 unbird   Crossbones+   -  Reputation: 6010

Like
0Likes
Like

Posted 24 July 2013 - 05:42 AM

There are two techniques (and two geometry shaders) in that example. One for the particle update, one for drawing. You probably misuse the update for drawing. As said, disable rasterization for the update technique.

Streamout uses point streams, that's why you get those single pixels. The draw pass expands those points to quads (two triangles).

 

Since I'm now caught here:

 

@Telanor: Two concerns: Grant your ParticleVertex a proper StructLayout (like in the original code), otherwise Marshal.SizeOf may go wrong. Also: Why is GPUParticles a static class ?


Edited by unbird, 24 July 2013 - 05:44 AM.


#26 Telanor   Members   -  Reputation: 1358

Like
0Likes
Like

Posted 25 July 2013 - 01:47 AM

@Telanor: Two concerns: Grant your ParticleVertex a proper StructLayout (like in the original code), otherwise Marshal.SizeOf may go wrong. Also: Why is GPUParticles a static class ?


Yea I noticed I missed the StructLayout after I posted that. I've since added it, it didn't make any difference though. GPUParticles is a static class because I was planning on running all the particles from that class.

#27 GuoLei   Members   -  Reputation: 120

Like
0Likes
Like

Posted 25 July 2013 - 07:57 AM

The info is in the MSDN doc, you're just misreading the compiler error. Admittedly, setting up SO in the effect file is a little cryptic.
 


parameter count mismatch (ConstructGSWithSO)

There are up to four streams from your geometry shader you can select from, not just three. You're missing a NULL.

Also, if I get the sample right, it uses one output stream only, so you can omit the (optional) buffer index altogether (an index of >3 e.g. doesn't make sense anyway, you only got 4 output streams).

This should work (at least it compiles)

GeometryShader gsStreamOut = ConstructGSWithSO( pGSComp, "SV_POSITION.xyz;NORMAL.xyz;COLOR.xyzw;TEXCOORD0.xy;TEXCOORD1.x;TEXCOORD2.xy;",NULL,NULL,NULL,-1);
Note the -1 at the end. This is actually D3D11_SO_NO_RASTERIZED_STREAM, since you don't need rasterization for the particle update. Not sure this will work, try 0 first instead (PixelShader is NULL anyway).

 

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

173985025201307252228022158823211327_000


Edited by GuoLei, 25 July 2013 - 08:31 AM.


#28 GuoLei007   Members   -  Reputation: 118

Like
0Likes
Like

Posted 25 July 2013 - 08:23 AM

 

@Telanor: Two concerns: Grant your ParticleVertex a proper StructLayout (like in the original code), otherwise Marshal.SizeOf may go wrong. Also: Why is GPUParticles a static class ?


Yea I noticed I missed the StructLayout after I posted that. I've since added it, it didn't make any difference though. GPUParticles is a static class because I was planning on running all the particles from that class.

 

I  has  success  I will  give  the  code  to  you   maybe the  elapsedTime  you  are  wrong  

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;
using MoonLight.Graphics;
using MoonLight.Vertex;
using MoonLight.Scene;
using MoonLight.Dispose;
using MoonLight.Time;

namespace MoonLight.Graphics.Particle
{
   

    public  class ParticleSystem:IMovableObj, IRenderableObj, IDisposable
    {

        BasicScene m_BasicScene;

        string m_Name;
        public string Name
        {
            get { return m_Name; }
        }

        SceneNode m_ParentSceneNode;

        public SceneNode ParentSceneNode
        {
            get { return m_ParentSceneNode; }
            set { m_ParentSceneNode = value; }
        }

       
        private const int MaxParticles = 1024 * 16;
        private const int MaxNew = 128;

        public const uint Flag_Constrained = 1;
        public const uint Flag_Fast_Fade = 2;

        private  Buffer m_SpawnBuffer;
        private  Buffer m_DrawFromBuffer;
        private  Buffer M_StreamToBuffer;

        private  EffectPass m_UpdatePass;
        private  EffectPass m_RenderPass;
        private  InputLayout m_InputLayout;
        ShaderResourceView m_ParticleTextureView;
        Effect m_Effect;

        private  VertexParticle[] m_NewParticles;
        private  int m_NumNew=0;
      

        private Random m_Random = new Random();
        private float m_Elapsed;


        public ParticleSystem(BasicScene basicScene, string name, Effect effect, Texture2D particleTexture2D)
        {
            this.m_Name = name;
            m_BasicScene = basicScene;
            m_NewParticles = new VertexParticle[MaxNew];

            m_SpawnBuffer = new Buffer(m_BasicScene.WPFRenderHost.Device, new BufferDescription(VertexParticle.SizeInBytes * MaxNew, ResourceUsage.Dynamic, BindFlags.VertexBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, 0));
            m_DrawFromBuffer = new Buffer(m_BasicScene.WPFRenderHost.Device, new BufferDescription(VertexParticle.SizeInBytes * MaxParticles, ResourceUsage.Default, BindFlags.VertexBuffer | BindFlags.StreamOutput, CpuAccessFlags.None, ResourceOptionFlags.None, 0));
            M_StreamToBuffer = new Buffer(m_BasicScene.WPFRenderHost.Device, new BufferDescription(VertexParticle.SizeInBytes * MaxParticles, ResourceUsage.Default, BindFlags.VertexBuffer | BindFlags.StreamOutput, CpuAccessFlags.None, ResourceOptionFlags.None, 0));

            m_UpdatePass = effect.GetTechniqueByName("UpdateTeq").GetPassByIndex(0);
            m_RenderPass = effect.GetTechniqueByName("RenderTeq").GetPassByIndex(0);

            m_InputLayout = new InputLayout(m_BasicScene.WPFRenderHost.Device, m_UpdatePass.Description.Signature, VertexParticle.VertexDeclaration);
            m_Effect = effect;
            m_ParticleTextureView = new ShaderResourceView(m_BasicScene.WPFRenderHost.Device, particleTexture2D);

        
        
        }


        public 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 (m_NumNew >= MaxNew)
                return;

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

            // set the particle's flags 
            if (constrained) 
                v.Flags |= Flag_Constrained;
            if (fastFade) 
                v.Flags |= Flag_Fast_Fade;

            // append to buffer 
            m_NewParticles[m_NumNew++] = v;
        }


        public void AddToRenderQneue(RenderQueue renderQneue)
        {
            renderQneue.AddRenderableObj(this);
        }

        private Vector3 RandomDirection(Vector3 direction, float max)
        {
            float r1 = ((float)m_Random.NextDouble() * 2 - 1) * max;
            float r2 = ((float)m_Random.NextDouble() * 2 - 1) * max;
            float r3 = ((float)m_Random.NextDouble() * 2 - 1) * max;

            Quaternion q = Quaternion.RotationYawPitchRoll(r1, r2, r3);
            return Vector3.Transform(direction, q);
        }

        public void Draw(RenderTimer renderTimer)
        {
            if (m_BasicScene.SceneManager.RenderType == RenderType.Normal)
            {
                for (int i = 0; i < 128; i++)
                {
                    Vector3 position = Vector3.Zero;
                    Vector3 velocity = RandomDirection(Vector3.UnitY, MathUtil.TwoPi) * (float)m_Random.NextDouble(1.0, 4.0);
                    Color color = new Color((float)m_Random.NextDouble(), (float)m_Random.NextDouble(), (float)m_Random.NextDouble());
                    float startSize = 0.02f;
                    float endSize = 0.2f;
                    float lifetime = 2f;

                    Spawn(Vector3.Zero, velocity, color, startSize, endSize, lifetime, false, false);
                }
                m_Elapsed += ((float)renderTimer.IntervalMillseconds) / 1000;

                Advance();
                Render();
            }
        }
        void Advance()
        {
            m_BasicScene.WPFRenderHost.Device.ImmediateContext.OutputMerger.SetDepthStencilState(m_BasicScene.WPFRenderHost.DeviceStates.NoneDepthStencilState);
            m_BasicScene.WPFRenderHost.Device.ImmediateContext.InputAssembler.InputLayout = m_InputLayout;
            m_BasicScene.WPFRenderHost.Device.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.PointList;
            m_BasicScene.WPFRenderHost.Device.ImmediateContext.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(m_DrawFromBuffer, VertexParticle.SizeInBytes, 0));
            m_BasicScene.WPFRenderHost.Device.ImmediateContext.StreamOutput.SetTarget(M_StreamToBuffer, 0);

            m_UpdatePass.Apply(m_BasicScene.WPFRenderHost.Device.ImmediateContext);

            // Update particles on the gpu 
            m_BasicScene.WPFRenderHost.Device.ImmediateContext.DrawAuto();

            // See if we have any newly-spawned particles waiting 
            if (m_NumNew > 0)
            {
                // Copy new particles to vertex buffer and draw them to append them to stream output target 
                DataStream stream;
                m_BasicScene.WPFRenderHost.Device.ImmediateContext.MapSubresource(m_SpawnBuffer, MapMode.WriteDiscard, MapFlags.None, out stream);
                stream.WriteRange(m_NewParticles);
                m_BasicScene.WPFRenderHost.Device.ImmediateContext.UnmapSubresource(m_SpawnBuffer, 0);
                m_BasicScene.WPFRenderHost.Device.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.PointList;
                m_BasicScene.WPFRenderHost.Device.ImmediateContext.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(m_SpawnBuffer, VertexParticle.SizeInBytes, 0));
                m_BasicScene.WPFRenderHost.Device.ImmediateContext.Draw(m_NumNew, 0);
                m_NumNew = 0;
            }

            m_BasicScene.WPFRenderHost.Device.ImmediateContext.StreamOutput.SetTargets(null);

            // Swap vertex buffers 
            Utilities.Swap(ref m_DrawFromBuffer, ref M_StreamToBuffer);
        }

        void Render()
        {
            // Since we just swapped the vertex buffers, particleDrawFrom contains the current state 
            m_BasicScene.WPFRenderHost.Device.ImmediateContext.OutputMerger.SetBlendState(m_BasicScene.WPFRenderHost.DeviceStates.AdditiveState);
            m_BasicScene.WPFRenderHost.Device.ImmediateContext.OutputMerger.SetDepthStencilState(m_BasicScene.WPFRenderHost.DeviceStates.NoneDepthState);
            Vector3 cameraForward = m_BasicScene.SceneManager.Camera.Direction;
            Matrix lookAtMatrix = Matrix.Billboard(Vector3.Zero, m_BasicScene.SceneManager.Camera.Position, Vector3.UnitY, cameraForward);
            m_Effect.GetVariableByName("_view").AsMatrix().SetMatrix(m_BasicScene.SceneManager.Camera.View);
            m_Effect.GetVariableByName("_proj").AsMatrix().SetMatrix(m_BasicScene.SceneManager.Camera.Projection);
            m_Effect.GetVariableByName("_lookAtMatrix").AsMatrix().SetMatrix(lookAtMatrix);
            m_Effect.GetVariableByName("_elapsedSeconds").AsScalar().Set(m_Elapsed);
            m_Effect.GetVariableByName("_camDir").AsVector().Set(cameraForward);
            m_Effect.GetVariableByName("_gravity").AsVector().Set(9.81f);
            m_Effect.GetVariableByName("_texture").AsShaderResource().SetResource(m_ParticleTextureView);
            this.m_Elapsed = 0;


            m_BasicScene.WPFRenderHost.Device.ImmediateContext.InputAssembler.SetVertexBuffers(0, new VertexBufferBinding(m_DrawFromBuffer, VertexParticle.SizeInBytes, 0));
            m_BasicScene.WPFRenderHost.Device.ImmediateContext.InputAssembler.InputLayout = m_InputLayout;
            m_BasicScene.WPFRenderHost.Device.ImmediateContext.InputAssembler.PrimitiveTopology = PrimitiveTopology.PointList;
            m_RenderPass.Apply(m_BasicScene.WPFRenderHost.Device.ImmediateContext);
            m_BasicScene.WPFRenderHost.Device.ImmediateContext.DrawAuto();

            m_BasicScene.WPFRenderHost.Device.ImmediateContext.GeometryShader.Set(null);
        }

        public void Dispose()
        {
            Disposer.RemoveAndDispose(ref m_SpawnBuffer);
            Disposer.RemoveAndDispose(ref m_DrawFromBuffer);
            Disposer.RemoveAndDispose(ref M_StreamToBuffer);
            Disposer.RemoveAndDispose(ref m_ParticleTextureView);
            Disposer.RemoveAndDispose(ref m_InputLayout);
        }
    }
}


#29 unbird   Crossbones+   -  Reputation: 6010

Like
0Likes
Like

Posted 25 July 2013 - 02:33 PM

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 ?

#30 Telanor   Members   -  Reputation: 1358

Like
0Likes
Like

Posted 25 July 2013 - 03:47 PM

Yea the sample works perfectly fine, even in the VS graphics debugger. I tried switching to a non-static version and it still has the same problem. I'd love to provide you with any information I can but I'm not sure there's much to be had. Let me explain in more detail what's going on:

When I run the game normally, after the world loads up, I press a key to spawn 50k particles around me, the code runs, but I see absolutely nothing. Maybe their position is wrong, maybe they're too small, I don't know. So I try to run the VS graphics debugger, start up the game again, spawn the particles, press print screen and then it halts. If I leave the directx debug layer off, it just gives me a generic "External component threw an error" message.

Next I go turn on the debug layer and start it up again (without the graphics debugger). It runs without errors again. Starting it up with the graphics debugger, it now halts before I even have a chance to spawn any particles. It stops on the StreamOutput.SetTarget line in the `Advance` method, giving that warning about the query thing. I've tried making it so draw calls called before any particles have spawned don't run any code, but that still causes the same error once I do spawn the particles.

This is the CPU callstack, I can't imagine it'll be of much help:

callstack.png

I can't get the GPU callstack that the graphics debugger lists since it crashes before I can take a snapshot. I'm not sure where I'd get a D3D debug log from. If you can tell me how to I'll post that up as well.

#31 unbird   Crossbones+   -  Reputation: 6010

Like
0Likes
Like

Posted 25 July 2013 - 05:27 PM

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 ?



#32 GuoLei007   Members   -  Reputation: 118

Like
1Likes
Like

Posted 25 July 2013 - 05:32 PM

 

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? 



#33 Telanor   Members   -  Reputation: 1358

Like
0Likes
Like

Posted 25 July 2013 - 09:40 PM

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()));
	}
}



#34 unbird   Crossbones+   -  Reputation: 6010

Like
0Likes
Like

Posted 26 July 2013 - 10:58 AM

@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.



#35 Telanor   Members   -  Reputation: 1358

Like
1Likes
Like

Posted 27 July 2013 - 03:10 PM

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.

#36 GuoLei007   Members   -  Reputation: 118

Like
1Likes
Like

Posted 28 July 2013 - 05:40 PM

@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.



#37 Krohm   Crossbones+   -  Reputation: 3245

Like
1Likes
Like

Posted 29 July 2013 - 02:22 AM

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.

#38 unbird   Crossbones+   -  Reputation: 6010

Like
0Likes
Like

Posted 02 August 2013 - 02:07 PM

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

Edited by unbird, 02 August 2013 - 03:16 PM.


#39 Telanor   Members   -  Reputation: 1358

Like
0Likes
Like

Posted 08 August 2013 - 08:57 PM

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.

#40 Telanor   Members   -  Reputation: 1358

Like
0Likes
Like

Posted 08 August 2013 - 11:31 PM

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.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS