Created
December 18, 2017 22:27
-
-
Save alexpana/8c8a906ee072128a1cf5d088bcae98d7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
float FParticleRibbonEmitterInstance::Spawn(float DeltaTime) | |
{ | |
bool bProcessSpawnRate = Spawn_Source(DeltaTime); | |
if (bProcessSpawnRate == false) | |
{ | |
return SpawnFraction; | |
} | |
UParticleLODLevel* LODLevel = SpriteTemplate->LODLevels[0]; | |
check(LODLevel); | |
check(LODLevel->RequiredModule); | |
// Iterate over each trail | |
int32 TrailIdx = 0; | |
float MovementSpawnRate = 0.0f; | |
int32 MovementSpawnCount = 0; | |
float SpawnRate = 0.0f; | |
int32 SpawnCount = 0; | |
int32 BurstCount = 0; | |
float OldLeftover = SpawnFraction; | |
// For now, we are not supporting bursts on trails... | |
bool bProcessBurstList = false; | |
// Figure out spawn rate for this tick. | |
if (bProcessSpawnRate) | |
{ | |
float RateScale = LODLevel->SpawnModule->RateScale.GetValue(EmitterTime, Component) * LODLevel->SpawnModule->GetGlobalRateScale(); | |
float QualityMult = SpriteTemplate->GetQualityLevelSpawnRateMult(); | |
SpawnRate += LODLevel->SpawnModule->Rate.GetValue(EmitterTime, Component) * FMath::Clamp<float>(QualityMult, 0.0f, 1.0); | |
} | |
// Take Bursts into account as well... | |
if (bProcessBurstList) | |
{ | |
int32 Burst = 0; | |
float BurstTime = GetCurrentBurstRateOffset(DeltaTime, Burst); | |
BurstCount += Burst; | |
} | |
const int32 LocalMaxParticleInTrailCount = TrailTypeData->MaxParticleInTrailCount; | |
float SafetyLeftover = OldLeftover; | |
float NewLeftover = OldLeftover + DeltaTime * SpawnRate; | |
int32 SpawnNumber = FMath::FloorToInt(NewLeftover); | |
float SliceIncrement = (SpawnRate > 0.0f) ? (1.f / SpawnRate) : 0.0f; | |
float SpawnStartTime = DeltaTime + OldLeftover * SliceIncrement - SliceIncrement; | |
SpawnFraction = NewLeftover - SpawnNumber; | |
int32 TotalCount = MovementSpawnCount + SpawnNumber + BurstCount; | |
bool bNoLivingParticles = (ActiveParticles == 0); | |
//@todo. Don't allow more than TrailCount trails... | |
if (LocalMaxParticleInTrailCount > 0) | |
{ | |
int32 KillCount = (TotalCount + ActiveParticles) - LocalMaxParticleInTrailCount; | |
if (KillCount > 0) | |
{ | |
KillParticles(TrailIdx, KillCount); | |
} | |
// Don't allow the spawning of more particles than allowed... | |
TotalCount = FMath::Max<int32>(TotalCount,LocalMaxParticleInTrailCount); | |
} | |
// Handle growing arrays. | |
bool bProcessSpawn = true; | |
int32 NewCount = ActiveParticles + TotalCount; | |
if (NewCount >= MaxActiveParticles) | |
{ | |
if (DeltaTime < 0.25f) | |
{ | |
bProcessSpawn = Resize(NewCount + FMath::TruncToInt(FMath::Sqrt((float)NewCount)) + 1); | |
} | |
else | |
{ | |
bProcessSpawn = Resize((NewCount + FMath::TruncToInt(FMath::Sqrt((float)NewCount)) + 1), false); | |
} | |
} | |
if (bProcessSpawn == false) | |
{ | |
return SafetyLeftover; | |
} | |
// Find the start particle of the current trail... | |
FBaseParticle* StartParticle = NULL; | |
int32 StartIndex = -1; | |
FRibbonTypeDataPayload* StartTrailData = NULL; | |
GetTrailStart<FRibbonTypeDataPayload>(TrailIdx, StartIndex, StartTrailData, StartParticle); | |
bNoLivingParticles = (StartParticle == NULL); | |
bool bTilingTrail = !FMath::IsNearlyZero(TrailTypeData->TilingDistance); | |
FParticleEventInstancePayload* EventPayload = NULL; | |
if (LODLevel->EventGenerator) | |
{ | |
EventPayload = (FParticleEventInstancePayload*)GetModuleInstanceData(LODLevel->EventGenerator); | |
if (EventPayload && !EventPayload->bSpawnEventsPresent && !EventPayload->bBurstEventsPresent) | |
{ | |
EventPayload = NULL; | |
} | |
} | |
float ElapsedTime = RunningTime;//SecondsSinceCreation; | |
// Do we have SpawnRate driven spawning? | |
if ((SpawnRate > 0.0f) && (SpawnNumber > 0)) | |
{ | |
float Increment = (SpawnRate > 0.0f) ? (1.f / SpawnRate) : 0.0f; | |
float StartTime = DeltaTime + OldLeftover * Increment - Increment; | |
// Spawn particles. | |
// NOTE: SpawnRate assumes that the ParticleSystemComponent is the 'source' | |
FVector CurrentUp; | |
if (TrailTypeData->RenderAxis == Trails_SourceUp) | |
{ | |
CurrentUp = Component->GetComponentTransform().GetScaledAxis( EAxis::Z ); | |
} | |
else | |
{ | |
CurrentUp = FVector(0.0f, 0.0f, 1.0f); | |
} | |
float InvCount = 1.0f / SpawnNumber; | |
for (int32 SpawnIdx = 0; SpawnIdx < SpawnNumber; SpawnIdx++) | |
{ | |
check(ActiveParticles <= MaxActiveParticles); | |
int32 ParticleIndex = ParticleIndices[ActiveParticles]; | |
DECLARE_PARTICLE_PTR(Particle, ParticleData + ParticleStride * ParticleIndex); | |
FRibbonTypeDataPayload* TrailData = ((FRibbonTypeDataPayload*)((uint8*)Particle + TypeDataOffset)); | |
float SpawnTime = StartTime - SpawnIdx * Increment; | |
float TimeStep = FMath::Clamp<float>(InvCount * (SpawnIdx + 1), 0.0f, 1.0f); | |
float StoredSpawnTime = DeltaTime * TimeStep; | |
PreSpawn(Particle, Location, FVector::ZeroVector); | |
SetDeadIndex(TrailData->TrailIndex, ParticleIndex); | |
if (LODLevel->TypeDataModule) | |
{ | |
UParticleModuleTypeDataBase* pkBase = Cast<UParticleModuleTypeDataBase>(LODLevel->TypeDataModule); | |
pkBase->Spawn(this, TypeDataOffset, SpawnTime, Particle); | |
} | |
for (int32 ModuleIndex = 0; ModuleIndex < LODLevel->SpawnModules.Num(); ModuleIndex++) | |
{ | |
UParticleModule* SpawnModule = LODLevel->SpawnModules[ModuleIndex]; | |
if (SpawnModule->bEnabled) | |
{ | |
UParticleModule* OffsetModule = LODLevel->SpawnModules[ModuleIndex]; | |
SpawnModule->Spawn(this, GetModuleDataOffset(OffsetModule), SpawnTime, Particle); | |
} | |
} | |
PostSpawn(Particle, 1.f - float(SpawnIdx + 1) / float(SpawnNumber), SpawnTime); | |
GetParticleLifetimeAndSize(TrailIdx, Particle, bNoLivingParticles, Particle->OneOverMaxLifetime, Particle->Size.X); | |
Particle->RelativeTime = SpawnTime * Particle->OneOverMaxLifetime; | |
Particle->Size.Y = Particle->Size.X; | |
Particle->Size.Z = Particle->Size.Z; | |
Particle->BaseSize = Particle->Size; | |
if (EventPayload) | |
{ | |
LODLevel->EventGenerator->HandleParticleSpawned(this, EventPayload, Particle); | |
} | |
// Trail specific... | |
// Clear the next and previous - just to be safe | |
TrailData->Flags = TRAIL_EMITTER_SET_NEXT(TrailData->Flags, TRAIL_EMITTER_NULL_NEXT); | |
TrailData->Flags = TRAIL_EMITTER_SET_PREV(TrailData->Flags, TRAIL_EMITTER_NULL_PREV); | |
// Set the trail-specific data on this particle | |
TrailData->TrailIndex = TrailIdx; | |
TrailData->Tangent = -Particle->Velocity * DeltaTime; | |
TrailData->SpawnTime = ElapsedTime + StoredSpawnTime; | |
TrailData->SpawnDelta = SpawnIdx * Increment; | |
// Set the location and up vectors | |
TrailData->Up = CurrentUp; | |
TrailData->bMovementSpawned = false; | |
// If this is the true spawned particle, store off the spawn interpolated count | |
TrailData->bInterpolatedSpawn = false; | |
TrailData->SpawnedTessellationPoints = 1; | |
bool bAddedParticle = false; | |
// Determine which trail to attach to | |
if (bNoLivingParticles) | |
{ | |
// These are the first particles! | |
// Tag it as the 'only' | |
TrailData->Flags = TRAIL_EMITTER_SET_ONLY(TrailData->Flags); | |
TiledUDistanceTraveled[TrailIdx] = 0.0f; | |
TrailData->TiledU = 0.0f; | |
bNoLivingParticles = false; | |
bAddedParticle = true; | |
SetStartIndex(TrailData->TrailIndex, ParticleIndex); | |
} | |
else if (StartParticle) | |
{ | |
bAddedParticle = AddParticleHelper(TrailIdx, | |
StartIndex, (FTrailsBaseTypeDataPayload*)StartTrailData, | |
ParticleIndex, (FTrailsBaseTypeDataPayload*)TrailData | |
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) | |
, Component | |
#endif | |
); | |
} | |
if (bAddedParticle) | |
{ | |
if (bTilingTrail == true) | |
{ | |
if (StartParticle == NULL) | |
{ | |
TrailData->TiledU = 0.0f; | |
} | |
else | |
{ | |
FVector PositionDelta = Particle->Location - StartParticle->Location; | |
TiledUDistanceTraveled[TrailIdx] += PositionDelta.Size(); | |
TrailData->TiledU = TiledUDistanceTraveled[TrailIdx] / TrailTypeData->TilingDistance; | |
//@todo. Is there going to be a problem when distance gets REALLY high? | |
} | |
} | |
StartParticle = Particle; | |
StartIndex = ParticleIndex; | |
StartTrailData = TrailData; | |
ActiveParticles++; | |
if (StartTrailData->Tangent.IsNearlyZero()) | |
{ | |
FBaseParticle* NextSpawnedParticle = NULL; | |
FRibbonTypeDataPayload* NextSpawnedTrailData = NULL; | |
FTrailsBaseTypeDataPayload* TempPayload = NULL; | |
GetParticleInTrail(true, StartParticle, StartTrailData, GET_Next, GET_Spawned, NextSpawnedParticle, TempPayload); | |
NextSpawnedTrailData = (FRibbonTypeDataPayload*)(TempPayload); | |
if (NextSpawnedParticle != NULL) | |
{ | |
FVector PositionDelta = (StartParticle->Location - NextSpawnedParticle->Location); | |
float TimeDelta = StartTrailData->SpawnTime - NextSpawnedTrailData->SpawnTime; | |
StartTrailData->Tangent = PositionDelta / TimeDelta; | |
} | |
} | |
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) | |
if ((int32)ActiveParticles > LocalMaxParticleInTrailCount) | |
{ | |
if (Component && Component->GetWorld()) | |
{ | |
FString ErrorMessage = | |
FString::Printf(TEXT("Ribbon with too many particles: %5d vs. %5d, %s"), | |
ActiveParticles, LocalMaxParticleInTrailCount, | |
Component->Template ? *Component->Template->GetName() : TEXT("No template")); | |
FColor ErrorColor(255,0,0); | |
GEngine->AddOnScreenDebugMessage((uint64)((PTRINT)this), 5.0f, ErrorColor,ErrorMessage); | |
UE_LOG(LogParticles, Log, TEXT("%s"), *ErrorMessage); | |
} | |
} | |
#endif //#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) | |
INC_DWORD_STAT(STAT_TrailParticlesSpawned); | |
if ((TrailTypeData->bEnablePreviousTangentRecalculation == true) | |
&& (TrailTypeData->bTangentRecalculationEveryFrame == false)) | |
{ | |
// Find the 2 next SPAWNED particles in the trail (not interpolated). | |
// If there are 2, then the one about to be spawned will make a chain of 3 | |
// giving us data to better calculate the middle ones tangent. | |
// After doing so, we must also recalculate the tangents of the interpolated | |
// particles in the chain. | |
// The most recent spawned particle in the trail... | |
FBaseParticle* NextSpawnedParticle = NULL; | |
FRibbonTypeDataPayload* NextSpawnedTrailData = NULL; | |
// The second most recent spawned particle in the trail... | |
FBaseParticle* NextNextSpawnedParticle = NULL; | |
FRibbonTypeDataPayload* NextNextSpawnedTrailData = NULL; | |
FTrailsBaseTypeDataPayload* TempPayload = NULL; | |
// Grab the latest two spawned particles in the trail | |
GetParticleInTrail(true, StartParticle, StartTrailData, GET_Next, GET_Spawned, NextSpawnedParticle, TempPayload); | |
NextSpawnedTrailData = (FRibbonTypeDataPayload*)(TempPayload); | |
GetParticleInTrail(true, NextSpawnedParticle, NextSpawnedTrailData, GET_Next, GET_Spawned, NextNextSpawnedParticle, TempPayload); | |
NextNextSpawnedTrailData = (FRibbonTypeDataPayload*)(TempPayload); | |
if (NextSpawnedParticle != NULL) | |
{ | |
FVector NewTangent; | |
if (NextNextSpawnedParticle != NULL) | |
{ | |
// Calculate the new tangent from the previous and next position... | |
// LastSourcePosition will be that position of the first particle that will be spawned this frame | |
FVector PositionDelta = (StartParticle->Location - NextNextSpawnedParticle->Location); | |
float TimeDelta = StartTrailData->SpawnTime - NextNextSpawnedTrailData->SpawnTime; | |
NewTangent = PositionDelta / TimeDelta; | |
NextSpawnedTrailData->Tangent = NewTangent; | |
} | |
else //if (NextNextSpawnedParticle == NULL) | |
{ | |
// This is the second spawned particle in a trail... | |
// Calculate the new tangent from the previous and next position... | |
// LastSourcePosition will be that position of the first particle that will be spawned this frame | |
FVector PositionDelta = (StartParticle->Location - NextSpawnedParticle->Location); | |
float TimeDelta = StartTrailData->SpawnTime - NextSpawnedTrailData->SpawnTime; | |
NewTangent = PositionDelta / TimeDelta; | |
NextSpawnedTrailData->Tangent = NewTangent; | |
} | |
} | |
} | |
TrailSpawnTimes[0] = TrailData->SpawnTime; | |
} | |
else | |
{ | |
check(TEXT("Failed to add particle to trail!!!!")); | |
} | |
INC_DWORD_STAT_BY(STAT_TrailParticles, ActiveParticles); | |
INC_DWORD_STAT(STAT_SpriteParticlesSpawned); | |
} | |
} | |
//TickCount++; | |
return SpawnFraction; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment