babylon.quarks 0.27.0 → 0.28.0
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/CHANGELOG.md +425 -0
- package/README.md +3 -1
- 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.cts +4256 -831
- package/dist/types/index.d.ts +4256 -831
- package/package.json +7 -2
- package/src/BatchedRenderer.ts +93 -78
- package/src/EffectPool.ts +91 -12
- package/src/MeshSurfaceEmitter.ts +24 -13
- package/src/ParticleEmitter.ts +31 -3
- package/src/ParticleSystem.ts +92 -25
- package/src/QuarksLoader.ts +289 -171
- package/src/QuarksPrefab.ts +301 -94
- package/src/QuarksSerializer.ts +43 -15
- package/src/QuarksUtil.ts +64 -9
- package/src/SpriteBatch.ts +21 -6
- package/src/TrailBatch.ts +12 -6
- package/src/VFXBatch.ts +70 -528
- package/src/batchKey.ts +4 -2
- package/src/batchSettings.ts +546 -0
- package/src/effectDocumentJSON.ts +261 -0
- package/src/effectResources.ts +21 -24
- package/src/envAtlas.ts +8 -2
- package/src/geometryUtil.ts +1 -1
- package/src/index.ts +39 -4
- package/src/nodeId.ts +25 -2
- package/src/shaderProgram.ts +110 -16
- package/src/shaderVariants.ts +24 -4
- package/src/shaders/chunks/blend.ts +31 -0
- package/src/shaders/chunks/fog.ts +8 -3
- package/src/shaders/chunks/soft.ts +6 -5
- package/src/shaders/chunks/surface.ts +2 -2
- package/src/shaders/particle_frag.glsl.ts +3 -1
- package/src/shaders/particle_frag.wgsl.ts +2 -0
- package/src/shaders/particle_physics_frag.glsl.ts +5 -2
- package/src/shaders/particle_physics_frag.wgsl.ts +2 -0
- package/src/shaders/trail_frag.glsl.ts +4 -1
- package/src/shaders/trail_frag.wgsl.ts +2 -0
- package/src/system/EmissionController.ts +2 -4
- package/src/system/EventDispatcher.ts +26 -10
- package/src/system/geometry.ts +22 -29
- package/src/system/materialResolve.ts +56 -7
- package/src/system/normalize.ts +6 -1
- package/src/system/serialization.ts +54 -33
- package/src/system/settingsSchema.ts +32 -10
- package/src/system/types.ts +67 -28
- package/src/trailSettings.ts +9 -6
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type {BaseTexture} from '@babylonjs/core/Materials/Textures/baseTexture';
|
|
2
|
-
import
|
|
2
|
+
import {Texture} from '@babylonjs/core/Materials/Textures/texture';
|
|
3
3
|
import type {VFXBatchSettings} from '../BatchedRenderer';
|
|
4
4
|
|
|
5
5
|
/** Settings given next to a material, which win over what is read from it. */
|
|
@@ -14,6 +14,52 @@ export interface MaterialOverrides {
|
|
|
14
14
|
layerMask?: number;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* What a {@link ParticleSystem} reads its draw settings from: a Babylon material (`StandardMaterial`,
|
|
19
|
+
* `PBRMaterial`, a node material, …), or a material entry of an effect file once its texture slots
|
|
20
|
+
* are resolved to textures, as `ParticleSystem.fromJSON` does. Each field is read only when it is
|
|
21
|
+
* there, so any material fits; the particles are still drawn with quarks' own shaders. The particle
|
|
22
|
+
* texture is the first slot that holds a `Texture`.
|
|
23
|
+
*/
|
|
24
|
+
export interface ParticleMaterialSource {
|
|
25
|
+
/** A PBR material's base colour texture. */
|
|
26
|
+
albedoTexture?: BaseTexture | null;
|
|
27
|
+
/** A standard material's diffuse texture. */
|
|
28
|
+
diffuseTexture?: BaseTexture | null;
|
|
29
|
+
/** An emissive texture, read when there is no albedo or diffuse texture. */
|
|
30
|
+
emissiveTexture?: BaseTexture | null;
|
|
31
|
+
/** An opacity texture, read when there is none of the above. */
|
|
32
|
+
opacityTexture?: BaseTexture | null;
|
|
33
|
+
/** A base texture, read last. */
|
|
34
|
+
baseTexture?: BaseTexture | null;
|
|
35
|
+
/** The reflection texture; a cube is drawn through a 3×2 atlas built from it. */
|
|
36
|
+
reflectionTexture?: BaseTexture | null;
|
|
37
|
+
/** A PBR material's environment texture, read when there is no reflection texture. */
|
|
38
|
+
environmentTexture?: BaseTexture | null;
|
|
39
|
+
/** How strong the reflection is; the reflection texture's `level` when unset. */
|
|
40
|
+
reflectionLevel?: number;
|
|
41
|
+
/** A 3×2 env atlas for the reflection; the system stores the atlas it builds from a cube here. */
|
|
42
|
+
reflectionAtlas?: BaseTexture | null;
|
|
43
|
+
/** A Babylon alpha mode constant. */
|
|
44
|
+
alphaMode?: number;
|
|
45
|
+
/** Whether the material blends; decides `transparent`. */
|
|
46
|
+
needAlphaBlending?(): boolean;
|
|
47
|
+
/** Opacity, read for `transparent` when there is no `needAlphaBlending`. */
|
|
48
|
+
alpha?: number;
|
|
49
|
+
/** Inverted into `depthTest`. */
|
|
50
|
+
disableDepthTest?: boolean;
|
|
51
|
+
/** Inverted into `depthWrite`. */
|
|
52
|
+
disableDepthWrite?: boolean;
|
|
53
|
+
/** Read for `depthWrite` when there is no `disableDepthWrite`. */
|
|
54
|
+
forceDepthWrite?: boolean;
|
|
55
|
+
/** The alpha test cutoff is read only in an alpha-test mode (1 or 3). */
|
|
56
|
+
transparencyMode?: number | null;
|
|
57
|
+
/** The alpha test cutoff. */
|
|
58
|
+
alphaCutOff?: number;
|
|
59
|
+
/** The alpha test cutoff, as some materials name it. */
|
|
60
|
+
alphaCutOffValue?: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
17
63
|
/** The draw settings a {@link ParticleSystem} takes from a material, before the env atlas is built. */
|
|
18
64
|
export interface ResolvedMaterialSettings {
|
|
19
65
|
texture: Texture | null;
|
|
@@ -39,18 +85,21 @@ export function liveAtlas<T extends BaseTexture>(atlas: T | null | undefined): T
|
|
|
39
85
|
* material does not have keeps its `current` value.
|
|
40
86
|
*/
|
|
41
87
|
export function resolveMaterialSettings(
|
|
42
|
-
material:
|
|
88
|
+
material: ParticleMaterialSource | null | undefined,
|
|
43
89
|
overrides: MaterialOverrides,
|
|
44
90
|
current: VFXBatchSettings
|
|
45
91
|
): ResolvedMaterialSettings {
|
|
92
|
+
// The particle texture is a `Texture`: the first slot that holds one, so a cube in a slot is passed over.
|
|
46
93
|
const texture =
|
|
47
94
|
overrides.texture !== undefined
|
|
48
95
|
? overrides.texture
|
|
49
|
-
: (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
96
|
+
: ([
|
|
97
|
+
material?.albedoTexture,
|
|
98
|
+
material?.diffuseTexture,
|
|
99
|
+
material?.emissiveTexture,
|
|
100
|
+
material?.opacityTexture,
|
|
101
|
+
material?.baseTexture,
|
|
102
|
+
].find((slot): slot is Texture => slot instanceof Texture) ??
|
|
54
103
|
current.texture ??
|
|
55
104
|
null);
|
|
56
105
|
const reflectionTexture =
|
package/src/system/normalize.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {ConstantValue, FunctionValueGenerator, ValueGenerator, Vector2, Vector3} from 'quarks.core';
|
|
2
|
-
import type {MeshLighting, SortMode} from '../
|
|
2
|
+
import type {MeshLighting, RenderFace, SortMode} from '../batchSettings';
|
|
3
3
|
import type {BurstParameters, CullingMode} from './types';
|
|
4
4
|
|
|
5
5
|
// Normalisers shared by the ParticleSystem constructor, its setters and its JSON reader, so a
|
|
@@ -15,6 +15,11 @@ export function validSortMode(mode: unknown): SortMode {
|
|
|
15
15
|
return mode === 'distance' || mode === 'oldestInFront' || mode === 'youngestInFront' ? mode : 'none';
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
/** `face` if it is one of the render faces, else `'both'`. */
|
|
19
|
+
export function validRenderFace(face: unknown): RenderFace {
|
|
20
|
+
return face === 'front' || face === 'back' ? face : 'both';
|
|
21
|
+
}
|
|
22
|
+
|
|
18
23
|
/** `mode` if it is one of the culling modes, else `'always'`. */
|
|
19
24
|
export function validCullingMode(mode: unknown): CullingMode {
|
|
20
25
|
return mode === 'pause' || mode === 'pauseAndCatchUp' ? mode : 'always';
|
|
@@ -3,14 +3,20 @@ import type {BaseTexture} from '@babylonjs/core/Materials/Textures/baseTexture';
|
|
|
3
3
|
import {Texture} from '@babylonjs/core/Materials/Textures/texture';
|
|
4
4
|
import type {Scene} from '@babylonjs/core/scene';
|
|
5
5
|
import {
|
|
6
|
+
BehaviorToJSON,
|
|
6
7
|
ConstantValue,
|
|
7
8
|
EmitterFromJSON,
|
|
9
|
+
EmitterToJSON,
|
|
10
|
+
readFormatPart,
|
|
8
11
|
RendererEmitterSettings,
|
|
9
12
|
StretchedBillBoardSettings,
|
|
10
13
|
TrailSettings,
|
|
11
14
|
ValueGeneratorFromJSON,
|
|
12
15
|
Vector3,
|
|
16
|
+
Vector3ArrayJSON,
|
|
17
|
+
warnFormat,
|
|
13
18
|
} from 'quarks.core';
|
|
19
|
+
import type {MaterialTextureRef} from '../effectDocumentJSON';
|
|
14
20
|
import type {ParticleSystem} from '../ParticleSystem';
|
|
15
21
|
import {
|
|
16
22
|
trailCurveTension,
|
|
@@ -19,6 +25,7 @@ import {
|
|
|
19
25
|
trailTessellation,
|
|
20
26
|
trailTextureMode,
|
|
21
27
|
trailTextureScale,
|
|
28
|
+
type TrailOptions,
|
|
22
29
|
} from '../trailSettings';
|
|
23
30
|
import {
|
|
24
31
|
EROSION_DEFAULT_SOFTNESS,
|
|
@@ -28,8 +35,15 @@ import {
|
|
|
28
35
|
UV_DISTORTION_DEFAULT_UV,
|
|
29
36
|
} from '../VFXBatch';
|
|
30
37
|
import {resolveGeometryData} from './geometry';
|
|
38
|
+
import type {ParticleMaterialSource} from './materialResolve';
|
|
31
39
|
import {settingsFromJSON, settingsToJSON} from './settingsSchema';
|
|
32
|
-
import type {
|
|
40
|
+
import type {
|
|
41
|
+
BabylonMetaData,
|
|
42
|
+
ParticleSystemJSONParameters,
|
|
43
|
+
ParticleSystemParameters,
|
|
44
|
+
RendererEmitterSettingsJSON,
|
|
45
|
+
TrailSettingsJSON,
|
|
46
|
+
} from './types';
|
|
33
47
|
|
|
34
48
|
// Reading and writing a ParticleSystem's JSON. The class's toJSON and fromJSON call these.
|
|
35
49
|
|
|
@@ -49,8 +63,8 @@ function nextSerializationId(meta: BabylonMetaData, prefix: string): string {
|
|
|
49
63
|
}
|
|
50
64
|
|
|
51
65
|
/** The optional trail flags that are switched on, so JSON and clones only carry the ones in use. */
|
|
52
|
-
export function trailFlags(settings:
|
|
53
|
-
const flags: Partial<
|
|
66
|
+
export function trailFlags(settings: Partial<TrailOptions> | undefined): Partial<TrailOptions> {
|
|
67
|
+
const flags: Partial<TrailOptions> = {};
|
|
54
68
|
if (settings?.uvFromHead) flags.uvFromHead = true;
|
|
55
69
|
if (settings?.colorFromParticle) flags.colorFromParticle = true;
|
|
56
70
|
if (settings?.dieWithParticle) flags.dieWithParticle = true;
|
|
@@ -59,8 +73,8 @@ export function trailFlags(settings: TrailSettings | undefined): Partial<TrailSe
|
|
|
59
73
|
}
|
|
60
74
|
|
|
61
75
|
/** A trail's tessellation and curve tension, normalised, each only when it differs from the default. */
|
|
62
|
-
export function trailCurve(settings:
|
|
63
|
-
const curve: Partial<
|
|
76
|
+
export function trailCurve(settings: Partial<TrailOptions> | undefined): Partial<TrailOptions> {
|
|
77
|
+
const curve: Partial<TrailOptions> = {};
|
|
64
78
|
const tessellation = trailTessellation(settings);
|
|
65
79
|
const curveTension = trailCurveTension(settings);
|
|
66
80
|
if (tessellation > 0) curve.tessellation = tessellation;
|
|
@@ -72,8 +86,8 @@ export function trailCurve(settings: TrailSettings | undefined): Partial<TrailSe
|
|
|
72
86
|
* A trail's texture mode and scale, minimum vertex distance and lifetime, normalised, each only
|
|
73
87
|
* when it differs from the default.
|
|
74
88
|
*/
|
|
75
|
-
export function trailSampling(settings:
|
|
76
|
-
const out: Partial<
|
|
89
|
+
export function trailSampling(settings: Partial<TrailOptions> | undefined): Partial<TrailOptions> {
|
|
90
|
+
const out: Partial<TrailOptions> = {};
|
|
77
91
|
const textureMode = trailTextureMode(settings);
|
|
78
92
|
const textureScale = trailTextureScale(settings);
|
|
79
93
|
const minVertexDistance = trailMinVertexDistance(settings);
|
|
@@ -86,12 +100,12 @@ export function trailSampling(settings: TrailSettings | undefined): Partial<Trai
|
|
|
86
100
|
}
|
|
87
101
|
|
|
88
102
|
/** A trail's `followLocalOrigin`, only when on: off is the default. */
|
|
89
|
-
export function trailFollowLocalOrigin(settings:
|
|
103
|
+
export function trailFollowLocalOrigin(settings: Partial<TrailOptions> | undefined): Partial<TrailOptions> {
|
|
90
104
|
return settings?.followLocalOrigin ? {followLocalOrigin: true} : {};
|
|
91
105
|
}
|
|
92
106
|
|
|
93
107
|
/** A trail's side axis as JSON `[x, y, z]`, or nothing when unset. */
|
|
94
|
-
function trailSideAxisJSON(settings: TrailSettings | undefined): {sideAxis?:
|
|
108
|
+
function trailSideAxisJSON(settings: TrailSettings | undefined): {sideAxis?: Vector3ArrayJSON} {
|
|
95
109
|
const axis = settings?.sideAxis;
|
|
96
110
|
return axis ? {sideAxis: [axis.x, axis.y, axis.z]} : {};
|
|
97
111
|
}
|
|
@@ -120,7 +134,7 @@ function trailSideAxisFromJSON(value: unknown): {sideAxis?: Vector3} {
|
|
|
120
134
|
if (Number.isFinite(nx) && Number.isFinite(ny) && Number.isFinite(nz) && nx * nx + ny * ny + nz * nz > 0) {
|
|
121
135
|
return {sideAxis: new Vector3(nx, ny, nz)};
|
|
122
136
|
}
|
|
123
|
-
|
|
137
|
+
warnFormat(`sideAxis ${JSON.stringify(value)} is not a direction and is ignored`);
|
|
124
138
|
return {};
|
|
125
139
|
}
|
|
126
140
|
|
|
@@ -149,15 +163,17 @@ export function particleSystemToJSON(
|
|
|
149
163
|
|
|
150
164
|
// Only what differs from the defaults the constructor and fromJSON give a setting left out.
|
|
151
165
|
// The shape, the settings the table marks `always`, the geometry, the material and the
|
|
152
|
-
// behaviors are always written: the loaders of 0.27 and earlier
|
|
166
|
+
// behaviors list are always written: the loaders of 0.27 and earlier need them. Within the
|
|
167
|
+
// shape and each behavior, only the fields that differ from their defaults, which 0.27 reads
|
|
168
|
+
// and three.quarks may not (see docs/FORMAT.md).
|
|
153
169
|
return {
|
|
154
170
|
version: '3.0',
|
|
155
|
-
shape: system.emitterShape
|
|
171
|
+
shape: EmitterToJSON(system.emitterShape),
|
|
156
172
|
...settingsToJSON(system),
|
|
157
173
|
instancingGeometry: geometryUUID,
|
|
158
|
-
...(
|
|
174
|
+
...(rendererSettingsJSON ? {rendererEmitterSettings: rendererSettingsJSON} : {}),
|
|
159
175
|
material: materialUUID,
|
|
160
|
-
behaviors: system.behaviors.map((b) => b
|
|
176
|
+
behaviors: system.behaviors.map((b) => BehaviorToJSON(b, system)),
|
|
161
177
|
};
|
|
162
178
|
}
|
|
163
179
|
|
|
@@ -172,10 +188,10 @@ export function particleSystemParametersFromJSON(
|
|
|
172
188
|
scene?: Scene
|
|
173
189
|
): ParticleSystemParameters {
|
|
174
190
|
// A part the file leaves out takes the constructor's default, as a system made in code does.
|
|
175
|
-
const shape = json.shape ? EmitterFromJSON(json.shape
|
|
191
|
+
const shape = json.shape ? readFormatPart('shape', () => EmitterFromJSON(json.shape!, meta)) : undefined;
|
|
176
192
|
let rendererEmitterSettings: RendererEmitterSettings;
|
|
177
193
|
if (json.renderMode === RenderMode.Trail) {
|
|
178
|
-
const trailSettings = json.rendererEmitterSettings as
|
|
194
|
+
const trailSettings = json.rendererEmitterSettings as TrailSettingsJSON | undefined;
|
|
179
195
|
rendererEmitterSettings = {
|
|
180
196
|
startLength:
|
|
181
197
|
trailSettings?.startLength !== undefined
|
|
@@ -185,26 +201,31 @@ export function particleSystemParametersFromJSON(
|
|
|
185
201
|
...trailFlags(trailSettings),
|
|
186
202
|
...trailCurve(trailSettings),
|
|
187
203
|
...trailSampling(trailSettings),
|
|
188
|
-
...trailSideAxisFromJSON(
|
|
204
|
+
...trailSideAxisFromJSON(trailSettings?.sideAxis),
|
|
189
205
|
};
|
|
190
206
|
} else if (json.renderMode === RenderMode.StretchedBillBoard) {
|
|
191
|
-
|
|
207
|
+
// The render mode says which settings the file holds.
|
|
208
|
+
const stretched: Partial<StretchedBillBoardSettings> = {
|
|
209
|
+
...(json.rendererEmitterSettings as StretchedBillBoardSettings | undefined),
|
|
210
|
+
};
|
|
192
211
|
if (json.speedFactor !== undefined) {
|
|
193
|
-
|
|
212
|
+
stretched.speedFactor = json.speedFactor;
|
|
194
213
|
}
|
|
214
|
+
rendererEmitterSettings = stretched;
|
|
195
215
|
} else {
|
|
196
216
|
rendererEmitterSettings = {};
|
|
197
217
|
}
|
|
198
218
|
|
|
199
219
|
const materialMeta = json.material ? meta.materials?.[json.material] : undefined;
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
typeof
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
220
|
+
// Texture slots reference textures by uuid in a serialised meta, or hold them once a loader resolved them.
|
|
221
|
+
const resolveTexture = (ref: MaterialTextureRef | undefined): BaseTexture | null =>
|
|
222
|
+
typeof ref === 'string' ? (meta.textures?.[ref] ?? null) : (ref ?? null);
|
|
223
|
+
const mainTexture = resolveTexture(materialMeta?.texture ?? json.texture);
|
|
224
|
+
// Particles sample a 2D texture.
|
|
225
|
+
const texture = mainTexture instanceof Texture ? mainTexture : null;
|
|
226
|
+
const material: ParticleMaterialSource | undefined =
|
|
227
|
+
materialMeta?.sourceMaterial ??
|
|
228
|
+
(materialMeta ? {...materialMeta, reflectionAtlas: resolveTexture(materialMeta.reflectionAtlas)} : undefined);
|
|
208
229
|
const erosionMeta = materialMeta?.erosion;
|
|
209
230
|
const gradientMeta = materialMeta?.gradientMap;
|
|
210
231
|
const distortionMeta = materialMeta?.uvDistortion;
|
|
@@ -226,7 +247,7 @@ export function particleSystemParametersFromJSON(
|
|
|
226
247
|
instancingNormals: resolvedGeometry.normals,
|
|
227
248
|
rendererEmitterSettings,
|
|
228
249
|
texture,
|
|
229
|
-
material
|
|
250
|
+
material,
|
|
230
251
|
// The material entry wins over the system's own fields, which older files wrote too.
|
|
231
252
|
blendMode: materialMeta?.alphaMode ?? settings.blendMode ?? Constants.ALPHA_ADD,
|
|
232
253
|
transparent: materialMeta?.transparent ?? settings.transparent ?? true,
|
|
@@ -253,7 +274,7 @@ export function particleSystemParametersFromJSON(
|
|
|
253
274
|
}
|
|
254
275
|
|
|
255
276
|
/** The render mode's own settings as JSON: a trail's or a stretched billboard's, else none. */
|
|
256
|
-
function rendererEmitterSettingsJSON(system: ParticleSystem):
|
|
277
|
+
function rendererEmitterSettingsJSON(system: ParticleSystem): RendererEmitterSettingsJSON | undefined {
|
|
257
278
|
if (system.renderMode === RenderMode.Trail) {
|
|
258
279
|
const settings = system.rendererEmitterSettings as TrailSettings;
|
|
259
280
|
// `startLength` always, for loaders that read it without a default; the rest only when on.
|
|
@@ -263,8 +284,8 @@ function rendererEmitterSettingsJSON(system: ParticleSystem): RendererEmitterSet
|
|
|
263
284
|
...trailFlags(settings),
|
|
264
285
|
...trailCurve(settings),
|
|
265
286
|
...trailSampling(settings),
|
|
266
|
-
...
|
|
267
|
-
}
|
|
287
|
+
...trailSideAxisJSON(settings),
|
|
288
|
+
};
|
|
268
289
|
}
|
|
269
290
|
if (system.renderMode === RenderMode.StretchedBillBoard) {
|
|
270
291
|
return {
|
|
@@ -272,7 +293,7 @@ function rendererEmitterSettingsJSON(system: ParticleSystem): RendererEmitterSet
|
|
|
272
293
|
lengthFactor: (system.rendererEmitterSettings as StretchedBillBoardSettings).lengthFactor,
|
|
273
294
|
};
|
|
274
295
|
}
|
|
275
|
-
return
|
|
296
|
+
return undefined;
|
|
276
297
|
}
|
|
277
298
|
|
|
278
299
|
/** Writes the system's geometry into `meta` once per document, and returns its uuid. */
|
|
@@ -337,7 +358,7 @@ function materialMeta(system: ParticleSystem, meta: BabylonMetaData): string {
|
|
|
337
358
|
if (uuid === undefined) {
|
|
338
359
|
uuid = nextSerializationId(meta, 'quarks_texture');
|
|
339
360
|
textures.set(value, uuid);
|
|
340
|
-
meta.textures[uuid] = value
|
|
361
|
+
meta.textures[uuid] = value;
|
|
341
362
|
}
|
|
342
363
|
return uuid;
|
|
343
364
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {Constants} from '@babylonjs/core/Engines/constants';
|
|
2
|
+
import type {ColorGeneratorJSON, RotationGeneratorJSON, ValueGeneratorJSON, Vector3GeneratorJSON} from 'quarks.core';
|
|
2
3
|
import {
|
|
3
4
|
ColorGenerator,
|
|
4
5
|
ColorGeneratorFromJSON,
|
|
@@ -7,6 +8,7 @@ import {
|
|
|
7
8
|
FunctionColorGenerator,
|
|
8
9
|
FunctionValueGenerator,
|
|
9
10
|
GeneratorFromJSON,
|
|
11
|
+
readFormatPart,
|
|
10
12
|
RotationGenerator,
|
|
11
13
|
ValueGenerator,
|
|
12
14
|
ValueGeneratorFromJSON,
|
|
@@ -17,8 +19,20 @@ import {
|
|
|
17
19
|
} from 'quarks.core';
|
|
18
20
|
import type {ParticleSystem} from '../ParticleSystem';
|
|
19
21
|
import {RenderMode} from '../VFXBatch';
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
+
import {
|
|
23
|
+
DEFAULT_SOFT_FAR_FADE,
|
|
24
|
+
normalizeBursts,
|
|
25
|
+
validCullingMode,
|
|
26
|
+
validRenderFace,
|
|
27
|
+
validSortMode,
|
|
28
|
+
validTileCount,
|
|
29
|
+
} from './normalize';
|
|
30
|
+
import type {
|
|
31
|
+
BurstParameters,
|
|
32
|
+
BurstParametersJSON,
|
|
33
|
+
ParticleSystemJSONParameters,
|
|
34
|
+
ParticleSystemParameters,
|
|
35
|
+
} from './types';
|
|
22
36
|
|
|
23
37
|
/**
|
|
24
38
|
* One setting of a {@link ParticleSystem} that is a plain value or a generator: how to read it
|
|
@@ -54,6 +68,9 @@ export interface SettingDescriptor {
|
|
|
54
68
|
|
|
55
69
|
type Generator = {toJSON(): unknown; clone(): unknown};
|
|
56
70
|
|
|
71
|
+
/** A burst as files hold it, any field left out. */
|
|
72
|
+
type BurstJSON = Partial<BurstParametersJSON>;
|
|
73
|
+
|
|
57
74
|
/** A number, boolean or string compared by value. */
|
|
58
75
|
function plain<T>(
|
|
59
76
|
param: keyof ParticleSystemParameters,
|
|
@@ -97,11 +114,11 @@ function boolean(json: unknown): boolean | undefined {
|
|
|
97
114
|
* A generator, compared with its default through its JSON. `read` turns the JSON back into one;
|
|
98
115
|
* a bare number is read as a constant.
|
|
99
116
|
*/
|
|
100
|
-
function generator(
|
|
117
|
+
function generator<J>(
|
|
101
118
|
param: keyof ParticleSystemParameters,
|
|
102
119
|
get: (system: ParticleSystem) => Generator,
|
|
103
120
|
defaultValue: () => Generator,
|
|
104
|
-
read: (json:
|
|
121
|
+
read: (json: J) => unknown,
|
|
105
122
|
always = true
|
|
106
123
|
): SettingDescriptor {
|
|
107
124
|
const defaultJSON = JSON.stringify(defaultValue().toJSON());
|
|
@@ -111,7 +128,8 @@ function generator(
|
|
|
111
128
|
get,
|
|
112
129
|
isDefault: (value) => JSON.stringify((value as Generator).toJSON()) === defaultJSON,
|
|
113
130
|
toJSON: (value) => (value as Generator).toJSON(),
|
|
114
|
-
|
|
131
|
+
// The generator readers check the JSON they are given, and warn about what they cannot read.
|
|
132
|
+
fromJSON: (json) => (typeof json === 'number' ? new ConstantValue(json) : read(json as J)),
|
|
115
133
|
clone: (value) => (value as Generator).clone(),
|
|
116
134
|
};
|
|
117
135
|
}
|
|
@@ -152,19 +170,21 @@ export const SETTINGS: ReadonlyArray<SettingDescriptor> = [
|
|
|
152
170
|
'startRotation',
|
|
153
171
|
(s) => s.startRotation,
|
|
154
172
|
() => new ConstantValue(0),
|
|
155
|
-
(json
|
|
173
|
+
(json: ValueGeneratorJSON | RotationGeneratorJSON) =>
|
|
174
|
+
GeneratorFromJSON(json) as RotationGenerator | ValueGenerator | FunctionValueGenerator
|
|
156
175
|
),
|
|
157
176
|
generator(
|
|
158
177
|
'startSize',
|
|
159
178
|
(s) => s.startSize,
|
|
160
179
|
() => new ConstantValue(1),
|
|
161
|
-
(json
|
|
180
|
+
(json: ValueGeneratorJSON | Vector3GeneratorJSON) =>
|
|
181
|
+
GeneratorFromJSON(json) as Vector3Generator | ValueGenerator | FunctionValueGenerator
|
|
162
182
|
),
|
|
163
183
|
generator(
|
|
164
184
|
'startColor',
|
|
165
185
|
(s) => s.startColor,
|
|
166
186
|
() => new ConstantColor(new Vector4(1, 1, 1, 1)),
|
|
167
|
-
(json) => ColorGeneratorFromJSON(json) as ColorGenerator | FunctionColorGenerator
|
|
187
|
+
(json: ColorGeneratorJSON) => ColorGeneratorFromJSON(json) as ColorGenerator | FunctionColorGenerator
|
|
168
188
|
),
|
|
169
189
|
generator(
|
|
170
190
|
'emissionOverTime',
|
|
@@ -193,7 +213,7 @@ export const SETTINGS: ReadonlyArray<SettingDescriptor> = [
|
|
|
193
213
|
fromJSON: (json) =>
|
|
194
214
|
Array.isArray(json)
|
|
195
215
|
? normalizeBursts(
|
|
196
|
-
json.map((burst:
|
|
216
|
+
json.map((burst: BurstJSON) => ({
|
|
197
217
|
time: burst.time,
|
|
198
218
|
count:
|
|
199
219
|
typeof burst.count === 'number'
|
|
@@ -228,6 +248,7 @@ export const SETTINGS: ReadonlyArray<SettingDescriptor> = [
|
|
|
228
248
|
),
|
|
229
249
|
plain('seed', (s) => s.seed, undefined, number),
|
|
230
250
|
plain('sortMode', (s) => s.sortMode, 'none', validSortMode),
|
|
251
|
+
plain('renderFace', (s) => s.renderFace, 'both', validRenderFace),
|
|
231
252
|
plain(
|
|
232
253
|
'alignToDirection',
|
|
233
254
|
(s) => s.alignToDirection,
|
|
@@ -299,7 +320,8 @@ export function settingsFromJSON(json: ParticleSystemJSONParameters): Partial<Pa
|
|
|
299
320
|
if (value === undefined || value === null) {
|
|
300
321
|
continue;
|
|
301
322
|
}
|
|
302
|
-
const
|
|
323
|
+
const key = settingJSONKey(setting);
|
|
324
|
+
const read = readFormatPart(key, () => setting.fromJSON(value));
|
|
303
325
|
if (read !== undefined) {
|
|
304
326
|
parameters[setting.param] = read;
|
|
305
327
|
}
|
package/src/system/types.ts
CHANGED
|
@@ -1,18 +1,27 @@
|
|
|
1
|
+
import type {BaseTexture} from '@babylonjs/core/Materials/Textures/baseTexture';
|
|
1
2
|
import type {Texture} from '@babylonjs/core/Materials/Textures/texture';
|
|
2
3
|
import type {Scene} from '@babylonjs/core/scene';
|
|
3
4
|
import type {
|
|
4
5
|
Behavior,
|
|
6
|
+
BehaviorJSON,
|
|
5
7
|
ColorGenerator,
|
|
8
|
+
ColorGeneratorJSON,
|
|
6
9
|
EmitterShape,
|
|
7
10
|
FunctionColorGenerator,
|
|
8
|
-
FunctionJSON,
|
|
9
11
|
FunctionValueGenerator,
|
|
10
12
|
RendererEmitterSettings,
|
|
11
13
|
RotationGenerator,
|
|
14
|
+
RotationGeneratorJSON,
|
|
15
|
+
ShapeJSON,
|
|
16
|
+
StretchedBillBoardSettings,
|
|
12
17
|
ValueGenerator,
|
|
18
|
+
ValueGeneratorJSON,
|
|
13
19
|
Vector2,
|
|
14
20
|
Vector3,
|
|
21
|
+
Vector3ArrayJSON,
|
|
15
22
|
Vector3Generator,
|
|
23
|
+
Vector3GeneratorJSON,
|
|
24
|
+
Vector3JSON,
|
|
16
25
|
} from 'quarks.core';
|
|
17
26
|
import type {
|
|
18
27
|
MeshLighting,
|
|
@@ -20,10 +29,28 @@ import type {
|
|
|
20
29
|
ParticleErosionOptions,
|
|
21
30
|
ParticleGradientMap,
|
|
22
31
|
ParticleUVDistortionOptions,
|
|
32
|
+
RenderFace,
|
|
23
33
|
RenderMode,
|
|
24
34
|
SortMode,
|
|
25
35
|
TextureUV,
|
|
26
36
|
} from '../VFXBatch';
|
|
37
|
+
import type {GeometryEntry, QuarksMaterialJSON} from '../effectDocumentJSON';
|
|
38
|
+
import type {TrailOptions} from '../trailSettings';
|
|
39
|
+
import type {ParticleMaterialSource} from './materialResolve';
|
|
40
|
+
|
|
41
|
+
/** A trail's settings in JSON, each only when not its default: the start length as a generator's JSON, the side axis as `[x, y, z]`. */
|
|
42
|
+
export type TrailSettingsJSON = Partial<TrailOptions> & {
|
|
43
|
+
/** See `TrailSettings.startLength`. */
|
|
44
|
+
startLength?: ValueGeneratorJSON;
|
|
45
|
+
/** See `TrailSettings.sideAxis`; files may hold it as `{x, y, z}`. */
|
|
46
|
+
sideAxis?: Vector3ArrayJSON | Vector3JSON;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* A render mode's own settings in JSON, see {@link RendererEmitterSettings}: a trail's or a
|
|
51
|
+
* stretched billboard's. The other render modes have none, and their systems leave the field out.
|
|
52
|
+
*/
|
|
53
|
+
export type RendererEmitterSettingsJSON = TrailSettingsJSON | StretchedBillBoardSettings;
|
|
27
54
|
|
|
28
55
|
/**
|
|
29
56
|
* One burst of a system's emission (Unity's Emission Bursts): `count` particles at `time` seconds
|
|
@@ -64,6 +91,12 @@ export interface BurstParameters {
|
|
|
64
91
|
* An empty system is never culled, so it can start emitting and grow the
|
|
65
92
|
* bounds that decide its visibility. A system another one emits into is never
|
|
66
93
|
* culled either; its parent decides.
|
|
94
|
+
*
|
|
95
|
+
* The cameras tested are the scene's active cameras (`scene.activeCameras`, or
|
|
96
|
+
* `scene.activeCamera`), each only for the systems on a layer it renders
|
|
97
|
+
* (`camera.layerMask & system.layers.mask`). A camera that renders into a
|
|
98
|
+
* render target texture (a mirror, a minimap, a portal) is not one of them: a
|
|
99
|
+
* system seen only through one should keep `'always'`.
|
|
67
100
|
*/
|
|
68
101
|
export type CullingMode = 'always' | 'pause' | 'pauseAndCatchUp';
|
|
69
102
|
|
|
@@ -169,7 +202,7 @@ export interface ParticleSystemParameters {
|
|
|
169
202
|
/** @deprecated Set `speedFactor` in {@link rendererEmitterSettings} instead; this one wins when both are set. */
|
|
170
203
|
speedFactor?: number;
|
|
171
204
|
/** See {@link ParticleSystem.material}. Default none. */
|
|
172
|
-
material?:
|
|
205
|
+
material?: ParticleMaterialSource | null;
|
|
173
206
|
/** See {@link ParticleSystem.texture}. Unset takes the material's texture; null draws without one. */
|
|
174
207
|
texture?: Texture | null;
|
|
175
208
|
/** See {@link ParticleSystem.startTileIndex}. Default 0. */
|
|
@@ -236,6 +269,8 @@ export interface ParticleSystemParameters {
|
|
|
236
269
|
seed?: number;
|
|
237
270
|
/** Draw order within the batch, see {@link ParticleSystem.sortMode}. Default `'none'`. */
|
|
238
271
|
sortMode?: SortMode;
|
|
272
|
+
/** Which faces a mesh particle draws, see {@link ParticleSystem.renderFace}. Default `'both'`. */
|
|
273
|
+
renderFace?: RenderFace;
|
|
239
274
|
/** Whether particles start turned along their direction of travel, see {@link ParticleSystem.alignToDirection}. Default false. */
|
|
240
275
|
alignToDirection?: boolean;
|
|
241
276
|
/** Smallest on-screen size, as a fraction of the viewport height, see {@link ParticleSystem.minParticleSize}. Default 0. */
|
|
@@ -255,13 +290,15 @@ export interface BurstParametersJSON {
|
|
|
255
290
|
/** See {@link BurstParameters.time}. */
|
|
256
291
|
time: number;
|
|
257
292
|
/** See {@link BurstParameters.count}. */
|
|
258
|
-
count:
|
|
293
|
+
count: ValueGeneratorJSON | number;
|
|
259
294
|
/** See {@link BurstParameters.cycle}. */
|
|
260
295
|
cycle: number;
|
|
261
296
|
/** See {@link BurstParameters.interval}. */
|
|
262
297
|
interval: number;
|
|
263
298
|
/** See {@link BurstParameters.probability}. */
|
|
264
299
|
probability: number;
|
|
300
|
+
/** `cycle`, as files before it was named wrote it; read when there is no `cycle`. */
|
|
301
|
+
cycleCount?: number;
|
|
265
302
|
}
|
|
266
303
|
|
|
267
304
|
/**
|
|
@@ -288,23 +325,23 @@ export interface ParticleSystemJSONParameters {
|
|
|
288
325
|
/** See {@link ParticleSystem.duration}. */
|
|
289
326
|
duration?: number;
|
|
290
327
|
/** See {@link ParticleSystem.startDelay}. */
|
|
291
|
-
startDelay?:
|
|
328
|
+
startDelay?: ValueGeneratorJSON;
|
|
292
329
|
/** The emitter shape, as its `toJSON` writes it. */
|
|
293
|
-
shape?:
|
|
330
|
+
shape?: ShapeJSON;
|
|
294
331
|
/** See {@link ParticleSystem.startLife}. */
|
|
295
|
-
startLife?:
|
|
332
|
+
startLife?: ValueGeneratorJSON;
|
|
296
333
|
/** See {@link ParticleSystem.startSpeed}. */
|
|
297
|
-
startSpeed?:
|
|
334
|
+
startSpeed?: ValueGeneratorJSON;
|
|
298
335
|
/** See {@link ParticleSystem.startRotation}. */
|
|
299
|
-
startRotation?:
|
|
336
|
+
startRotation?: ValueGeneratorJSON | RotationGeneratorJSON;
|
|
300
337
|
/** See {@link ParticleSystem.startSize}. */
|
|
301
|
-
startSize?:
|
|
338
|
+
startSize?: ValueGeneratorJSON | Vector3GeneratorJSON;
|
|
302
339
|
/** See {@link ParticleSystem.startColor}. */
|
|
303
|
-
startColor?:
|
|
340
|
+
startColor?: ColorGeneratorJSON;
|
|
304
341
|
/** See {@link ParticleSystem.emissionOverTime}. */
|
|
305
|
-
emissionOverTime?:
|
|
342
|
+
emissionOverTime?: ValueGeneratorJSON;
|
|
306
343
|
/** See {@link ParticleSystem.emissionOverDistance}. */
|
|
307
|
-
emissionOverDistance?:
|
|
344
|
+
emissionOverDistance?: ValueGeneratorJSON;
|
|
308
345
|
/** See {@link ParticleSystem.emissionBursts}. */
|
|
309
346
|
emissionBursts?: Array<BurstParametersJSON>;
|
|
310
347
|
/** See {@link ParticleSystem.maxParticles}. */
|
|
@@ -312,12 +349,12 @@ export interface ParticleSystemJSONParameters {
|
|
|
312
349
|
/** See {@link ParticleSystem.onlyUsedByOther}. */
|
|
313
350
|
onlyUsedByOther?: boolean;
|
|
314
351
|
/**
|
|
315
|
-
* Trail, stretched or mesh settings; a trail's `startLength` as `
|
|
352
|
+
* Trail, stretched or mesh settings; a trail's `startLength` as `ValueGeneratorJSON`. Left out when
|
|
316
353
|
* the render mode has none.
|
|
317
354
|
*/
|
|
318
|
-
rendererEmitterSettings?:
|
|
319
|
-
/** Uuid of the mesh particles' geometry entry. */
|
|
320
|
-
instancingGeometry?:
|
|
355
|
+
rendererEmitterSettings?: RendererEmitterSettingsJSON;
|
|
356
|
+
/** Uuid of the mesh particles' geometry entry; a document made in code may hold the entry itself. */
|
|
357
|
+
instancingGeometry?: string | GeometryEntry;
|
|
321
358
|
/** A {@link RenderMode} value. */
|
|
322
359
|
renderMode?: number;
|
|
323
360
|
/** See {@link ParticleSystem.renderOrder}. */
|
|
@@ -336,6 +373,8 @@ export interface ParticleSystemJSONParameters {
|
|
|
336
373
|
seed?: number;
|
|
337
374
|
/** Written only when not `'none'`. */
|
|
338
375
|
sortMode?: SortMode;
|
|
376
|
+
/** Written only when not `'both'`. */
|
|
377
|
+
renderFace?: RenderFace;
|
|
339
378
|
/** Written only when true. */
|
|
340
379
|
alignToDirection?: boolean;
|
|
341
380
|
/** Written only when not 0. */
|
|
@@ -351,7 +390,7 @@ export interface ParticleSystemJSONParameters {
|
|
|
351
390
|
/** The camera layer mask. */
|
|
352
391
|
layers?: number;
|
|
353
392
|
/** See {@link ParticleSystem.startTileIndex}. */
|
|
354
|
-
startTileIndex?:
|
|
393
|
+
startTileIndex?: ValueGeneratorJSON | number;
|
|
355
394
|
/** See {@link ParticleSystem.uTileCount}. */
|
|
356
395
|
uTileCount?: number;
|
|
357
396
|
/** See {@link ParticleSystem.vTileCount}. */
|
|
@@ -375,7 +414,7 @@ export interface ParticleSystemJSONParameters {
|
|
|
375
414
|
/** See {@link ParticleSystemParameters.alphaTest}. */
|
|
376
415
|
alphaTest?: number;
|
|
377
416
|
/** Each behavior as its `toJSON` writes it. */
|
|
378
|
-
behaviors?:
|
|
417
|
+
behaviors?: BehaviorJSON[];
|
|
379
418
|
/** See {@link ParticleSystem.worldSpace}. */
|
|
380
419
|
worldSpace?: boolean;
|
|
381
420
|
/** `[x, y, z]`; written only when non-zero. */
|
|
@@ -392,19 +431,19 @@ export interface ParticleSystemJSONParameters {
|
|
|
392
431
|
*/
|
|
393
432
|
export interface BabylonMetaData {
|
|
394
433
|
/** Textures by uuid; null for one that could not be made. */
|
|
395
|
-
textures: {[uuid: string]:
|
|
434
|
+
textures: {[uuid: string]: BaseTexture | null};
|
|
396
435
|
/** Material entries by uuid. */
|
|
397
|
-
materials: {[uuid: string]:
|
|
436
|
+
materials: {[uuid: string]: QuarksMaterialJSON};
|
|
398
437
|
/** Geometry entries by uuid. */
|
|
399
|
-
geometries: {[uuid: string]:
|
|
400
|
-
/**
|
|
401
|
-
images?: {[uuid: string]:
|
|
438
|
+
geometries: {[uuid: string]: GeometryEntry};
|
|
439
|
+
/** Not used by babylon.quarks; kept for three.js-shaped documents. */
|
|
440
|
+
images?: {[uuid: string]: unknown};
|
|
441
|
+
/** Not used by babylon.quarks; kept for three.js-shaped documents. */
|
|
442
|
+
shapes?: {[uuid: string]: unknown};
|
|
402
443
|
/** Not used by babylon.quarks; kept for three.js-shaped documents. */
|
|
403
|
-
|
|
444
|
+
skeletons?: {[uuid: string]: unknown};
|
|
404
445
|
/** Not used by babylon.quarks; kept for three.js-shaped documents. */
|
|
405
|
-
|
|
446
|
+
animations?: {[uuid: string]: unknown};
|
|
406
447
|
/** Not used by babylon.quarks; kept for three.js-shaped documents. */
|
|
407
|
-
|
|
408
|
-
/** Nodes by uuid, which a mesh surface shape links to. */
|
|
409
|
-
nodes?: {[uuid: string]: any};
|
|
448
|
+
nodes?: {[uuid: string]: unknown};
|
|
410
449
|
}
|