babylon.quarks 0.17.9 → 0.18.1
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/dist/babylon.quarks.cjs +1 -1
- package/dist/babylon.quarks.cjs.map +1 -1
- package/dist/babylon.quarks.esm.js +1 -1
- package/dist/babylon.quarks.esm.js.map +1 -1
- package/dist/babylon.quarks.umd.min.js +1 -1
- package/dist/babylon.quarks.umd.min.js.map +1 -1
- package/dist/types/index.d.ts +39 -1
- package/package.json +1 -1
- package/src/BatchedRenderer.ts +34 -3
- package/src/ParticleSystem.ts +96 -8
- package/src/QuarksLoader.ts +14 -1
- package/src/QuarksUtil.ts +18 -0
- package/src/SpriteBatch.ts +32 -9
package/dist/types/index.d.ts
CHANGED
|
@@ -823,7 +823,7 @@ interface IEmitter {
|
|
|
823
823
|
visible: boolean;
|
|
824
824
|
matrixWorld: any;
|
|
825
825
|
}
|
|
826
|
-
type ParticleSystemEventType = "emitEnd" | "destroy" | "particleDied";
|
|
826
|
+
type ParticleSystemEventType = "emitEnd" | "finished" | "destroy" | "particleDied";
|
|
827
827
|
interface ParticleSystemEvent {
|
|
828
828
|
type: ParticleSystemEventType;
|
|
829
829
|
particleSystem: IParticleSystem;
|
|
@@ -877,6 +877,12 @@ interface IParticleSystem {
|
|
|
877
877
|
rendererEmitterSettings: RendererEmitterSettings;
|
|
878
878
|
emissionState: EmissionState;
|
|
879
879
|
paused: boolean;
|
|
880
|
+
/** True after `endEmit()` — emission window closed (non-looping duration elapsed). */
|
|
881
|
+
readonly isEmitEnded: boolean;
|
|
882
|
+
/** Whether more particles can still spawn (bursts, rate, distance). */
|
|
883
|
+
hasPendingEmission(): boolean;
|
|
884
|
+
/** Non-looping system with no live particles and no pending emission. */
|
|
885
|
+
isFinished(): boolean;
|
|
880
886
|
pause(): void;
|
|
881
887
|
stop(): void;
|
|
882
888
|
play(): void;
|
|
@@ -2382,6 +2388,16 @@ declare class BatchedRenderer extends TransformNode {
|
|
|
2382
2388
|
getAdaptivePerformanceState(): AdaptivePerformanceState;
|
|
2383
2389
|
private applyAdaptiveQuality;
|
|
2384
2390
|
update(delta: number): void;
|
|
2391
|
+
/** Rebuild instance buffers from current particle state without advancing simulation. */
|
|
2392
|
+
refreshBatches(): void;
|
|
2393
|
+
/** Per-batch particle vs GPU instance counts — for diagnosing stale render state. */
|
|
2394
|
+
getBatchRenderStats(): Array<{
|
|
2395
|
+
batchIndex: number;
|
|
2396
|
+
renderMode: RenderMode;
|
|
2397
|
+
instanceCount: number;
|
|
2398
|
+
particleCount: number;
|
|
2399
|
+
systemNames: string[];
|
|
2400
|
+
}>;
|
|
2385
2401
|
dispose(): void;
|
|
2386
2402
|
}
|
|
2387
2403
|
|
|
@@ -2415,6 +2431,8 @@ declare class SpriteBatch extends VFXBatch {
|
|
|
2415
2431
|
private rotationMat2_;
|
|
2416
2432
|
private lastStretchedSpeedFactor;
|
|
2417
2433
|
update(): void;
|
|
2434
|
+
/** Pushes a zero-alpha instance so stale instancing data cannot linger on screen. */
|
|
2435
|
+
private uploadClearedInstance;
|
|
2418
2436
|
dispose(): void;
|
|
2419
2437
|
}
|
|
2420
2438
|
|
|
@@ -2615,6 +2633,7 @@ declare class ParticleSystem implements IParticleSystem {
|
|
|
2615
2633
|
private prewarmed;
|
|
2616
2634
|
private emitEnded;
|
|
2617
2635
|
private markForDestroy;
|
|
2636
|
+
private finishedEventFired;
|
|
2618
2637
|
private startDelayTimeLeft;
|
|
2619
2638
|
private previousEmitterPos?;
|
|
2620
2639
|
private tempEmitterPos;
|
|
@@ -2626,10 +2645,17 @@ declare class ParticleSystem implements IParticleSystem {
|
|
|
2626
2645
|
private materialRef;
|
|
2627
2646
|
private qualityFactor;
|
|
2628
2647
|
private useFastTrailHistory;
|
|
2648
|
+
private simulationAccumulator;
|
|
2649
|
+
private destroyed;
|
|
2629
2650
|
/** @internal **/
|
|
2630
2651
|
_renderer?: BatchedRenderer;
|
|
2631
2652
|
set time(time: number);
|
|
2632
2653
|
get time(): number;
|
|
2654
|
+
get isEmitEnded(): boolean;
|
|
2655
|
+
/** Whether continuous or queued emission can still spawn particles before the system is done. */
|
|
2656
|
+
hasPendingEmission(): boolean;
|
|
2657
|
+
/** Non-looping system with no particles left and nothing left to emit. */
|
|
2658
|
+
isFinished(): boolean;
|
|
2633
2659
|
get layers(): {
|
|
2634
2660
|
mask: number;
|
|
2635
2661
|
};
|
|
@@ -2675,6 +2701,9 @@ declare class ParticleSystem implements IParticleSystem {
|
|
|
2675
2701
|
private firstTimeUpdate;
|
|
2676
2702
|
/** @internal */
|
|
2677
2703
|
update(delta: number): void;
|
|
2704
|
+
/** Advances emission, behaviors, motion and culling by one fixed timestep. */
|
|
2705
|
+
private simulateStep;
|
|
2706
|
+
private notifyFinished;
|
|
2678
2707
|
emit(delta: number, emissionState: EmissionState, emitterMatrix: Matrix4): void;
|
|
2679
2708
|
toJSON(metaData?: BabylonMetaData | string, _options?: SerializationOptions): ParticleSystemJSONParameters;
|
|
2680
2709
|
static fromJSON(json: ParticleSystemJSONParameters, meta: BabylonMetaData, dependencies?: {
|
|
@@ -2704,6 +2733,8 @@ declare class QuarksUtil {
|
|
|
2704
2733
|
static restart(root: Node): void;
|
|
2705
2734
|
static setAutoDestroy(root: Node, autoDestroy: boolean): void;
|
|
2706
2735
|
static endEmit(root: Node): void;
|
|
2736
|
+
/** True when every emitter under `root` is a finished non-looping system (or looping). */
|
|
2737
|
+
static isEffectFinished(root: Node): boolean;
|
|
2707
2738
|
private static traverseNode;
|
|
2708
2739
|
}
|
|
2709
2740
|
|
|
@@ -2722,6 +2753,13 @@ declare class QuarksLoader {
|
|
|
2722
2753
|
private extractInterleavedAttribute;
|
|
2723
2754
|
private int32ArrayToFloat32;
|
|
2724
2755
|
private parseImages;
|
|
2756
|
+
/**
|
|
2757
|
+
* `img.url` is already absolute for data/blob URIs and full http(s) URLs — common for
|
|
2758
|
+
* "portable" exports that embed textures as base64 (see ensurePortableTextureUrl in
|
|
2759
|
+
* babylon.quarks-editor). Prepending baseUrl to those turns e.g.
|
|
2760
|
+
* "data:image/png;base64,AAAA" into an invalid path like "/some/dir/data:image/png;base64,AAAA".
|
|
2761
|
+
*/
|
|
2762
|
+
private resolveImageUrl;
|
|
2725
2763
|
private parseTextures;
|
|
2726
2764
|
private mapWrapMode;
|
|
2727
2765
|
private parseMaterials;
|
package/package.json
CHANGED
package/src/BatchedRenderer.ts
CHANGED
|
@@ -194,9 +194,7 @@ export class BatchedRenderer extends TransformNode {
|
|
|
194
194
|
for (const ps of this.systemToBatchIndex.keys()) {
|
|
195
195
|
(ps as ParticleSystem).update(delta);
|
|
196
196
|
}
|
|
197
|
-
|
|
198
|
-
this.batches[i].update();
|
|
199
|
-
}
|
|
197
|
+
this.refreshBatches();
|
|
200
198
|
if (!adaptiveState.enabled) {
|
|
201
199
|
return;
|
|
202
200
|
}
|
|
@@ -217,6 +215,39 @@ export class BatchedRenderer extends TransformNode {
|
|
|
217
215
|
}
|
|
218
216
|
}
|
|
219
217
|
|
|
218
|
+
/** Rebuild instance buffers from current particle state without advancing simulation. */
|
|
219
|
+
refreshBatches(): void {
|
|
220
|
+
for (let i = 0; i < this.batches.length; i++) {
|
|
221
|
+
this.batches[i].update();
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/** Per-batch particle vs GPU instance counts — for diagnosing stale render state. */
|
|
226
|
+
getBatchRenderStats(): Array<{
|
|
227
|
+
batchIndex: number;
|
|
228
|
+
renderMode: RenderMode;
|
|
229
|
+
instanceCount: number;
|
|
230
|
+
particleCount: number;
|
|
231
|
+
systemNames: string[];
|
|
232
|
+
}> {
|
|
233
|
+
return this.batches.map((batch, batchIndex) => {
|
|
234
|
+
let particleCount = 0;
|
|
235
|
+
const systemNames: string[] = [];
|
|
236
|
+
for (const system of batch.systems) {
|
|
237
|
+
const ps = system as ParticleSystem;
|
|
238
|
+
particleCount += ps.particleNum;
|
|
239
|
+
systemNames.push(ps.emitter.name);
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
batchIndex,
|
|
243
|
+
renderMode: batch.settings.renderMode,
|
|
244
|
+
instanceCount: batch.mesh.forcedInstanceCount ?? 0,
|
|
245
|
+
particleCount,
|
|
246
|
+
systemNames,
|
|
247
|
+
};
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
220
251
|
dispose(): void {
|
|
221
252
|
for (const batch of this.batches) {
|
|
222
253
|
batch.dispose();
|
package/src/ParticleSystem.ts
CHANGED
|
@@ -56,6 +56,8 @@ const tempQ = new Quaternion();
|
|
|
56
56
|
const tempV = new Vector3();
|
|
57
57
|
const tempV2 = new Vector3();
|
|
58
58
|
const PREWARM_FPS = 60;
|
|
59
|
+
const SIMULATION_STEP = 1 / PREWARM_FPS;
|
|
60
|
+
const MAX_SIMULATION_STEPS_PER_FRAME = 8;
|
|
59
61
|
|
|
60
62
|
const DEFAULT_POSITIONS = new Float32Array([
|
|
61
63
|
-0.5, -0.5, 0,
|
|
@@ -205,6 +207,7 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
205
207
|
private prewarmed: boolean;
|
|
206
208
|
private emitEnded: boolean;
|
|
207
209
|
private markForDestroy: boolean;
|
|
210
|
+
private finishedEventFired = false;
|
|
208
211
|
private startDelayTimeLeft = 0;
|
|
209
212
|
private previousEmitterPos?: Vector3;
|
|
210
213
|
private tempEmitterPos: Vector3 = new Vector3();
|
|
@@ -216,6 +219,8 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
216
219
|
private materialRef: any = null;
|
|
217
220
|
private qualityFactor = 1;
|
|
218
221
|
private useFastTrailHistory = true;
|
|
222
|
+
private simulationAccumulator = 0;
|
|
223
|
+
private destroyed = false;
|
|
219
224
|
/** @internal **/
|
|
220
225
|
_renderer?: BatchedRenderer;
|
|
221
226
|
|
|
@@ -227,6 +232,52 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
227
232
|
return this.emissionState.time;
|
|
228
233
|
}
|
|
229
234
|
|
|
235
|
+
get isEmitEnded(): boolean {
|
|
236
|
+
return this.emitEnded;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** Whether continuous or queued emission can still spawn particles before the system is done. */
|
|
240
|
+
hasPendingEmission(): boolean {
|
|
241
|
+
if (this.looping) {
|
|
242
|
+
return true;
|
|
243
|
+
}
|
|
244
|
+
if (this.emitEnded) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
if (this.onlyUsedByOther) {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
const state = this.emissionState;
|
|
251
|
+
if (state.waitEmiting > 0) {
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
if (state.burstIndex < this.emissionBursts.length) {
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
if (state.time >= this.duration) {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
const timeRatio = state.time / this.duration;
|
|
261
|
+
if (this.emissionOverTime.genValue(this.memory, timeRatio) > 0) {
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
return this.emissionOverDistance.genValue(this.memory, timeRatio) > 0;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/** Non-looping system with no particles left and nothing left to emit. */
|
|
268
|
+
isFinished(): boolean {
|
|
269
|
+
if (this.looping) {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
if (this.particleNum > 0) {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
if (this.onlyUsedByOther) {
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
return !this.hasPendingEmission();
|
|
279
|
+
}
|
|
280
|
+
|
|
230
281
|
get layers() {
|
|
231
282
|
return this.layerMaskProxy;
|
|
232
283
|
}
|
|
@@ -737,6 +788,10 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
737
788
|
}
|
|
738
789
|
|
|
739
790
|
dispose() {
|
|
791
|
+
if (this.destroyed) {
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
this.destroyed = true;
|
|
740
795
|
if (this._renderer) this._renderer.deleteSystem(this);
|
|
741
796
|
this.emitter.dispose();
|
|
742
797
|
this.fire({type: 'destroy', particleSystem: this});
|
|
@@ -754,6 +809,7 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
754
809
|
this.behaviors.forEach((behavior) => behavior.reset());
|
|
755
810
|
this.emitEnded = false;
|
|
756
811
|
this.markForDestroy = false;
|
|
812
|
+
this.finishedEventFired = false;
|
|
757
813
|
this.prewarmed = false;
|
|
758
814
|
this.emissionBursts.forEach((burst) => burst.count.startGen(this.memory));
|
|
759
815
|
this.emissionOverDistance.startGen(this.memory);
|
|
@@ -761,6 +817,8 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
761
817
|
this.startDelayTimeLeft = this.startDelay.genValue(this.memory, 0);
|
|
762
818
|
this.previousEmitterPos = undefined;
|
|
763
819
|
this.emitterVelocity.set(0, 0, 0);
|
|
820
|
+
this.simulationAccumulator = 0;
|
|
821
|
+
this.destroyed = false;
|
|
764
822
|
}
|
|
765
823
|
|
|
766
824
|
private firstTimeUpdate = true;
|
|
@@ -774,8 +832,7 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
774
832
|
this.emitter.computeWorldMatrix(true);
|
|
775
833
|
}
|
|
776
834
|
|
|
777
|
-
if (this.
|
|
778
|
-
if (this.markForDestroy) this.dispose();
|
|
835
|
+
if (!this.looping && this.finishedEventFired && this.particleNum === 0) {
|
|
779
836
|
return;
|
|
780
837
|
}
|
|
781
838
|
|
|
@@ -815,6 +872,19 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
815
872
|
this.startDelayTimeLeft = 0;
|
|
816
873
|
}
|
|
817
874
|
|
|
875
|
+
this.simulationAccumulator += delta;
|
|
876
|
+
const stepsToRun = Math.min(
|
|
877
|
+
MAX_SIMULATION_STEPS_PER_FRAME,
|
|
878
|
+
Math.floor((this.simulationAccumulator + 1e-9) / SIMULATION_STEP)
|
|
879
|
+
);
|
|
880
|
+
for (let i = 0; i < stepsToRun; i++) {
|
|
881
|
+
this.simulateStep(SIMULATION_STEP);
|
|
882
|
+
}
|
|
883
|
+
this.simulationAccumulator -= stepsToRun * SIMULATION_STEP;
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
/** Advances emission, behaviors, motion and culling by one fixed timestep. */
|
|
887
|
+
private simulateStep(delta: number): void {
|
|
818
888
|
if (!this.onlyUsedByOther) {
|
|
819
889
|
this.emit(delta, this.emissionState, this.emitter.matrixWorld);
|
|
820
890
|
}
|
|
@@ -879,6 +949,21 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
879
949
|
}
|
|
880
950
|
}
|
|
881
951
|
this.particleNum = liveParticleCount;
|
|
952
|
+
this.notifyFinished();
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
private notifyFinished(): void {
|
|
956
|
+
if (!this.isFinished()) {
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
if (!this.finishedEventFired) {
|
|
960
|
+
this.finishedEventFired = true;
|
|
961
|
+
this.fire({type: 'finished', particleSystem: this});
|
|
962
|
+
}
|
|
963
|
+
if (this.autoDestroy) {
|
|
964
|
+
this.markForDestroy = true;
|
|
965
|
+
this.dispose();
|
|
966
|
+
}
|
|
882
967
|
}
|
|
883
968
|
|
|
884
969
|
emit(delta: number, emissionState: EmissionState, emitterMatrix: Matrix4) {
|
|
@@ -899,12 +984,6 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
899
984
|
const emissionBurstCount = emissionBursts.length;
|
|
900
985
|
const qualityFactor = this.qualityFactor;
|
|
901
986
|
|
|
902
|
-
const totalSpawn = Math.floor(emissionState.waitEmiting);
|
|
903
|
-
if (totalSpawn > 0) {
|
|
904
|
-
this.spawn(totalSpawn, emissionState, emitterMatrix);
|
|
905
|
-
emissionState.waitEmiting -= totalSpawn;
|
|
906
|
-
}
|
|
907
|
-
|
|
908
987
|
while (
|
|
909
988
|
emissionState.burstIndex < emissionBurstCount &&
|
|
910
989
|
emissionBursts[emissionState.burstIndex].time <= emissionState.time
|
|
@@ -937,6 +1016,15 @@ export class ParticleSystem implements IParticleSystem {
|
|
|
937
1016
|
}
|
|
938
1017
|
}
|
|
939
1018
|
}
|
|
1019
|
+
|
|
1020
|
+
// Accrue before spawning so replacement particles can appear on the same
|
|
1021
|
+
// frame an old one dies (rate * lifetime ≈ 1 would otherwise flicker).
|
|
1022
|
+
const totalSpawn = Math.floor(emissionState.waitEmiting);
|
|
1023
|
+
if (totalSpawn > 0) {
|
|
1024
|
+
this.spawn(totalSpawn, emissionState, emitterMatrix);
|
|
1025
|
+
emissionState.waitEmiting -= totalSpawn;
|
|
1026
|
+
}
|
|
1027
|
+
|
|
940
1028
|
if (emissionState.previousWorldPos === undefined) emissionState.previousWorldPos = new Vector3();
|
|
941
1029
|
emissionState.previousWorldPos.set(emitterMatrix.elements[12], emitterMatrix.elements[13], emitterMatrix.elements[14]);
|
|
942
1030
|
emissionState.time += delta;
|
package/src/QuarksLoader.ts
CHANGED
|
@@ -255,10 +255,23 @@ export class QuarksLoader {
|
|
|
255
255
|
private parseImages(images: any[], baseUrl: string, _meta: LoadedMeta): void {
|
|
256
256
|
(this as any)._images = {};
|
|
257
257
|
for (const img of images) {
|
|
258
|
-
(this as any)._images[img.uuid] = img.url ? baseUrl
|
|
258
|
+
(this as any)._images[img.uuid] = img.url ? this.resolveImageUrl(baseUrl, img.url) : null;
|
|
259
259
|
}
|
|
260
260
|
}
|
|
261
261
|
|
|
262
|
+
/**
|
|
263
|
+
* `img.url` is already absolute for data/blob URIs and full http(s) URLs — common for
|
|
264
|
+
* "portable" exports that embed textures as base64 (see ensurePortableTextureUrl in
|
|
265
|
+
* babylon.quarks-editor). Prepending baseUrl to those turns e.g.
|
|
266
|
+
* "data:image/png;base64,AAAA" into an invalid path like "/some/dir/data:image/png;base64,AAAA".
|
|
267
|
+
*/
|
|
268
|
+
private resolveImageUrl(baseUrl: string, url: string): string {
|
|
269
|
+
if (/^(data|blob):/i.test(url) || /^[a-z][a-z0-9+.-]*:\/\//i.test(url) || url.startsWith('/')) {
|
|
270
|
+
return url;
|
|
271
|
+
}
|
|
272
|
+
return baseUrl + url;
|
|
273
|
+
}
|
|
274
|
+
|
|
262
275
|
private parseTextures(textures: any[], meta: LoadedMeta): void {
|
|
263
276
|
const images = (this as any)._images || {};
|
|
264
277
|
for (const texDef of textures) {
|
package/src/QuarksUtil.ts
CHANGED
|
@@ -56,6 +56,24 @@ export class QuarksUtil {
|
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/** True when every emitter under `root` is a finished non-looping system (or looping). */
|
|
60
|
+
static isEffectFinished(root: Node): boolean {
|
|
61
|
+
let found = false;
|
|
62
|
+
let finished = true;
|
|
63
|
+
QuarksUtil.runOnAllParticleEmitters(root, (emitter) => {
|
|
64
|
+
found = true;
|
|
65
|
+
const system = emitter.system as unknown as ParticleSystem;
|
|
66
|
+
if (system.looping) {
|
|
67
|
+
finished = false;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (!system.isFinished()) {
|
|
71
|
+
finished = false;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return found && finished;
|
|
75
|
+
}
|
|
76
|
+
|
|
59
77
|
private static traverseNode(node: Node, callback: (node: Node) => void): void {
|
|
60
78
|
callback(node);
|
|
61
79
|
const children = node.getChildren();
|
package/src/SpriteBatch.ts
CHANGED
|
@@ -383,15 +383,38 @@ export class SpriteBatch extends VFXBatch {
|
|
|
383
383
|
// single frame (common with short lifetimes + low emission overlap) causes flicker.
|
|
384
384
|
this.mesh.forcedInstanceCount = index;
|
|
385
385
|
|
|
386
|
-
if (index
|
|
387
|
-
this.
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
386
|
+
if (index === 0) {
|
|
387
|
+
this.uploadClearedInstance(isMeshRender, isStretchedRender);
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
this.offsetVB.update(this.offsetBuffer);
|
|
392
|
+
this.sizeVB.update(this.sizeBuffer);
|
|
393
|
+
this.colorVB.update(this.colorBuffer);
|
|
394
|
+
this.uvTileVB.update(this.uvTileBuffer);
|
|
395
|
+
this.rotationVB.update(this.rotationBuffer);
|
|
396
|
+
if (isStretchedRender && this.velocityVB && this.velocityBuffer) {
|
|
397
|
+
this.velocityVB.update(this.velocityBuffer);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/** Pushes a zero-alpha instance so stale instancing data cannot linger on screen. */
|
|
402
|
+
private uploadClearedInstance(isMeshRender: boolean, isStretchedRender: boolean): void {
|
|
403
|
+
this.colorBuffer[3] = 0;
|
|
404
|
+
this.sizeBuffer[0] = 0;
|
|
405
|
+
this.sizeBuffer[1] = 0;
|
|
406
|
+
this.sizeBuffer[2] = 0;
|
|
407
|
+
this.colorVB.update(this.colorBuffer.subarray(0, 4));
|
|
408
|
+
this.sizeVB.update(this.sizeBuffer.subarray(0, 3));
|
|
409
|
+
this.offsetVB.update(this.offsetBuffer.subarray(0, 3));
|
|
410
|
+
this.uvTileVB.update(this.uvTileBuffer.subarray(0, 1));
|
|
411
|
+
if (isMeshRender) {
|
|
412
|
+
this.rotationVB.update(this.rotationBuffer.subarray(0, 4));
|
|
413
|
+
} else {
|
|
414
|
+
this.rotationVB.update(this.rotationBuffer.subarray(0, 1));
|
|
415
|
+
}
|
|
416
|
+
if (isStretchedRender && this.velocityVB && this.velocityBuffer) {
|
|
417
|
+
this.velocityVB.update(this.velocityBuffer.subarray(0, 4));
|
|
395
418
|
}
|
|
396
419
|
}
|
|
397
420
|
|