@vgai/engine 0.2.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/LICENSE +202 -0
- package/README.md +35 -0
- package/package.json +55 -0
- package/src/adapter/authoring.ts +402 -0
- package/src/adapter/colyseus-networking-adapter.ts +72 -0
- package/src/adapter/first-party-systems.ts +103 -0
- package/src/adapter/game-adapter.ts +151 -0
- package/src/adapter/host-context.ts +77 -0
- package/src/adapter/index.ts +85 -0
- package/src/adapter/ingest/game-contract.ts +59 -0
- package/src/adapter/ingest/overlay-applier.ts +207 -0
- package/src/adapter/ingest/overlay-apply.ts +124 -0
- package/src/adapter/ingest/overlay-file.ts +126 -0
- package/src/adapter/ingest/overlay-report.ts +176 -0
- package/src/adapter/ingest/scene-capture.ts +307 -0
- package/src/adapter/ingest/upstream-pin.ts +52 -0
- package/src/adapter/loop-gate-report.ts +54 -0
- package/src/adapter/rapier-physics-adapter.ts +56 -0
- package/src/adapter/system-adapter.ts +154 -0
- package/src/adapter/transform.ts +18 -0
- package/src/adapter/vgai-scene-game-adapter.ts +886 -0
- package/src/adapter/world-kind.ts +34 -0
- package/src/ai/navigation.ts +164 -0
- package/src/animation/anim-graph-types.ts +56 -0
- package/src/animation/anim-graph.ts +406 -0
- package/src/animation/anim-system.ts +28 -0
- package/src/animation/blend-node.ts +119 -0
- package/src/animation/property-track.ts +178 -0
- package/src/animation/schema.ts +204 -0
- package/src/assets.ts +80 -0
- package/src/audio/ambient.ts +300 -0
- package/src/audio/impacts.ts +212 -0
- package/src/audio/index.ts +7 -0
- package/src/audio/movement.ts +140 -0
- package/src/audio/musical.ts +200 -0
- package/src/audio/ui-sounds.ts +171 -0
- package/src/audio/vehicle.ts +235 -0
- package/src/audio/weapons.ts +152 -0
- package/src/core/game-loop.ts +127 -0
- package/src/core/system-runner.ts +298 -0
- package/src/core/types.ts +58 -0
- package/src/dev/console-bridge.ts +83 -0
- package/src/dev/debug-draw.ts +80 -0
- package/src/dev/logger.ts +119 -0
- package/src/ecs/component-manager.ts +748 -0
- package/src/ecs/game-component.ts +147 -0
- package/src/ecs/hmr-swap-report.ts +65 -0
- package/src/input/input-manager.ts +439 -0
- package/src/input/input-types.ts +19 -0
- package/src/input/schema.ts +129 -0
- package/src/loader.ts +70 -0
- package/src/manifest/index.ts +24 -0
- package/src/manifest/load-file.ts +16 -0
- package/src/manifest/load.ts +378 -0
- package/src/manifest/schema.ts +375 -0
- package/src/physics/collision-system.ts +76 -0
- package/src/physics/physics-registry.ts +83 -0
- package/src/physics/transform-writer.ts +41 -0
- package/src/physics/trigger-dispatch.ts +97 -0
- package/src/react/game-state.tsx +172 -0
- package/src/render/auto-batcher.ts +169 -0
- package/src/render/render-batch-system.ts +268 -0
- package/src/render/render-features.ts +146 -0
- package/src/render/render-settings.ts +72 -0
- package/src/runtime/create-runtime.ts +1152 -0
- package/src/runtime/frame-selector-cache.ts +81 -0
- package/src/runtime/game.ts +1003 -0
- package/src/runtime/input-router.ts +213 -0
- package/src/runtime/mount-game.ts +269 -0
- package/src/runtime/mount-manifest.ts +361 -0
- package/src/runtime/scene-ui-bridge.ts +86 -0
- package/src/runtime/scene-ui-data.ts +119 -0
- package/src/runtime/state-bridge.ts +79 -0
- package/src/runtime/types.ts +196 -0
- package/src/scene/asset-loaders.ts +195 -0
- package/src/scene/asset-paths.ts +123 -0
- package/src/scene/asset-registry.ts +67 -0
- package/src/scene/collider-dimensions.ts +125 -0
- package/src/scene/component-registry.ts +40 -0
- package/src/scene/defaults.ts +164 -0
- package/src/scene/geometries/index.ts +7 -0
- package/src/scene/geometries/terrain.ts +42 -0
- package/src/scene/geometry-registry.ts +42 -0
- package/src/scene/instance-registry.ts +84 -0
- package/src/scene/instancers/grid.ts +38 -0
- package/src/scene/instancers/index.ts +7 -0
- package/src/scene/light-camera-factory.ts +97 -0
- package/src/scene/material-factory.ts +211 -0
- package/src/scene/material-registry.ts +73 -0
- package/src/scene/materials/index.ts +7 -0
- package/src/scene/materials/water.ts +56 -0
- package/src/scene/parse.ts +71 -0
- package/src/scene/particles-factory.ts +383 -0
- package/src/scene/scene-apply.ts +356 -0
- package/src/scene/scene-diff-schema.ts +115 -0
- package/src/scene/scene-diff-types.ts +29 -0
- package/src/scene/scene-loader.ts +1533 -0
- package/src/scene/scene-query.ts +63 -0
- package/src/scene/scene-types.ts +34 -0
- package/src/scene/scene-version.ts +40 -0
- package/src/scene/schema/animation.ts +95 -0
- package/src/scene/schema/audio.ts +25 -0
- package/src/scene/schema/camera.ts +21 -0
- package/src/scene/schema/collider.ts +69 -0
- package/src/scene/schema/entity-ref.ts +78 -0
- package/src/scene/schema/entity.ts +169 -0
- package/src/scene/schema/environment.ts +384 -0
- package/src/scene/schema/index.ts +95 -0
- package/src/scene/schema/instances.ts +35 -0
- package/src/scene/schema/joint.ts +26 -0
- package/src/scene/schema/light.ts +38 -0
- package/src/scene/schema/material.ts +113 -0
- package/src/scene/schema/mesh.ts +108 -0
- package/src/scene/schema/particles.ts +398 -0
- package/src/scene/schema/physics.ts +49 -0
- package/src/scene/schema/scene-file.ts +299 -0
- package/src/scene/schema/shadow.ts +24 -0
- package/src/scene/schema/spline.ts +21 -0
- package/src/scene/schema/tuples.ts +21 -0
- package/src/scene/schema/ui.ts +602 -0
- package/src/scene/user-data.ts +203 -0
- package/src/setup/setup-audio.ts +60 -0
- package/src/setup/setup-particles.ts +23 -0
- package/src/setup/setup-physics.ts +67 -0
- package/src/setup/setup-renderer.ts +529 -0
- package/src/types-n8ao.d.ts +37 -0
- package/src/types-realism-effects.d.ts +61 -0
- package/src/world2d/authoring-2d.ts +208 -0
- package/src/world2d/capture-to-scene2d.ts +52 -0
- package/src/world2d/collision-2d.ts +106 -0
- package/src/world2d/components-2d.ts +86 -0
- package/src/world2d/index.ts +66 -0
- package/src/world2d/ingest-iframe-2d.ts +255 -0
- package/src/world2d/ingest2d.ts +131 -0
- package/src/world2d/physics2d-registry.ts +49 -0
- package/src/world2d/pixi-game-adapter.ts +325 -0
- package/src/world2d/pixi-surface.ts +78 -0
- package/src/world2d/scene-capture-2d.ts +117 -0
- package/src/world2d/scene2d-loader.ts +308 -0
- package/src/world2d/schema/entity2d.ts +145 -0
- package/src/world2d/schema/physics2d.ts +53 -0
- package/src/world2d/schema/sprite.ts +71 -0
- package/src/world2d/schema/tilemap.ts +22 -0
- package/src/world2d/schema/tuples2d.ts +25 -0
- package/src/world2d/system-adapters-2d.ts +49 -0
- package/src/world2d/transform-writer-2d.ts +24 -0
- package/src/world2d/types.ts +55 -0
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
// biome-ignore-all lint/suspicious/noExplicitAny: quarks' API uses untyped FunctionJSON internally; our Zod types are structurally compatible but TS can't unify them
|
|
2
|
+
/**
|
|
3
|
+
* Converts SceneParticles JSON → three.quarks ParticleSystem.
|
|
4
|
+
*
|
|
5
|
+
* Shared between the editor entity-factory and the runtime scene-loader.
|
|
6
|
+
* The schema mirrors quarks' native JSON format, so most fields pass through
|
|
7
|
+
* directly to quarks' fromJSON or constructor methods.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
ApplyForce,
|
|
12
|
+
ChangeEmitDirection,
|
|
13
|
+
CircleEmitter,
|
|
14
|
+
ColorGeneratorFromJSON,
|
|
15
|
+
ColorOverLife,
|
|
16
|
+
ConeEmitter,
|
|
17
|
+
DonutEmitter,
|
|
18
|
+
ForceOverLife,
|
|
19
|
+
FrameOverLife,
|
|
20
|
+
GravityForce,
|
|
21
|
+
GridEmitter,
|
|
22
|
+
HemisphereEmitter,
|
|
23
|
+
LimitSpeedOverLife,
|
|
24
|
+
Noise,
|
|
25
|
+
OrbitOverLife,
|
|
26
|
+
PointEmitter,
|
|
27
|
+
Vector3 as QVector3,
|
|
28
|
+
RectangleEmitter,
|
|
29
|
+
RotationOverLife,
|
|
30
|
+
SizeOverLife,
|
|
31
|
+
SpeedOverLife,
|
|
32
|
+
SphereEmitter,
|
|
33
|
+
TurbulenceField,
|
|
34
|
+
ValueGeneratorFromJSON,
|
|
35
|
+
WidthOverLength,
|
|
36
|
+
} from 'quarks.core';
|
|
37
|
+
import * as THREE from 'three';
|
|
38
|
+
import { type BatchedRenderer, ParticleSystem, RenderMode } from 'three.quarks';
|
|
39
|
+
import type { SceneParticles } from './scene-types';
|
|
40
|
+
import type {
|
|
41
|
+
BehaviorJSON,
|
|
42
|
+
ColorGeneratorJSON,
|
|
43
|
+
EmitterShapeJSON,
|
|
44
|
+
ValueGeneratorJSON,
|
|
45
|
+
} from './schema/particles';
|
|
46
|
+
|
|
47
|
+
// --- Render mode mapping ---
|
|
48
|
+
|
|
49
|
+
const RENDER_MODE_MAP: Record<string, RenderMode> = {
|
|
50
|
+
billboard: RenderMode.BillBoard,
|
|
51
|
+
stretchedBillboard: RenderMode.StretchedBillBoard,
|
|
52
|
+
mesh: RenderMode.Mesh,
|
|
53
|
+
trail: RenderMode.Trail,
|
|
54
|
+
horizontalBillboard: RenderMode.HorizontalBillBoard,
|
|
55
|
+
verticalBillboard: RenderMode.VerticalBillBoard,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// --- Texture loader (shared cache) ---
|
|
59
|
+
|
|
60
|
+
import { textureLoader } from '../loader';
|
|
61
|
+
|
|
62
|
+
const particleTexCache = new Map<string, THREE.Texture>();
|
|
63
|
+
|
|
64
|
+
function loadParticleTexture(url: string): THREE.Texture {
|
|
65
|
+
const cached = particleTexCache.get(url);
|
|
66
|
+
if (cached) return cached;
|
|
67
|
+
const tex = textureLoader.load(url);
|
|
68
|
+
particleTexCache.set(url, tex);
|
|
69
|
+
return tex;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// --- Helpers ---
|
|
73
|
+
|
|
74
|
+
/** Strip keys with undefined values so exactOptionalPropertyTypes is satisfied. */
|
|
75
|
+
function defined(obj: Record<string, any>): any {
|
|
76
|
+
const result: Record<string, unknown> = {};
|
|
77
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
78
|
+
if (v !== undefined) result[k] = v;
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// --- Emitter shape ---
|
|
84
|
+
|
|
85
|
+
function createEmitterShape(json: EmitterShapeJSON) {
|
|
86
|
+
switch (json.type) {
|
|
87
|
+
case 'point':
|
|
88
|
+
return new PointEmitter();
|
|
89
|
+
case 'sphere':
|
|
90
|
+
return new SphereEmitter(
|
|
91
|
+
defined({ radius: json.radius, arc: json.arc, thickness: json.thickness }),
|
|
92
|
+
);
|
|
93
|
+
case 'hemisphere':
|
|
94
|
+
return new HemisphereEmitter(
|
|
95
|
+
defined({ radius: json.radius, arc: json.arc, thickness: json.thickness }),
|
|
96
|
+
);
|
|
97
|
+
case 'cone':
|
|
98
|
+
return new ConeEmitter(
|
|
99
|
+
defined({
|
|
100
|
+
radius: json.radius,
|
|
101
|
+
arc: json.arc,
|
|
102
|
+
thickness: json.thickness,
|
|
103
|
+
angle: json.angle,
|
|
104
|
+
}),
|
|
105
|
+
);
|
|
106
|
+
case 'circle':
|
|
107
|
+
return new CircleEmitter(
|
|
108
|
+
defined({ radius: json.radius, arc: json.arc, thickness: json.thickness }),
|
|
109
|
+
);
|
|
110
|
+
case 'donut':
|
|
111
|
+
return new DonutEmitter(
|
|
112
|
+
defined({
|
|
113
|
+
radius: json.radius,
|
|
114
|
+
arc: json.arc,
|
|
115
|
+
thickness: json.thickness,
|
|
116
|
+
donutRadius: json.donutRadius,
|
|
117
|
+
}),
|
|
118
|
+
);
|
|
119
|
+
case 'rectangle':
|
|
120
|
+
return new RectangleEmitter(
|
|
121
|
+
defined({ width: json.width, height: json.height, thickness: json.thickness }),
|
|
122
|
+
);
|
|
123
|
+
case 'grid':
|
|
124
|
+
return new GridEmitter(
|
|
125
|
+
defined({ width: json.width, height: json.height, column: json.column, row: json.row }),
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// --- Value / Color generators ---
|
|
131
|
+
// Our Zod-inferred types are structurally identical to quarks' FunctionJSON
|
|
132
|
+
// but TypeScript can't unify them, so we cast through the untyped bridge.
|
|
133
|
+
|
|
134
|
+
function valueGen(json: ValueGeneratorJSON) {
|
|
135
|
+
return ValueGeneratorFromJSON(json as any);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function colorGen(json: ColorGeneratorJSON) {
|
|
139
|
+
return ColorGeneratorFromJSON(json as any);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// --- Behaviors ---
|
|
143
|
+
|
|
144
|
+
function createBehavior(json: BehaviorJSON): any {
|
|
145
|
+
switch (json.type) {
|
|
146
|
+
case 'ApplyForce':
|
|
147
|
+
return new ApplyForce(
|
|
148
|
+
new QVector3(json.direction[0], json.direction[1], json.direction[2]),
|
|
149
|
+
valueGen(json.magnitude) as any,
|
|
150
|
+
);
|
|
151
|
+
case 'ColorOverLife':
|
|
152
|
+
return new ColorOverLife(colorGen(json.color) as any);
|
|
153
|
+
case 'SizeOverLife':
|
|
154
|
+
return new SizeOverLife(valueGen(json.size) as any);
|
|
155
|
+
case 'SpeedOverLife':
|
|
156
|
+
return new SpeedOverLife(valueGen(json.speed) as any);
|
|
157
|
+
case 'RotationOverLife':
|
|
158
|
+
return new RotationOverLife(valueGen(json.angularVelocity) as any);
|
|
159
|
+
case 'ForceOverLife':
|
|
160
|
+
return new ForceOverLife(
|
|
161
|
+
valueGen(json.x) as any,
|
|
162
|
+
valueGen(json.y) as any,
|
|
163
|
+
valueGen(json.z) as any,
|
|
164
|
+
);
|
|
165
|
+
case 'OrbitOverLife':
|
|
166
|
+
return new OrbitOverLife(
|
|
167
|
+
valueGen(json.orbitSpeed) as any,
|
|
168
|
+
json.axis ? new QVector3(json.axis[0], json.axis[1], json.axis[2]) : undefined,
|
|
169
|
+
);
|
|
170
|
+
case 'Noise':
|
|
171
|
+
return new Noise(
|
|
172
|
+
valueGen(json.frequency) as any,
|
|
173
|
+
valueGen(json.power) as any,
|
|
174
|
+
json.positionAmount ? (valueGen(json.positionAmount) as any) : undefined,
|
|
175
|
+
json.rotationAmount ? (valueGen(json.rotationAmount) as any) : undefined,
|
|
176
|
+
);
|
|
177
|
+
case 'TurbulenceField':
|
|
178
|
+
return new TurbulenceField(
|
|
179
|
+
new QVector3(json.scale[0], json.scale[1], json.scale[2]),
|
|
180
|
+
json.octaves,
|
|
181
|
+
new QVector3(
|
|
182
|
+
json.velocityMultiplier[0],
|
|
183
|
+
json.velocityMultiplier[1],
|
|
184
|
+
json.velocityMultiplier[2],
|
|
185
|
+
),
|
|
186
|
+
new QVector3(json.timeScale[0], json.timeScale[1], json.timeScale[2]),
|
|
187
|
+
);
|
|
188
|
+
case 'FrameOverLife':
|
|
189
|
+
return new FrameOverLife(valueGen(json.frame) as any);
|
|
190
|
+
case 'LimitSpeedOverLife':
|
|
191
|
+
return new LimitSpeedOverLife(valueGen(json.speed) as any, json.dampen);
|
|
192
|
+
case 'ChangeEmitDirection':
|
|
193
|
+
return new ChangeEmitDirection(valueGen(json.angle) as any);
|
|
194
|
+
case 'GravityForce':
|
|
195
|
+
return new GravityForce(
|
|
196
|
+
new QVector3(json.center[0], json.center[1], json.center[2]),
|
|
197
|
+
json.magnitude,
|
|
198
|
+
);
|
|
199
|
+
case 'WidthOverLength':
|
|
200
|
+
return new WidthOverLength(valueGen(json.width) as any);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// --- Material ---
|
|
205
|
+
|
|
206
|
+
function createParticleMaterial(mat: SceneParticles['material']): THREE.Material {
|
|
207
|
+
const textures: Record<string, THREE.Texture> = {};
|
|
208
|
+
if (mat.map) textures['map'] = loadParticleTexture(mat.map);
|
|
209
|
+
|
|
210
|
+
const blending = mat.blending === 'normal' ? THREE.NormalBlending : THREE.AdditiveBlending;
|
|
211
|
+
const transparent = mat.transparent !== false;
|
|
212
|
+
const depthWrite = mat.depthWrite ?? false;
|
|
213
|
+
const side =
|
|
214
|
+
mat.side === 'back'
|
|
215
|
+
? THREE.BackSide
|
|
216
|
+
: mat.side === 'double'
|
|
217
|
+
? THREE.DoubleSide
|
|
218
|
+
: THREE.FrontSide;
|
|
219
|
+
|
|
220
|
+
if (mat.type === 'standard') {
|
|
221
|
+
return new THREE.MeshStandardMaterial({
|
|
222
|
+
color: mat.color ?? '#ffffff',
|
|
223
|
+
...textures,
|
|
224
|
+
blending,
|
|
225
|
+
transparent,
|
|
226
|
+
depthWrite,
|
|
227
|
+
side,
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
return new THREE.MeshBasicMaterial({
|
|
232
|
+
color: mat.color ?? '#ffffff',
|
|
233
|
+
...textures,
|
|
234
|
+
blending,
|
|
235
|
+
transparent,
|
|
236
|
+
depthWrite,
|
|
237
|
+
side,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// --- Default sprite texture (soft radial gradient) ---
|
|
242
|
+
|
|
243
|
+
let _defaultSpriteTex: THREE.Texture | null = null;
|
|
244
|
+
|
|
245
|
+
function getDefaultSpriteTex(): THREE.Texture {
|
|
246
|
+
if (_defaultSpriteTex) return _defaultSpriteTex;
|
|
247
|
+
const canvas = document.createElement('canvas');
|
|
248
|
+
canvas.width = 16;
|
|
249
|
+
canvas.height = 16;
|
|
250
|
+
const c2d = canvas.getContext('2d')!;
|
|
251
|
+
const grad = c2d.createRadialGradient(8, 8, 0, 8, 8, 8);
|
|
252
|
+
grad.addColorStop(0, 'rgba(255,255,255,1)');
|
|
253
|
+
grad.addColorStop(1, 'rgba(255,255,255,0)');
|
|
254
|
+
c2d.fillStyle = grad;
|
|
255
|
+
c2d.fillRect(0, 0, 16, 16);
|
|
256
|
+
_defaultSpriteTex = new THREE.CanvasTexture(canvas);
|
|
257
|
+
return _defaultSpriteTex;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// --- Public API ---
|
|
261
|
+
|
|
262
|
+
export interface ParticleSystemResult {
|
|
263
|
+
/** The emitter Object3D (add to scene for transform) */
|
|
264
|
+
emitter: THREE.Object3D;
|
|
265
|
+
/** The ParticleSystem instance (register with BatchedRenderer) */
|
|
266
|
+
system: ParticleSystem;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Create a three.quarks ParticleSystem from SceneParticles JSON data.
|
|
271
|
+
*/
|
|
272
|
+
// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: straightforward field-by-field mapping
|
|
273
|
+
export function createParticleSystemFromData(data: SceneParticles): ParticleSystemResult {
|
|
274
|
+
const material = createParticleMaterial(data.material);
|
|
275
|
+
|
|
276
|
+
// Apply default sprite if no texture specified
|
|
277
|
+
if (!data.material.map && 'map' in material) {
|
|
278
|
+
(material as THREE.MeshBasicMaterial).map = getDefaultSpriteTex();
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Build params, strip undefined keys for exactOptionalPropertyTypes compat
|
|
282
|
+
const params: Record<string, unknown> = { material };
|
|
283
|
+
|
|
284
|
+
if (data.autoDestroy != null) params['autoDestroy'] = data.autoDestroy;
|
|
285
|
+
if (data.looping != null) params['looping'] = data.looping;
|
|
286
|
+
if (data.prewarm != null) params['prewarm'] = data.prewarm;
|
|
287
|
+
if (data.duration != null) params['duration'] = data.duration;
|
|
288
|
+
if (data.shape) params['shape'] = createEmitterShape(data.shape);
|
|
289
|
+
|
|
290
|
+
if (data.startLife) params['startLife'] = valueGen(data.startLife);
|
|
291
|
+
if (data.startSpeed) params['startSpeed'] = valueGen(data.startSpeed);
|
|
292
|
+
if (data.startSize) params['startSize'] = valueGen(data.startSize);
|
|
293
|
+
if (data.startRotation) params['startRotation'] = valueGen(data.startRotation);
|
|
294
|
+
if (data.startColor) params['startColor'] = colorGen(data.startColor);
|
|
295
|
+
if (data.startTileIndex) params['startTileIndex'] = valueGen(data.startTileIndex);
|
|
296
|
+
|
|
297
|
+
// Trail mode requires startLength inside rendererEmitterSettings, not as a top-level param
|
|
298
|
+
if (data.renderMode === 'trail' && data.startLength) {
|
|
299
|
+
params['rendererEmitterSettings'] = { startLength: valueGen(data.startLength) };
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (data.emissionOverTime) params['emissionOverTime'] = valueGen(data.emissionOverTime);
|
|
303
|
+
if (data.emissionOverDistance)
|
|
304
|
+
params['emissionOverDistance'] = valueGen(data.emissionOverDistance);
|
|
305
|
+
if (data.emissionBursts) {
|
|
306
|
+
params['emissionBursts'] = data.emissionBursts.map((b) => ({
|
|
307
|
+
time: b.time,
|
|
308
|
+
count: valueGen(b.count),
|
|
309
|
+
cycle: b.cycle ?? 1,
|
|
310
|
+
interval: b.interval ?? 0,
|
|
311
|
+
probability: b.probability ?? 1,
|
|
312
|
+
}));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
if (data.behaviors) params['behaviors'] = data.behaviors.map(createBehavior);
|
|
316
|
+
if (data.renderMode != null) params['renderMode'] = RENDER_MODE_MAP[data.renderMode];
|
|
317
|
+
if (data.worldSpace != null) params['worldSpace'] = data.worldSpace;
|
|
318
|
+
if (data.renderOrder != null) params['renderOrder'] = data.renderOrder;
|
|
319
|
+
if (data.uTileCount != null) params['uTileCount'] = data.uTileCount;
|
|
320
|
+
if (data.vTileCount != null) params['vTileCount'] = data.vTileCount;
|
|
321
|
+
if (data.blendTiles != null) params['blendTiles'] = data.blendTiles;
|
|
322
|
+
if (data.softParticles != null) params['softParticles'] = data.softParticles;
|
|
323
|
+
if (data.softFarFade != null) params['softFarFade'] = data.softFarFade;
|
|
324
|
+
if (data.softNearFade != null) params['softNearFade'] = data.softNearFade;
|
|
325
|
+
|
|
326
|
+
const ps = new ParticleSystem(params as any);
|
|
327
|
+
|
|
328
|
+
return { emitter: ps.emitter, system: ps };
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Register a particle system with a BatchedRenderer.
|
|
333
|
+
*/
|
|
334
|
+
export function registerParticleSystem(
|
|
335
|
+
batchedRenderer: BatchedRenderer,
|
|
336
|
+
system: ParticleSystem,
|
|
337
|
+
): void {
|
|
338
|
+
batchedRenderer.addSystem(system);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Unregister a particle system from a BatchedRenderer.
|
|
343
|
+
*/
|
|
344
|
+
export function unregisterParticleSystem(
|
|
345
|
+
batchedRenderer: BatchedRenderer,
|
|
346
|
+
system: ParticleSystem,
|
|
347
|
+
): void {
|
|
348
|
+
batchedRenderer.deleteSystem(system);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Default particle data for creating a new particle emitter via AddSectionMenu.
|
|
353
|
+
*/
|
|
354
|
+
export function defaultParticlesData(): SceneParticles {
|
|
355
|
+
return {
|
|
356
|
+
looping: true,
|
|
357
|
+
duration: 2,
|
|
358
|
+
shape: { type: 'cone', radius: 0.1, angle: 0.3 },
|
|
359
|
+
startLife: { type: 'IntervalValue', a: 0.5, b: 1.5 },
|
|
360
|
+
startSpeed: { type: 'IntervalValue', a: 1, b: 3 },
|
|
361
|
+
startSize: { type: 'IntervalValue', a: 0.05, b: 0.15 },
|
|
362
|
+
startColor: {
|
|
363
|
+
type: 'ConstantColor',
|
|
364
|
+
color: { r: 1, g: 0.8, b: 0.2, a: 1 },
|
|
365
|
+
},
|
|
366
|
+
emissionOverTime: { type: 'ConstantValue', value: 30 },
|
|
367
|
+
behaviors: [
|
|
368
|
+
{
|
|
369
|
+
type: 'SizeOverLife',
|
|
370
|
+
size: {
|
|
371
|
+
type: 'PiecewiseBezier',
|
|
372
|
+
functions: [{ function: { p0: 1, p1: 0.67, p2: 0.33, p3: 0 }, start: 0 }],
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
],
|
|
376
|
+
material: {
|
|
377
|
+
type: 'basic',
|
|
378
|
+
blending: 'additive',
|
|
379
|
+
transparent: true,
|
|
380
|
+
depthWrite: false,
|
|
381
|
+
},
|
|
382
|
+
};
|
|
383
|
+
}
|