babylon.quarks 0.17.2 → 0.17.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -1
- package/src/BatchedRenderer.ts +94 -2
- package/src/ParticleSystem.ts +161 -49
- package/src/SpriteBatch.ts +25 -12
- package/src/TrailBatch.ts +167 -93
- package/src/VFXBatch.ts +7 -1
- package/src/index.ts +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "babylon.quarks",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.3",
|
|
4
4
|
"description": "A High-Performance Particle System for Babylon.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/types/index.d.ts",
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
"build:js": "cross-env NODE_ENV=production rollup -c",
|
|
26
26
|
"build": "npm run clean && npm run build:types && npm run build:js",
|
|
27
27
|
"test": "jest",
|
|
28
|
+
"test:coverage": "jest --coverage",
|
|
28
29
|
"prettier": "prettier --write --ignore-unknown **/*.ts"
|
|
29
30
|
},
|
|
30
31
|
"repository": {
|
package/src/BatchedRenderer.ts
CHANGED
|
@@ -30,15 +30,44 @@ export interface VFXBatchSettings {
|
|
|
30
30
|
layerMask: number;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export interface AdaptivePerformanceOptions {
|
|
34
|
+
targetFrameMs: number;
|
|
35
|
+
minQuality: number;
|
|
36
|
+
maxQuality: number;
|
|
37
|
+
decreaseStep: number;
|
|
38
|
+
increaseStep: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface AdaptivePerformanceState extends AdaptivePerformanceOptions {
|
|
42
|
+
enabled: boolean;
|
|
43
|
+
currentQuality: number;
|
|
44
|
+
lastFrameCpuMs: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
33
47
|
export class BatchedRenderer extends TransformNode {
|
|
34
48
|
batches: Array<VFXBatch> = [];
|
|
35
49
|
systemToBatchIndex: Map<IParticleSystem, number> = new Map<IParticleSystem, number>();
|
|
36
50
|
depthTexture: BaseTexture | null = null;
|
|
51
|
+
private adaptivePerformanceState: AdaptivePerformanceState = {
|
|
52
|
+
enabled: false,
|
|
53
|
+
targetFrameMs: 16.7,
|
|
54
|
+
minQuality: 0.35,
|
|
55
|
+
maxQuality: 1,
|
|
56
|
+
decreaseStep: 0.08,
|
|
57
|
+
increaseStep: 0.02,
|
|
58
|
+
currentQuality: 1,
|
|
59
|
+
lastFrameCpuMs: 0,
|
|
60
|
+
};
|
|
61
|
+
private lastAppliedQuality = Number.NaN;
|
|
37
62
|
|
|
38
63
|
constructor(name: string, scene: Scene) {
|
|
39
64
|
super(name, scene);
|
|
40
65
|
}
|
|
41
66
|
|
|
67
|
+
private static clamp(value: number, min: number, max: number): number {
|
|
68
|
+
return Math.max(min, Math.min(max, value));
|
|
69
|
+
}
|
|
70
|
+
|
|
42
71
|
private static equals(a: StoredBatchSettings, b: VFXBatchSettings): boolean {
|
|
43
72
|
return (
|
|
44
73
|
a.materialBlendMode === b.materialBlendMode &&
|
|
@@ -62,6 +91,9 @@ export class BatchedRenderer extends TransformNode {
|
|
|
62
91
|
|
|
63
92
|
addSystem(system: IParticleSystem) {
|
|
64
93
|
(system as unknown as ParticleSystem)._renderer = this;
|
|
94
|
+
if (this.adaptivePerformanceState.enabled) {
|
|
95
|
+
(system as any).setQualityFactor?.(this.adaptivePerformanceState.currentQuality);
|
|
96
|
+
}
|
|
65
97
|
const settings = (system as unknown as ParticleSystem).getRendererSettings();
|
|
66
98
|
for (let i = 0; i < this.batches.length; i++) {
|
|
67
99
|
if (BatchedRenderer.equals(this.batches[i].settings, settings)) {
|
|
@@ -115,13 +147,73 @@ export class BatchedRenderer extends TransformNode {
|
|
|
115
147
|
}
|
|
116
148
|
}
|
|
117
149
|
|
|
150
|
+
configureAdaptivePerformance(options: Partial<AdaptivePerformanceOptions> = {}) {
|
|
151
|
+
const state = this.adaptivePerformanceState;
|
|
152
|
+
const minQuality = BatchedRenderer.clamp(options.minQuality ?? state.minQuality, 0.05, 1);
|
|
153
|
+
const maxQuality = BatchedRenderer.clamp(options.maxQuality ?? state.maxQuality, minQuality, 1);
|
|
154
|
+
state.targetFrameMs = Math.max(options.targetFrameMs ?? state.targetFrameMs, 0.1);
|
|
155
|
+
state.minQuality = minQuality;
|
|
156
|
+
state.maxQuality = maxQuality;
|
|
157
|
+
state.decreaseStep = Math.max(options.decreaseStep ?? state.decreaseStep, 0.001);
|
|
158
|
+
state.increaseStep = Math.max(options.increaseStep ?? state.increaseStep, 0.001);
|
|
159
|
+
state.currentQuality = BatchedRenderer.clamp(state.currentQuality, state.minQuality, state.maxQuality);
|
|
160
|
+
state.enabled = true;
|
|
161
|
+
this.lastAppliedQuality = Number.NaN;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
disableAdaptivePerformance(resetQuality = true) {
|
|
165
|
+
this.adaptivePerformanceState.enabled = false;
|
|
166
|
+
if (resetQuality) {
|
|
167
|
+
this.adaptivePerformanceState.currentQuality = this.adaptivePerformanceState.maxQuality;
|
|
168
|
+
this.applyAdaptiveQuality();
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
getAdaptivePerformanceState(): AdaptivePerformanceState {
|
|
173
|
+
return {...this.adaptivePerformanceState};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private applyAdaptiveQuality() {
|
|
177
|
+
const quality = this.adaptivePerformanceState.currentQuality;
|
|
178
|
+
if (quality === this.lastAppliedQuality) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
for (const ps of this.systemToBatchIndex.keys()) {
|
|
182
|
+
(ps as any).setQualityFactor?.(quality);
|
|
183
|
+
}
|
|
184
|
+
this.lastAppliedQuality = quality;
|
|
185
|
+
}
|
|
186
|
+
|
|
118
187
|
update(delta: number) {
|
|
119
|
-
|
|
188
|
+
const adaptiveState = this.adaptivePerformanceState;
|
|
189
|
+
const frameStart = adaptiveState.enabled ? performance.now() : 0;
|
|
190
|
+
if (adaptiveState.enabled) {
|
|
191
|
+
this.applyAdaptiveQuality();
|
|
192
|
+
}
|
|
193
|
+
for (const ps of this.systemToBatchIndex.keys()) {
|
|
120
194
|
(ps as any).update(delta);
|
|
121
|
-
}
|
|
195
|
+
}
|
|
122
196
|
for (let i = 0; i < this.batches.length; i++) {
|
|
123
197
|
this.batches[i].update();
|
|
124
198
|
}
|
|
199
|
+
if (!adaptiveState.enabled) {
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
adaptiveState.lastFrameCpuMs = performance.now() - frameStart;
|
|
204
|
+
if (adaptiveState.lastFrameCpuMs > adaptiveState.targetFrameMs) {
|
|
205
|
+
adaptiveState.currentQuality = BatchedRenderer.clamp(
|
|
206
|
+
adaptiveState.currentQuality - adaptiveState.decreaseStep,
|
|
207
|
+
adaptiveState.minQuality,
|
|
208
|
+
adaptiveState.maxQuality
|
|
209
|
+
);
|
|
210
|
+
} else {
|
|
211
|
+
adaptiveState.currentQuality = BatchedRenderer.clamp(
|
|
212
|
+
adaptiveState.currentQuality + adaptiveState.increaseStep,
|
|
213
|
+
adaptiveState.minQuality,
|
|
214
|
+
adaptiveState.maxQuality
|
|
215
|
+
);
|
|
216
|
+
}
|
|
125
217
|
}
|
|
126
218
|
|
|
127
219
|
dispose(): void {
|
package/src/ParticleSystem.ts
CHANGED
|
@@ -206,6 +206,8 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
206
206
|
private listeners: {[event: string]: Array<(event: ParticleSystemEvent) => void>} = {};
|
|
207
207
|
private readonly layerMaskProxy: {mask: number};
|
|
208
208
|
private materialRef: any = null;
|
|
209
|
+
private qualityFactor = 1;
|
|
210
|
+
private useFastTrailHistory = true;
|
|
209
211
|
/** @internal **/
|
|
210
212
|
_renderer?: BatchedRenderer;
|
|
211
213
|
|
|
@@ -456,6 +458,7 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
456
458
|
|
|
457
459
|
this.emissionBursts.forEach((burst) => burst.count.startGen(this.memory));
|
|
458
460
|
this.emissionOverDistance.startGen(this.memory);
|
|
461
|
+
this.refreshTrailHistoryMode();
|
|
459
462
|
|
|
460
463
|
this.emitEnded = false;
|
|
461
464
|
this.markForDestroy = false;
|
|
@@ -474,6 +477,7 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
474
477
|
layerMask?: number;
|
|
475
478
|
} = {}
|
|
476
479
|
) {
|
|
480
|
+
/* istanbul ignore if -- rendererSettings is always assigned in the constructor before any code path can call this private method */
|
|
477
481
|
if (!this.rendererSettings) {
|
|
478
482
|
return;
|
|
479
483
|
}
|
|
@@ -534,17 +538,93 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
534
538
|
play() { this.paused = false; }
|
|
535
539
|
stop() { this.restart(); this.pause(); }
|
|
536
540
|
|
|
541
|
+
private refreshTrailHistoryMode() {
|
|
542
|
+
this.useFastTrailHistory = !this.behaviors.some((behavior) => (behavior as any).type === 'WidthOverLength');
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
private ensureTrailHistoryCapacity(particle: TrailParticle, capacity: number) {
|
|
546
|
+
const trailAny = particle as any;
|
|
547
|
+
if (trailAny._trailHistoryCapacity === capacity && trailAny._trailHistoryPositions) {
|
|
548
|
+
return;
|
|
549
|
+
}
|
|
550
|
+
trailAny._trailHistoryCapacity = capacity;
|
|
551
|
+
trailAny._trailHistoryPositions = new Float32Array(capacity * 3);
|
|
552
|
+
trailAny._trailHistorySizes = new Float32Array(capacity);
|
|
553
|
+
trailAny._trailHistoryColors = new Float32Array(capacity * 4);
|
|
554
|
+
trailAny._trailHistoryHead = 0;
|
|
555
|
+
trailAny._trailHistoryCount = 0;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
private resetTrailHistory(particle: TrailParticle) {
|
|
559
|
+
const trailAny = particle as any;
|
|
560
|
+
trailAny._trailHistoryHead = 0;
|
|
561
|
+
trailAny._trailHistoryCount = 0;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
private getTrailHistoryCount(particle: TrailParticle): number {
|
|
565
|
+
const trailAny = particle as any;
|
|
566
|
+
const fastHistoryCount = trailAny._trailHistoryCount;
|
|
567
|
+
if (typeof fastHistoryCount === 'number') {
|
|
568
|
+
return fastHistoryCount;
|
|
569
|
+
}
|
|
570
|
+
return particle.previous.length;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
private updateFastTrailHistory(particle: TrailParticle) {
|
|
574
|
+
const trailAny = particle as any;
|
|
575
|
+
const capacity = Math.max(1, Math.ceil(particle.length));
|
|
576
|
+
this.ensureTrailHistoryCapacity(particle, capacity);
|
|
577
|
+
let head = trailAny._trailHistoryHead as number;
|
|
578
|
+
let count = trailAny._trailHistoryCount as number;
|
|
579
|
+
const positions = trailAny._trailHistoryPositions as Float32Array;
|
|
580
|
+
const sizes = trailAny._trailHistorySizes as Float32Array;
|
|
581
|
+
const colors = trailAny._trailHistoryColors as Float32Array;
|
|
582
|
+
|
|
583
|
+
if (particle.age <= particle.life) {
|
|
584
|
+
const posIndex = head * 3;
|
|
585
|
+
positions[posIndex] = particle.position.x;
|
|
586
|
+
positions[posIndex + 1] = particle.position.y;
|
|
587
|
+
positions[posIndex + 2] = particle.position.z;
|
|
588
|
+
sizes[head] = particle.size.x;
|
|
589
|
+
const colorIndex = head * 4;
|
|
590
|
+
colors[colorIndex] = particle.color.x;
|
|
591
|
+
colors[colorIndex + 1] = particle.color.y;
|
|
592
|
+
colors[colorIndex + 2] = particle.color.z;
|
|
593
|
+
colors[colorIndex + 3] = particle.color.w;
|
|
594
|
+
head = (head + 1) % capacity;
|
|
595
|
+
if (count < capacity) {
|
|
596
|
+
count++;
|
|
597
|
+
}
|
|
598
|
+
} else if (count > 0) {
|
|
599
|
+
count--;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
trailAny._trailHistoryHead = head;
|
|
603
|
+
trailAny._trailHistoryCount = count;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
setQualityFactor(qualityFactor: number) {
|
|
607
|
+
this.qualityFactor = Math.max(0.1, Math.min(1, qualityFactor));
|
|
608
|
+
}
|
|
609
|
+
|
|
537
610
|
private spawn(count: number, emissionState: EmissionState, matrix: Matrix4) {
|
|
538
611
|
tempQ.setFromRotationMatrix(matrix);
|
|
539
612
|
const translation = tempV;
|
|
540
613
|
const scale = tempV2;
|
|
541
614
|
matrix.decompose(translation, tempQ, scale);
|
|
615
|
+
const behaviors = this.behaviors;
|
|
616
|
+
const behaviorCount = behaviors.length;
|
|
617
|
+
const renderMode = this.rendererSettings.renderMode;
|
|
618
|
+
const isTrailMode = renderMode === RenderMode.Trail;
|
|
619
|
+
const timeRatio = emissionState.time / this.duration;
|
|
620
|
+
const trailSettings = isTrailMode ? (this.rendererEmitterSettings as TrailSettings) : undefined;
|
|
621
|
+
const followLocalOrigin = Boolean(trailSettings?.followLocalOrigin);
|
|
542
622
|
|
|
543
623
|
for (let i = 0; i < count; i++) {
|
|
544
624
|
emissionState.burstParticleIndex = i;
|
|
545
625
|
this.particleNum++;
|
|
546
|
-
|
|
547
|
-
if (
|
|
626
|
+
if (this.particles.length < this.particleNum) {
|
|
627
|
+
if (isTrailMode) {
|
|
548
628
|
this.particles.push(new TrailParticle());
|
|
549
629
|
} else {
|
|
550
630
|
this.particles.push(new SpriteParticle());
|
|
@@ -557,15 +637,15 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
557
637
|
this.startColor.genColor(particle.memory, particle.startColor, this.emissionState.time);
|
|
558
638
|
particle.color.copy(particle.startColor);
|
|
559
639
|
this.startSpeed.startGen(particle.memory);
|
|
560
|
-
particle.startSpeed = this.startSpeed.genValue(particle.memory,
|
|
640
|
+
particle.startSpeed = this.startSpeed.genValue(particle.memory, timeRatio);
|
|
561
641
|
this.startLife.startGen(particle.memory);
|
|
562
|
-
particle.life = this.startLife.genValue(particle.memory,
|
|
642
|
+
particle.life = this.startLife.genValue(particle.memory, timeRatio);
|
|
563
643
|
particle.age = 0;
|
|
564
644
|
this.startSize.startGen(particle.memory);
|
|
565
645
|
if (this.startSize.type === 'vec3function') {
|
|
566
|
-
(this.startSize as Vector3Generator).genValue(particle.memory, particle.startSize,
|
|
646
|
+
(this.startSize as Vector3Generator).genValue(particle.memory, particle.startSize, timeRatio);
|
|
567
647
|
} else {
|
|
568
|
-
const size = (this.startSize as FunctionValueGenerator).genValue(particle.memory,
|
|
648
|
+
const size = (this.startSize as FunctionValueGenerator).genValue(particle.memory, timeRatio);
|
|
569
649
|
particle.startSize.set(size, size, size);
|
|
570
650
|
}
|
|
571
651
|
this.startTileIndex.startGen(particle.memory);
|
|
@@ -581,33 +661,40 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
581
661
|
) {
|
|
582
662
|
const sprite = particle as SpriteParticle;
|
|
583
663
|
this.startRotation.startGen(particle.memory);
|
|
584
|
-
if (
|
|
664
|
+
if (renderMode === RenderMode.Mesh) {
|
|
585
665
|
if (!(sprite.rotation instanceof Quaternion)) {
|
|
586
666
|
sprite.rotation = new Quaternion();
|
|
587
667
|
}
|
|
588
668
|
if (this.startRotation.type === 'rotation') {
|
|
589
|
-
this.startRotation.genValue(particle.memory, sprite.rotation as Quaternion, 1,
|
|
669
|
+
this.startRotation.genValue(particle.memory, sprite.rotation as Quaternion, 1, timeRatio);
|
|
590
670
|
} else {
|
|
591
|
-
(sprite.rotation as Quaternion).setFromAxisAngle(UP, this.startRotation.genValue(sprite.memory,
|
|
671
|
+
(sprite.rotation as Quaternion).setFromAxisAngle(UP, this.startRotation.genValue(sprite.memory, timeRatio));
|
|
592
672
|
}
|
|
593
673
|
} else {
|
|
594
674
|
if (this.startRotation.type === 'rotation') {
|
|
595
675
|
sprite.rotation = 0;
|
|
596
676
|
} else {
|
|
597
|
-
sprite.rotation = this.startRotation.genValue(sprite.memory,
|
|
677
|
+
sprite.rotation = this.startRotation.genValue(sprite.memory, timeRatio);
|
|
598
678
|
}
|
|
599
679
|
}
|
|
600
|
-
} else if (
|
|
680
|
+
} else if (isTrailMode && trailSettings) {
|
|
601
681
|
const trail = particle as TrailParticle;
|
|
602
|
-
|
|
603
|
-
trail.length =
|
|
682
|
+
trailSettings.startLength.startGen(trail.memory);
|
|
683
|
+
trail.length = trailSettings.startLength.genValue(trail.memory, timeRatio);
|
|
684
|
+
if (this.useFastTrailHistory) {
|
|
685
|
+
this.ensureTrailHistoryCapacity(trail, Math.max(1, Math.ceil(trail.length)));
|
|
686
|
+
this.resetTrailHistory(trail);
|
|
687
|
+
}
|
|
604
688
|
}
|
|
605
689
|
|
|
606
690
|
this.emitterShape.initialize(particle, emissionState);
|
|
607
691
|
|
|
608
|
-
if (
|
|
692
|
+
if (isTrailMode && followLocalOrigin) {
|
|
609
693
|
const trail = particle as TrailParticle;
|
|
610
|
-
|
|
694
|
+
if (!trail.localPosition) {
|
|
695
|
+
trail.localPosition = new Vector3();
|
|
696
|
+
}
|
|
697
|
+
trail.localPosition.copy(trail.position);
|
|
611
698
|
}
|
|
612
699
|
|
|
613
700
|
if (this.worldSpace) {
|
|
@@ -624,8 +711,8 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
624
711
|
}
|
|
625
712
|
}
|
|
626
713
|
|
|
627
|
-
for (let j = 0; j <
|
|
628
|
-
|
|
714
|
+
for (let j = 0; j < behaviorCount; j++) {
|
|
715
|
+
behaviors[j].initialize(particle, this);
|
|
629
716
|
}
|
|
630
717
|
}
|
|
631
718
|
}
|
|
@@ -697,49 +784,66 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
697
784
|
this.emit(delta, this.emissionState, this.emitter.matrixWorld);
|
|
698
785
|
}
|
|
699
786
|
|
|
787
|
+
const particles = this.particles;
|
|
788
|
+
const behaviorCount = this.behaviors.length;
|
|
789
|
+
const particleCount = this.particleNum;
|
|
700
790
|
this.emitterShape.update(this, delta);
|
|
701
|
-
for (let j = 0; j <
|
|
702
|
-
this.behaviors[j]
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
791
|
+
for (let j = 0; j < behaviorCount; j++) {
|
|
792
|
+
const behavior = this.behaviors[j];
|
|
793
|
+
behavior.frameUpdate(delta);
|
|
794
|
+
for (let i = 0; i < particleCount; i++) {
|
|
795
|
+
const particle = particles[i];
|
|
796
|
+
if (!particle.died) {
|
|
797
|
+
behavior.update(particle, delta);
|
|
706
798
|
}
|
|
707
799
|
}
|
|
708
800
|
}
|
|
709
801
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
802
|
+
const followLocalOrigin =
|
|
803
|
+
this.rendererSettings.renderMode === RenderMode.Trail &&
|
|
804
|
+
(this.rendererEmitterSettings as TrailSettings).followLocalOrigin;
|
|
805
|
+
const emitterMatrix = this.emitter.matrixWorld;
|
|
806
|
+
for (let i = 0; i < particleCount; i++) {
|
|
807
|
+
const particle = particles[i];
|
|
808
|
+
if (followLocalOrigin && (particle as TrailParticle).localPosition) {
|
|
809
|
+
particle.position.copy((particle as TrailParticle).localPosition!);
|
|
810
|
+
if (particle.parentMatrix) {
|
|
811
|
+
particle.position.applyMatrix4(particle.parentMatrix);
|
|
718
812
|
} else {
|
|
719
|
-
|
|
813
|
+
particle.position.applyMatrix4(emitterMatrix);
|
|
720
814
|
}
|
|
721
815
|
} else {
|
|
722
|
-
|
|
816
|
+
particle.position.addScaledVector(particle.velocity, delta * particle.speedModifier);
|
|
723
817
|
}
|
|
724
|
-
|
|
818
|
+
particle.age += delta;
|
|
725
819
|
}
|
|
726
820
|
|
|
727
821
|
if (this.rendererSettings.renderMode === RenderMode.Trail) {
|
|
728
|
-
for (let i = 0; i <
|
|
729
|
-
|
|
822
|
+
for (let i = 0; i < particleCount; i++) {
|
|
823
|
+
const trailParticle = particles[i] as TrailParticle;
|
|
824
|
+
if (this.useFastTrailHistory) {
|
|
825
|
+
this.updateFastTrailHistory(trailParticle);
|
|
826
|
+
} else {
|
|
827
|
+
trailParticle.update();
|
|
828
|
+
}
|
|
730
829
|
}
|
|
731
830
|
}
|
|
732
831
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
this.
|
|
832
|
+
let liveParticleCount = this.particleNum;
|
|
833
|
+
for (let i = 0; i < liveParticleCount; i++) {
|
|
834
|
+
const particle = particles[i];
|
|
835
|
+
if (
|
|
836
|
+
particle.died &&
|
|
837
|
+
(!(particle instanceof TrailParticle) || this.getTrailHistoryCount(particle as TrailParticle) === 0)
|
|
838
|
+
) {
|
|
839
|
+
particles[i] = particles[liveParticleCount - 1];
|
|
840
|
+
particles[liveParticleCount - 1] = particle;
|
|
841
|
+
liveParticleCount--;
|
|
739
842
|
i--;
|
|
740
843
|
this.fire({type: 'particleDied', particleSystem: this, particle: particle});
|
|
741
844
|
}
|
|
742
845
|
}
|
|
846
|
+
this.particleNum = liveParticleCount;
|
|
743
847
|
}
|
|
744
848
|
|
|
745
849
|
emit(delta: number, emissionState: EmissionState, emitterMatrix: Matrix4) {
|
|
@@ -756,17 +860,22 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
756
860
|
}
|
|
757
861
|
|
|
758
862
|
this.normalMatrix.getNormalMatrix(emitterMatrix);
|
|
863
|
+
const emissionBursts = this.emissionBursts;
|
|
864
|
+
const emissionBurstCount = emissionBursts.length;
|
|
865
|
+
const qualityFactor = this.qualityFactor;
|
|
759
866
|
|
|
760
867
|
const totalSpawn = Math.ceil(emissionState.waitEmiting);
|
|
761
868
|
this.spawn(totalSpawn, emissionState, emitterMatrix);
|
|
762
869
|
emissionState.waitEmiting -= totalSpawn;
|
|
763
870
|
|
|
764
871
|
while (
|
|
765
|
-
emissionState.burstIndex <
|
|
766
|
-
|
|
872
|
+
emissionState.burstIndex < emissionBurstCount &&
|
|
873
|
+
emissionBursts[emissionState.burstIndex].time <= emissionState.time
|
|
767
874
|
) {
|
|
768
|
-
|
|
769
|
-
|
|
875
|
+
const burst = emissionBursts[emissionState.burstIndex];
|
|
876
|
+
if (Math.random() < burst.probability) {
|
|
877
|
+
const rawCount = burst.count.genValue(this.memory, this.time);
|
|
878
|
+
const count = qualityFactor >= 0.999 ? rawCount : Math.floor(rawCount * qualityFactor);
|
|
770
879
|
emissionState.isBursting = true;
|
|
771
880
|
emissionState.burstParticleCount = count;
|
|
772
881
|
this.spawn(count, emissionState, emitterMatrix);
|
|
@@ -776,12 +885,14 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
776
885
|
}
|
|
777
886
|
|
|
778
887
|
if (!this.emitEnded) {
|
|
779
|
-
|
|
888
|
+
const timeRatio = emissionState.time / this.duration;
|
|
889
|
+
emissionState.waitEmiting += delta * this.emissionOverTime.genValue(this.memory, timeRatio) * qualityFactor;
|
|
780
890
|
|
|
781
|
-
|
|
891
|
+
const previousWorldPos = emissionState.previousWorldPos;
|
|
892
|
+
if (previousWorldPos !== undefined) {
|
|
782
893
|
this.temp.set(emitterMatrix.elements[12], emitterMatrix.elements[13], emitterMatrix.elements[14]);
|
|
783
|
-
emissionState.travelDistance +=
|
|
784
|
-
const emitPerMeter = this.emissionOverDistance.genValue(this.memory,
|
|
894
|
+
emissionState.travelDistance += previousWorldPos.distanceTo(this.temp);
|
|
895
|
+
const emitPerMeter = this.emissionOverDistance.genValue(this.memory, timeRatio) * qualityFactor;
|
|
785
896
|
if (emissionState.travelDistance * emitPerMeter > 0) {
|
|
786
897
|
const count = Math.floor(emissionState.travelDistance * emitPerMeter);
|
|
787
898
|
emissionState.travelDistance -= count / emitPerMeter;
|
|
@@ -1071,6 +1182,7 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
1071
1182
|
|
|
1072
1183
|
addBehavior(behavior: Behavior) {
|
|
1073
1184
|
this.behaviors.push(behavior);
|
|
1185
|
+
this.refreshTrailHistoryMode();
|
|
1074
1186
|
}
|
|
1075
1187
|
|
|
1076
1188
|
getRendererSettings(): VFXBatchSettings {
|
package/src/SpriteBatch.ts
CHANGED
|
@@ -111,6 +111,7 @@ export class SpriteBatch extends VFXBatch {
|
|
|
111
111
|
|
|
112
112
|
rebuildMaterial(): void {
|
|
113
113
|
const shaderName = `quarksParticle_${this.settings.renderMode}_${Date.now()}`;
|
|
114
|
+
this.lastStretchedSpeedFactor = Number.NaN;
|
|
114
115
|
let vertexShader: string;
|
|
115
116
|
let fragmentShader: string;
|
|
116
117
|
const defines: string[] = [];
|
|
@@ -247,10 +248,14 @@ export class SpriteBatch extends VFXBatch {
|
|
|
247
248
|
private quaternion3_ = new Quaternion();
|
|
248
249
|
private rotationMat_ = new Matrix3();
|
|
249
250
|
private rotationMat2_ = new Matrix3();
|
|
251
|
+
private lastStretchedSpeedFactor = Number.NaN;
|
|
250
252
|
|
|
251
253
|
update(): void {
|
|
252
254
|
let index = 0;
|
|
253
255
|
let particleCount = 0;
|
|
256
|
+
const renderMode = this.settings.renderMode;
|
|
257
|
+
const isMeshRender = renderMode === RenderMode.Mesh;
|
|
258
|
+
const isStretchedRender = renderMode === RenderMode.StretchedBillBoard;
|
|
254
259
|
|
|
255
260
|
const visibleSystems = this.getVisibleSystems();
|
|
256
261
|
for (const system of visibleSystems) {
|
|
@@ -266,15 +271,19 @@ export class SpriteBatch extends VFXBatch {
|
|
|
266
271
|
const rotation = this.quaternion2_;
|
|
267
272
|
const translation = this.vector2_;
|
|
268
273
|
const scale = this.vector3_;
|
|
274
|
+
const systemWorldSpace = system.worldSpace;
|
|
269
275
|
system.emitter.matrixWorld.decompose(translation, rotation, scale);
|
|
270
276
|
this.rotationMat_.setFromMatrix4(system.emitter.matrixWorld);
|
|
277
|
+
const absScaleX = Math.abs(scale.x);
|
|
278
|
+
const absScaleY = Math.abs(scale.y);
|
|
279
|
+
const absScaleZ = Math.abs(scale.z);
|
|
271
280
|
|
|
272
281
|
for (let j = 0; j < particleNum; j++, index++) {
|
|
273
282
|
const particle = particles[j] as SpriteParticle;
|
|
274
283
|
|
|
275
|
-
if (
|
|
284
|
+
if (isMeshRender) {
|
|
276
285
|
let q: Quaternion;
|
|
277
|
-
if (
|
|
286
|
+
if (systemWorldSpace) {
|
|
278
287
|
q = particle.rotation as Quaternion;
|
|
279
288
|
} else {
|
|
280
289
|
let parentQ: Quaternion;
|
|
@@ -296,7 +305,7 @@ export class SpriteBatch extends VFXBatch {
|
|
|
296
305
|
}
|
|
297
306
|
|
|
298
307
|
let vec: Vector3;
|
|
299
|
-
if (
|
|
308
|
+
if (systemWorldSpace) {
|
|
300
309
|
vec = particle.position;
|
|
301
310
|
} else {
|
|
302
311
|
vec = this.vector_;
|
|
@@ -319,7 +328,7 @@ export class SpriteBatch extends VFXBatch {
|
|
|
319
328
|
this.colorBuffer[ci + 3] = particle.color.w;
|
|
320
329
|
|
|
321
330
|
const si = index * 3;
|
|
322
|
-
if (
|
|
331
|
+
if (systemWorldSpace) {
|
|
323
332
|
this.sizeBuffer[si] = particle.size.x;
|
|
324
333
|
this.sizeBuffer[si + 1] = particle.size.y;
|
|
325
334
|
this.sizeBuffer[si + 2] = particle.size.z;
|
|
@@ -329,20 +338,20 @@ export class SpriteBatch extends VFXBatch {
|
|
|
329
338
|
this.sizeBuffer[si + 1] = particle.size.y;
|
|
330
339
|
this.sizeBuffer[si + 2] = particle.size.z;
|
|
331
340
|
} else {
|
|
332
|
-
this.sizeBuffer[si] = particle.size.x *
|
|
333
|
-
this.sizeBuffer[si + 1] = particle.size.y *
|
|
334
|
-
this.sizeBuffer[si + 2] = particle.size.z *
|
|
341
|
+
this.sizeBuffer[si] = particle.size.x * absScaleX;
|
|
342
|
+
this.sizeBuffer[si + 1] = particle.size.y * absScaleY;
|
|
343
|
+
this.sizeBuffer[si + 2] = particle.size.z * absScaleZ;
|
|
335
344
|
}
|
|
336
345
|
}
|
|
337
346
|
|
|
338
347
|
this.uvTileBuffer[index] = particle.uvTile;
|
|
339
348
|
|
|
340
|
-
if (
|
|
349
|
+
if (isStretchedRender && this.velocityBuffer) {
|
|
341
350
|
let speedFactor = (system.rendererEmitterSettings as StretchedBillBoardSettings).speedFactor;
|
|
342
351
|
if (speedFactor === 0) speedFactor = 0.001;
|
|
343
352
|
const lengthFactor = (system.rendererEmitterSettings as StretchedBillBoardSettings).lengthFactor;
|
|
344
353
|
let vel: Vector3;
|
|
345
|
-
if (
|
|
354
|
+
if (systemWorldSpace) {
|
|
346
355
|
vel = particle.velocity;
|
|
347
356
|
} else {
|
|
348
357
|
vel = this.vector_;
|
|
@@ -362,9 +371,13 @@ export class SpriteBatch extends VFXBatch {
|
|
|
362
371
|
}
|
|
363
372
|
}
|
|
364
373
|
|
|
365
|
-
if (
|
|
374
|
+
if (isStretchedRender && this.mesh.material instanceof ShaderMaterial && visibleSystems.length > 0) {
|
|
366
375
|
const speedFactor = (visibleSystems[0].rendererEmitterSettings as StretchedBillBoardSettings).speedFactor ?? 1.0;
|
|
367
|
-
|
|
376
|
+
const clampedSpeedFactor = speedFactor === 0 ? 0.001 : speedFactor;
|
|
377
|
+
if (clampedSpeedFactor !== this.lastStretchedSpeedFactor) {
|
|
378
|
+
this.mesh.material.setFloat('speedFactor', clampedSpeedFactor);
|
|
379
|
+
this.lastStretchedSpeedFactor = clampedSpeedFactor;
|
|
380
|
+
}
|
|
368
381
|
}
|
|
369
382
|
|
|
370
383
|
this.mesh.forcedInstanceCount = index;
|
|
@@ -376,7 +389,7 @@ export class SpriteBatch extends VFXBatch {
|
|
|
376
389
|
this.colorVB.update(this.colorBuffer);
|
|
377
390
|
this.uvTileVB.update(this.uvTileBuffer);
|
|
378
391
|
this.rotationVB.update(this.rotationBuffer);
|
|
379
|
-
if (
|
|
392
|
+
if (isStretchedRender && this.velocityVB && this.velocityBuffer) {
|
|
380
393
|
this.velocityVB.update(this.velocityBuffer);
|
|
381
394
|
}
|
|
382
395
|
}
|
package/src/TrailBatch.ts
CHANGED
|
@@ -27,6 +27,15 @@ export class TrailBatch extends VFXBatch {
|
|
|
27
27
|
private sideVB!: VertexBuffer;
|
|
28
28
|
private widthVB!: VertexBuffer;
|
|
29
29
|
|
|
30
|
+
private getTrailHistoryCount(particle: TrailParticle): number {
|
|
31
|
+
const trailAny = particle as any;
|
|
32
|
+
const fastHistoryCount = trailAny._trailHistoryCount;
|
|
33
|
+
if (typeof fastHistoryCount === 'number') {
|
|
34
|
+
return fastHistoryCount;
|
|
35
|
+
}
|
|
36
|
+
return particle.previous.length;
|
|
37
|
+
}
|
|
38
|
+
|
|
30
39
|
constructor(settings: VFXBatchSettings, scene: Scene) {
|
|
31
40
|
super(settings, scene);
|
|
32
41
|
this.maxParticles = 10000;
|
|
@@ -61,7 +70,7 @@ export class TrailBatch extends VFXBatch {
|
|
|
61
70
|
this.mesh.setVerticesData(VertexBuffer.PositionKind, this.positionBuffer, true);
|
|
62
71
|
this.mesh.setVerticesData(VertexBuffer.UVKind, this.uvBuffer, true);
|
|
63
72
|
this.mesh.setVerticesData(VertexBuffer.ColorKind, this.colorBuffer, true, 4);
|
|
64
|
-
this.mesh.setIndices(
|
|
73
|
+
this.mesh.setIndices(this.indexBuffer.subarray(0, 6), null, true);
|
|
65
74
|
const engine = this.scene.getEngine();
|
|
66
75
|
this.previousVB = new VertexBuffer(engine, this.previousBuffer, 'previous', true, false, 3, false);
|
|
67
76
|
this.nextVB = new VertexBuffer(engine, this.nextBuffer, 'next', true, false, 3, false);
|
|
@@ -162,7 +171,7 @@ export class TrailBatch extends VFXBatch {
|
|
|
162
171
|
const visibleSystems = this.getVisibleSystems();
|
|
163
172
|
for (const system of visibleSystems) {
|
|
164
173
|
for (let j = 0; j < system.particleNum; j++) {
|
|
165
|
-
particleCount += (system.particles[j] as TrailParticle)
|
|
174
|
+
particleCount += this.getTrailHistoryCount(system.particles[j] as TrailParticle) * 2;
|
|
166
175
|
}
|
|
167
176
|
}
|
|
168
177
|
if (particleCount > this.maxParticles) {
|
|
@@ -185,109 +194,177 @@ export class TrailBatch extends VFXBatch {
|
|
|
185
194
|
const vTileCount = this.settings.vTileCount;
|
|
186
195
|
const tileWidth = 1 / uTileCount;
|
|
187
196
|
const tileHeight = 1 / vTileCount;
|
|
197
|
+
const systemWorldSpace = system.worldSpace;
|
|
198
|
+
const objectScale = (Math.abs(scale.x) + Math.abs(scale.y) + Math.abs(scale.z)) / 3;
|
|
188
199
|
|
|
189
200
|
for (let j = 0; j < particleNum; j++) {
|
|
190
201
|
const particle = particles[j] as TrailParticle;
|
|
202
|
+
const particleAny = particle as any;
|
|
203
|
+
const fastHistoryCount = particleAny._trailHistoryCount as number | undefined;
|
|
204
|
+
const fastHistoryCapacity = particleAny._trailHistoryCapacity as number | undefined;
|
|
205
|
+
const fastHistoryHead = particleAny._trailHistoryHead as number | undefined;
|
|
206
|
+
const fastHistoryPositions = particleAny._trailHistoryPositions as Float32Array | undefined;
|
|
207
|
+
const fastHistorySizes = particleAny._trailHistorySizes as Float32Array | undefined;
|
|
208
|
+
const fastHistoryColors = particleAny._trailHistoryColors as Float32Array | undefined;
|
|
209
|
+
const hasFastHistory =
|
|
210
|
+
typeof fastHistoryCount === 'number' &&
|
|
211
|
+
fastHistoryCount > 0 &&
|
|
212
|
+
typeof fastHistoryCapacity === 'number' &&
|
|
213
|
+
typeof fastHistoryHead === 'number' &&
|
|
214
|
+
fastHistoryPositions instanceof Float32Array &&
|
|
215
|
+
fastHistorySizes instanceof Float32Array &&
|
|
216
|
+
fastHistoryColors instanceof Float32Array;
|
|
217
|
+
const historyCapacity = hasFastHistory ? (fastHistoryCapacity as number) : 0;
|
|
218
|
+
const historyHead = hasFastHistory ? (fastHistoryHead as number) : 0;
|
|
219
|
+
const historyPositions = fastHistoryPositions as Float32Array;
|
|
220
|
+
const historySizes = fastHistorySizes as Float32Array;
|
|
221
|
+
const historyColors = fastHistoryColors as Float32Array;
|
|
222
|
+
const particleHistory = particle.previous;
|
|
223
|
+
const particleHistoryLength = hasFastHistory ? fastHistoryCount : particleHistory.length;
|
|
224
|
+
if (particleHistoryLength === 0) {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
191
227
|
const col = particle.uvTile % vTileCount;
|
|
192
228
|
const row = Math.floor(particle.uvTile / vTileCount + 0.001);
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
let
|
|
197
|
-
let
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
let
|
|
208
|
-
|
|
209
|
-
|
|
229
|
+
const particleMatrix = particle.parentMatrix as unknown as Matrix4 | undefined;
|
|
230
|
+
const matrixToUse = particleMatrix ?? system.emitter.matrixWorld;
|
|
231
|
+
|
|
232
|
+
let previousNode = particleHistory.head;
|
|
233
|
+
let currentNode = previousNode;
|
|
234
|
+
let nextNode = currentNode?.next ?? currentNode;
|
|
235
|
+
const oldestFastHistoryIndex = hasFastHistory
|
|
236
|
+
? (historyHead - particleHistoryLength + historyCapacity) % historyCapacity
|
|
237
|
+
: 0;
|
|
238
|
+
|
|
239
|
+
for (let i = 0; i < particleHistoryLength; i++, index += 2) {
|
|
240
|
+
let currentX: number;
|
|
241
|
+
let currentY: number;
|
|
242
|
+
let currentZ: number;
|
|
243
|
+
let currentSize: number;
|
|
244
|
+
let currentColorX: number;
|
|
245
|
+
let currentColorY: number;
|
|
246
|
+
let currentColorZ: number;
|
|
247
|
+
let currentColorW: number;
|
|
248
|
+
let previousX: number;
|
|
249
|
+
let previousY: number;
|
|
250
|
+
let previousZ: number;
|
|
251
|
+
let nextX: number;
|
|
252
|
+
let nextY: number;
|
|
253
|
+
let nextZ: number;
|
|
254
|
+
|
|
255
|
+
if (hasFastHistory) {
|
|
256
|
+
const currentHistoryIndex = (oldestFastHistoryIndex + i) % historyCapacity;
|
|
257
|
+
const previousHistoryIndex = i === 0 ? currentHistoryIndex : (oldestFastHistoryIndex + i - 1) % historyCapacity;
|
|
258
|
+
const nextHistoryIndex =
|
|
259
|
+
i + 1 < particleHistoryLength
|
|
260
|
+
? (oldestFastHistoryIndex + i + 1) % historyCapacity
|
|
261
|
+
: currentHistoryIndex;
|
|
262
|
+
|
|
263
|
+
const currentPosIndex = currentHistoryIndex * 3;
|
|
264
|
+
const previousPosIndex = previousHistoryIndex * 3;
|
|
265
|
+
const nextPosIndex = nextHistoryIndex * 3;
|
|
266
|
+
|
|
267
|
+
currentX = historyPositions[currentPosIndex];
|
|
268
|
+
currentY = historyPositions[currentPosIndex + 1];
|
|
269
|
+
currentZ = historyPositions[currentPosIndex + 2];
|
|
270
|
+
previousX = historyPositions[previousPosIndex];
|
|
271
|
+
previousY = historyPositions[previousPosIndex + 1];
|
|
272
|
+
previousZ = historyPositions[previousPosIndex + 2];
|
|
273
|
+
nextX = historyPositions[nextPosIndex];
|
|
274
|
+
nextY = historyPositions[nextPosIndex + 1];
|
|
275
|
+
nextZ = historyPositions[nextPosIndex + 2];
|
|
276
|
+
|
|
277
|
+
currentSize = historySizes[currentHistoryIndex];
|
|
278
|
+
const currentColorIndex = currentHistoryIndex * 4;
|
|
279
|
+
currentColorX = historyColors[currentColorIndex];
|
|
280
|
+
currentColorY = historyColors[currentColorIndex + 1];
|
|
281
|
+
currentColorZ = historyColors[currentColorIndex + 2];
|
|
282
|
+
currentColorW = historyColors[currentColorIndex + 3];
|
|
210
283
|
} else {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
284
|
+
const previous = previousNode!.data as RecordState;
|
|
285
|
+
const current = currentNode!.data as RecordState;
|
|
286
|
+
const next = nextNode!.data as RecordState;
|
|
287
|
+
currentX = current.position.x;
|
|
288
|
+
currentY = current.position.y;
|
|
289
|
+
currentZ = current.position.z;
|
|
290
|
+
previousX = previous.position.x;
|
|
291
|
+
previousY = previous.position.y;
|
|
292
|
+
previousZ = previous.position.z;
|
|
293
|
+
nextX = next.position.x;
|
|
294
|
+
nextY = next.position.y;
|
|
295
|
+
nextZ = next.position.z;
|
|
296
|
+
currentSize = current.size;
|
|
297
|
+
currentColorX = current.color.x;
|
|
298
|
+
currentColorY = current.color.y;
|
|
299
|
+
currentColorZ = current.color.z;
|
|
300
|
+
currentColorW = current.color.w;
|
|
217
301
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
} else {
|
|
233
|
-
this.vector_.copy(previous.position).applyMatrix4(system.emitter.matrixWorld);
|
|
234
|
-
}
|
|
235
|
-
prevPos = this.vector_;
|
|
236
|
-
}
|
|
237
|
-
this.previousBuffer[pi] = prevPos.x;
|
|
238
|
-
this.previousBuffer[pi + 1] = prevPos.y;
|
|
239
|
-
this.previousBuffer[pi + 2] = prevPos.z;
|
|
240
|
-
this.previousBuffer[pi + 3] = prevPos.x;
|
|
241
|
-
this.previousBuffer[pi + 4] = prevPos.y;
|
|
242
|
-
this.previousBuffer[pi + 5] = prevPos.z;
|
|
243
|
-
|
|
244
|
-
let nextPos: Vector3;
|
|
245
|
-
if (system.worldSpace) {
|
|
246
|
-
nextPos = next.position;
|
|
247
|
-
} else {
|
|
248
|
-
if (particle.parentMatrix) {
|
|
249
|
-
this.vector_.copy(next.position).applyMatrix4(particle.parentMatrix as unknown as Matrix4);
|
|
250
|
-
} else {
|
|
251
|
-
this.vector_.copy(next.position).applyMatrix4(system.emitter.matrixWorld);
|
|
252
|
-
}
|
|
253
|
-
nextPos = this.vector_;
|
|
302
|
+
|
|
303
|
+
if (!systemWorldSpace) {
|
|
304
|
+
this.vector_.set(currentX, currentY, currentZ).applyMatrix4(matrixToUse);
|
|
305
|
+
currentX = this.vector_.x;
|
|
306
|
+
currentY = this.vector_.y;
|
|
307
|
+
currentZ = this.vector_.z;
|
|
308
|
+
this.vector_.set(previousX, previousY, previousZ).applyMatrix4(matrixToUse);
|
|
309
|
+
previousX = this.vector_.x;
|
|
310
|
+
previousY = this.vector_.y;
|
|
311
|
+
previousZ = this.vector_.z;
|
|
312
|
+
this.vector_.set(nextX, nextY, nextZ).applyMatrix4(matrixToUse);
|
|
313
|
+
nextX = this.vector_.x;
|
|
314
|
+
nextY = this.vector_.y;
|
|
315
|
+
nextZ = this.vector_.z;
|
|
254
316
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
this.
|
|
258
|
-
this.
|
|
259
|
-
this.
|
|
260
|
-
this.
|
|
317
|
+
|
|
318
|
+
const pi = index * 3;
|
|
319
|
+
this.positionBuffer[pi] = currentX;
|
|
320
|
+
this.positionBuffer[pi + 1] = currentY;
|
|
321
|
+
this.positionBuffer[pi + 2] = currentZ;
|
|
322
|
+
this.positionBuffer[pi + 3] = currentX;
|
|
323
|
+
this.positionBuffer[pi + 4] = currentY;
|
|
324
|
+
this.positionBuffer[pi + 5] = currentZ;
|
|
325
|
+
|
|
326
|
+
this.previousBuffer[pi] = previousX;
|
|
327
|
+
this.previousBuffer[pi + 1] = previousY;
|
|
328
|
+
this.previousBuffer[pi + 2] = previousZ;
|
|
329
|
+
this.previousBuffer[pi + 3] = previousX;
|
|
330
|
+
this.previousBuffer[pi + 4] = previousY;
|
|
331
|
+
this.previousBuffer[pi + 5] = previousZ;
|
|
332
|
+
|
|
333
|
+
this.nextBuffer[pi] = nextX;
|
|
334
|
+
this.nextBuffer[pi + 1] = nextY;
|
|
335
|
+
this.nextBuffer[pi + 2] = nextZ;
|
|
336
|
+
this.nextBuffer[pi + 3] = nextX;
|
|
337
|
+
this.nextBuffer[pi + 4] = nextY;
|
|
338
|
+
this.nextBuffer[pi + 5] = nextZ;
|
|
261
339
|
|
|
262
340
|
this.sideBuffer[index] = 1;
|
|
263
341
|
this.sideBuffer[index + 1] = -1;
|
|
264
342
|
|
|
265
|
-
if (
|
|
266
|
-
this.widthBuffer[index] =
|
|
267
|
-
this.widthBuffer[index + 1] =
|
|
343
|
+
if (systemWorldSpace || particle.parentMatrix) {
|
|
344
|
+
this.widthBuffer[index] = currentSize;
|
|
345
|
+
this.widthBuffer[index + 1] = currentSize;
|
|
268
346
|
} else {
|
|
269
|
-
|
|
270
|
-
this.widthBuffer[index] =
|
|
271
|
-
this.widthBuffer[index + 1] = current.size * objectScale;
|
|
347
|
+
this.widthBuffer[index] = currentSize * objectScale;
|
|
348
|
+
this.widthBuffer[index + 1] = currentSize * objectScale;
|
|
272
349
|
}
|
|
273
350
|
|
|
274
351
|
const ui = index * 2;
|
|
275
|
-
this.uvBuffer[ui] = (i /
|
|
352
|
+
this.uvBuffer[ui] = (i / particleHistoryLength + col) * tileWidth;
|
|
276
353
|
this.uvBuffer[ui + 1] = (vTileCount - row - 1) * tileHeight;
|
|
277
|
-
this.uvBuffer[ui + 2] = (i /
|
|
354
|
+
this.uvBuffer[ui + 2] = (i / particleHistoryLength + col) * tileWidth;
|
|
278
355
|
this.uvBuffer[ui + 3] = (vTileCount - row) * tileHeight;
|
|
279
356
|
|
|
280
357
|
const cci = index * 4;
|
|
281
|
-
this.colorBuffer[cci] =
|
|
282
|
-
this.colorBuffer[cci + 1] =
|
|
283
|
-
this.colorBuffer[cci + 2] =
|
|
284
|
-
this.colorBuffer[cci + 3] =
|
|
285
|
-
this.colorBuffer[cci + 4] =
|
|
286
|
-
this.colorBuffer[cci + 5] =
|
|
287
|
-
this.colorBuffer[cci + 6] =
|
|
288
|
-
this.colorBuffer[cci + 7] =
|
|
289
|
-
|
|
290
|
-
if (i + 1 <
|
|
358
|
+
this.colorBuffer[cci] = currentColorX;
|
|
359
|
+
this.colorBuffer[cci + 1] = currentColorY;
|
|
360
|
+
this.colorBuffer[cci + 2] = currentColorZ;
|
|
361
|
+
this.colorBuffer[cci + 3] = currentColorW;
|
|
362
|
+
this.colorBuffer[cci + 4] = currentColorX;
|
|
363
|
+
this.colorBuffer[cci + 5] = currentColorY;
|
|
364
|
+
this.colorBuffer[cci + 6] = currentColorZ;
|
|
365
|
+
this.colorBuffer[cci + 7] = currentColorW;
|
|
366
|
+
|
|
367
|
+
if (i + 1 < particleHistoryLength) {
|
|
291
368
|
this.indexBuffer[triangles * 3] = index;
|
|
292
369
|
this.indexBuffer[triangles * 3 + 1] = index + 1;
|
|
293
370
|
this.indexBuffer[triangles * 3 + 2] = index + 2;
|
|
@@ -298,13 +375,10 @@ export class TrailBatch extends VFXBatch {
|
|
|
298
375
|
triangles++;
|
|
299
376
|
}
|
|
300
377
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
if (curIter.value !== undefined) {
|
|
306
|
-
next = curIter.value as RecordState;
|
|
307
|
-
}
|
|
378
|
+
if (!hasFastHistory) {
|
|
379
|
+
previousNode = currentNode;
|
|
380
|
+
currentNode = nextNode;
|
|
381
|
+
nextNode = nextNode?.next ?? nextNode;
|
|
308
382
|
}
|
|
309
383
|
}
|
|
310
384
|
}
|
|
@@ -313,7 +387,7 @@ export class TrailBatch extends VFXBatch {
|
|
|
313
387
|
if (index > 0 && triangles > 0) {
|
|
314
388
|
this.mesh.updateVerticesData(VertexBuffer.PositionKind, this.positionBuffer);
|
|
315
389
|
this.mesh.updateVerticesData(VertexBuffer.UVKind, this.uvBuffer);
|
|
316
|
-
this.mesh.updateIndices(
|
|
390
|
+
this.mesh.updateIndices(this.indexBuffer.subarray(0, triangles * 3));
|
|
317
391
|
this.previousVB.update(this.previousBuffer);
|
|
318
392
|
this.nextVB.update(this.nextBuffer);
|
|
319
393
|
this.sideVB.update(this.sideBuffer);
|
package/src/VFXBatch.ts
CHANGED
|
@@ -81,7 +81,13 @@ export abstract class VFXBatch {
|
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
getVisibleSystems(): IParticleSystem[] {
|
|
84
|
-
|
|
84
|
+
const visibleSystems: IParticleSystem[] = [];
|
|
85
|
+
for (const system of this.systems) {
|
|
86
|
+
if (system.emitter.visible) {
|
|
87
|
+
visibleSystems.push(system);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return visibleSystems;
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
applyDepthTexture(depthTexture: BaseTexture | null): void {
|
package/src/index.ts
CHANGED