Skip to content

Commit

Permalink
fix: GPU particles color and transform now match CPU version
Browse files Browse the repository at this point in the history
  • Loading branch information
eonarheim committed Dec 7, 2024
1 parent 655cd8b commit 886e25c
Show file tree
Hide file tree
Showing 7 changed files with 74 additions and 26 deletions.
52 changes: 46 additions & 6 deletions sandbox/tests/gpu-particles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@ 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(500, 500),
pos: ex.vec(100, 0),
z: 1,
emitterType: ex.EmitterType.Circle,
maxParticles: 1000,
particle: {
// transform: ex.ParticleTransform.Local,
minSpeed: 1,
maxSpeed: 10,
minAngle: 3.4,
Expand All @@ -26,17 +27,56 @@ var particles = new ex.GpuParticleEmitter({
endColor: ex.Color.Transparent
},
radius: 1,
emitRate: 1,
emitRate: 100,
isEmitting: true
});

game.input.pointers.primary.on('move', (evt) => {
particles.pos.x = evt.worldPos.x;
particles.pos.y = evt.worldPos.y;
var cpuParticles = new ex.ParticleEmitter({
pos: ex.vec(-100, 0),
z: 1,
emitterType: ex.EmitterType.Circle,
particle: {
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: 100,
isEmitting: true
});

particles.isEmitting = true;
game.add(particles);
// game.add(particles);

var particleParent = new ex.Actor({
pos: ex.vec(400, 400),
width: 10,
height: 10,
color: ex.Color.Red
});
game.add(particleParent);

game.input.pointers.primary.on('move', (evt) => {
particleParent.pos.x = evt.worldPos.x;
particleParent.pos.y = evt.worldPos.y;
});

game.input.pointers.primary.on('wheel', (ev) => {
game.currentScene.camera.zoom += ev.deltaY / 1000;
game.currentScene.camera.zoom = ex.clamp(game.currentScene.camera.zoom, 0.05, 100);
});

particleParent.addChild(particles);
particleParent.addChild(cpuParticles);

game.add(
new ex.Actor({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ void main(){
float dist = 1.0 - length(uv);
float edge = fwidth(dot(uv, uv));
float circle = smoothstep(-edge/2.0, edge/2.0, dist);
vec4 color = mix(beginColor, endColor, 1.0 - lifePct) * startOpacity;
fragColor = color * (fade ? lifePct : 1.0) * circle;
vec3 color = mix(beginColor.rgb, endColor.rgb, 1.0 - lifePct);
fragColor.rgb = color;
fragColor.a = startOpacity * circle * (fade ? lifePct : 1.0);// * mix(beginColor.a, endColor.a, 1.0 - lifePct);
fragColor.rgb *= fragColor.a;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { HTMLImageSource } from '../ExcaliburGraphicsContext';
import { ImageSourceAttributeConstants } from '../../ImageSource';
import { parseImageWrapping } from '../../Wrapping';
import { parseImageFiltering } from '../../Filtering';
import { AffineMatrix } from '../../../Math/affine-matrix';
import { ParticleTransform } from '../../../Particles/Particles';

export class ParticleRenderer implements RendererPlugin {
Expand Down Expand Up @@ -65,7 +64,10 @@ export class ParticleRenderer implements RendererPlugin {

this._shader.use();
this._shader.setUniformMatrix('u_matrix', this._context.ortho);
const transform = renderer.particle.transform === ParticleTransform.Local ? this._context.getTransform() : AffineMatrix.identity();
const transform =
renderer.particle.transform === ParticleTransform.Local
? this._context.getTransform()
: this._context.getTransform().multiply(renderer.emitter.transform.get().inverse);
this._shader.setUniformAffineMatrix('u_transform', transform);
this._shader.setUniformBoolean('fade', renderer.particle.fade ? true : false);
this._shader.setUniformBoolean('useTexture', renderer.particle.graphic ? true : false);
Expand Down Expand Up @@ -108,12 +110,6 @@ export class ParticleRenderer implements RendererPlugin {
// gl.bindTexture(gl.TEXTURE_2D, obstacleTex);
// gl.uniform1i(u_obstacle, 1);

// Blending wont work because ex doesn't have a depth attachment
// gl.enable(gl.DEPTH_TEST);
// gl.enable(gl.BLEND);
// gl.blendEquation(gl.FUNC_ADD);
// gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);

renderer.draw(gl);
}
hasPendingDraws(): boolean {
Expand Down
9 changes: 8 additions & 1 deletion src/engine/Particles/GpuParticleEmitter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { Actor, clamp, Engine, ExcaliburGraphicsContextWebGL, GraphicsComponent, ParticleRenderer, Random, vec, Vector } from '../';
import { Engine } from '../Engine';
import { Actor } from '../Actor';
import { EmitterType } from './EmitterType';
import { ParticleEmitterArgs, ParticleTransform } from './Particles';
import { GpuParticleConfig, GpuParticleRenderer } from './GpuParticleRenderer';
import { GraphicsComponent } from '../Graphics/GraphicsComponent';
import { Random } from '../Math/Random';
import { vec, Vector } from '../Math/vector';
import { clamp } from '../Math';
import { ExcaliburGraphicsContextWebGL } from '../Graphics/Context/ExcaliburGraphicsContextWebGL';
import { ParticleRenderer } from '../Graphics/Context/particle-renderer/particle-renderer';

export class GpuParticleEmitter extends Actor {
public particle: GpuParticleConfig = {
Expand Down
21 changes: 12 additions & 9 deletions src/engine/Particles/GpuParticleRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { TwoPI } from '../Math/util';
import { randomInRange, TwoPI } from '../Math/util';
import { ExcaliburGraphicsContextWebGL } from '../Graphics/Context/ExcaliburGraphicsContextWebGL';
import { GpuParticleEmitter } from './GpuParticleEmitter';
import { ParticleConfig, ParticleTransform } from './Particles';
import { Random } from '../Math/Random';
import { Sprite } from '../Graphics/Sprite';
import { EmitterType } from './EmitterType';
import { assert } from '../Util/Assert';
import { vec } from '../Math/vector';

export interface GpuParticleConfig extends ParticleConfig {
/**
Expand Down Expand Up @@ -164,6 +165,10 @@ export class GpuParticleRenderer {
let countParticle = 0;
for (let i = startIndex; i < endIndex; i += this._numInputFloats) {
const angle = this._random.floating(this.particle.minAngle || 0, this.particle.maxAngle || TwoPI);
const speedX = this._random.floating(this.particle.minSpeed || 0, this.particle.maxSpeed || 0);
const speedY = this._random.floating(this.particle.minSpeed || 0, this.particle.maxSpeed || 0);
const dx = speedX * Math.cos(angle);
const dy = speedY * Math.sin(angle);
let ranX: number = 0;
let ranY: number = 0;
if (this.emitter.emitterType === EmitterType.Rectangle) {
Expand All @@ -174,15 +179,13 @@ export class GpuParticleRenderer {
ranX = radius * Math.cos(angle);
ranY = radius * Math.sin(angle);
}

const tx = this.emitter.transform.apply(vec(ranX, ranY));
const data = [
this.particle.transform === ParticleTransform.Local ? ranX : this.emitter.transform.pos.x + ranX,
this.particle.transform === ParticleTransform.Local ? ranY : this.emitter.transform.pos.y + ranY, // pos in world space
this._random.floating(this.particle.minSpeed || 0, this.particle.maxSpeed || 0),
this._random.floating(this.particle.minSpeed || 0, this.particle.maxSpeed || 0), // velocity
this.particle.randomRotation
? this._random.floating(this.particle.minAngle || 0, this.particle.maxAngle || TwoPI)
: this.particle.rotation || 0, // rotation
this.particle.transform === ParticleTransform.Local ? ranX : tx.x,
this.particle.transform === ParticleTransform.Local ? ranY : tx.y, // pos in world space
dx,
dy, // velocity
this.particle.randomRotation ? randomInRange(0, TwoPI, this._random) : this.particle.rotation || 0, // rotation
this.particle.angularVelocity || 0, // angular velocity
this._particleLife // life
];
Expand Down
Binary file modified src/spec/images/GpuParticlesSpec/particles-wrapped.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified src/spec/images/GpuParticlesSpec/particles.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 886e25c

Please sign in to comment.