瀏覽代碼

GPU particles: Some fixes

Panagiotis Christopoulos Charitos 1 月之前
父節點
當前提交
fd7007be67
共有 3 個文件被更改,包括 52 次插入25 次删除
  1. 48 22
      AnKi/Shaders/GpuParticlesGass.ankiprog
  2. 2 1
      AnKi/Shaders/Include/GpuSceneTypes.h
  3. 2 2
      AnKi/Shaders/Include/ParticleTypes.h

+ 48 - 22
AnKi/Shaders/GpuParticlesGass.ankiprog

@@ -64,7 +64,7 @@ void appendAlive(GpuSceneParticleEmitter2 emitter, Vec3 particlePos, F32 particl
 	}
 }
 
-void simulateParticle(AnKiParticleEmitterProperties props, GpuSceneParticleEmitter2 emitter, F32 life, F32 death)
+void simulateParticle(AnKiParticleEmitterProperties props, GpuSceneParticleEmitter2 emitter, F32 lifeFactor)
 {
 	const F32 m = readProp<F32>(emitter, ParticleProperty::kMass);
 	const Vec3 g = readProp<Vec4>(emitter, GRAVITY_PROP).xyz;
@@ -73,13 +73,12 @@ void simulateParticle(AnKiParticleEmitterProperties props, GpuSceneParticleEmitt
 	Vec3 x = readProp<Vec3>(emitter, ParticleProperty::kPosition);
 	const Vec3 prevX = x;
 
-	const F32 lifeFactor = death / life;
-
 	simulatePhysics(F, m, g_consts.m_dt, v, x);
 
 	// Write
 	writeProp(emitter, ParticleProperty::kVelocity, v);
-	writeProp(emitter, ParticleProperty::kLife, life + g_consts.m_dt);
+	const F32 maxLife = readProp<F32>(emitter, ParticleProperty::kMaxLife);
+	writeProp(emitter, ParticleProperty::kLifeFactor, lifeFactor + g_consts.m_dt / maxLife);
 	writeProp(emitter, ParticleProperty::kPosition, x);
 	writeProp(emitter, ParticleProperty::kPreviousPosition, prevX);
 
@@ -95,7 +94,7 @@ void simulateParticle(AnKiParticleEmitterProperties props, GpuSceneParticleEmitt
 	appendAlive(emitter, x, scale);
 }
 
-void initializeParticle(AnKiParticleEmitterProperties props, GpuSceneParticleEmitter2 emitter, Mat3x4 emitterTrf)
+void initializeParticle(AnKiParticleEmitterProperties props, GpuSceneParticleEmitter2 emitter, Mat3x4 emitterTrf, Bool makeAlive)
 {
 	const Vec3 m = getRandomRange(props.m_minMass, props.m_maxMass);
 
@@ -109,8 +108,8 @@ void initializeParticle(AnKiParticleEmitterProperties props, GpuSceneParticleEmi
 
 	// Store
 	writeProp(emitter, ParticleProperty::kVelocity, v);
-	writeProp(emitter, ParticleProperty::kLife, 0.0);
-	writeProp(emitter, ParticleProperty::kDeathTime, getRandomRange(props.m_minParticleLife, props.m_maxParticleLife));
+	writeProp(emitter, ParticleProperty::kLifeFactor, makeAlive ? 0.0 : 1.0);
+	writeProp(emitter, ParticleProperty::kMaxLife, getRandomRange(props.m_minParticleLife, props.m_maxParticleLife));
 	writeProp(emitter, ParticleProperty::kPosition, x);
 	writeProp(emitter, ParticleProperty::kPreviousPosition, x);
 	writeProp(emitter, ParticleProperty::kMass, m);
@@ -132,37 +131,59 @@ void initializeParticle(AnKiParticleEmitterProperties props, GpuSceneParticleEmi
 
 [numthreads(ANKI_WAVE_SIZE, 1, 1)] void main(COMPUTE_ARGS)
 {
+	particlesInitGlobals(svDispatchThreadId.x);
+
 	GpuSceneParticleEmitter2 emitter = g_gpuSceneParticleEmitters[g_consts.m_gpuSceneParticleEmitterIndex];
 	const AnKiParticleEmitterProperties props = loadAnKiParticleEmitterProperties(g_gpuScene, emitter.m_particleEmitterPropertiesOffset);
 	const Mat3x4 emitterTrf = g_gpuSceneTransforms[emitter.m_worldTransformsIndex];
 
+	const Bool reinit = emitter.m_reinitializeOnNextUpdate;
 	const Bool canEmitThisFrame = emitter.m_timeLeftForNextEmission - g_consts.m_dt <= 0.0;
-	const U32 particleIdx = svDispatchThreadId.x;
-
-	particlesInitGlobals(particleIdx);
 
 	if(emitter.m_particleCount < g_particleIdx)
 	{
-		const F32 life = readProp<F32>(emitter, ParticleProperty::kLife);
-		const F32 deathTime = readProp<F32>(emitter, ParticleProperty::kDeathTime);
+		// Decide what to do
+		Bool init = false;
+		Bool makeAlive = false;
+		Bool simulate = false;
+		F32 lifeFactor = 1.0;
 
-		const Bool alive = life < deathTime;
-		if(alive)
-		{
-			// Simulate the particle
-			simulateParticle(props, emitter, life, deathTime);
-		}
-		else if(canEmitThisFrame)
+		if(reinit)
 		{
 			U32 emittedParticleCount;
 			InterlockedAdd(g_scratch[0].m_emittedParticleCount, 1, emittedParticleCount);
 
-			if(emittedParticleCount < emitter.m_particlesPerEmission)
+			init = true;
+			makeAlive = emittedParticleCount < emitter.m_particlesPerEmission;
+		}
+		else
+		{
+			lifeFactor = readProp<F32>(emitter, ParticleProperty::kLifeFactor);
+			const Bool alive = lifeFactor < 1.0;
+
+			if(alive)
 			{
-				// Emit new particle
-				initializeParticle(props, emitter, emitterTrf);
+				simulate = true;
+			}
+			else if(canEmitThisFrame)
+			{
+				U32 emittedParticleCount;
+				InterlockedAdd(g_scratch[0].m_emittedParticleCount, 1, emittedParticleCount);
+
+				init = emittedParticleCount < emitter.m_particlesPerEmission;
+				makeAlive = true;
 			}
 		}
+
+		// Do the actual work
+		if(simulate)
+		{
+			simulateParticle(props, emitter, lifeFactor);
+		}
+		else if(init)
+		{
+			initializeParticle(props, emitter, emitterTrf, makeAlive);
+		}
 	}
 
 	// Sync to make sure all the atomic ops have finished before the following code reads them
@@ -208,6 +229,11 @@ void initializeParticle(AnKiParticleEmitterProperties props, GpuSceneParticleEmi
 			{
 				g_gpuSceneParticleEmitters[g_consts.m_gpuSceneParticleEmitterIndex].m_timeLeftForNextEmission -= g_consts.m_dt;
 			}
+
+			if(reinit)
+			{
+				g_gpuSceneParticleEmitters[g_consts.m_gpuSceneParticleEmitterIndex].m_reinitializeOnNextUpdate = 0;
+			}
 		}
 	}
 }

+ 2 - 1
AnKi/Shaders/Include/GpuSceneTypes.h

@@ -113,7 +113,8 @@ struct GpuSceneParticleEmitter2
 	U32 m_worldTransformsIndex;
 
 	U32 m_boundingVolumeOffset; // Points to its GpuSceneRenderableBoundingVolume. It's an offset because there are many arrays with bvolumes.
-	U32 m_padding[3];
+	U32 m_reinitializeOnNextUpdate ANKI_CPP_CODE(= 1); // Re-init all particles on next update
+	U32 m_padding[2];
 };
 static_assert(sizeof(GpuSceneParticleEmitter2) % sizeof(Vec4) == 0);
 

+ 2 - 2
AnKi/Shaders/Include/ParticleTypes.h

@@ -38,8 +38,8 @@ struct ParticleSimulationConstants
 enum class ParticleProperty
 {
 	kVelocity, // Vec3
-	kLife, // F32
-	kDeathTime, // F32
+	kLifeFactor, // F32. 0.0: just born, 1.0 dead
+	kMaxLife, // F32
 	kPosition, // Vec3
 	kScale, // Vec3
 	kRotation, // Quat: 4xF32