Browse Source

Adding gpu emitter rate using atomic buffer.

clementlandrin 10 months ago
parent
commit
ccdd8547c7
2 changed files with 43 additions and 12 deletions
  1. 13 9
      hrt/prefab/fx/gpuemitter/BaseSpawn.hx
  2. 30 3
      hrt/prefab/fx/gpuemitter/GPUEmitter.hx

+ 13 - 9
hrt/prefab/fx/gpuemitter/BaseSpawn.hx

@@ -6,13 +6,14 @@ class BaseSpawn extends ComputeUtils {
 			modelView : Mat4, 
 		}>;
 		@param var particleBuffer : RWPartialBuffer<{ speed : Vec3, lifeTime : Float, lifeRatio : Float }>;
+		@param var atomic : RWBuffer<Int>;
 
 		@const var SPEED_NORMAL : Bool;
 		@param var minLifeTime : Float;
 		@param var maxLifeTime : Float;
 		@param var minStartSpeed : Float;
 		@param var maxStartSpeed : Float;
-		@param var rate : Float;
+		@param var rate : Int;
 		@param var absPos : Mat4;
 
 		var lifeTime : Float;
@@ -29,14 +30,17 @@ class BaseSpawn extends ComputeUtils {
 		function main() {
 			var idx = computeVar.globalInvocation.x;
 			if ( particleBuffer[idx].lifeTime < 0.0 ) {
-				batchBuffer[idx].modelView = modelView;
-				var s = vec3(0.0, 0.0, 1.0);
-				if ( SPEED_NORMAL )
-					s = emitNormal;
-				particleBuffer[idx].speed = s * maxStartSpeed;
-				particleBuffer[idx].lifeTime = lifeTime;
-				// Keep in memory duration of particle to normalize curve update.
-				particleBuffer[idx].lifeRatio = 1.0 / lifeTime;
+				var c = atomicAdd(atomic, 0, 1);
+				if ( c < rate ) {
+					batchBuffer[idx].modelView = modelView;
+					var s = vec3(0.0, 0.0, 1.0);
+					if ( SPEED_NORMAL )
+						s = emitNormal;
+					particleBuffer[idx].speed = s * maxStartSpeed;
+					particleBuffer[idx].lifeTime = lifeTime;
+					// Keep in memory duration of particle to normalize curve update.
+					particleBuffer[idx].lifeRatio = 1.0 / lifeTime;
+				}
 			}
 		}
 	}

+ 30 - 3
hrt/prefab/fx/gpuemitter/GPUEmitter.hx

@@ -55,6 +55,7 @@ typedef Data = {
 
 typedef ParticleBuffer = {
 	var buffer : h3d.Buffer;
+	var atomic : h3d.Buffer;
 	var next : ParticleBuffer;
 }
 
@@ -71,9 +72,10 @@ class GPUEmitterObject extends h3d.scene.MeshBatch {
 	var paramTexture : h3d.mat.Texture;
 
 	var particleBuffers : ParticleBuffer; 
-
 	var particleShader : ParticleShader;
 
+	var rateAccumulation : Float = 0.0;
+
 	public function new(data, primitive, materials, ?parent) {
 		super(primitive, null, parent);
 		fxAnim = null;
@@ -112,7 +114,7 @@ class GPUEmitterObject extends h3d.scene.MeshBatch {
 
 		var alloc = hxd.impl.Allocator.get();
 		if ( particleBuffers == null )
-			particleBuffers = { buffer : null, next : null};
+			particleBuffers = { buffer : null, atomic : null, next : null};
 		var particleBuffer = particleBuffers;
 		var p = dataPasses;
 		var particleBufferFormat = hxd.BufferFormat.make([
@@ -140,10 +142,11 @@ class GPUEmitterObject extends h3d.scene.MeshBatch {
 					floats[i * stride + 7] = 0.0;
 				}
 				particleBuffer.buffer = alloc.ofFloats(floats, particleBufferFormat, UniformReadWrite);
+				particleBuffer.atomic = alloc.allocBuffer( 1, hxd.BufferFormat.VEC4_DATA, UniformReadWrite );
 			}
 			p = p.next;
 			if ( p != null && particleBuffer.next == null ) {
-				particleBuffer.next = { buffer : null, next : null};
+				particleBuffer.next = { buffer : null, atomic : null, next : null};
 			}
 
 			particleBuffer = particleBuffer.next;
@@ -207,11 +210,33 @@ class GPUEmitterObject extends h3d.scene.MeshBatch {
 		var p = dataPasses;
 		var particleBuffer = particleBuffers;
 		while ( p != null ) {
+			if ( countBytes == null ) {
+				countBytes = haxe.io.Bytes.alloc(4*4);
+				countBytes.setInt32(0, 0);
+				countBytes.setInt32(1, 0);
+				countBytes.setInt32(2, 0);
+				countBytes.setInt32(3, 0);
+			}
+			particleBuffer.atomic.uploadBytes(countBytes, 0, 1);
+
 			var baseSpawn = spawnPass.getShader(BaseSpawn);
 			baseSpawn.maxLifeTime = data.maxLifeTime;
 			baseSpawn.minLifeTime = data.minLifeTime;
 			baseSpawn.maxStartSpeed = data.maxStartSpeed;
 			baseSpawn.minStartSpeed = data.minStartSpeed;
+			if ( data.rate > 0 ) {
+				var r = data.rate * ctx.elapsedTime;
+				baseSpawn.rate = Math.floor(r);
+				if ( baseSpawn.rate == 0 ) {
+					baseSpawn.rate = Math.floor(rateAccumulation);
+					if ( baseSpawn.rate == 0 )
+						rateAccumulation += r;
+					else
+						rateAccumulation = 0.0;
+				} else
+					rateAccumulation = 0.0;
+			} else
+				baseSpawn.rate = instanceCount;
 			switch ( data.speedMode ) {
 			case Normal:
 				baseSpawn.SPEED_NORMAL = true;
@@ -288,6 +313,7 @@ class GPUEmitterObject extends h3d.scene.MeshBatch {
 
 				baseSpawn.batchBuffer = b;
 				baseSpawn.particleBuffer = particleBuffer.buffer;
+				baseSpawn.atomic = particleBuffer.atomic;
 
 				baseSimulation.batchBuffer = b;
 				baseSimulation.particleBuffer = particleBuffer.buffer;
@@ -335,6 +361,7 @@ class GPUEmitterObject extends h3d.scene.MeshBatch {
 		var b = particleBuffers;
 		while ( b != null ) {
 			b.buffer.dispose();
+			b.atomic.dispose();
 			b = b.next;
 		}
 		particleBuffers = null;