From 655cd8b69c7275db04d4b188f4cdb36918c4e46e Mon Sep 17 00:00:00 2001 From: Erik Onarheim Date: Thu, 5 Dec 2024 22:42:26 -0600 Subject: [PATCH] fix: gpu particles size is fixed and tolerant of non-integer values --- sandbox/tests/gpu-particles/index.ts | 46 ++++++++---------- .../particle-renderer/particle-vertex.glsl | 4 +- src/engine/Particles/GpuParticleEmitter.ts | 5 +- src/engine/Particles/ParticleEmitter.ts | 4 ++ .../GpuParticlesSpec/particles-wrapped.png | Bin 9570 -> 10310 bytes .../images/GpuParticlesSpec/particles.png | Bin 6498 -> 7533 bytes 6 files changed, 31 insertions(+), 28 deletions(-) diff --git a/sandbox/tests/gpu-particles/index.ts b/sandbox/tests/gpu-particles/index.ts index 55d9054f..7ea00e7b 100644 --- a/sandbox/tests/gpu-particles/index.ts +++ b/sandbox/tests/gpu-particles/index.ts @@ -7,31 +7,27 @@ var game = new ex.Engine({ var swordImg = new ex.ImageSource('https://cdn.rawgit.com/excaliburjs/Excalibur/7dd48128/assets/sword.png'); var particles = new ex.GpuParticleEmitter({ - pos: ex.vec(300, 500), - maxParticles: 10_000, - emitRate: 1000, - radius: 100, - width: 200, - height: 100, - emitterType: ex.EmitterType.Rectangle, + pos: ex.vec(500, 500), + z: 1, + emitterType: ex.EmitterType.Circle, + maxParticles: 1000, particle: { - acc: ex.vec(0, -100), - // opacity: 0.1, - beginColor: ex.Color.Orange, - endColor: ex.Color.Purple, - // fade: true, - focus: ex.vec(0, -400), - focusAccel: 1000, - startSize: 100, - endSize: 0, - life: 3000, - minSpeed: -100, - maxSpeed: 100, - angularVelocity: 2, - randomRotation: true, - transform: ex.ParticleTransform.Local - // graphic: swordImg.toSprite() - } + minSpeed: 1, + maxSpeed: 10, + minAngle: 3.4, + maxAngle: 6, + opacity: 0.7, + life: 2000, + maxSize: 5, + minSize: 5, + startSize: 5, + endSize: 1, + beginColor: ex.Color.fromRGB(23, 106, 170, 0.1), + endColor: ex.Color.Transparent + }, + radius: 1, + emitRate: 1, + isEmitting: true }); game.input.pointers.primary.on('move', (evt) => { @@ -44,7 +40,7 @@ game.add(particles); game.add( new ex.Actor({ - width: 200, + width: 100, height: 100, color: ex.Color.Red, pos: ex.vec(400, 400) diff --git a/src/engine/Graphics/Context/particle-renderer/particle-vertex.glsl b/src/engine/Graphics/Context/particle-renderer/particle-vertex.glsl index 05946c6c..f01a0bc5 100644 --- a/src/engine/Graphics/Context/particle-renderer/particle-vertex.glsl +++ b/src/engine/Graphics/Context/particle-renderer/particle-vertex.glsl @@ -51,7 +51,7 @@ void main(){ float lifePercent = finalLifeMs / maxLifeMs; vec2 transformedPos = (u_matrix * u_transform * vec4(finalPosition,0.,1.)).xy; - + float scale = sqrt(u_transform[0][0] * u_transform[0][0] + u_transform[1][1] * u_transform[1][1]); gl_Position = vec4(transformedPos, 1.0 - lifePercent, 1.); // use life percent to sort z - gl_PointSize = mix(startSize, endSize, 1.0 - lifePercent); + gl_PointSize = mix(startSize, endSize, 1.0 - lifePercent) * scale; } \ No newline at end of file diff --git a/src/engine/Particles/GpuParticleEmitter.ts b/src/engine/Particles/GpuParticleEmitter.ts index 407bb1e2..f3791281 100644 --- a/src/engine/Particles/GpuParticleEmitter.ts +++ b/src/engine/Particles/GpuParticleEmitter.ts @@ -92,7 +92,10 @@ export class GpuParticleEmitter extends Actor { } public emitParticles(particleCount: number) { - this.renderer.emitParticles(particleCount); + if (particleCount <= 0) { + return; + } + this.renderer.emitParticles(particleCount | 0); // coerce to integer } public clearParticles() { diff --git a/src/engine/Particles/ParticleEmitter.ts b/src/engine/Particles/ParticleEmitter.ts index 71c99142..98e2ffc2 100644 --- a/src/engine/Particles/ParticleEmitter.ts +++ b/src/engine/Particles/ParticleEmitter.ts @@ -103,6 +103,10 @@ export class ParticleEmitter extends Actor { * @param particleCount Number of particles to emit right now */ public emitParticles(particleCount: number) { + if (particleCount <= 0) { + return; + } + particleCount = particleCount | 0; // coerce to int for (let i = 0; i < particleCount; i++) { const p = this._createParticle(); if (this?.scene?.world) { diff --git a/src/spec/images/GpuParticlesSpec/particles-wrapped.png b/src/spec/images/GpuParticlesSpec/particles-wrapped.png index 05467eccf7b4a4ff745da93b8801112a44ac7bc3..7c7761942a4ed0592ffbd5bf99e23dbcbf94fff3 100644 GIT binary patch literal 10310 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 vHfq}u()z4*}Q$iB}QT?zp diff --git a/src/spec/images/GpuParticlesSpec/particles.png b/src/spec/images/GpuParticlesSpec/particles.png index 1a78e8e2e55d850a0955fdffdc4c9a6a8ceab54f..797ed1000b621861967ab91e8b2d88e93e5fc66e 100644 GIT binary patch literal 7533 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 -- 2.51.2