@babylonjs/core 9.3.1 → 9.3.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/Engines/AbstractEngine/abstractEngine.textureSelector.d.ts +45 -0
- package/Engines/AbstractEngine/abstractEngine.textureSelector.js +69 -0
- package/Engines/AbstractEngine/abstractEngine.textureSelector.js.map +1 -0
- package/Engines/AbstractEngine/index.d.ts +2 -0
- package/Engines/AbstractEngine/index.js +4 -0
- package/Engines/AbstractEngine/index.js.map +1 -1
- package/Engines/Extensions/engine.textureSelector.d.ts +2 -45
- package/Engines/Extensions/engine.textureSelector.js +8 -68
- package/Engines/Extensions/engine.textureSelector.js.map +1 -1
- package/Engines/abstractEngine.js +2 -2
- package/Engines/abstractEngine.js.map +1 -1
- package/FlowGraph/flowGraph.d.ts +22 -0
- package/FlowGraph/flowGraph.js +11 -0
- package/FlowGraph/flowGraph.js.map +1 -1
- package/FlowGraph/flowGraphCoordinator.d.ts +2 -1
- package/FlowGraph/flowGraphCoordinator.js +4 -2
- package/FlowGraph/flowGraphCoordinator.js.map +1 -1
- package/FlowGraph/flowGraphParser.js +7 -0
- package/FlowGraph/flowGraphParser.js.map +1 -1
- package/FlowGraph/typeDefinitions.d.ts +8 -0
- package/FlowGraph/typeDefinitions.js.map +1 -1
- package/Lights/Clustered/clusteredLightContainer.d.ts +1 -0
- package/Lights/Clustered/clusteredLightContainer.js +19 -0
- package/Lights/Clustered/clusteredLightContainer.js.map +1 -1
- package/Lights/light.d.ts +6 -0
- package/Lights/light.js +8 -0
- package/Lights/light.js.map +1 -1
- package/Lights/spotLight.d.ts +2 -0
- package/Lights/spotLight.js +10 -0
- package/Lights/spotLight.js.map +1 -1
- package/Materials/Background/backgroundMaterial.js +4 -1
- package/Materials/Background/backgroundMaterial.js.map +1 -1
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.js +6 -2
- package/Materials/GaussianSplatting/gaussianSplattingMaterial.js.map +1 -1
- package/Materials/Node/Blocks/Dual/lightBlock.d.ts +8 -0
- package/Materials/Node/Blocks/Dual/lightBlock.js +16 -0
- package/Materials/Node/Blocks/Dual/lightBlock.js.map +1 -1
- package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.js +3 -0
- package/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock.js.map +1 -1
- package/Materials/Node/nodeMaterial.js +4 -1
- package/Materials/Node/nodeMaterial.js.map +1 -1
- package/Materials/PBR/openpbrMaterial.js +4 -1
- package/Materials/PBR/openpbrMaterial.js.map +1 -1
- package/Materials/PBR/pbrBaseMaterial.js +4 -1
- package/Materials/PBR/pbrBaseMaterial.js.map +1 -1
- package/Materials/materialHelper.functions.d.ts +12 -0
- package/Materials/materialHelper.functions.js +24 -0
- package/Materials/materialHelper.functions.js.map +1 -1
- package/Materials/standardMaterial.js +4 -1
- package/Materials/standardMaterial.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.d.ts +13 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.js +26 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMesh.js.map +1 -1
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.d.ts +3 -0
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.js +113 -10
- package/Meshes/GaussianSplatting/gaussianSplattingMeshBase.js.map +1 -1
- package/Misc/tools.js +1 -1
- package/Misc/tools.js.map +1 -1
- package/Particles/gpuParticleSystem.d.ts +35 -2
- package/Particles/gpuParticleSystem.js +272 -6
- package/Particles/gpuParticleSystem.js.map +1 -1
- package/Particles/thinParticleSystem.js +5 -0
- package/Particles/thinParticleSystem.js.map +1 -1
- package/Rendering/depthRenderer.d.ts +8 -0
- package/Rendering/depthRenderer.js +48 -13
- package/Rendering/depthRenderer.js.map +1 -1
- package/Rendering/depthRendererSceneComponent.d.ts +1 -0
- package/Rendering/depthRendererSceneComponent.js +26 -0
- package/Rendering/depthRendererSceneComponent.js.map +1 -1
- package/Shaders/gpuRenderParticles.vertex.js +7 -0
- package/Shaders/gpuRenderParticles.vertex.js.map +1 -1
- package/XR/features/WebXRBodyTracking.d.ts +952 -0
- package/XR/features/WebXRBodyTracking.js +2221 -0
- package/XR/features/WebXRBodyTracking.js.map +1 -0
- package/XR/features/index.d.ts +1 -0
- package/XR/features/index.js +1 -0
- package/XR/features/index.js.map +1 -1
- package/XR/webXRFeaturesManager.d.ts +7 -0
- package/XR/webXRFeaturesManager.js +4 -0
- package/XR/webXRFeaturesManager.js.map +1 -1
- package/package.json +1 -1
- package/sceneComponent.d.ts +1 -0
- package/sceneComponent.js +1 -0
- package/sceneComponent.js.map +1 -1
|
@@ -6,6 +6,7 @@ import { Color4 } from "../Maths/math.color.js";
|
|
|
6
6
|
import { VertexBuffer } from "../Buffers/buffer.js";
|
|
7
7
|
import { type IParticleSystem } from "./IParticleSystem.js";
|
|
8
8
|
import { BaseParticleSystem } from "./baseParticleSystem.js";
|
|
9
|
+
import { ParticleSystem } from "./particleSystem.js";
|
|
9
10
|
import { Attractor } from "./attractor.js";
|
|
10
11
|
import { type IDisposable, Scene } from "../scene.js";
|
|
11
12
|
import { type Effect } from "../Materials/effect.js";
|
|
@@ -45,6 +46,8 @@ export declare class GPUParticleSystem extends BaseParticleSystem implements IDi
|
|
|
45
46
|
private _targetIndex;
|
|
46
47
|
private _sourceBuffer;
|
|
47
48
|
private _targetBuffer;
|
|
49
|
+
/** Set to true when any entry in `_colorGradients` has a `color2` (per-particle random color range). */
|
|
50
|
+
private _hasColorGradientColor2;
|
|
48
51
|
private _currentRenderId;
|
|
49
52
|
private _currentRenderingCameraUniqueId;
|
|
50
53
|
private _started;
|
|
@@ -264,9 +267,10 @@ export declare class GPUParticleSystem extends BaseParticleSystem implements IDi
|
|
|
264
267
|
* Adds a new color gradient
|
|
265
268
|
* @param gradient defines the gradient to use (between 0 and 1)
|
|
266
269
|
* @param color1 defines the color to affect to the specified gradient
|
|
270
|
+
* @param color2 defines an optional second color to be used to produce a random color per particle at the gradient (lerped with color1 using a per-particle random value)
|
|
267
271
|
* @returns the current particle system
|
|
268
272
|
*/
|
|
269
|
-
addColorGradient(gradient: number, color1: Color4): GPUParticleSystem;
|
|
273
|
+
addColorGradient(gradient: number, color1: Color4, color2?: Color4): GPUParticleSystem;
|
|
270
274
|
private _refreshColorGradient;
|
|
271
275
|
/** Force the system to rebuild all gradients that need to be resync */
|
|
272
276
|
forceRefreshGradients(): void;
|
|
@@ -462,7 +466,7 @@ export declare class GPUParticleSystem extends BaseParticleSystem implements IDi
|
|
|
462
466
|
/**
|
|
463
467
|
* @internal
|
|
464
468
|
*/
|
|
465
|
-
static _GetAttributeNamesOrOptions(hasColorGradients?: boolean, isAnimationSheetEnabled?: boolean, isBillboardBased?: boolean, isBillboardStretched?: boolean, isBillboardStretchedLocal?: boolean): string[];
|
|
469
|
+
static _GetAttributeNamesOrOptions(hasColorGradients?: boolean, isAnimationSheetEnabled?: boolean, isBillboardBased?: boolean, isBillboardStretched?: boolean, isBillboardStretchedLocal?: boolean, hasColorGradientColor2?: boolean): string[];
|
|
466
470
|
/**
|
|
467
471
|
* @internal
|
|
468
472
|
*/
|
|
@@ -523,6 +527,35 @@ export declare class GPUParticleSystem extends BaseParticleSystem implements IDi
|
|
|
523
527
|
* @returns the cloned particle system
|
|
524
528
|
*/
|
|
525
529
|
clone(name: string, newEmitter: any, cloneTexture?: boolean): GPUParticleSystem;
|
|
530
|
+
/**
|
|
531
|
+
* Creates a new GPUParticleSystem from an existing CPU ParticleSystem, copying all shared properties.
|
|
532
|
+
* Features that are not supported on the GPU (sub-emitters, custom `startDirectionFunction` /
|
|
533
|
+
* `startPositionFunction`, `customShader`, ramp/remap gradients) are logged as warnings and skipped.
|
|
534
|
+
* Flow maps are converted: the CPU `FlowMap` image data is uploaded to a new `RawTexture` which is
|
|
535
|
+
* assigned to the result.
|
|
536
|
+
*
|
|
537
|
+
* Note: a custom `updateFunction` on the source cannot be detected (the property is always assigned
|
|
538
|
+
* to a default) and has no equivalent on the GPU path, so any custom per-frame update logic will be
|
|
539
|
+
* silently dropped.
|
|
540
|
+
*
|
|
541
|
+
* Textures (particleTexture, noiseTexture) are shared by reference between the source and the result.
|
|
542
|
+
* All other mutable state (colors, vectors, emitter type, gradients, attractors) is cloned so that
|
|
543
|
+
* the two systems can be modified independently after the call.
|
|
544
|
+
*
|
|
545
|
+
* Note: unlike the GPUParticleSystem constructor, `emitRateControl` defaults to `true` here so that
|
|
546
|
+
* changes to `emitRate` on the converted system behave the same as on the CPU source. Pass
|
|
547
|
+
* `{ emitRateControl: false }` explicitly to opt out.
|
|
548
|
+
* @param source The CPU ParticleSystem to convert
|
|
549
|
+
* @param sceneOrEngine The scene or engine the new GPU particle system belongs to
|
|
550
|
+
* @param options Optional options forwarded to the new GPU particle system (capacity, randomTextureSize, emitRateControl, maxAttractors). `capacity` defaults to the source capacity and `emitRateControl` defaults to `true`.
|
|
551
|
+
* @returns A new GPUParticleSystem with shared properties copied from the source
|
|
552
|
+
*/
|
|
553
|
+
static fromParticleSystem(source: ParticleSystem, sceneOrEngine: Scene | AbstractEngine, options?: Partial<{
|
|
554
|
+
capacity: number;
|
|
555
|
+
randomTextureSize: number;
|
|
556
|
+
emitRateControl: boolean;
|
|
557
|
+
maxAttractors: number;
|
|
558
|
+
}>): GPUParticleSystem;
|
|
526
559
|
/**
|
|
527
560
|
* Serializes the particle system to a JSON object
|
|
528
561
|
* @param serializeTexture defines if the texture must be serialized as well
|
|
@@ -309,13 +309,14 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
309
309
|
* Adds a new color gradient
|
|
310
310
|
* @param gradient defines the gradient to use (between 0 and 1)
|
|
311
311
|
* @param color1 defines the color to affect to the specified gradient
|
|
312
|
+
* @param color2 defines an optional second color to be used to produce a random color per particle at the gradient (lerped with color1 using a per-particle random value)
|
|
312
313
|
* @returns the current particle system
|
|
313
314
|
*/
|
|
314
|
-
addColorGradient(gradient, color1) {
|
|
315
|
+
addColorGradient(gradient, color1, color2) {
|
|
315
316
|
if (!this._colorGradients) {
|
|
316
317
|
this._colorGradients = [];
|
|
317
318
|
}
|
|
318
|
-
const colorGradient = new ColorGradient(gradient, color1);
|
|
319
|
+
const colorGradient = new ColorGradient(gradient, color1, color2);
|
|
319
320
|
this._colorGradients.push(colorGradient);
|
|
320
321
|
this._refreshColorGradient(true);
|
|
321
322
|
this._releaseBuffers();
|
|
@@ -334,11 +335,24 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
334
335
|
return 0;
|
|
335
336
|
});
|
|
336
337
|
}
|
|
338
|
+
// Recompute whether any stop uses a color2 range. Done here (not inside _createColorGradientTexture)
|
|
339
|
+
// so the flag is available to both define generation (fillDefines) and render vertex buffer layout
|
|
340
|
+
// (_createVertexBuffers), which can run before the texture is recreated.
|
|
341
|
+
this._hasColorGradientColor2 = false;
|
|
342
|
+
for (const g of this._colorGradients) {
|
|
343
|
+
if (g.color2) {
|
|
344
|
+
this._hasColorGradientColor2 = true;
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
337
348
|
if (this._colorGradientsTexture) {
|
|
338
349
|
this._colorGradientsTexture.dispose();
|
|
339
350
|
this._colorGradientsTexture = null;
|
|
340
351
|
}
|
|
341
352
|
}
|
|
353
|
+
else {
|
|
354
|
+
this._hasColorGradientColor2 = false;
|
|
355
|
+
}
|
|
342
356
|
}
|
|
343
357
|
/** Force the system to rebuild all gradients that need to be resync */
|
|
344
358
|
forceRefreshGradients() {
|
|
@@ -358,6 +372,8 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
358
372
|
removeColorGradient(gradient) {
|
|
359
373
|
this._removeGradientAndTexture(gradient, this._colorGradients, this._colorGradientsTexture);
|
|
360
374
|
this._colorGradientsTexture = null;
|
|
375
|
+
// The set of remaining gradients may no longer contain a color2; recompute the flag.
|
|
376
|
+
this._refreshColorGradient();
|
|
361
377
|
return this;
|
|
362
378
|
}
|
|
363
379
|
/**
|
|
@@ -659,6 +675,8 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
659
675
|
this._emitCount = 0;
|
|
660
676
|
this._renderVertexBuffers = [];
|
|
661
677
|
this._targetIndex = 0;
|
|
678
|
+
/** Set to true when any entry in `_colorGradients` has a `color2` (per-particle random color range). */
|
|
679
|
+
this._hasColorGradientColor2 = false;
|
|
662
680
|
this._currentRenderId = -1;
|
|
663
681
|
this._currentRenderingCameraUniqueId = -1;
|
|
664
682
|
this._started = false;
|
|
@@ -824,6 +842,11 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
824
842
|
offset += 3;
|
|
825
843
|
renderVertexBuffers["life"] = renderBuffer.createVertexBuffer("life", offset, 1, this._attributesStrideSize, true);
|
|
826
844
|
offset += 1;
|
|
845
|
+
if (this._hasColorGradientColor2) {
|
|
846
|
+
// Expose `seed` to the render shader so it can pick a stable per-particle mix factor between
|
|
847
|
+
// the color1 and color2 rows of the color gradient texture.
|
|
848
|
+
renderVertexBuffers["seed"] = renderBuffer.createVertexBuffer("seed", offset, 4, this._attributesStrideSize, true);
|
|
849
|
+
}
|
|
827
850
|
offset += 4; // seed
|
|
828
851
|
if (this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED || this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL) {
|
|
829
852
|
renderVertexBuffers["direction"] = renderBuffer.createVertexBuffer("direction", offset, 3, this._attributesStrideSize, true);
|
|
@@ -1159,11 +1182,16 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
1159
1182
|
/**
|
|
1160
1183
|
* @internal
|
|
1161
1184
|
*/
|
|
1162
|
-
static _GetAttributeNamesOrOptions(hasColorGradients = false, isAnimationSheetEnabled = false, isBillboardBased = false, isBillboardStretched = false, isBillboardStretchedLocal = false) {
|
|
1185
|
+
static _GetAttributeNamesOrOptions(hasColorGradients = false, isAnimationSheetEnabled = false, isBillboardBased = false, isBillboardStretched = false, isBillboardStretchedLocal = false, hasColorGradientColor2 = false) {
|
|
1163
1186
|
const attributeNamesOrOptions = [VertexBuffer.PositionKind, "age", "life", "size", "angle"];
|
|
1164
1187
|
if (!hasColorGradients) {
|
|
1165
1188
|
attributeNamesOrOptions.push(VertexBuffer.ColorKind);
|
|
1166
1189
|
}
|
|
1190
|
+
else if (hasColorGradientColor2) {
|
|
1191
|
+
// When packing a color1/color2 range into the gradient texture, the render shader needs the
|
|
1192
|
+
// particle's persistent random seed to pick a stable per-particle mix factor.
|
|
1193
|
+
attributeNamesOrOptions.push("seed");
|
|
1194
|
+
}
|
|
1167
1195
|
if (isAnimationSheetEnabled) {
|
|
1168
1196
|
attributeNamesOrOptions.push("cellIndex");
|
|
1169
1197
|
}
|
|
@@ -1238,6 +1266,9 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
1238
1266
|
}
|
|
1239
1267
|
if (this._colorGradientsTexture) {
|
|
1240
1268
|
defines.push("#define COLORGRADIENTS");
|
|
1269
|
+
if (this._hasColorGradientColor2) {
|
|
1270
|
+
defines.push("#define COLORGRADIENTS_COLOR2");
|
|
1271
|
+
}
|
|
1241
1272
|
}
|
|
1242
1273
|
if (this.isAnimationSheetEnabled) {
|
|
1243
1274
|
defines.push("#define ANIMATESHEET");
|
|
@@ -1257,7 +1288,7 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
1257
1288
|
* @param samplers Samplers array to fill
|
|
1258
1289
|
*/
|
|
1259
1290
|
fillUniformsAttributesAndSamplerNames(uniforms, attributes, samplers) {
|
|
1260
|
-
attributes.push(...GPUParticleSystem._GetAttributeNamesOrOptions(!!this._colorGradientsTexture, this._isAnimationSheetEnabled, this._isBillboardBased, this._isBillboardBased && (this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED || this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL), this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL));
|
|
1291
|
+
attributes.push(...GPUParticleSystem._GetAttributeNamesOrOptions(!!this._colorGradientsTexture, this._isAnimationSheetEnabled, this._isBillboardBased, this._isBillboardBased && (this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED || this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL), this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL, this._hasColorGradientColor2));
|
|
1261
1292
|
uniforms.push(...GPUParticleSystem._GetEffectCreationOptions(this._isAnimationSheetEnabled, this.useLogarithmicDepth, this.applyFog));
|
|
1262
1293
|
samplers.push("diffuseSampler", "colorGradientSampler");
|
|
1263
1294
|
if (this._imageProcessingConfiguration) {
|
|
@@ -1421,7 +1452,11 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
1421
1452
|
if (!this._colorGradients || !this._colorGradients.length || this._colorGradientsTexture) {
|
|
1422
1453
|
return;
|
|
1423
1454
|
}
|
|
1424
|
-
|
|
1455
|
+
// When any stop has a color2, pack color1 into row 0 and color2 into row 1. The render shader
|
|
1456
|
+
// samples both rows and lerps using the particle's persistent seed.x for per-particle randomness.
|
|
1457
|
+
const hasColor2 = this._hasColorGradientColor2;
|
|
1458
|
+
const height = hasColor2 ? 2 : 1;
|
|
1459
|
+
const data = new Uint8Array(this._rawTextureWidth * 4 * height);
|
|
1425
1460
|
const tmpColor = TmpColors.Color4[0];
|
|
1426
1461
|
for (let x = 0; x < this._rawTextureWidth; x++) {
|
|
1427
1462
|
const ratio = x / this._rawTextureWidth;
|
|
@@ -1433,7 +1468,23 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
1433
1468
|
data[x * 4 + 3] = tmpColor.a * 255;
|
|
1434
1469
|
});
|
|
1435
1470
|
}
|
|
1436
|
-
|
|
1471
|
+
if (hasColor2) {
|
|
1472
|
+
const rowOffset = this._rawTextureWidth * 4;
|
|
1473
|
+
for (let x = 0; x < this._rawTextureWidth; x++) {
|
|
1474
|
+
const ratio = x / this._rawTextureWidth;
|
|
1475
|
+
GradientHelper.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, scale) => {
|
|
1476
|
+
const cg = currentGradient;
|
|
1477
|
+
const ng = nextGradient;
|
|
1478
|
+
// Fall back to color1 for stops without a color2 so the row stays continuous.
|
|
1479
|
+
Color4.LerpToRef(cg.color2 ?? cg.color1, ng.color2 ?? ng.color1, scale, tmpColor);
|
|
1480
|
+
data[rowOffset + x * 4] = tmpColor.r * 255;
|
|
1481
|
+
data[rowOffset + x * 4 + 1] = tmpColor.g * 255;
|
|
1482
|
+
data[rowOffset + x * 4 + 2] = tmpColor.b * 255;
|
|
1483
|
+
data[rowOffset + x * 4 + 3] = tmpColor.a * 255;
|
|
1484
|
+
});
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
this._colorGradientsTexture = RawTexture.CreateRGBATexture(data, this._rawTextureWidth, height, this._scene, false, false, 1);
|
|
1437
1488
|
this._colorGradientsTexture.name = "colorGradients";
|
|
1438
1489
|
}
|
|
1439
1490
|
_render(blendMode, emitterWM) {
|
|
@@ -1881,6 +1932,10 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
1881
1932
|
this.noiseTexture.dispose();
|
|
1882
1933
|
this.noiseTexture = null;
|
|
1883
1934
|
}
|
|
1935
|
+
if (disposeTexture && this._flowMap) {
|
|
1936
|
+
this._flowMap.dispose();
|
|
1937
|
+
this._flowMap = null;
|
|
1938
|
+
}
|
|
1884
1939
|
// Callback
|
|
1885
1940
|
this.onStoppedObservable.clear();
|
|
1886
1941
|
this.onDisposeObservable.notifyObservers(this);
|
|
@@ -1918,6 +1973,217 @@ export class GPUParticleSystem extends BaseParticleSystem {
|
|
|
1918
1973
|
result.emitter = newEmitter;
|
|
1919
1974
|
return result;
|
|
1920
1975
|
}
|
|
1976
|
+
/**
|
|
1977
|
+
* Creates a new GPUParticleSystem from an existing CPU ParticleSystem, copying all shared properties.
|
|
1978
|
+
* Features that are not supported on the GPU (sub-emitters, custom `startDirectionFunction` /
|
|
1979
|
+
* `startPositionFunction`, `customShader`, ramp/remap gradients) are logged as warnings and skipped.
|
|
1980
|
+
* Flow maps are converted: the CPU `FlowMap` image data is uploaded to a new `RawTexture` which is
|
|
1981
|
+
* assigned to the result.
|
|
1982
|
+
*
|
|
1983
|
+
* Note: a custom `updateFunction` on the source cannot be detected (the property is always assigned
|
|
1984
|
+
* to a default) and has no equivalent on the GPU path, so any custom per-frame update logic will be
|
|
1985
|
+
* silently dropped.
|
|
1986
|
+
*
|
|
1987
|
+
* Textures (particleTexture, noiseTexture) are shared by reference between the source and the result.
|
|
1988
|
+
* All other mutable state (colors, vectors, emitter type, gradients, attractors) is cloned so that
|
|
1989
|
+
* the two systems can be modified independently after the call.
|
|
1990
|
+
*
|
|
1991
|
+
* Note: unlike the GPUParticleSystem constructor, `emitRateControl` defaults to `true` here so that
|
|
1992
|
+
* changes to `emitRate` on the converted system behave the same as on the CPU source. Pass
|
|
1993
|
+
* `{ emitRateControl: false }` explicitly to opt out.
|
|
1994
|
+
* @param source The CPU ParticleSystem to convert
|
|
1995
|
+
* @param sceneOrEngine The scene or engine the new GPU particle system belongs to
|
|
1996
|
+
* @param options Optional options forwarded to the new GPU particle system (capacity, randomTextureSize, emitRateControl, maxAttractors). `capacity` defaults to the source capacity and `emitRateControl` defaults to `true`.
|
|
1997
|
+
* @returns A new GPUParticleSystem with shared properties copied from the source
|
|
1998
|
+
*/
|
|
1999
|
+
static fromParticleSystem(source, sceneOrEngine, options) {
|
|
2000
|
+
// Warn on features that cannot be represented on a GPU particle system.
|
|
2001
|
+
if (source.subEmitters && source.subEmitters.length > 0) {
|
|
2002
|
+
Logger.Warn("GPUParticleSystem.fromParticleSystem: 'subEmitters' is not supported on GPUParticleSystem and will be skipped.");
|
|
2003
|
+
}
|
|
2004
|
+
if (source.startDirectionFunction) {
|
|
2005
|
+
Logger.Warn("GPUParticleSystem.fromParticleSystem: 'startDirectionFunction' is not supported on GPUParticleSystem and will be skipped.");
|
|
2006
|
+
}
|
|
2007
|
+
if (source.startPositionFunction) {
|
|
2008
|
+
Logger.Warn("GPUParticleSystem.fromParticleSystem: 'startPositionFunction' is not supported on GPUParticleSystem and will be skipped.");
|
|
2009
|
+
}
|
|
2010
|
+
if (source.customShader) {
|
|
2011
|
+
Logger.Warn("GPUParticleSystem.fromParticleSystem: 'customShader' is not supported on GPUParticleSystem and will be skipped.");
|
|
2012
|
+
}
|
|
2013
|
+
const sourceRampGradients = source.getRampGradients();
|
|
2014
|
+
if (sourceRampGradients && sourceRampGradients.length > 0) {
|
|
2015
|
+
Logger.Warn("GPUParticleSystem.fromParticleSystem: 'rampGradients' are not supported on GPUParticleSystem and will be skipped.");
|
|
2016
|
+
}
|
|
2017
|
+
const sourceColorRemapGradients = source.getColorRemapGradients();
|
|
2018
|
+
if (sourceColorRemapGradients && sourceColorRemapGradients.length > 0) {
|
|
2019
|
+
Logger.Warn("GPUParticleSystem.fromParticleSystem: 'colorRemapGradients' are not supported on GPUParticleSystem and will be skipped.");
|
|
2020
|
+
}
|
|
2021
|
+
const sourceAlphaRemapGradients = source.getAlphaRemapGradients();
|
|
2022
|
+
if (sourceAlphaRemapGradients && sourceAlphaRemapGradients.length > 0) {
|
|
2023
|
+
Logger.Warn("GPUParticleSystem.fromParticleSystem: 'alphaRemapGradients' are not supported on GPUParticleSystem and will be skipped.");
|
|
2024
|
+
}
|
|
2025
|
+
const capacity = options?.capacity ?? source.getCapacity();
|
|
2026
|
+
const gpuOptions = { capacity };
|
|
2027
|
+
if (options?.randomTextureSize !== undefined) {
|
|
2028
|
+
gpuOptions.randomTextureSize = options.randomTextureSize;
|
|
2029
|
+
}
|
|
2030
|
+
// Default emitRateControl to true here: on a freshly constructed GPUParticleSystem the default is
|
|
2031
|
+
// false for backwards compatibility, but when converting an existing CPU system users expect
|
|
2032
|
+
// changes to emitRate to take effect — matching CPU behavior.
|
|
2033
|
+
gpuOptions.emitRateControl = options?.emitRateControl ?? true;
|
|
2034
|
+
if (options?.maxAttractors !== undefined) {
|
|
2035
|
+
gpuOptions.maxAttractors = options.maxAttractors;
|
|
2036
|
+
}
|
|
2037
|
+
const gpu = new GPUParticleSystem(source.name + " (GPU)", gpuOptions, sceneOrEngine, null, source.isAnimationSheetEnabled);
|
|
2038
|
+
gpu.id = source.id;
|
|
2039
|
+
// Emitter (shared by reference: mesh or Vector3 — users expect both systems to follow the same source).
|
|
2040
|
+
gpu.emitter = source.emitter;
|
|
2041
|
+
// Emitter type — cloned for independence.
|
|
2042
|
+
if (source.particleEmitterType) {
|
|
2043
|
+
gpu.particleEmitterType = source.particleEmitterType.clone();
|
|
2044
|
+
}
|
|
2045
|
+
// Textures — shared by reference.
|
|
2046
|
+
gpu.particleTexture = source.particleTexture;
|
|
2047
|
+
if (source.noiseTexture) {
|
|
2048
|
+
gpu.noiseTexture = source.noiseTexture;
|
|
2049
|
+
}
|
|
2050
|
+
// Colors.
|
|
2051
|
+
gpu.color1 = source.color1.clone();
|
|
2052
|
+
gpu.color2 = source.color2.clone();
|
|
2053
|
+
gpu.colorDead = source.colorDead.clone();
|
|
2054
|
+
gpu.textureMask = source.textureMask.clone();
|
|
2055
|
+
// Sizes.
|
|
2056
|
+
gpu.minSize = source.minSize;
|
|
2057
|
+
gpu.maxSize = source.maxSize;
|
|
2058
|
+
gpu.minScaleX = source.minScaleX;
|
|
2059
|
+
gpu.maxScaleX = source.maxScaleX;
|
|
2060
|
+
gpu.minScaleY = source.minScaleY;
|
|
2061
|
+
gpu.maxScaleY = source.maxScaleY;
|
|
2062
|
+
// Speeds / rotation.
|
|
2063
|
+
gpu.minEmitPower = source.minEmitPower;
|
|
2064
|
+
gpu.maxEmitPower = source.maxEmitPower;
|
|
2065
|
+
gpu.minAngularSpeed = source.minAngularSpeed;
|
|
2066
|
+
gpu.maxAngularSpeed = source.maxAngularSpeed;
|
|
2067
|
+
gpu.minInitialRotation = source.minInitialRotation;
|
|
2068
|
+
gpu.maxInitialRotation = source.maxInitialRotation;
|
|
2069
|
+
// Lifetime.
|
|
2070
|
+
gpu.minLifeTime = source.minLifeTime;
|
|
2071
|
+
gpu.maxLifeTime = source.maxLifeTime;
|
|
2072
|
+
// Emission.
|
|
2073
|
+
gpu.emitRate = source.emitRate;
|
|
2074
|
+
gpu.manualEmitCount = source.manualEmitCount;
|
|
2075
|
+
// Physics.
|
|
2076
|
+
gpu.gravity = source.gravity.clone();
|
|
2077
|
+
gpu.limitVelocityDamping = source.limitVelocityDamping;
|
|
2078
|
+
// Rendering.
|
|
2079
|
+
gpu.blendMode = source.blendMode;
|
|
2080
|
+
gpu.billboardMode = source.billboardMode;
|
|
2081
|
+
gpu.isBillboardBased = source.isBillboardBased;
|
|
2082
|
+
gpu.forceDepthWrite = source.forceDepthWrite;
|
|
2083
|
+
gpu.useLogarithmicDepth = source.useLogarithmicDepth;
|
|
2084
|
+
gpu.renderingGroupId = source.renderingGroupId;
|
|
2085
|
+
gpu.layerMask = source.layerMask;
|
|
2086
|
+
// Animation sheet.
|
|
2087
|
+
gpu.startSpriteCellID = source.startSpriteCellID;
|
|
2088
|
+
gpu.endSpriteCellID = source.endSpriteCellID;
|
|
2089
|
+
gpu.spriteCellWidth = source.spriteCellWidth;
|
|
2090
|
+
gpu.spriteCellHeight = source.spriteCellHeight;
|
|
2091
|
+
gpu.spriteCellChangeSpeed = source.spriteCellChangeSpeed;
|
|
2092
|
+
gpu.spriteCellLoop = source.spriteCellLoop;
|
|
2093
|
+
gpu.spriteRandomStartCell = source.spriteRandomStartCell;
|
|
2094
|
+
// Space.
|
|
2095
|
+
gpu.isLocal = source.isLocal;
|
|
2096
|
+
gpu.worldOffset = source.worldOffset.clone();
|
|
2097
|
+
gpu.translationPivot = source.translationPivot.clone();
|
|
2098
|
+
// Lifecycle.
|
|
2099
|
+
gpu.targetStopDuration = source.targetStopDuration;
|
|
2100
|
+
gpu.disposeOnStop = source.disposeOnStop;
|
|
2101
|
+
gpu.startDelay = source.startDelay;
|
|
2102
|
+
gpu.preWarmCycles = source.preWarmCycles;
|
|
2103
|
+
gpu.preWarmStepOffset = source.preWarmStepOffset;
|
|
2104
|
+
gpu.updateSpeed = source.updateSpeed;
|
|
2105
|
+
gpu.preventAutoStart = source.preventAutoStart;
|
|
2106
|
+
// Animations (shared by reference, matching the rest of the scene-graph convention).
|
|
2107
|
+
gpu.animations = source.animations;
|
|
2108
|
+
gpu.beginAnimationOnStart = source.beginAnimationOnStart;
|
|
2109
|
+
gpu.beginAnimationFrom = source.beginAnimationFrom;
|
|
2110
|
+
gpu.beginAnimationTo = source.beginAnimationTo;
|
|
2111
|
+
gpu.beginAnimationLoop = source.beginAnimationLoop;
|
|
2112
|
+
// Noise.
|
|
2113
|
+
gpu.noiseStrength = source.noiseStrength.clone();
|
|
2114
|
+
// Flow map — convert the CPU FlowMap (JS-side image data) into a RawTexture for GPU sampling.
|
|
2115
|
+
// The CPU FlowMap stores image data top-left origin and flips V in its sampler; to get the
|
|
2116
|
+
// same orientation under the GPU shader's non-flipped sampling, the uploaded texture needs invertY=true.
|
|
2117
|
+
if (source.flowMap) {
|
|
2118
|
+
const sourceFlowMap = source.flowMap;
|
|
2119
|
+
const flowTexture = new RawTexture(new Uint8Array(sourceFlowMap.data.buffer, sourceFlowMap.data.byteOffset, sourceFlowMap.data.byteLength), sourceFlowMap.width, sourceFlowMap.height, 5, sceneOrEngine, false, true, 2);
|
|
2120
|
+
gpu.flowMap = flowTexture;
|
|
2121
|
+
gpu.flowMapStrength = source.flowMapStrength;
|
|
2122
|
+
}
|
|
2123
|
+
// Gradients.
|
|
2124
|
+
const colorGradients = source.getColorGradients();
|
|
2125
|
+
if (colorGradients) {
|
|
2126
|
+
for (const g of colorGradients) {
|
|
2127
|
+
gpu.addColorGradient(g.gradient, g.color1.clone(), g.color2?.clone());
|
|
2128
|
+
}
|
|
2129
|
+
}
|
|
2130
|
+
const sizeGradients = source.getSizeGradients();
|
|
2131
|
+
if (sizeGradients) {
|
|
2132
|
+
for (const g of sizeGradients) {
|
|
2133
|
+
gpu.addSizeGradient(g.gradient, g.factor1, g.factor2);
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
const angularSpeedGradients = source.getAngularSpeedGradients();
|
|
2137
|
+
if (angularSpeedGradients) {
|
|
2138
|
+
for (const g of angularSpeedGradients) {
|
|
2139
|
+
gpu.addAngularSpeedGradient(g.gradient, g.factor1, g.factor2);
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
const velocityGradients = source.getVelocityGradients();
|
|
2143
|
+
if (velocityGradients) {
|
|
2144
|
+
for (const g of velocityGradients) {
|
|
2145
|
+
gpu.addVelocityGradient(g.gradient, g.factor1, g.factor2);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
const limitVelocityGradients = source.getLimitVelocityGradients();
|
|
2149
|
+
if (limitVelocityGradients) {
|
|
2150
|
+
for (const g of limitVelocityGradients) {
|
|
2151
|
+
gpu.addLimitVelocityGradient(g.gradient, g.factor1, g.factor2);
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
const dragGradients = source.getDragGradients();
|
|
2155
|
+
if (dragGradients) {
|
|
2156
|
+
for (const g of dragGradients) {
|
|
2157
|
+
gpu.addDragGradient(g.gradient, g.factor1, g.factor2);
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
const emitRateGradients = source.getEmitRateGradients();
|
|
2161
|
+
if (emitRateGradients) {
|
|
2162
|
+
for (const g of emitRateGradients) {
|
|
2163
|
+
gpu.addEmitRateGradient(g.gradient, g.factor1, g.factor2);
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
const startSizeGradients = source.getStartSizeGradients();
|
|
2167
|
+
if (startSizeGradients) {
|
|
2168
|
+
for (const g of startSizeGradients) {
|
|
2169
|
+
gpu.addStartSizeGradient(g.gradient, g.factor1, g.factor2);
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2172
|
+
const lifeTimeGradients = source.getLifeTimeGradients();
|
|
2173
|
+
if (lifeTimeGradients) {
|
|
2174
|
+
for (const g of lifeTimeGradients) {
|
|
2175
|
+
gpu.addLifeTimeGradient(g.gradient, g.factor1, g.factor2);
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
// Attractors — cloned.
|
|
2179
|
+
for (const attractor of source.attractors) {
|
|
2180
|
+
const newAttractor = new Attractor();
|
|
2181
|
+
newAttractor.position = attractor.position.clone();
|
|
2182
|
+
newAttractor.strength = attractor.strength;
|
|
2183
|
+
gpu.addAttractor(newAttractor);
|
|
2184
|
+
}
|
|
2185
|
+
return gpu;
|
|
2186
|
+
}
|
|
1921
2187
|
/**
|
|
1922
2188
|
* Serializes the particle system to a JSON object
|
|
1923
2189
|
* @param serializeTexture defines if the texture must be serialized as well
|