// Copyright Epic Games, Inc. All Rights Reserved. #include "NiagaraStatelessCommon.ush" #include "/Engine/Private/ComputeShaderUtils.ush" //#include "WaveOpUtil.ush" ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #define PARTICLE_ATTRIBUTE_OUTPUT(TYPE, NAME) int Permutation_##NAME##Component; #define PARTICLE_ATTRIBUTE_OUTPUT_IMPLICIT(TYPE, NAME) int Permutation_##NAME##Component; #define PARTICLE_ATTRIBUTE_TRANSIENT(TYPE, NAME) PARTICLE_ATTRIBUTES #undef PARTICLE_ATTRIBUTE #undef PARTICLE_ATTRIBUTE_OUTPUT_IMPLICIT #undef PARTICLE_ATTRIBUTE_TRANSIENT ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TBD this might produce sub optimal code, needs investigate and is temporary #include "Modules/NiagaraStatelessModule_CalculateAccurateVelocity.ush" #include "Modules/NiagaraStatelessModule_CameraOffset.ush" #include "Modules/NiagaraStatelessModule_DynamicMaterialParameters.ush" #include "Modules/NiagaraStatelessModule_InitializeParticle.ush" #include "Modules/NiagaraStatelessModule_InitialMeshOrientation.ush" #include "Modules/NiagaraStatelessModule_MeshIndex.ush" #include "Modules/NiagaraStatelessModule_MeshRotationRate.ush" #include "Modules/NiagaraStatelessModule_RotateAroundPoint.ush" #include "Modules/NiagaraStatelessModule_ShapeLocation.ush" #include "Modules/NiagaraStatelessModule_ScaleColor.ush" #include "Modules/NiagaraStatelessModule_ScaleRibbonWidth.ush" #include "Modules/NiagaraStatelessModule_ScaleSpriteSize.ush" #include "Modules/NiagaraStatelessModule_ScaleSpriteSizeBySpeed.ush" #include "Modules/NiagaraStatelessModule_ScaleMeshSize.ush" #include "Modules/NiagaraStatelessModule_ScaleMeshSizebySpeed.ush" #include "Modules/NiagaraStatelessModule_SolveVelocitiesAndForces.ush" #include "Modules/NiagaraStatelessModule_SpriteFacingAndAlignment.ush" #include "Modules/NiagaraStatelessModule_SpriteRotationRate.ush" #include "Modules/NiagaraStatelessModule_SubUVAnimation.ush" ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// uint Common_RandomSeed; float Common_SimulationTime; float Common_SimulationDeltaTime; float Common_SimulationInvDeltaTime; uint Common_GPUCountBufferOffset; RWBuffer Common_GPUCountBuffer; DECLARE_SCALAR_ARRAY(uint, SpawnInfo_NumActive, NIAGARA_MAX_GPU_SPAWN_INFOS); DECLARE_SCALAR_ARRAY(uint, SpawnInfo_ParticleOffset, NIAGARA_MAX_GPU_SPAWN_INFOS); DECLARE_SCALAR_ARRAY(uint, SpawnInfo_UniqueOffset, NIAGARA_MAX_GPU_SPAWN_INFOS); DECLARE_SCALAR_ARRAY(float, SpawnInfo_Time, NIAGARA_MAX_GPU_SPAWN_INFOS); DECLARE_SCALAR_ARRAY(float, SpawnInfo_Rate, NIAGARA_MAX_GPU_SPAWN_INFOS); DECLARE_SCALAR_ARRAY(float, SpawnInfo_LifetimeScale, NIAGARA_MAX_GPU_SPAWN_INFOS); DECLARE_SCALAR_ARRAY(float, SpawnInfo_LifetimeBias, NIAGARA_MAX_GPU_SPAWN_INFOS); ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Null_Simulate(inout FStatelessParticle Particle) { } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// [numthreads(THREADGROUP_SIZE, 1, 1)] void StatelessMain(uint3 GroupId : SV_GroupID, int GroupThreadIndex : SV_GroupIndex) { // Convert thread ID into linear thread uint LinearThreadId = GetUnWrappedDispatchThreadId(GroupId, GroupThreadIndex, THREADGROUP_SIZE); // Initialize our particle data FStatelessParticle Particle = (FStatelessParticle)0;; Particle.Age = -1.0f; // Find which spawn info we belong to and fill out details uint ModuleSeedOffset = 0; { uint SpawnInfoIndex = LinearThreadId; for ( int i=0; i < NIAGARA_MAX_GPU_SPAWN_INFOS; ++i ) { const uint SpawnInfoNumActive = GET_SCALAR_ARRAY_ELEMENT(SpawnInfo_NumActive, i); const uint SpawnInfoParticleOffset = GET_SCALAR_ARRAY_ELEMENT(SpawnInfo_ParticleOffset, i); const uint SpawnInfoUniqueOffset = GET_SCALAR_ARRAY_ELEMENT(SpawnInfo_UniqueOffset, i); const float SpawnInfoTime = GET_SCALAR_ARRAY_ELEMENT(SpawnInfo_Time, i); const float SpawnInfoRate = GET_SCALAR_ARRAY_ELEMENT(SpawnInfo_Rate, i); const float SpawnInfoLifetimeScale = GET_SCALAR_ARRAY_ELEMENT(SpawnInfo_LifetimeScale, i); const float SpawnInfoLifetimeBias = GET_SCALAR_ARRAY_ELEMENT(SpawnInfo_LifetimeBias, i); if ( SpawnInfoIndex < SpawnInfoNumActive ) { const uint SpawnParticleIndex = SpawnInfoIndex + SpawnInfoParticleOffset; Particle.UniqueIndex = SpawnInfoIndex + SpawnInfoUniqueOffset + SpawnInfoParticleOffset; Particle.Age = Common_SimulationTime - (SpawnInfoTime + float(SpawnParticleIndex) * SpawnInfoRate); GRandomSeedInternal = FNiagaraStatelessDefinitions::MakeRandomSeed(Common_RandomSeed, Particle.UniqueIndex, ModuleSeedOffset++, 0); Particle.Lifetime = RandomScaleBiasFloat(0, SpawnInfoLifetimeScale, SpawnInfoLifetimeBias); break; } SpawnInfoIndex -= SpawnInfoNumActive; } if ( Particle.Age < 0.0f ) { return; } } // Initialize variables / determine lifetime / etc if ( Particle.Lifetime <= 0.0f || Particle.Age >= Particle.Lifetime ) { return; } Particle.NormalizedAge = Particle.Age / Particle.Lifetime; Particle.PreviousAge = max(Particle.Age - Common_SimulationDeltaTime, 0.0f); Particle.PreviousNormalizedAge = Particle.PreviousAge / Particle.Lifetime; Particle.DeltaTime = Common_SimulationDeltaTime; Particle.InvDeltaTime = Common_SimulationInvDeltaTime; Particle.bAlive = true; Particle.MaterialRandom = RandomFloat(1); // Run Particle Simulate #define PARTICLE_MODULE(NAME) \ GRandomSeedInternal = FNiagaraStatelessDefinitions::MakeRandomSeed(Common_RandomSeed, Particle.UniqueIndex, ModuleSeedOffset++, 0); \ ##NAME##_Simulate(Particle); PARTICLE_MODULES #undef PARTICLE_MODULE if ( !Particle.bAlive ) { return; } // Output Particles that are still alive uint OutputIndex; //WaveInterlockedAddScalar_(Common_GPUCountBuffer[Common_GPUCountBufferOffset], 1, Particle.OutputIndex); InterlockedAdd(Common_GPUCountBuffer[Common_GPUCountBufferOffset], 1, OutputIndex); #define PARTICLE_ATTRIBUTE_OUTPUT(TYPE, NAME) if ( IsValidComponent(Permutation_##NAME##Component) ) { OutputComponentData(OutputIndex, Permutation_##NAME##Component, Particle.##NAME); } #define PARTICLE_ATTRIBUTE_OUTPUT_IMPLICIT(TYPE, NAME) if ( IsValidComponent(Permutation_##NAME##Component) ) { OutputComponentData(OutputIndex, Permutation_##NAME##Component, Particle.##NAME); } #define PARTICLE_ATTRIBUTE_TRANSIENT(TYPE, NAME) PARTICLE_ATTRIBUTES #undef PARTICLE_ATTRIBUTE #undef PARTICLE_ATTRIBUTE_OUTPUT_IMPLICIT #undef PARTICLE_ATTRIBUTE_TRANSIENT }