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