@polarfront-lab/ionian 3.0.6-hotfix.1 → 3.0.6
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/README.md +94 -1
- package/dist/index.d.ts +14 -4
- package/dist/ionian.iife.js +1 -1
- package/dist/ionian.iife.js.map +1 -1
- package/dist/ionian.js +157 -137
- package/dist/ionian.js.map +1 -1
- package/package.json +17 -4
package/dist/ionian.js
CHANGED
|
@@ -35,10 +35,11 @@ class DefaultEventEmitter {
|
|
|
35
35
|
this.emitter.on(type, handler);
|
|
36
36
|
}
|
|
37
37
|
once(type, handler) {
|
|
38
|
-
|
|
39
|
-
this.emitter.off(type,
|
|
38
|
+
const wrappedHandler = (payload) => {
|
|
39
|
+
this.emitter.off(type, wrappedHandler);
|
|
40
40
|
handler(payload);
|
|
41
|
-
}
|
|
41
|
+
};
|
|
42
|
+
this.emitter.on(type, wrappedHandler);
|
|
42
43
|
}
|
|
43
44
|
dispose() {
|
|
44
45
|
this.emitter.all.clear();
|
|
@@ -83,20 +84,27 @@ function clamp(value, min, max) {
|
|
|
83
84
|
value = Math.max(value, min);
|
|
84
85
|
return value;
|
|
85
86
|
}
|
|
87
|
+
const DEFAULT_DRACO_DECODER_PATH = "https://www.gstatic.com/draco/versioned/decoders/1.5.7/";
|
|
86
88
|
class AssetService {
|
|
87
|
-
constructor(eventEmitter) {
|
|
89
|
+
constructor(eventEmitter, options = {}) {
|
|
88
90
|
__publicField(this, "serviceState", "created");
|
|
89
91
|
__publicField(this, "eventEmitter");
|
|
90
92
|
__publicField(this, "meshes", /* @__PURE__ */ new Map());
|
|
91
93
|
__publicField(this, "textures", /* @__PURE__ */ new Map());
|
|
92
94
|
__publicField(this, "gltfLoader", new GLTFLoader());
|
|
93
95
|
__publicField(this, "textureLoader", new THREE.TextureLoader());
|
|
94
|
-
__publicField(this, "dracoLoader"
|
|
96
|
+
__publicField(this, "dracoLoader");
|
|
95
97
|
__publicField(this, "solidColorTextures", /* @__PURE__ */ new Map());
|
|
96
98
|
__publicField(this, "fallbackTexture", new THREE.DataTexture(new Uint8Array([127, 127, 127, 255]), 1, 1, THREE.RGBAFormat));
|
|
97
99
|
this.eventEmitter = eventEmitter;
|
|
98
|
-
|
|
99
|
-
|
|
100
|
+
const decoderPath = options.dracoDecoderPath === void 0 ? DEFAULT_DRACO_DECODER_PATH : options.dracoDecoderPath;
|
|
101
|
+
if (decoderPath !== null) {
|
|
102
|
+
this.dracoLoader = new DRACOLoader();
|
|
103
|
+
this.dracoLoader.setDecoderPath(decoderPath);
|
|
104
|
+
this.gltfLoader.setDRACOLoader(this.dracoLoader);
|
|
105
|
+
} else {
|
|
106
|
+
this.dracoLoader = null;
|
|
107
|
+
}
|
|
100
108
|
this.fallbackTexture.name = "default-fallback-texture";
|
|
101
109
|
this.updateServiceState("ready");
|
|
102
110
|
}
|
|
@@ -189,17 +197,15 @@ class AssetService {
|
|
|
189
197
|
* @returns The loaded mesh or null.
|
|
190
198
|
*/
|
|
191
199
|
async loadMeshAsync(id, url, options = {}) {
|
|
192
|
-
const gltf = await this.gltfLoader.loadAsync(url);
|
|
193
200
|
try {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const mesh = gltf.scene.children[0];
|
|
200
|
-
this.register(id, mesh);
|
|
201
|
-
return mesh;
|
|
201
|
+
const gltf = await this.gltfLoader.loadAsync(url);
|
|
202
|
+
const mesh = this.findMesh(gltf.scene, options.meshName);
|
|
203
|
+
if (!mesh) {
|
|
204
|
+
this.eventEmitter.emit("invalidRequest", { message: `failed to load mesh: ${id}. mesh not found` });
|
|
205
|
+
return null;
|
|
202
206
|
}
|
|
207
|
+
this.register(id, mesh);
|
|
208
|
+
return mesh;
|
|
203
209
|
} catch (error) {
|
|
204
210
|
this.eventEmitter.emit("invalidRequest", { message: `failed to load mesh: ${id}. ${error}` });
|
|
205
211
|
return null;
|
|
@@ -222,6 +228,7 @@ class AssetService {
|
|
|
222
228
|
}
|
|
223
229
|
}
|
|
224
230
|
dispose() {
|
|
231
|
+
var _a;
|
|
225
232
|
this.updateServiceState("disposed");
|
|
226
233
|
this.meshes.forEach((mesh) => disposeMesh(mesh));
|
|
227
234
|
this.meshes.clear();
|
|
@@ -229,12 +236,29 @@ class AssetService {
|
|
|
229
236
|
this.textures.clear();
|
|
230
237
|
this.solidColorTextures.forEach((texture) => texture.dispose());
|
|
231
238
|
this.solidColorTextures.clear();
|
|
239
|
+
(_a = this.dracoLoader) == null ? void 0 : _a.dispose();
|
|
232
240
|
this.fallbackTexture.dispose();
|
|
233
241
|
}
|
|
234
242
|
updateServiceState(serviceState) {
|
|
235
243
|
this.serviceState = serviceState;
|
|
236
244
|
this.eventEmitter.emit("serviceStateUpdated", { type: "asset", state: serviceState });
|
|
237
245
|
}
|
|
246
|
+
findMesh(root, meshName) {
|
|
247
|
+
if (meshName) {
|
|
248
|
+
const named = root.getObjectByName(meshName);
|
|
249
|
+
return isMesh(named) ? named : null;
|
|
250
|
+
}
|
|
251
|
+
let found = null;
|
|
252
|
+
root.traverse((object) => {
|
|
253
|
+
if (!found && isMesh(object)) {
|
|
254
|
+
found = object;
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
return found;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function isMesh(object) {
|
|
261
|
+
return !!object && "isMesh" in object && object.isMesh === true;
|
|
238
262
|
}
|
|
239
263
|
const _face = new Triangle();
|
|
240
264
|
const _color = new Vector3();
|
|
@@ -444,14 +468,13 @@ class DataTextureService {
|
|
|
444
468
|
if (cachedTexture) {
|
|
445
469
|
return cachedTexture;
|
|
446
470
|
}
|
|
447
|
-
const
|
|
448
|
-
const array = sampleMesh(meshData, this.textureSize);
|
|
471
|
+
const array = sampleMesh(asset, this.textureSize);
|
|
449
472
|
const dataTexture = createDataTexture(array, this.textureSize);
|
|
450
473
|
dataTexture.name = asset.name;
|
|
451
474
|
this.dataTextures.set(asset.uuid, dataTexture);
|
|
452
475
|
return dataTexture;
|
|
453
476
|
}
|
|
454
|
-
dispose() {
|
|
477
|
+
async dispose() {
|
|
455
478
|
this.dataTextures.forEach((texture) => texture.dispose());
|
|
456
479
|
this.dataTextures.clear();
|
|
457
480
|
if (this.currentAtlas) {
|
|
@@ -511,38 +534,28 @@ class DataTextureService {
|
|
|
511
534
|
}
|
|
512
535
|
}
|
|
513
536
|
}
|
|
514
|
-
function
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
scale: { x: mesh.scale.x, y: mesh.scale.y, z: mesh.scale.z }
|
|
520
|
-
};
|
|
521
|
-
}
|
|
522
|
-
function sampleMesh(meshData, size) {
|
|
523
|
-
const geometry = new THREE.BufferGeometry();
|
|
524
|
-
geometry.setAttribute("position", new THREE.BufferAttribute(new Float32Array(meshData.position), 3));
|
|
525
|
-
if (meshData.normal) {
|
|
526
|
-
geometry.setAttribute("normal", new THREE.BufferAttribute(new Float32Array(meshData.normal), 3));
|
|
527
|
-
}
|
|
528
|
-
const material = new THREE.MeshBasicMaterial();
|
|
529
|
-
const mesh = new THREE.Mesh(geometry, material);
|
|
530
|
-
mesh.scale.set(meshData.scale.x, meshData.scale.y, meshData.scale.z);
|
|
537
|
+
function sampleMesh(sourceMesh, size) {
|
|
538
|
+
sourceMesh.updateWorldMatrix(true, false);
|
|
539
|
+
const geometry = sourceMesh.geometry.clone();
|
|
540
|
+
geometry.applyMatrix4(sourceMesh.matrixWorld);
|
|
541
|
+
const mesh = new THREE.Mesh(geometry);
|
|
531
542
|
const sampler = new MeshSurfaceSampler(mesh).build();
|
|
532
543
|
const data = new Float32Array(size * size * 4);
|
|
533
544
|
const position = new THREE.Vector3();
|
|
534
|
-
|
|
535
|
-
for (let
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
545
|
+
try {
|
|
546
|
+
for (let i = 0; i < size; i++) {
|
|
547
|
+
for (let j = 0; j < size; j++) {
|
|
548
|
+
const index = i * size + j;
|
|
549
|
+
sampler.sample(position);
|
|
550
|
+
data[4 * index] = position.x;
|
|
551
|
+
data[4 * index + 1] = position.y;
|
|
552
|
+
data[4 * index + 2] = position.z;
|
|
553
|
+
data[4 * index + 3] = (Math.random() - 0.5) * 0.01;
|
|
554
|
+
}
|
|
542
555
|
}
|
|
556
|
+
} finally {
|
|
557
|
+
geometry.dispose();
|
|
543
558
|
}
|
|
544
|
-
geometry.dispose();
|
|
545
|
-
material.dispose();
|
|
546
559
|
return data;
|
|
547
560
|
}
|
|
548
561
|
const instanceFragmentShader = `
|
|
@@ -707,15 +720,16 @@ class InstancedMeshManager {
|
|
|
707
720
|
/**
|
|
708
721
|
* Resizes or replaces the instanced mesh.
|
|
709
722
|
* @param size The new size of the instanced mesh.
|
|
710
|
-
* @returns
|
|
723
|
+
* @returns An object containing the updated mesh, the previous mesh, and a boolean indicating whether the mesh was updated.
|
|
711
724
|
*/
|
|
712
725
|
resize(size) {
|
|
713
|
-
if (this.size === size) return this.mesh;
|
|
726
|
+
if (this.size === size) return { current: this.mesh, previous: this.mesh };
|
|
714
727
|
this.size = size;
|
|
715
728
|
const prev = this.mesh;
|
|
716
729
|
this.mesh = this.createInstancedMesh(size, prev.geometry, prev.material);
|
|
717
|
-
prev.
|
|
718
|
-
|
|
730
|
+
this.copyMeshState(prev, this.mesh);
|
|
731
|
+
this.replaceMeshInParent(prev, this.mesh);
|
|
732
|
+
return { current: this.mesh, previous: prev };
|
|
719
733
|
}
|
|
720
734
|
/**
|
|
721
735
|
* Disposes the resources used by the InstancedMeshManager.
|
|
@@ -724,7 +738,6 @@ class InstancedMeshManager {
|
|
|
724
738
|
this.mesh.dispose();
|
|
725
739
|
this.geometries.forEach((geometry) => geometry.dispose());
|
|
726
740
|
this.shaderMaterial.dispose();
|
|
727
|
-
this.fallbackGeometry.dispose();
|
|
728
741
|
this.uvRefsCache.clear();
|
|
729
742
|
this.geometries.clear();
|
|
730
743
|
}
|
|
@@ -783,6 +796,41 @@ class InstancedMeshManager {
|
|
|
783
796
|
const count = size * size;
|
|
784
797
|
return new THREE.InstancedMesh(geometry, material, count);
|
|
785
798
|
}
|
|
799
|
+
copyMeshState(source, target) {
|
|
800
|
+
target.name = source.name;
|
|
801
|
+
target.up.copy(source.up);
|
|
802
|
+
target.position.copy(source.position);
|
|
803
|
+
target.quaternion.copy(source.quaternion);
|
|
804
|
+
target.scale.copy(source.scale);
|
|
805
|
+
target.matrix.copy(source.matrix);
|
|
806
|
+
target.matrixWorld.copy(source.matrixWorld);
|
|
807
|
+
target.matrixAutoUpdate = source.matrixAutoUpdate;
|
|
808
|
+
target.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;
|
|
809
|
+
target.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
|
|
810
|
+
target.layers.mask = source.layers.mask;
|
|
811
|
+
target.visible = source.visible;
|
|
812
|
+
target.castShadow = source.castShadow;
|
|
813
|
+
target.receiveShadow = source.receiveShadow;
|
|
814
|
+
target.frustumCulled = source.frustumCulled;
|
|
815
|
+
target.renderOrder = source.renderOrder;
|
|
816
|
+
target.animations = source.animations;
|
|
817
|
+
target.userData = source.userData;
|
|
818
|
+
target.customDepthMaterial = source.customDepthMaterial;
|
|
819
|
+
target.customDistanceMaterial = source.customDistanceMaterial;
|
|
820
|
+
target.onBeforeRender = source.onBeforeRender;
|
|
821
|
+
target.onAfterRender = source.onAfterRender;
|
|
822
|
+
}
|
|
823
|
+
replaceMeshInParent(previous, current) {
|
|
824
|
+
const parent = previous.parent;
|
|
825
|
+
if (!parent) return;
|
|
826
|
+
const previousIndex = parent.children.indexOf(previous);
|
|
827
|
+
parent.add(current);
|
|
828
|
+
parent.remove(previous);
|
|
829
|
+
const currentIndex = parent.children.indexOf(current);
|
|
830
|
+
if (previousIndex < 0 || currentIndex < 0 || previousIndex === currentIndex) return;
|
|
831
|
+
parent.children.splice(currentIndex, 1);
|
|
832
|
+
parent.children.splice(Math.min(previousIndex, parent.children.length), 0, current);
|
|
833
|
+
}
|
|
786
834
|
}
|
|
787
835
|
class IntersectionService {
|
|
788
836
|
/**
|
|
@@ -796,11 +844,8 @@ class IntersectionService {
|
|
|
796
844
|
__publicField(this, "mousePosition", new THREE.Vector2());
|
|
797
845
|
__publicField(this, "camera");
|
|
798
846
|
__publicField(this, "meshSequenceGeometries", []);
|
|
799
|
-
// ADDED: Store cloned geometries
|
|
800
847
|
__publicField(this, "meshSequenceUUIDs", []);
|
|
801
|
-
// ADDED: Track UUIDs to avoid redundant cloning
|
|
802
848
|
__publicField(this, "overallProgress", 0);
|
|
803
|
-
// ADDED: Store overall progress (0-1)
|
|
804
849
|
__publicField(this, "intersectionMesh", new THREE.Mesh());
|
|
805
850
|
// Use a single mesh for intersection target
|
|
806
851
|
__publicField(this, "geometryNeedsUpdate");
|
|
@@ -1555,15 +1600,12 @@ class SimulationRendererService {
|
|
|
1555
1600
|
__publicField(this, "state");
|
|
1556
1601
|
__publicField(this, "textureSize");
|
|
1557
1602
|
__publicField(this, "overallProgress");
|
|
1558
|
-
// ADDED: Store overall progress
|
|
1559
1603
|
__publicField(this, "velocityTractionForce");
|
|
1560
1604
|
__publicField(this, "positionalTractionForce");
|
|
1561
1605
|
__publicField(this, "simulationRenderer");
|
|
1562
1606
|
__publicField(this, "webGLRenderer");
|
|
1563
1607
|
__publicField(this, "eventEmitter");
|
|
1564
|
-
// Store atlas info
|
|
1565
1608
|
__publicField(this, "currentAtlasEntry", null);
|
|
1566
|
-
// ADDED
|
|
1567
1609
|
__publicField(this, "lastKnownVelocityDataTexture");
|
|
1568
1610
|
__publicField(this, "lastKnownPositionDataTexture");
|
|
1569
1611
|
this.eventEmitter = eventEmitter;
|
|
@@ -1642,41 +1684,13 @@ class SimulationRendererService {
|
|
|
1642
1684
|
this.simulationRenderer.setMaxRepelDistance(distance);
|
|
1643
1685
|
}
|
|
1644
1686
|
}
|
|
1645
|
-
class ExecutionStatusMap {
|
|
1646
|
-
constructor() {
|
|
1647
|
-
__publicField(this, "execStatus", /* @__PURE__ */ new Map());
|
|
1648
|
-
}
|
|
1649
|
-
get(type) {
|
|
1650
|
-
const status = this.execStatus.get(type);
|
|
1651
|
-
if (!status) {
|
|
1652
|
-
this.execStatus.set(type, "idle");
|
|
1653
|
-
return "idle";
|
|
1654
|
-
}
|
|
1655
|
-
return status;
|
|
1656
|
-
}
|
|
1657
|
-
set(type, status) {
|
|
1658
|
-
this.execStatus.set(type, status);
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1661
1687
|
class TransitionService {
|
|
1662
1688
|
constructor(eventEmitter) {
|
|
1663
1689
|
__publicField(this, "eventEmitter");
|
|
1664
1690
|
__publicField(this, "transitions", /* @__PURE__ */ new Map());
|
|
1665
|
-
__publicField(this, "execStatus");
|
|
1666
1691
|
__publicField(this, "ongoingTransitions", /* @__PURE__ */ new Map());
|
|
1667
|
-
__publicField(this, "boundHandleTransitionCancelled");
|
|
1668
1692
|
this.eventEmitter = eventEmitter;
|
|
1669
|
-
this.
|
|
1670
|
-
this.boundHandleTransitionCancelled = this.handleTransitionCancelledEvent.bind(this);
|
|
1671
|
-
this.eventEmitter.on("transitionCancelled", this.boundHandleTransitionCancelled);
|
|
1672
|
-
}
|
|
1673
|
-
dispose() {
|
|
1674
|
-
this.eventEmitter.off("transitionCancelled", this.boundHandleTransitionCancelled);
|
|
1675
|
-
this.ongoingTransitions.forEach((transition) => {
|
|
1676
|
-
transition.cancelled = true;
|
|
1677
|
-
});
|
|
1678
|
-
this.ongoingTransitions.clear();
|
|
1679
|
-
this.transitions.clear();
|
|
1693
|
+
this.eventEmitter.on("transitionCancelled", this.handleTransitionCancelledEvent.bind(this));
|
|
1680
1694
|
}
|
|
1681
1695
|
/**
|
|
1682
1696
|
* Enqueues a transition.
|
|
@@ -1740,6 +1754,7 @@ class TransitionService {
|
|
|
1740
1754
|
if (ongoingTransition) {
|
|
1741
1755
|
ongoingTransition.cancelled = true;
|
|
1742
1756
|
(_a = ongoingTransition.onTransitionCancelled) == null ? void 0 : _a.call(ongoingTransition);
|
|
1757
|
+
this.ongoingTransitions.delete(type);
|
|
1743
1758
|
}
|
|
1744
1759
|
}
|
|
1745
1760
|
emitTransitionProgress(type, progress) {
|
|
@@ -1749,6 +1764,28 @@ class TransitionService {
|
|
|
1749
1764
|
this.eventEmitter.emit("transitionFinished", { type });
|
|
1750
1765
|
}
|
|
1751
1766
|
}
|
|
1767
|
+
function resolveSequenceInterpolation(progress, itemCount) {
|
|
1768
|
+
if (itemCount <= 1) {
|
|
1769
|
+
return { indexA: 0, indexB: 0, localProgress: 0 };
|
|
1770
|
+
}
|
|
1771
|
+
const clampedProgress = Math.max(0, Math.min(progress, 1));
|
|
1772
|
+
const totalSegments = itemCount - 1;
|
|
1773
|
+
const scaledProgress = clampedProgress * totalSegments;
|
|
1774
|
+
if (clampedProgress >= 1) {
|
|
1775
|
+
return {
|
|
1776
|
+
indexA: totalSegments,
|
|
1777
|
+
indexB: totalSegments,
|
|
1778
|
+
localProgress: 1
|
|
1779
|
+
};
|
|
1780
|
+
}
|
|
1781
|
+
const indexA = Math.floor(scaledProgress);
|
|
1782
|
+
const indexB = Math.min(indexA + 1, totalSegments);
|
|
1783
|
+
return {
|
|
1784
|
+
indexA,
|
|
1785
|
+
indexB,
|
|
1786
|
+
localProgress: scaledProgress - indexA
|
|
1787
|
+
};
|
|
1788
|
+
}
|
|
1752
1789
|
class ParticlesEngine {
|
|
1753
1790
|
/**
|
|
1754
1791
|
* Creates a new ParticlesEngine instance.
|
|
@@ -1767,21 +1804,16 @@ class ParticlesEngine {
|
|
|
1767
1804
|
__publicField(this, "engineState");
|
|
1768
1805
|
__publicField(this, "intersectionService");
|
|
1769
1806
|
__publicField(this, "meshSequenceAtlasTexture", null);
|
|
1770
|
-
|
|
1807
|
+
__publicField(this, "lastRenderElapsedTimeSeconds", null);
|
|
1771
1808
|
__publicField(this, "eventEmitter");
|
|
1772
|
-
// Bound event handlers for proper cleanup
|
|
1773
|
-
__publicField(this, "boundHandleServiceStateUpdated");
|
|
1774
|
-
__publicField(this, "boundHandleInteractionPositionUpdated");
|
|
1775
1809
|
const { scene, renderer, camera, textureSize, useIntersection = true } = params;
|
|
1776
1810
|
this.eventEmitter = new DefaultEventEmitter();
|
|
1777
1811
|
this.serviceStates = this.getInitialServiceStates();
|
|
1778
|
-
this.
|
|
1779
|
-
this.boundHandleInteractionPositionUpdated = this.handleInteractionPositionUpdated.bind(this);
|
|
1780
|
-
this.eventEmitter.on("serviceStateUpdated", this.boundHandleServiceStateUpdated);
|
|
1812
|
+
this.eventEmitter.on("serviceStateUpdated", this.handleServiceStateUpdated.bind(this));
|
|
1781
1813
|
this.scene = scene;
|
|
1782
1814
|
this.renderer = renderer;
|
|
1783
1815
|
this.engineState = this.initialEngineState(params);
|
|
1784
|
-
this.assetService = new AssetService(this.eventEmitter);
|
|
1816
|
+
this.assetService = new AssetService(this.eventEmitter, { dracoDecoderPath: params.dracoDecoderPath });
|
|
1785
1817
|
this.transitionService = new TransitionService(this.eventEmitter);
|
|
1786
1818
|
this.dataTextureManager = new DataTextureService(this.eventEmitter, textureSize);
|
|
1787
1819
|
this.simulationRendererService = new SimulationRendererService(this.eventEmitter, textureSize, this.renderer);
|
|
@@ -1790,18 +1822,23 @@ class ParticlesEngine {
|
|
|
1790
1822
|
this.intersectionService = new IntersectionService(this.eventEmitter, camera);
|
|
1791
1823
|
if (!useIntersection) this.intersectionService.setActive(false);
|
|
1792
1824
|
this.setOverallProgress(0, false);
|
|
1793
|
-
this.eventEmitter.on("interactionPositionUpdated", this.
|
|
1825
|
+
this.eventEmitter.on("interactionPositionUpdated", this.handleInteractionPositionUpdated.bind(this));
|
|
1794
1826
|
}
|
|
1795
1827
|
/**
|
|
1796
1828
|
* Renders the scene.
|
|
1797
1829
|
* @param elapsedTime The elapsed time since the last frame.
|
|
1798
1830
|
*/
|
|
1799
|
-
render(
|
|
1800
|
-
const
|
|
1801
|
-
this.
|
|
1831
|
+
render(elapsedTimeMs) {
|
|
1832
|
+
const elapsedTimeSeconds = elapsedTimeMs / 1e3;
|
|
1833
|
+
const deltaTimeSeconds = this.lastRenderElapsedTimeSeconds === null ? 0 : Math.max(0, elapsedTimeSeconds - this.lastRenderElapsedTimeSeconds);
|
|
1834
|
+
this.lastRenderElapsedTimeSeconds = elapsedTimeSeconds;
|
|
1835
|
+
this.renderFrame(deltaTimeSeconds, elapsedTimeSeconds);
|
|
1836
|
+
}
|
|
1837
|
+
renderFrame(deltaTimeSeconds, elapsedTimeSeconds) {
|
|
1838
|
+
this.transitionService.compute(elapsedTimeSeconds);
|
|
1802
1839
|
this.intersectionService.calculate(this.instancedMeshManager.getMesh());
|
|
1803
|
-
this.simulationRendererService.compute(
|
|
1804
|
-
this.instancedMeshManager.update(
|
|
1840
|
+
this.simulationRendererService.compute(deltaTimeSeconds);
|
|
1841
|
+
this.instancedMeshManager.update(elapsedTimeSeconds);
|
|
1805
1842
|
this.instancedMeshManager.updateVelocityTexture(this.simulationRendererService.getVelocityTexture());
|
|
1806
1843
|
this.instancedMeshManager.updatePositionTexture(this.simulationRendererService.getPositionTexture());
|
|
1807
1844
|
}
|
|
@@ -1810,27 +1847,30 @@ class ParticlesEngine {
|
|
|
1810
1847
|
this.eventEmitter.emit("textureSequenceUpdated", { sequence });
|
|
1811
1848
|
this.setOverallProgress(0, false);
|
|
1812
1849
|
}
|
|
1813
|
-
// --- Update setTextureSize ---
|
|
1814
1850
|
async setTextureSize(size) {
|
|
1815
1851
|
if (this.engineState.textureSize === size) {
|
|
1816
1852
|
return;
|
|
1817
1853
|
}
|
|
1854
|
+
const meshSequence = [...this.engineState.meshSequence];
|
|
1855
|
+
const overallProgress = this.engineState.overallProgress;
|
|
1818
1856
|
this.engineState.textureSize = size;
|
|
1819
1857
|
this.dataTextureManager.setTextureSize(size);
|
|
1820
1858
|
this.simulationRendererService.setTextureSize(size);
|
|
1821
|
-
this.
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1859
|
+
const { current, previous } = this.instancedMeshManager.resize(size);
|
|
1860
|
+
if (current !== previous) {
|
|
1861
|
+
previous.dispose();
|
|
1862
|
+
if (!current.parent) {
|
|
1863
|
+
this.scene.add(current);
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
if (meshSequence.length > 0) {
|
|
1867
|
+
await this.setMeshSequence(meshSequence);
|
|
1826
1868
|
}
|
|
1827
1869
|
this.simulationRendererService.setVelocityTractionForce(this.engineState.velocityTractionForce);
|
|
1828
1870
|
this.simulationRendererService.setPositionalTractionForce(this.engineState.positionalTractionForce);
|
|
1829
1871
|
this.simulationRendererService.setMaxRepelDistance(this.engineState.maxRepelDistance);
|
|
1830
|
-
this.simulationRendererService.setOverallProgress(this.engineState.overallProgress);
|
|
1831
|
-
this.intersectionService.setOverallProgress(this.engineState.overallProgress);
|
|
1832
1872
|
this.instancedMeshManager.setGeometrySize(this.engineState.instanceGeometryScale);
|
|
1833
|
-
this.setOverallProgress(
|
|
1873
|
+
this.setOverallProgress(overallProgress, false);
|
|
1834
1874
|
}
|
|
1835
1875
|
registerMesh(id, mesh) {
|
|
1836
1876
|
this.assetService.register(id, mesh);
|
|
@@ -1838,8 +1878,8 @@ class ParticlesEngine {
|
|
|
1838
1878
|
registerMatcap(id, matcap) {
|
|
1839
1879
|
this.assetService.register(id, matcap);
|
|
1840
1880
|
}
|
|
1841
|
-
async fetchAndRegisterMesh(id, url) {
|
|
1842
|
-
return await this.assetService.loadMeshAsync(id, url);
|
|
1881
|
+
async fetchAndRegisterMesh(id, url, options) {
|
|
1882
|
+
return await this.assetService.loadMeshAsync(id, url, options);
|
|
1843
1883
|
}
|
|
1844
1884
|
async fetchAndRegisterMatcap(id, url) {
|
|
1845
1885
|
return await this.assetService.loadTextureAsync(id, url);
|
|
@@ -1932,7 +1972,7 @@ class ParticlesEngine {
|
|
|
1932
1972
|
this.engineState.overallProgress = clampedProgress;
|
|
1933
1973
|
this.simulationRendererService.setOverallProgress(clampedProgress);
|
|
1934
1974
|
this.intersectionService.setOverallProgress(clampedProgress);
|
|
1935
|
-
const { textureA, textureB, localProgress } = this.calculateTextureInterpolation(
|
|
1975
|
+
const { textureA, textureB, localProgress } = this.calculateTextureInterpolation(clampedProgress);
|
|
1936
1976
|
this.instancedMeshManager.updateTextureInterpolation(textureA, textureB, localProgress);
|
|
1937
1977
|
}
|
|
1938
1978
|
/**
|
|
@@ -1998,27 +2038,22 @@ class ParticlesEngine {
|
|
|
1998
2038
|
* Disposes the resources used by the engine.
|
|
1999
2039
|
*/
|
|
2000
2040
|
dispose() {
|
|
2001
|
-
var _a, _b, _c, _d, _e, _f
|
|
2041
|
+
var _a, _b, _c, _d, _e, _f;
|
|
2002
2042
|
if (this.scene && this.instancedMeshManager) {
|
|
2003
2043
|
this.scene.remove(this.instancedMeshManager.getMesh());
|
|
2004
2044
|
}
|
|
2005
|
-
this.eventEmitter.off("serviceStateUpdated", this.boundHandleServiceStateUpdated);
|
|
2006
|
-
this.eventEmitter.off("interactionPositionUpdated", this.boundHandleInteractionPositionUpdated);
|
|
2007
2045
|
(_a = this.simulationRendererService) == null ? void 0 : _a.dispose();
|
|
2008
2046
|
(_b = this.instancedMeshManager) == null ? void 0 : _b.dispose();
|
|
2009
2047
|
(_c = this.intersectionService) == null ? void 0 : _c.dispose();
|
|
2010
2048
|
(_d = this.assetService) == null ? void 0 : _d.dispose();
|
|
2011
2049
|
(_e = this.dataTextureManager) == null ? void 0 : _e.dispose();
|
|
2012
|
-
(_f = this.
|
|
2013
|
-
(_g = this.eventEmitter) == null ? void 0 : _g.dispose();
|
|
2050
|
+
(_f = this.eventEmitter) == null ? void 0 : _f.dispose();
|
|
2014
2051
|
}
|
|
2015
2052
|
initialEngineState(params) {
|
|
2016
2053
|
return {
|
|
2017
2054
|
textureSize: params.textureSize,
|
|
2018
2055
|
meshSequence: [],
|
|
2019
|
-
// ADDED
|
|
2020
2056
|
overallProgress: 0,
|
|
2021
|
-
// ADDED
|
|
2022
2057
|
textureSequence: [],
|
|
2023
2058
|
velocityTractionForce: 0.1,
|
|
2024
2059
|
positionalTractionForce: 0.1,
|
|
@@ -2051,23 +2086,7 @@ class ParticlesEngine {
|
|
|
2051
2086
|
const tex = this.getTextureForSequenceItem(sequence[0]);
|
|
2052
2087
|
return { textureA: tex, textureB: tex, localProgress: 0 };
|
|
2053
2088
|
}
|
|
2054
|
-
const
|
|
2055
|
-
const progressPerSegment = 1 / totalSegments;
|
|
2056
|
-
const scaledProgress = progress * totalSegments;
|
|
2057
|
-
let indexA = Math.floor(scaledProgress);
|
|
2058
|
-
let indexB = indexA + 1;
|
|
2059
|
-
indexA = Math.max(0, Math.min(indexA, totalSegments));
|
|
2060
|
-
indexB = Math.max(0, Math.min(indexB, totalSegments));
|
|
2061
|
-
let localProgress = 0;
|
|
2062
|
-
if (progressPerSegment > 0) {
|
|
2063
|
-
localProgress = (progress - indexA * progressPerSegment) / progressPerSegment;
|
|
2064
|
-
}
|
|
2065
|
-
if (progress >= 1) {
|
|
2066
|
-
indexA = totalSegments;
|
|
2067
|
-
indexB = totalSegments;
|
|
2068
|
-
localProgress = 1;
|
|
2069
|
-
}
|
|
2070
|
-
localProgress = Math.max(0, Math.min(localProgress, 1));
|
|
2089
|
+
const { indexA, indexB, localProgress } = resolveSequenceInterpolation(progress, numItems);
|
|
2071
2090
|
const itemA = sequence[indexA];
|
|
2072
2091
|
const itemB = sequence[indexB];
|
|
2073
2092
|
const textureA = this.getTextureForSequenceItem(itemA);
|
|
@@ -2083,6 +2102,7 @@ class ParticlesEngine {
|
|
|
2083
2102
|
}
|
|
2084
2103
|
}
|
|
2085
2104
|
export {
|
|
2086
|
-
ParticlesEngine
|
|
2105
|
+
ParticlesEngine,
|
|
2106
|
+
resolveSequenceInterpolation
|
|
2087
2107
|
};
|
|
2088
2108
|
//# sourceMappingURL=ionian.js.map
|