@woosh/meep-engine 2.29.0 → 2.30.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/core/process/worker/WorkerBuilder.js +5 -1
- package/engine/Engine.d.ts +5 -1
- package/engine/Engine.js +35 -17
- package/engine/EngineHarness.js +9 -1
- package/engine/asset/loaders/image/codec/CodecWithFallback.js +1 -1
- package/engine/asset/loaders/image/png/PNGReader.js +19 -21
- package/engine/ecs/EntityManager.js +10 -0
- package/engine/graphics/ecs/camera/topdown/ComputeCameraFacingVector.js +21 -0
- package/engine/graphics/ecs/camera/topdown/TopDownCameraController.js +10 -14
- package/engine/graphics/ecs/camera/topdown/TopDownCameraControllerSystem.js +4 -24
- package/engine/graphics/particles/particular/engine/ParticularEngine.js +1 -0
- package/engine/graphics/particles/particular/engine/emitter/PARTICLE_ATTRIBUTES.js +3 -0
- package/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +27 -15
- package/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +30 -10
- package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +4 -6
- package/engine/graphics/particles/particular/engine/parameter/ParameterTrackSet.js +6 -3
- package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +271 -1
- package/engine/graphics/particles/particular/engine/renderers/billboard/prototypeBillboardRenderer.js +164 -0
- package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +10 -555
- package/engine/graphics/particles/particular/engine/simulator/AbstractSimulationStep.js +6 -0
- package/engine/graphics/particles/particular/engine/simulator/SimulationStepFixedPhysics.js +16 -1
- package/engine/graphics/particles/particular/engine/simulator/update_parameters.js +41 -0
- package/engine/graphics/render/buffer/FrameBufferManager.js +2 -0
- package/engine/graphics/render/visibility/IncrementalDeltaSet.js +5 -0
- package/engine/graphics/render/visibility/VisibilityComputer.js +6 -6
- package/engine/graphics/render/visibility/VisibilityFilter.js +10 -0
- package/package.json +1 -1
|
@@ -125,7 +125,11 @@ WorkerBuilder.prototype.build = function () {
|
|
|
125
125
|
' if(method === undefined){',
|
|
126
126
|
' sendError(new Error("API named \'"+methodName+"\' was not found."));',
|
|
127
127
|
' }else{',
|
|
128
|
-
'
|
|
128
|
+
' try{',
|
|
129
|
+
' method.apply(null,parameters).then(sendResult, sendError);',
|
|
130
|
+
' }catch(e){',
|
|
131
|
+
' sendError(e);',
|
|
132
|
+
' }',
|
|
129
133
|
' }',
|
|
130
134
|
'};'
|
|
131
135
|
]);
|
package/engine/Engine.d.ts
CHANGED
|
@@ -9,8 +9,12 @@ import {EntityManager} from "./ecs/EntityManager";
|
|
|
9
9
|
import View from "../view/View";
|
|
10
10
|
import Ticker from "./simulation/Ticker";
|
|
11
11
|
|
|
12
|
+
export interface IEngineInitializationOptions {
|
|
13
|
+
entityManager?: EntityManager
|
|
14
|
+
}
|
|
15
|
+
|
|
12
16
|
export default class Engine {
|
|
13
|
-
constructor(platform: EnginePlatform);
|
|
17
|
+
constructor(platform: EnginePlatform, options?: IEngineInitializationOptions);
|
|
14
18
|
|
|
15
19
|
public get viewStack(): View
|
|
16
20
|
|
package/engine/Engine.js
CHANGED
|
@@ -52,9 +52,10 @@ class Engine {
|
|
|
52
52
|
/**
|
|
53
53
|
*
|
|
54
54
|
* @param {EnginePlatform} platform
|
|
55
|
+
* @param {EntityManager} [entityManager]
|
|
55
56
|
* @constructor
|
|
56
57
|
*/
|
|
57
|
-
constructor(platform) {
|
|
58
|
+
constructor(platform, { entityManager } = {}) {
|
|
58
59
|
assert.defined(platform, 'platform');
|
|
59
60
|
|
|
60
61
|
/**
|
|
@@ -81,6 +82,21 @@ class Engine {
|
|
|
81
82
|
*/
|
|
82
83
|
this.performance = new MetricCollection();
|
|
83
84
|
|
|
85
|
+
const using_external_entity_manager = entityManager !== undefined;
|
|
86
|
+
|
|
87
|
+
//setup entity component system
|
|
88
|
+
if (using_external_entity_manager) {
|
|
89
|
+
// external entity manager provided
|
|
90
|
+
this.entityManager = entityManager;
|
|
91
|
+
} else {
|
|
92
|
+
this.entityManager = new EntityManager();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
*
|
|
97
|
+
* @type {Ticker}
|
|
98
|
+
*/
|
|
99
|
+
this.ticker = new Ticker();
|
|
84
100
|
|
|
85
101
|
this.__performacne_monitor = new PeriodicConsolePrinter(15, () => {
|
|
86
102
|
const metrics = this.performance;
|
|
@@ -112,6 +128,22 @@ class Engine {
|
|
|
112
128
|
return `FPS: ${v_fps}, RENDER: ${v_render}ms, SIMULATION: ${v_sim}ms`;
|
|
113
129
|
});
|
|
114
130
|
|
|
131
|
+
|
|
132
|
+
if (!using_external_entity_manager) {
|
|
133
|
+
// subscribe simulator to common ticker
|
|
134
|
+
this.ticker.subscribe(timeDelta => {
|
|
135
|
+
const t0 = performance.now();
|
|
136
|
+
this.entityManager.simulate(timeDelta);
|
|
137
|
+
|
|
138
|
+
const t1 = performance.now();
|
|
139
|
+
const duration = (t1 - t0) / 1000;
|
|
140
|
+
|
|
141
|
+
// record frame time
|
|
142
|
+
this.performance.get(METRIC_ID_SIMULATION).record(duration);
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
115
147
|
this.initialize();
|
|
116
148
|
}
|
|
117
149
|
|
|
@@ -168,9 +200,6 @@ class Engine {
|
|
|
168
200
|
this.localization = new Localization();
|
|
169
201
|
this.localization.setAssetManager(this.assetManager);
|
|
170
202
|
|
|
171
|
-
//setup entity component system
|
|
172
|
-
const em = this.entityManager = new EntityManager();
|
|
173
|
-
|
|
174
203
|
|
|
175
204
|
const innerWidth = window.innerWidth / 3;
|
|
176
205
|
const innerHeight = window.innerHeight / 3;
|
|
@@ -182,7 +211,7 @@ class Engine {
|
|
|
182
211
|
*
|
|
183
212
|
* @type {GraphicsEngine}
|
|
184
213
|
*/
|
|
185
|
-
const ge = this.graphics = new GraphicsEngine(this.camera,
|
|
214
|
+
const ge = this.graphics = new GraphicsEngine(this.camera, this.entityManager);
|
|
186
215
|
|
|
187
216
|
try {
|
|
188
217
|
ge.start();
|
|
@@ -208,18 +237,6 @@ class Engine {
|
|
|
208
237
|
*/
|
|
209
238
|
this.gui = new GUIEngine();
|
|
210
239
|
|
|
211
|
-
this.ticker = new Ticker();
|
|
212
|
-
this.ticker.subscribe(timeDelta => {
|
|
213
|
-
const t0 = performance.now();
|
|
214
|
-
this.entityManager.simulate(timeDelta);
|
|
215
|
-
|
|
216
|
-
const t1 = performance.now();
|
|
217
|
-
const duration = (t1 - t0) / 1000;
|
|
218
|
-
|
|
219
|
-
// record frame time
|
|
220
|
-
this.performance.get(METRIC_ID_SIMULATION).record(duration);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
240
|
/**
|
|
224
241
|
* @readonly
|
|
225
242
|
* @type {SceneManager}
|
|
@@ -492,6 +509,7 @@ class Engine {
|
|
|
492
509
|
|
|
493
510
|
const frame_delay = (t1 - t0) / 1000;
|
|
494
511
|
|
|
512
|
+
// swap variables
|
|
495
513
|
t0 = t1;
|
|
496
514
|
|
|
497
515
|
// record metric
|
package/engine/EngineHarness.js
CHANGED
|
@@ -24,6 +24,8 @@ import WaterSystem from "./graphics/ecs/water/WaterSystem.js";
|
|
|
24
24
|
import KeyboardCameraController from "./input/ecs/controllers/KeyboardCameraController.js";
|
|
25
25
|
import { EngineConfiguration } from "./EngineConfiguration.js";
|
|
26
26
|
import { JsonAssetLoader } from "./asset/loaders/JsonAssetLoader.js";
|
|
27
|
+
import { logger } from "./logging/GlobalLogger.js";
|
|
28
|
+
import { ConsoleLoggerBackend } from "./logging/ConsoleLoggerBackend.js";
|
|
27
29
|
|
|
28
30
|
/**
|
|
29
31
|
*
|
|
@@ -77,6 +79,8 @@ export class EngineHarness {
|
|
|
77
79
|
|
|
78
80
|
window.engine = this.engine;
|
|
79
81
|
|
|
82
|
+
logger.addBackend(new ConsoleLoggerBackend());
|
|
83
|
+
|
|
80
84
|
this.p = null;
|
|
81
85
|
}
|
|
82
86
|
|
|
@@ -321,7 +325,7 @@ export class EngineHarness {
|
|
|
321
325
|
|
|
322
326
|
/**
|
|
323
327
|
*
|
|
324
|
-
* @param {number} cameraEntity
|
|
328
|
+
* @param {number} [cameraEntity]
|
|
325
329
|
* @param {Engine} engine
|
|
326
330
|
* @param {number} [sensitivity]
|
|
327
331
|
* @param {Element} domElement
|
|
@@ -335,6 +339,10 @@ export class EngineHarness {
|
|
|
335
339
|
sensitivity = 0.01
|
|
336
340
|
}) {
|
|
337
341
|
|
|
342
|
+
if (cameraEntity === undefined) {
|
|
343
|
+
cameraEntity = ecd.getAnyComponent(Camera).entity;
|
|
344
|
+
}
|
|
345
|
+
|
|
338
346
|
const em = engine.entityManager;
|
|
339
347
|
|
|
340
348
|
if (em.getSystem(InputControllerSystem) === null) {
|
|
@@ -7,19 +7,6 @@ import { PNG } from './PNG.js';
|
|
|
7
7
|
import { BinaryBuffer } from "../../../../../core/binary/BinaryBuffer.js";
|
|
8
8
|
import { isArrayEqualStrict } from "../../../../../core/collection/array/isArrayEqualStrict.js";
|
|
9
9
|
|
|
10
|
-
var inflate = function (data, callback) {
|
|
11
|
-
let result;
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
result = zlib.inflate(new Uint8Array(data));
|
|
15
|
-
|
|
16
|
-
callback(null, result);
|
|
17
|
-
} catch (e) {
|
|
18
|
-
callback(e);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
};
|
|
22
|
-
|
|
23
10
|
function readUInt32(buffer, offset) {
|
|
24
11
|
return (buffer[offset] << 24) +
|
|
25
12
|
(buffer[offset + 1] << 16) +
|
|
@@ -294,11 +281,14 @@ PNGReader.prototype.unFilterNone = function (scanline, scanline_offset, pixels,
|
|
|
294
281
|
PNGReader.prototype.unFilterSub = function (scanline, scanline_offset, pixels, bpp, of, length) {
|
|
295
282
|
var i = 0;
|
|
296
283
|
|
|
297
|
-
for (; i < bpp; i++)
|
|
284
|
+
for (; i < bpp; i++) {
|
|
285
|
+
pixels[of + i] = scanline[i + scanline_offset];
|
|
286
|
+
}
|
|
298
287
|
|
|
299
288
|
for (; i < length; i++) {
|
|
300
289
|
// Raw(x) + Raw(x - bpp)
|
|
301
|
-
|
|
290
|
+
const of_i = of + i;
|
|
291
|
+
pixels[of_i] = (scanline[i + scanline_offset] + pixels[of_i - bpp]) & 0xFF;
|
|
302
292
|
}
|
|
303
293
|
};
|
|
304
294
|
|
|
@@ -336,19 +326,26 @@ PNGReader.prototype.unFilterAverage = function (scanline, scanline_offset, pixel
|
|
|
336
326
|
}
|
|
337
327
|
// Prior(x) == 0 && Raw(x - bpp) != 0 (right shift, prevent doubles)
|
|
338
328
|
for (; i < length; i++) {
|
|
339
|
-
|
|
329
|
+
const of_i = of + i;
|
|
330
|
+
pixels[of_i] = (scanline[i + scanline_offset] + (pixels[of_i - bpp] >> 1)) & 0xFF;
|
|
340
331
|
}
|
|
341
332
|
} else {
|
|
342
333
|
// Prior(x) != 0 && Raw(x - bpp) == 0
|
|
343
334
|
for (; i < bpp; i++) {
|
|
344
|
-
|
|
335
|
+
const of_i = of + i;
|
|
336
|
+
|
|
337
|
+
pixels[of_i] = (scanline[i + scanline_offset] + (pixels[of_i - length] >> 1)) & 0xFF;
|
|
345
338
|
}
|
|
346
339
|
// Prior(x) != 0 && Raw(x - bpp) != 0
|
|
347
340
|
for (; i < length; i++) {
|
|
348
341
|
byte = scanline[i + scanline_offset];
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
342
|
+
|
|
343
|
+
const of_i = of + i;
|
|
344
|
+
|
|
345
|
+
prev = pixels[of_i - bpp];
|
|
346
|
+
prior = pixels[of_i - length];
|
|
347
|
+
|
|
348
|
+
pixels[of_i] = (byte + (prev + prior >> 1)) & 0xFF;
|
|
352
349
|
}
|
|
353
350
|
}
|
|
354
351
|
};
|
|
@@ -387,10 +384,11 @@ PNGReader.prototype.unFilterPaeth = function (scanline, scanline_offset, pixels,
|
|
|
387
384
|
pixels[of + i] = (scanline[i + scanline_offset] + pixels[of + i - bpp]) & 0xFF;
|
|
388
385
|
}
|
|
389
386
|
} else {
|
|
387
|
+
const of1 = of - length;
|
|
390
388
|
// Prior(x) != 0 && Raw(x - bpp) == 0
|
|
391
389
|
// paethPredictor(x, 0, 0) is always x
|
|
392
390
|
for (; i < bpp; i++) {
|
|
393
|
-
pixels[of + i] = (scanline[i + scanline_offset] + pixels[
|
|
391
|
+
pixels[of + i] = (scanline[i + scanline_offset] + pixels[of1 + i]) & 0xFF;
|
|
394
392
|
}
|
|
395
393
|
// Prior(x) != 0 && Raw(x - bpp) != 0
|
|
396
394
|
for (; i < length; i++) {
|
|
@@ -699,6 +699,16 @@ EntityManager.prototype.startSystem = function (system, successCallback, errorCa
|
|
|
699
699
|
* @param {function} errorCallback executed if entity manager encounters an error during startup
|
|
700
700
|
*/
|
|
701
701
|
EntityManager.prototype.startup = function (readyCallback, errorCallback) {
|
|
702
|
+
if (this.state === EntityManagerState.Starting) {
|
|
703
|
+
throw new IllegalStateException(`System is currently in starting state`);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
if (this.state === EntityManagerState.Running) {
|
|
707
|
+
// already running, do nothing
|
|
708
|
+
readyCallback();
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
|
|
702
712
|
assert.isFunction(readyCallback, 'readyCallback');
|
|
703
713
|
assert.isFunction(errorCallback, 'errorCallback');
|
|
704
714
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import Quaternion from "../../../../../core/geom/Quaternion.js";
|
|
2
|
+
import Vector3 from "../../../../../core/geom/Vector3.js";
|
|
3
|
+
|
|
4
|
+
const q = new Quaternion();
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {number} yaw
|
|
9
|
+
* @param {number} pitch
|
|
10
|
+
* @param roll
|
|
11
|
+
* @param {Vector3} result
|
|
12
|
+
*/
|
|
13
|
+
export function computeCameraFacingVector(yaw, pitch, roll, result) {
|
|
14
|
+
q.__setFromEuler(pitch, yaw, roll, 'ZYX');
|
|
15
|
+
q.normalize();
|
|
16
|
+
|
|
17
|
+
result.copy(Vector3.forward);
|
|
18
|
+
result.applyQuaternion(q);
|
|
19
|
+
result.normalize();
|
|
20
|
+
|
|
21
|
+
}
|
|
@@ -10,6 +10,7 @@ import { Euler, Matrix4 } from "three";
|
|
|
10
10
|
|
|
11
11
|
const m4 = new Matrix4();
|
|
12
12
|
const euler = new Euler();
|
|
13
|
+
const scratch_vector3 = new Vector3();
|
|
13
14
|
|
|
14
15
|
const panOffset = new Vector3();
|
|
15
16
|
|
|
@@ -21,25 +22,20 @@ const panOffset = new Vector3();
|
|
|
21
22
|
* @param {TopDownCameraController} output rotation delta
|
|
22
23
|
*/
|
|
23
24
|
export function rotate_from_view(displacement_x, displacement_y, input, output) {
|
|
24
|
-
const rotation_matrix = new Matrix4();
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
euler.set(input.pitch, input.yaw, input.roll)
|
|
27
|
+
m4.makeRotationFromEuler(euler);
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
const up = scratch_vector3;
|
|
30
|
+
scratch_vector3.copy(Vector3.up);
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
m_original.makeRotationFromEuler(euler1);
|
|
32
|
+
up.applyMatrix4_three(m4);
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
// detect when camera is upside-down
|
|
35
|
+
const y_multiplier = up.y <= 0 ? -1 : 1;
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
output.pitch = euler.x;
|
|
41
|
-
output.yaw = euler.y;
|
|
42
|
-
output.roll = euler.z;
|
|
37
|
+
output.pitch -= displacement_y;
|
|
38
|
+
output.yaw += displacement_x * y_multiplier;
|
|
43
39
|
}
|
|
44
40
|
|
|
45
41
|
/**
|
|
@@ -13,7 +13,6 @@ import { System } from '../../../../ecs/System.js';
|
|
|
13
13
|
import TopDownCameraController from './TopDownCameraController.js';
|
|
14
14
|
|
|
15
15
|
import { Euler as ThreeEuler } from 'three';
|
|
16
|
-
import Quaternion from "../../../../../core/geom/Quaternion.js";
|
|
17
16
|
|
|
18
17
|
|
|
19
18
|
const v3_scratch = new Vector3();
|
|
@@ -74,25 +73,6 @@ export function computeTopDownTransform(control, result) {
|
|
|
74
73
|
result.position.copy(v3_scratch);
|
|
75
74
|
}
|
|
76
75
|
|
|
77
|
-
const q = new Quaternion();
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
*
|
|
81
|
-
* @param {number} yaw
|
|
82
|
-
* @param {number} pitch
|
|
83
|
-
* @param roll
|
|
84
|
-
* @param {Vector3} result
|
|
85
|
-
*/
|
|
86
|
-
export function computeCameraFacingVector(yaw, pitch, roll, result) {
|
|
87
|
-
q.__setFromEuler(pitch, yaw, roll, 'ZYX');
|
|
88
|
-
q.normalize();
|
|
89
|
-
|
|
90
|
-
result.copy(Vector3.forward);
|
|
91
|
-
result.applyQuaternion(q);
|
|
92
|
-
result.normalize();
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
76
|
/**
|
|
97
77
|
*
|
|
98
78
|
* @param {Transform} transform
|
|
@@ -123,11 +103,11 @@ export function setCameraControllerFromTransform(transform, controller, distance
|
|
|
123
103
|
|
|
124
104
|
controller.distance = distance;
|
|
125
105
|
|
|
126
|
-
const targetOffset = direction.clone()
|
|
127
|
-
|
|
106
|
+
const targetOffset = direction.clone();
|
|
107
|
+
targetOffset.multiplyScalar(controller.distance);
|
|
128
108
|
|
|
129
|
-
const target = transform.position.clone()
|
|
130
|
-
|
|
109
|
+
const target = transform.position.clone();
|
|
110
|
+
target.sub(targetOffset);
|
|
131
111
|
|
|
132
112
|
controller.target.copy(target)
|
|
133
113
|
}
|
|
@@ -132,6 +132,7 @@ ParticularEngine.prototype.advanceEmitter = function (emitter, timeDelta) {
|
|
|
132
132
|
|
|
133
133
|
const step = steps[type];
|
|
134
134
|
|
|
135
|
+
step.emitter = emitter;
|
|
135
136
|
step.timeDelta = timeDelta;
|
|
136
137
|
step.particles = emitter.particles;
|
|
137
138
|
step.layer_parameters[j] = stepDefinition.parameters;
|
|
@@ -3,7 +3,10 @@ export const PARTICLE_ATTRIBUTE_AGE = 1;
|
|
|
3
3
|
export const PARTICLE_ATTRIBUTE_DEATH_AGE = 2;
|
|
4
4
|
export const PARTICLE_ATTRIBUTE_UV = 3;
|
|
5
5
|
export const PARTICLE_ATTRIBUTE_SIZE = 4;
|
|
6
|
+
export const PARTICLE_ATTRIBUTE_SIZE_INITIAL = 11;
|
|
6
7
|
export const PARTICLE_ATTRIBUTE_LAYER_POSITION = 5;
|
|
7
8
|
export const PARTICLE_ATTRIBUTE_VELOCITY = 6;
|
|
8
9
|
export const PARTICLE_ATTRIBUTE_ROTATION = 7;
|
|
9
10
|
export const PARTICLE_ATTRIBUTE_ROTATION_SPEED = 8;
|
|
11
|
+
export const PARTICLE_ATTRIBUTE_COLOR = 9;
|
|
12
|
+
export const PARTICLE_ATTRIBUTE_BLEND = 10;
|
|
@@ -22,12 +22,14 @@ import { ParticleEmitterFlag } from "./ParticleEmitterFlag.js";
|
|
|
22
22
|
import { AABB3 } from "../../../../../../core/bvh2/aabb3/AABB3.js";
|
|
23
23
|
import {
|
|
24
24
|
PARTICLE_ATTRIBUTE_AGE,
|
|
25
|
+
PARTICLE_ATTRIBUTE_BLEND,
|
|
25
26
|
PARTICLE_ATTRIBUTE_DEATH_AGE,
|
|
26
27
|
PARTICLE_ATTRIBUTE_LAYER_POSITION,
|
|
27
28
|
PARTICLE_ATTRIBUTE_POSITION,
|
|
28
29
|
PARTICLE_ATTRIBUTE_ROTATION,
|
|
29
30
|
PARTICLE_ATTRIBUTE_ROTATION_SPEED,
|
|
30
31
|
PARTICLE_ATTRIBUTE_SIZE,
|
|
32
|
+
PARTICLE_ATTRIBUTE_SIZE_INITIAL,
|
|
31
33
|
PARTICLE_ATTRIBUTE_UV,
|
|
32
34
|
PARTICLE_ATTRIBUTE_VELOCITY
|
|
33
35
|
} from "./PARTICLE_ATTRIBUTES.js";
|
|
@@ -39,7 +41,7 @@ import { randomPointInBox } from "../../../../../../core/geom/random/randomPoint
|
|
|
39
41
|
import { randomPointOnBox } from "../../../../../../core/geom/random/randomPointOnBox.js";
|
|
40
42
|
import { EmissionFromType } from "./EmissionFromType.js";
|
|
41
43
|
import { EmissionShapeType } from "./EmissionShapeType.js";
|
|
42
|
-
|
|
44
|
+
import { update_parameters } from "../simulator/update_parameters.js";
|
|
43
45
|
|
|
44
46
|
const EMPTY_GEOMETRY = new BufferGeometry();
|
|
45
47
|
|
|
@@ -635,7 +637,7 @@ export class ParticleEmitter {
|
|
|
635
637
|
|
|
636
638
|
build() {
|
|
637
639
|
|
|
638
|
-
this.particles = new ParticlePool(
|
|
640
|
+
this.particles = new ParticlePool(PARTICULAR_PARTICLE_SPECIFICATION);
|
|
639
641
|
|
|
640
642
|
//make overallocation a bit more aggressive to prevent frequent resizing
|
|
641
643
|
this.particles.shrinkFactor = 0.5;
|
|
@@ -1004,7 +1006,7 @@ export class ParticleEmitter {
|
|
|
1004
1006
|
//write particle size
|
|
1005
1007
|
const size = layer.particleSize.sampleRandom(random);
|
|
1006
1008
|
|
|
1007
|
-
particles.writeAttributeScalar(ref,
|
|
1009
|
+
particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_SIZE_INITIAL, size);
|
|
1008
1010
|
|
|
1009
1011
|
//write UV
|
|
1010
1012
|
const atlasPatch = layer.__atlasPatch;
|
|
@@ -1027,6 +1029,10 @@ export class ParticleEmitter {
|
|
|
1027
1029
|
}
|
|
1028
1030
|
|
|
1029
1031
|
particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_LAYER_POSITION, layerPosition);
|
|
1032
|
+
|
|
1033
|
+
update_parameters(ref, particles, layer, initialAge / deathAge);
|
|
1034
|
+
|
|
1035
|
+
particles.writeAttributeScalar(ref,PARTICLE_ATTRIBUTE_BLEND,this.blendingMode);
|
|
1030
1036
|
}
|
|
1031
1037
|
|
|
1032
1038
|
//update time buffer
|
|
@@ -1124,7 +1130,7 @@ export class ParticleEmitter {
|
|
|
1124
1130
|
//write size
|
|
1125
1131
|
const size = layer.particleSize.sampleRandom(random);
|
|
1126
1132
|
|
|
1127
|
-
particles.writeAttributeScalar(ref,
|
|
1133
|
+
particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_SIZE_INITIAL, size);
|
|
1128
1134
|
|
|
1129
1135
|
//write UV
|
|
1130
1136
|
const atlasPatch = layer.__atlasPatch;
|
|
@@ -1151,6 +1157,9 @@ export class ParticleEmitter {
|
|
|
1151
1157
|
|
|
1152
1158
|
particles.writeAttributeScalar(ref, PARTICLE_ATTRIBUTE_LAYER_POSITION, layerPosition);
|
|
1153
1159
|
|
|
1160
|
+
update_parameters(ref, particles, layer, initialAge / deathAge);
|
|
1161
|
+
|
|
1162
|
+
particles.writeAttributeScalar(ref,PARTICLE_ATTRIBUTE_BLEND,this.blendingMode);
|
|
1154
1163
|
}
|
|
1155
1164
|
|
|
1156
1165
|
if (spritesNeedUpdate) {
|
|
@@ -1253,17 +1262,20 @@ const defaultPointsMaterial = new PointsMaterial({ color: 0xFFFFFF });
|
|
|
1253
1262
|
|
|
1254
1263
|
|
|
1255
1264
|
//build particle spec
|
|
1256
|
-
const
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1265
|
+
export const PARTICULAR_PARTICLE_SPECIFICATION = new ParticleSpecification();
|
|
1266
|
+
|
|
1267
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('position', ParticleAttributeType.Vector3, ParticleDataType.Float32));
|
|
1268
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('age', ParticleAttributeType.Scalar, ParticleDataType.Float32));
|
|
1269
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('deathAge', ParticleAttributeType.Scalar, ParticleDataType.Float32));
|
|
1270
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('atlasPatch', ParticleAttributeType.Vector4, ParticleDataType.Float32));
|
|
1271
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('size', ParticleAttributeType.Scalar, ParticleDataType.Float32));
|
|
1272
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('layerPosition', ParticleAttributeType.Scalar, ParticleDataType.Float32));
|
|
1273
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('velocity', ParticleAttributeType.Vector3, ParticleDataType.Float32));
|
|
1274
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('rotation', ParticleAttributeType.Scalar, ParticleDataType.Float32));
|
|
1275
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('rotationSpeed', ParticleAttributeType.Scalar, ParticleDataType.Float32));
|
|
1276
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('color', ParticleAttributeType.Vector4, ParticleDataType.Float32));
|
|
1277
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('blending', ParticleAttributeType.Scalar, ParticleDataType.Uint8));
|
|
1278
|
+
PARTICULAR_PARTICLE_SPECIFICATION.add(new ParticleAttribute('size_initial', ParticleAttributeType.Scalar, ParticleDataType.Float32));
|
|
1267
1279
|
|
|
1268
1280
|
|
|
1269
1281
|
const frustum = new Frustum();
|
|
@@ -74,8 +74,10 @@ export class ParticlePool {
|
|
|
74
74
|
this.occupancy.set(index, true);
|
|
75
75
|
|
|
76
76
|
//ensure attribute arrays are large enough
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
const min_capacity = index + 1;
|
|
78
|
+
|
|
79
|
+
if (this.capacity < min_capacity) {
|
|
80
|
+
this.growCapacity(min_capacity);
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
return index;
|
|
@@ -86,7 +88,9 @@ export class ParticlePool {
|
|
|
86
88
|
* @returns {boolean}
|
|
87
89
|
*/
|
|
88
90
|
hasHoles() {
|
|
89
|
-
|
|
91
|
+
const occupancy = this.occupancy;
|
|
92
|
+
|
|
93
|
+
return occupancy.nextClearBit(0) < occupancy.size();
|
|
90
94
|
}
|
|
91
95
|
|
|
92
96
|
/**
|
|
@@ -111,6 +115,8 @@ export class ParticlePool {
|
|
|
111
115
|
holeIndex = occupancy.nextClearBit(0);
|
|
112
116
|
lastIndex = occupancy.previousSetBit(occupancy.size());
|
|
113
117
|
|
|
118
|
+
const attributes = this.attributes;
|
|
119
|
+
|
|
114
120
|
while (holeIndex < lastIndex) {
|
|
115
121
|
|
|
116
122
|
//move occupancy flag from the last to the hole
|
|
@@ -119,7 +125,7 @@ export class ParticlePool {
|
|
|
119
125
|
|
|
120
126
|
//move attribute values
|
|
121
127
|
for (attributeIndex = 0; attributeIndex < numAttributes; attributeIndex++) {
|
|
122
|
-
const attribute =
|
|
128
|
+
const attribute = attributes[attributeIndex];
|
|
123
129
|
|
|
124
130
|
const itemSize = attribute.itemSize;
|
|
125
131
|
|
|
@@ -127,13 +133,13 @@ export class ParticlePool {
|
|
|
127
133
|
*
|
|
128
134
|
* @type {Float32Array}
|
|
129
135
|
*/
|
|
130
|
-
const
|
|
136
|
+
const attribute_array = attribute.array;
|
|
131
137
|
|
|
132
138
|
//do swaps in the old array
|
|
133
139
|
const targetIndex = holeIndex * itemSize;
|
|
134
140
|
const sourceIndex = lastIndex * itemSize;
|
|
135
141
|
|
|
136
|
-
|
|
142
|
+
attribute_array.copyWithin(targetIndex, sourceIndex, sourceIndex + itemSize);
|
|
137
143
|
}
|
|
138
144
|
|
|
139
145
|
//move hole and last cursors
|
|
@@ -269,7 +275,14 @@ export class ParticlePool {
|
|
|
269
275
|
* @param {number} capacity
|
|
270
276
|
*/
|
|
271
277
|
growCapacity(capacity) {
|
|
272
|
-
const newCapacity = Math.floor(
|
|
278
|
+
const newCapacity = Math.floor(
|
|
279
|
+
max3(
|
|
280
|
+
capacity,
|
|
281
|
+
this.capacity * this.growFactor,
|
|
282
|
+
this.capacity + GROW_MIN_STEP
|
|
283
|
+
)
|
|
284
|
+
);
|
|
285
|
+
|
|
273
286
|
this.setCapacity(newCapacity);
|
|
274
287
|
}
|
|
275
288
|
|
|
@@ -278,8 +291,13 @@ export class ParticlePool {
|
|
|
278
291
|
* @param {number} newCapacity
|
|
279
292
|
*/
|
|
280
293
|
shrinkCapacity(newCapacity) {
|
|
281
|
-
if (
|
|
294
|
+
if (
|
|
295
|
+
newCapacity < this.capacity * this.shrinkFactor
|
|
296
|
+
&& newCapacity < this.capacity - SHRINK_THRESHOLD
|
|
297
|
+
) {
|
|
298
|
+
|
|
282
299
|
this.setCapacity(newCapacity);
|
|
300
|
+
|
|
283
301
|
}
|
|
284
302
|
}
|
|
285
303
|
|
|
@@ -293,8 +311,10 @@ export class ParticlePool {
|
|
|
293
311
|
return;
|
|
294
312
|
}
|
|
295
313
|
|
|
296
|
-
|
|
297
|
-
|
|
314
|
+
const occupancy_size = this.occupancy.size();
|
|
315
|
+
|
|
316
|
+
if (newCapacity < occupancy_size) {
|
|
317
|
+
throw new Error(`Can not set capacity (=${newCapacity}) below occupancy set size (=${occupancy_size})`);
|
|
298
318
|
}
|
|
299
319
|
|
|
300
320
|
this.capacity = newCapacity;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { inverseLerp } from "../../../../../../core/math/inverseLerp.js";
|
|
2
|
-
import {
|
|
3
|
-
computeHashFloatArray,
|
|
4
|
-
computeHashIntegerArray
|
|
5
|
-
} from "../../../../../../core/math/MathUtils.js";
|
|
2
|
+
import { computeHashFloatArray, computeHashIntegerArray } from "../../../../../../core/math/MathUtils.js";
|
|
6
3
|
import { assert } from "../../../../../../core/assert.js";
|
|
7
4
|
import { max2 } from "../../../../../../core/math/max2.js";
|
|
8
5
|
import { min2 } from "../../../../../../core/math/min2.js";
|
|
@@ -123,11 +120,12 @@ export class ParameterLookupTable {
|
|
|
123
120
|
/**
|
|
124
121
|
*
|
|
125
122
|
* @param {number} position
|
|
126
|
-
* @param {number[]} result
|
|
123
|
+
* @param {number[]|Float32Array|Float64Array} result
|
|
127
124
|
*/
|
|
128
125
|
sample(position, result) {
|
|
129
126
|
assert.isNumber(position, 'position');
|
|
130
|
-
assert.
|
|
127
|
+
assert.greaterThanOrEqual(position, 0, 'position');
|
|
128
|
+
// assert.ok(position >= 0 && position <= 1, `position must be between 0 and 1, instead was ${position}`);
|
|
131
129
|
|
|
132
130
|
const itemSize = this.itemSize;
|
|
133
131
|
const data = this.data;
|
|
@@ -37,12 +37,15 @@ ParameterTrackSet.prototype.forEach = function (visitor) {
|
|
|
37
37
|
*/
|
|
38
38
|
ParameterTrackSet.prototype.getTrackByName = function (name) {
|
|
39
39
|
const tracks = this.tracks;
|
|
40
|
-
|
|
40
|
+
|
|
41
|
+
const tracks_array = tracks.asArray();
|
|
42
|
+
|
|
43
|
+
const nTracks = tracks_array.length;
|
|
41
44
|
|
|
42
45
|
for (let i = 0; i < nTracks; i++) {
|
|
43
|
-
const parameterTrack =
|
|
46
|
+
const parameterTrack = tracks_array[i];
|
|
44
47
|
|
|
45
|
-
if(parameterTrack.name === name){
|
|
48
|
+
if (parameterTrack.name === name) {
|
|
46
49
|
return parameterTrack;
|
|
47
50
|
}
|
|
48
51
|
}
|