//prepare to perform the particle logic void IParticleProcessor.BeginDrawPass(int pass, float deltaTime, int step) { float maxTimeStep = ((float)this.maxParticleTimeStep) * this.systemStepDeltaTime; float time = ((float)(step & (this.maxParticleTimeStep - 1))) * this.systemStepDeltaTime; deltaTime = systemStepDeltaTime; activeRenderPass = this.renderPasses[pass]; frameBufferToggle = !frameBufferToggle; if (activeRenderPass == null) { return; // this can happen when a particle system is disposed } if (this.processorData.FrameShader != null) { (this.processorData.FrameShader as GpuParticleShader).SetConstants(activeRenderPass.globals, deltaTime, time, maxTimeStep); } if (this.processorData.FrameMoveShader != null) { (this.processorData.FrameMoveShader as GpuParticleShader).SetConstants(activeRenderPass.globals, deltaTime, time, maxTimeStep); } if (this.processorData.OnceShader != null) { (this.processorData.OnceShader as GpuParticleShader).SetConstants(activeRenderPass.globals, deltaTime, time, maxTimeStep); } if (this.processorData.OnceCloneShader != null) { (this.processorData.OnceCloneShader as GpuParticleShader).SetConstants(activeRenderPass.globals, deltaTime, time, maxTimeStep); } }
/// <summary></summary> public void Dispose() { DisposeMember(ref positionSizeBufferA); DisposeMember(ref velocityRotationBufferA); DisposeMember(ref userBufferA); DisposeMember(ref colourBufferA); DisposeMember(ref positionSizeBufferB); DisposeMember(ref velocityRotationBufferB); DisposeMember(ref userBufferB); DisposeMember(ref colourBufferB); DisposeMember(ref lifeStoreBufferA); DisposeMember(ref lifeStoreBufferB); DisposeMember(ref mrtGroupA); DisposeMember(ref mrtGroupB); lifeStepParticleData = null; allProcessors = null; activeRenderPass = null; verticesRenderIndex = null; scissorTest = null; backgroundFillPass = null; randomTexture = null; shaderRandomValues = null; }
void IParticleProcessor.Update(int particleCount, float particleCountF, float delatTime, float[] globals, CopyAction[] copyActions, int copyActionCount, AddAction[] addActions, int addActionCount, int step) { //update may be called multiple times for a single frame //so store the update data in GpuParticleRenderPass instances //instances are reused //get a free pass to copy in action data if (renderPassCount == renderPasses.Length) { Array.Resize(ref renderPasses, renderPasses.Length * 2); } GpuParticleRenderPass pass = renderPasses[renderPassCount]; if (pass == null) { //allocate a pass pass = new GpuParticleRenderPass(this.allProcessors); renderPasses[renderPassCount] = pass; } //copy in the action data... pass.ParticleCount = particleCount; pass.ParticleCountF = particleCountF; for (int i = 0; i < globals.Length; i++) { pass.globals[i] = globals[i]; } if (copyActionCount > 0) { //allocate int count = 2; while (copyActionCount > count) { count *= 2; // keep allocations as powers of two } if (pass.CopyData == null || pass.CopyData.Length < copyActionCount) { Array.Resize(ref pass.CopyData, count); } //reset the count pass.CopyCount = copyActionCount; //write the data int i = 0; while (i != copyActionCount) { pass.CopyData[i].X = copyActions[i].indexToF; pass.CopyData[i].Y = copyActions[i].indexFromF; i++; //ZW store the life / age data } } if (addActionCount > 0) { //count the number of actions for each type for (int i = 0; i < addActionCount; i++) { pass.AddLists[addActions[i].cloneTypeIndex + 1].AddCount++; } //allocate the storage for each action by type for (int i = 0; i < pass.AddLists.Length; i++) { int listCount = pass.AddLists[i].AddCount; pass.AddLists[i].AddCount = 0; if (listCount == 0) { continue; } Vector4[] list = pass.AddLists[i].AddData; if (list != null && list.Length >= listCount) { continue; } int count = 4; while (listCount > count) { count *= 2; // keep allocations as powers of two } if (list == null || list.Length < listCount) { Array.Resize(ref pass.AddLists[i].AddData, count); if (pass.AddLists[i].processor == null) { //this processor also sets positions Array.Resize(ref pass.AddLists[i].AddDetails, count); } } } //fill up the data for (int i = 0; i < addActionCount; i++) { ProcessorAddList list = pass.AddLists[addActions[i].cloneTypeIndex + 1]; int index = list.AddCount; list.AddData[index].X = addActions[i].indexF; //when cloneFromIndex is -1, cloneFromIndexF stores the starting x coord list.AddData[index].Y = addActions[i].cloneFromIndexF; //ZW store the life / age data (set in next block, if needed) if (addActions[i].cloneFromIndex == -1) { //store the position of the particle (it's not being cloned) list.AddDetails[index] = addActions[i].spawnDetails; } list.AddCount++; } } //done... //except... //copy in the data to the 'Life storage' list. //this is a separate texture that stores life and age of each particle //this is rather inefficient unfortunately if (usesLifeStorage && (copyActionCount > 0 || addActionCount > 0)) { //unfortunately, there is a lot of int-to-float conversion here //stored step is wrapped to help precision float startStep = ((float)(step & (this.maxParticleTimeStep - 1))) * this.systemStepDeltaTime; //allocate int count = 2; while (copyActionCount + addActionCount > count) { count *= 2; // keep allocations as powers of two } if (pass.LifeData == null || pass.LifeData.Length < copyActionCount + addActionCount) { Array.Resize(ref pass.LifeData, count); } count = 2; while (pass.ParticleCount > count) { count *= 2; } if (lifeStepParticleData == null || lifeStepParticleData.Length < pass.ParticleCount) { Array.Resize(ref lifeStepParticleData, count); } count = 0; Vector3[] data = pass.LifeData; Vector3 v = new Vector3(); Vector2 store = new Vector2(); for (int i = 0; i < pass.AddLists.Length; i++) { pass.AddLists[i].AddCount = 0; } //move a particle for (int i = 0; i < copyActionCount; i++) { v.X = copyActions[i].indexToF; //get it's life data store = lifeStepParticleData[copyActions[i].indexFrom]; //store in case it moves again lifeStepParticleData[copyActions[i].indexTo] = store; v.Y = store.X; v.Z = store.Y; #if DEBUG if (v.Y == 0 && v.Z == 0) { throw new ArgumentException(); } #endif //a copy will read the life / age from the texture //update the CopyData data too //as the ZW values need to store this data pass.CopyData[count].Z = store.X; pass.CopyData[count].W = store.Y; data[count++] = v; } //data is stored as 'index, age, start time' for (int i = 0; i < addActionCount; i++) { v.X = addActions[i].indexF; v.Y = ((float)addActions[i].lifeSteps) * this.systemStepDeltaTime; v.Z = startStep; //update the AddList data too //as the ZW values need to store this data ProcessorAddList list = pass.AddLists[addActions[i].cloneTypeIndex + 1]; list.AddData[list.AddCount].Z = v.Y; list.AddData[list.AddCount].W = v.Z; list.AddCount++; store.X = v.Y; store.Y = v.Z; //need to store this data for particles that are moved (see above) lifeStepParticleData[addActions[i].index] = store; data[count++] = v; } pass.LifeCount = count; } renderPassCount++; }