@polarfront-lab/ionian 1.0.6 → 1.1.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/dist/index.d.ts +15 -19
- package/dist/ionian.iife.js +2 -2
- package/dist/ionian.iife.js.map +1 -1
- package/dist/ionian.js +220 -143
- package/dist/ionian.js.map +1 -1
- package/package.json +12 -33
- package/dist/ionian.umd.cjs +0 -7
- package/dist/ionian.umd.cjs.map +0 -1
package/dist/ionian.js
CHANGED
|
@@ -3,6 +3,7 @@ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { en
|
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
import * as THREE from "three";
|
|
5
5
|
import { Mesh, OrthographicCamera, BufferGeometry, Float32BufferAttribute, NearestFilter, ShaderMaterial, WebGLRenderTarget, FloatType, RGBAFormat, DataTexture, ClampToEdgeWrapping } from "three";
|
|
6
|
+
import { GLTFLoader, DRACOLoader } from "three-stdlib";
|
|
6
7
|
const linear = (n) => n;
|
|
7
8
|
function mitt(n) {
|
|
8
9
|
return { all: n = n || /* @__PURE__ */ new Map(), on: function(t, e) {
|
|
@@ -2033,7 +2034,7 @@ var genericPoolExports = requireGenericPool();
|
|
|
2033
2034
|
const genericPool = /* @__PURE__ */ getDefaultExportFromCjs(genericPoolExports);
|
|
2034
2035
|
const workerFactory = {
|
|
2035
2036
|
create: async () => {
|
|
2036
|
-
const workerPath = new URL("data:video/mp2t;base64,
|
|
2037
|
+
const workerPath = new URL("data:video/mp2t;base64,aW1wb3J0IHsgTWVzaERhdGEgfSBmcm9tICdAL2xpYi90eXBlcyc7CmltcG9ydCAqIGFzIENvbWxpbmsgZnJvbSAnY29tbGluayc7CmltcG9ydCAqIGFzIFRIUkVFIGZyb20gJ3RocmVlJzsKaW1wb3J0IHsgTWVzaFN1cmZhY2VTYW1wbGVyIH0gZnJvbSAndGhyZWUvZXhhbXBsZXMvanNtL21hdGgvTWVzaFN1cmZhY2VTYW1wbGVyLmpzJzsKCmV4cG9ydCBpbnRlcmZhY2UgTWVzaFNhbXBsZXJBUEkgewogIHNhbXBsZU1lc2g6IChtZXNoRGF0YTogTWVzaERhdGEsIHNpemU6IG51bWJlcikgPT4gUHJvbWlzZTxGbG9hdDMyQXJyYXk+Owp9Cgpjb25zdCBhcGkgPSB7CiAgc2FtcGxlTWVzaDogKG1lc2hEYXRhOiBNZXNoRGF0YSwgc2l6ZTogbnVtYmVyKTogRmxvYXQzMkFycmF5ID0+IHsKICAgIGNvbnN0IGdlb21ldHJ5ID0gbmV3IFRIUkVFLkJ1ZmZlckdlb21ldHJ5KCk7CiAgICBnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoJ3Bvc2l0aW9uJywgbmV3IFRIUkVFLkJ1ZmZlckF0dHJpYnV0ZShuZXcgRmxvYXQzMkFycmF5KG1lc2hEYXRhLnBvc2l0aW9uKSwgMykpOwogICAgaWYgKG1lc2hEYXRhLm5vcm1hbCkgewogICAgICBnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoJ25vcm1hbCcsIG5ldyBUSFJFRS5CdWZmZXJBdHRyaWJ1dGUobmV3IEZsb2F0MzJBcnJheShtZXNoRGF0YS5ub3JtYWwpLCAzKSk7CiAgICB9CiAgICBjb25zdCBtYXRlcmlhbCA9IG5ldyBUSFJFRS5NZXNoQmFzaWNNYXRlcmlhbCgpOwogICAgY29uc3QgbWVzaCA9IG5ldyBUSFJFRS5NZXNoKGdlb21ldHJ5LCBtYXRlcmlhbCk7CiAgICBtZXNoLnNjYWxlLnNldChtZXNoRGF0YS5zY2FsZS54LCBtZXNoRGF0YS5zY2FsZS55LCBtZXNoRGF0YS5zY2FsZS56KTsKCiAgICBjb25zdCBzYW1wbGVyID0gbmV3IE1lc2hTdXJmYWNlU2FtcGxlcihtZXNoKS5idWlsZCgpOwogICAgY29uc3QgZGF0YSA9IG5ldyBGbG9hdDMyQXJyYXkoc2l6ZSAqIHNpemUgKiA0KTsKICAgIGNvbnN0IHBvc2l0aW9uID0gbmV3IFRIUkVFLlZlY3RvcjMoKTsKCiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHNpemU7IGkrKykgewogICAgICBmb3IgKGxldCBqID0gMDsgaiA8IHNpemU7IGorKykgewogICAgICAgIGNvbnN0IGluZGV4ID0gaSAqIHNpemUgKyBqOwogICAgICAgIHNhbXBsZXIuc2FtcGxlKHBvc2l0aW9uKTsKICAgICAgICBkYXRhWzQgKiBpbmRleF0gPSBwb3NpdGlvbi54ICogbWVzaERhdGEuc2NhbGUueDsKICAgICAgICBkYXRhWzQgKiBpbmRleCArIDFdID0gcG9zaXRpb24ueSAqIG1lc2hEYXRhLnNjYWxlLnk7CiAgICAgICAgZGF0YVs0ICogaW5kZXggKyAyXSA9IHBvc2l0aW9uLnogKiBtZXNoRGF0YS5zY2FsZS56OwogICAgICAgIGRhdGFbNCAqIGluZGV4ICsgM10gPSAoTWF0aC5yYW5kb20oKSAtIDAuNSkgKiAwLjAxOwogICAgICB9CiAgICB9CgogICAgcmV0dXJuIGRhdGE7CiAgfSwKfTsKCkNvbWxpbmsuZXhwb3NlKGFwaSk7Cg==", import.meta.url);
|
|
2037
2038
|
const worker = new Worker(workerPath, { type: "module" });
|
|
2038
2039
|
return wrap(worker);
|
|
2039
2040
|
},
|
|
@@ -2071,16 +2072,13 @@ function createSpherePoints(size) {
|
|
|
2071
2072
|
}
|
|
2072
2073
|
return createDataTexture(data, size);
|
|
2073
2074
|
}
|
|
2074
|
-
function
|
|
2075
|
-
|
|
2076
|
-
if (
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
map.set(source.id, source.item);
|
|
2081
|
-
}
|
|
2075
|
+
function disposeMesh(mesh) {
|
|
2076
|
+
mesh.geometry.dispose();
|
|
2077
|
+
if (mesh.material instanceof THREE.Material) {
|
|
2078
|
+
mesh.material.dispose();
|
|
2079
|
+
} else {
|
|
2080
|
+
mesh.material.forEach((material) => material.dispose());
|
|
2082
2081
|
}
|
|
2083
|
-
return map;
|
|
2084
2082
|
}
|
|
2085
2083
|
function clamp(value, min, max) {
|
|
2086
2084
|
value = Math.min(value, max);
|
|
@@ -2092,71 +2090,44 @@ class DataTextureService {
|
|
|
2092
2090
|
* Creates a new DataTextureManager instance.
|
|
2093
2091
|
* @param eventEmitter
|
|
2094
2092
|
* @param textureSize
|
|
2095
|
-
* @param meshes Optional initial meshes.
|
|
2096
2093
|
*/
|
|
2097
|
-
constructor(eventEmitter, textureSize
|
|
2094
|
+
constructor(eventEmitter, textureSize) {
|
|
2098
2095
|
__publicField(this, "textureSize");
|
|
2099
|
-
__publicField(this, "meshes");
|
|
2100
2096
|
__publicField(this, "dataTextures");
|
|
2101
2097
|
__publicField(this, "eventEmitter");
|
|
2102
2098
|
this.eventEmitter = eventEmitter;
|
|
2103
2099
|
this.textureSize = textureSize;
|
|
2104
|
-
this.meshes = copyOf(meshes);
|
|
2105
2100
|
this.dataTextures = /* @__PURE__ */ new Map();
|
|
2106
2101
|
this.updateServiceState("ready");
|
|
2107
2102
|
}
|
|
2108
|
-
/**
|
|
2109
|
-
* Registers a mesh.
|
|
2110
|
-
* @param id The ID of the mesh.
|
|
2111
|
-
* @param mesh The mesh to register.
|
|
2112
|
-
*/
|
|
2113
|
-
async register(id, mesh) {
|
|
2114
|
-
this.meshes.set(id, mesh);
|
|
2115
|
-
}
|
|
2116
2103
|
setTextureSize(textureSize) {
|
|
2117
2104
|
if (this.textureSize === textureSize) return;
|
|
2118
2105
|
this.textureSize = textureSize;
|
|
2119
2106
|
this.dataTextures.forEach((texture) => texture.dispose());
|
|
2120
2107
|
this.dataTextures.clear();
|
|
2121
2108
|
}
|
|
2122
|
-
getMesh(id) {
|
|
2123
|
-
return this.meshes.get(id);
|
|
2124
|
-
}
|
|
2125
|
-
/**
|
|
2126
|
-
* Gets the data texture for the specified mesh ID and current texture size.
|
|
2127
|
-
* Returns the fallback data texture if the specified mesh ID is not found.
|
|
2128
|
-
* @param id The ID of the mesh.
|
|
2129
|
-
* @returns The data texture, or undefined if not found and no fallback is available.
|
|
2130
|
-
*/
|
|
2131
|
-
async getDataTexture(id) {
|
|
2132
|
-
return await this.prepareMesh(id);
|
|
2133
|
-
}
|
|
2134
2109
|
/**
|
|
2135
2110
|
* Prepares a mesh for sampling.
|
|
2136
|
-
* @
|
|
2111
|
+
* @returns The prepared data texture.
|
|
2112
|
+
* @param asset The asset to prepare.
|
|
2137
2113
|
*/
|
|
2138
|
-
async
|
|
2139
|
-
|
|
2140
|
-
throw new Error(`Mesh with id "${id}" does not exist.`);
|
|
2141
|
-
}
|
|
2142
|
-
const texture = this.dataTextures.get(id);
|
|
2114
|
+
async getDataTexture(asset) {
|
|
2115
|
+
const texture = this.dataTextures.get(asset.name);
|
|
2143
2116
|
if (texture) {
|
|
2144
2117
|
return texture;
|
|
2145
2118
|
}
|
|
2146
|
-
const
|
|
2147
|
-
const meshData = parseMeshData(mesh);
|
|
2119
|
+
const meshData = parseMeshData(asset);
|
|
2148
2120
|
const worker = await pool.acquire();
|
|
2149
2121
|
try {
|
|
2150
|
-
const
|
|
2151
|
-
const
|
|
2152
|
-
|
|
2153
|
-
return
|
|
2122
|
+
const array = await worker.sampleMesh(meshData, this.textureSize);
|
|
2123
|
+
const dataTexture = createDataTexture(array, this.textureSize);
|
|
2124
|
+
dataTexture.name = asset.name;
|
|
2125
|
+
return dataTexture;
|
|
2154
2126
|
} finally {
|
|
2155
2127
|
await pool.release(worker);
|
|
2156
2128
|
}
|
|
2157
2129
|
}
|
|
2158
2130
|
async dispose() {
|
|
2159
|
-
this.meshes.clear();
|
|
2160
2131
|
this.dataTextures.clear();
|
|
2161
2132
|
this.updateServiceState("disposed");
|
|
2162
2133
|
}
|
|
@@ -2298,11 +2269,9 @@ class InstancedMeshManager {
|
|
|
2298
2269
|
* @param matcap The matcap texture to set.
|
|
2299
2270
|
*/
|
|
2300
2271
|
setOriginMatcap(matcap) {
|
|
2301
|
-
console.log("set source matcap", matcap);
|
|
2302
2272
|
this.matcapMaterial.uniforms.uSourceMatcap.value = matcap;
|
|
2303
2273
|
}
|
|
2304
2274
|
setDestinationMatcap(matcap) {
|
|
2305
|
-
console.log("set target matcap", matcap);
|
|
2306
2275
|
this.matcapMaterial.uniforms.uTargetMatcap.value = matcap;
|
|
2307
2276
|
}
|
|
2308
2277
|
setProgress(float) {
|
|
@@ -2319,7 +2288,6 @@ class InstancedMeshManager {
|
|
|
2319
2288
|
* Use the matcap material for the instanced mesh.
|
|
2320
2289
|
*/
|
|
2321
2290
|
useMatcapMaterial() {
|
|
2322
|
-
console.log("Using matcap material");
|
|
2323
2291
|
this.mesh.material = this.matcapMaterial;
|
|
2324
2292
|
}
|
|
2325
2293
|
/**
|
|
@@ -2330,8 +2298,6 @@ class InstancedMeshManager {
|
|
|
2330
2298
|
const material = this.materials.get(id);
|
|
2331
2299
|
if (material) {
|
|
2332
2300
|
this.mesh.material = material;
|
|
2333
|
-
} else {
|
|
2334
|
-
console.warn(`material with id "${id}" not found`);
|
|
2335
2301
|
}
|
|
2336
2302
|
}
|
|
2337
2303
|
/**
|
|
@@ -2342,8 +2308,6 @@ class InstancedMeshManager {
|
|
|
2342
2308
|
const geometry = this.geometries.get(id);
|
|
2343
2309
|
if (geometry) {
|
|
2344
2310
|
this.mesh.geometry = geometry;
|
|
2345
|
-
} else {
|
|
2346
|
-
console.warn(`geometry with id "${id}" not found`);
|
|
2347
2311
|
}
|
|
2348
2312
|
}
|
|
2349
2313
|
/**
|
|
@@ -2394,7 +2358,6 @@ class InstancedMeshManager {
|
|
|
2394
2358
|
if (previous === geometry) {
|
|
2395
2359
|
return;
|
|
2396
2360
|
}
|
|
2397
|
-
console.log(`geometry with id "${id}" already exists. replacing...`);
|
|
2398
2361
|
}
|
|
2399
2362
|
const uvRefs = this.getUVRefs(this.size);
|
|
2400
2363
|
geometry.setAttribute("uvRef", uvRefs);
|
|
@@ -2415,7 +2378,6 @@ class InstancedMeshManager {
|
|
|
2415
2378
|
if (previous === material) {
|
|
2416
2379
|
return;
|
|
2417
2380
|
}
|
|
2418
|
-
console.log(`material with id "${id}" already exists. replacing...`);
|
|
2419
2381
|
}
|
|
2420
2382
|
if (this.mesh.material === previous) {
|
|
2421
2383
|
this.mesh.material = material;
|
|
@@ -2470,8 +2432,6 @@ class IntersectionService {
|
|
|
2470
2432
|
constructor(eventEmitter, camera, originGeometry, destinationGeometry) {
|
|
2471
2433
|
__publicField(this, "raycaster", new THREE.Raycaster());
|
|
2472
2434
|
__publicField(this, "mousePosition", new THREE.Vector2());
|
|
2473
|
-
__publicField(this, "mouseEntered", false);
|
|
2474
|
-
__publicField(this, "mousePositionChanged", false);
|
|
2475
2435
|
__publicField(this, "camera");
|
|
2476
2436
|
__publicField(this, "originGeometry");
|
|
2477
2437
|
__publicField(this, "destinationGeometry");
|
|
@@ -2489,6 +2449,9 @@ class IntersectionService {
|
|
|
2489
2449
|
this.destinationGeometry = destinationGeometry;
|
|
2490
2450
|
this.geometryNeedsUpdate = true;
|
|
2491
2451
|
}
|
|
2452
|
+
getIntersectionMesh() {
|
|
2453
|
+
return this.intersectionMesh;
|
|
2454
|
+
}
|
|
2492
2455
|
/**
|
|
2493
2456
|
* Set the camera used for raycasting.
|
|
2494
2457
|
* @param camera
|
|
@@ -2533,36 +2496,23 @@ class IntersectionService {
|
|
|
2533
2496
|
* @param mousePosition
|
|
2534
2497
|
*/
|
|
2535
2498
|
setMousePosition(mousePosition) {
|
|
2536
|
-
if (mousePosition)
|
|
2537
|
-
if (!this.mousePosition.equals(mousePosition)) {
|
|
2538
|
-
this.mousePosition.copy(mousePosition);
|
|
2539
|
-
this.mousePositionChanged = true;
|
|
2540
|
-
}
|
|
2541
|
-
this.mouseEntered = true;
|
|
2542
|
-
} else {
|
|
2543
|
-
this.mouseEntered = false;
|
|
2544
|
-
this.mousePositionChanged = false;
|
|
2545
|
-
}
|
|
2499
|
+
if (mousePosition) this.mousePosition.copy(mousePosition);
|
|
2546
2500
|
}
|
|
2547
2501
|
/**
|
|
2548
2502
|
* Calculate the intersection.
|
|
2549
2503
|
* @returns The intersection point or undefined if no intersection was found.
|
|
2550
2504
|
*/
|
|
2551
|
-
calculate() {
|
|
2505
|
+
calculate(instancedMesh) {
|
|
2506
|
+
this.updateIntersectionMesh(instancedMesh);
|
|
2552
2507
|
if (!this.camera) return;
|
|
2553
|
-
if (!this.mouseEntered) return;
|
|
2554
2508
|
if (this.geometryNeedsUpdate) {
|
|
2555
2509
|
this.geometryNeedsUpdate = false;
|
|
2556
2510
|
this.blendedGeometry = this.getBlendedGeometry();
|
|
2557
|
-
this.mousePositionChanged = true;
|
|
2558
2511
|
}
|
|
2559
|
-
if (this.
|
|
2560
|
-
this.
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
} else {
|
|
2564
|
-
this.intersection = void 0;
|
|
2565
|
-
}
|
|
2512
|
+
if (this.blendedGeometry) {
|
|
2513
|
+
this.intersection = this.getFirstIntersection(this.camera, instancedMesh);
|
|
2514
|
+
} else {
|
|
2515
|
+
this.intersection = void 0;
|
|
2566
2516
|
}
|
|
2567
2517
|
if (this.intersection) {
|
|
2568
2518
|
this.eventEmitter.emit("interactionPositionUpdated", { position: this.intersection });
|
|
@@ -2579,12 +2529,25 @@ class IntersectionService {
|
|
|
2579
2529
|
(_a = this.blendedGeometry) == null ? void 0 : _a.dispose();
|
|
2580
2530
|
this.intersectionMesh.geometry.dispose();
|
|
2581
2531
|
}
|
|
2582
|
-
|
|
2532
|
+
updateIntersectionMesh(instancedMesh) {
|
|
2533
|
+
if (this.blendedGeometry) {
|
|
2534
|
+
if (this.blendedGeometry.uuid !== this.intersectionMesh.geometry.uuid) {
|
|
2535
|
+
this.intersectionMesh.geometry.dispose();
|
|
2536
|
+
this.intersectionMesh.geometry = this.blendedGeometry;
|
|
2537
|
+
}
|
|
2538
|
+
}
|
|
2539
|
+
this.intersectionMesh.matrix.copy(instancedMesh.matrixWorld);
|
|
2540
|
+
this.intersectionMesh.matrixWorld.copy(instancedMesh.matrixWorld);
|
|
2541
|
+
this.intersectionMesh.matrixAutoUpdate = false;
|
|
2542
|
+
this.intersectionMesh.updateMatrixWorld(true);
|
|
2543
|
+
}
|
|
2544
|
+
getFirstIntersection(camera, instancedMesh) {
|
|
2583
2545
|
this.raycaster.setFromCamera(this.mousePosition, camera);
|
|
2584
|
-
this.intersectionMesh.geometry = geometry;
|
|
2585
2546
|
const intersection = this.raycaster.intersectObject(this.intersectionMesh, false)[0];
|
|
2586
2547
|
if (intersection) {
|
|
2587
|
-
|
|
2548
|
+
const worldPoint = intersection.point.clone();
|
|
2549
|
+
const localPoint = instancedMesh.worldToLocal(worldPoint);
|
|
2550
|
+
return new THREE.Vector4(localPoint.x, localPoint.y, localPoint.z, 1);
|
|
2588
2551
|
}
|
|
2589
2552
|
}
|
|
2590
2553
|
getBlendedGeometry() {
|
|
@@ -2622,46 +2585,6 @@ class IntersectionService {
|
|
|
2622
2585
|
return blended;
|
|
2623
2586
|
}
|
|
2624
2587
|
}
|
|
2625
|
-
class MatcapService {
|
|
2626
|
-
constructor(eventEmitter, matcaps) {
|
|
2627
|
-
__publicField(this, "matcaps", /* @__PURE__ */ new Map());
|
|
2628
|
-
__publicField(this, "eventEmitter");
|
|
2629
|
-
__publicField(this, "fallbackMatcap", new THREE.DataTexture(new Uint8Array([127, 127, 127, 255]), 1, 1, THREE.RGBAFormat));
|
|
2630
|
-
this.eventEmitter = eventEmitter;
|
|
2631
|
-
if (matcaps) {
|
|
2632
|
-
matcaps.forEach(({ id, item }) => this.setMatcap(id, item));
|
|
2633
|
-
}
|
|
2634
|
-
this.updateServiceState("ready");
|
|
2635
|
-
}
|
|
2636
|
-
getMatcap(id) {
|
|
2637
|
-
const texture = this.matcaps.get(id);
|
|
2638
|
-
if (!texture) {
|
|
2639
|
-
this.eventEmitter.emit("invalidRequest", { message: `invalid matcap request: ${id}` });
|
|
2640
|
-
return this.fallbackMatcap;
|
|
2641
|
-
} else {
|
|
2642
|
-
return texture;
|
|
2643
|
-
}
|
|
2644
|
-
}
|
|
2645
|
-
setMatcap(id, texture) {
|
|
2646
|
-
const previous = this.matcaps.get(id);
|
|
2647
|
-
if (previous === texture) return;
|
|
2648
|
-
this.matcaps.set(id, texture);
|
|
2649
|
-
if (previous) {
|
|
2650
|
-
this.eventEmitter.emit("matcapReplaced", { id });
|
|
2651
|
-
previous.dispose();
|
|
2652
|
-
} else {
|
|
2653
|
-
this.eventEmitter.emit("matcapRegistered", { id });
|
|
2654
|
-
}
|
|
2655
|
-
}
|
|
2656
|
-
dispose() {
|
|
2657
|
-
this.updateServiceState("disposed");
|
|
2658
|
-
this.matcaps.forEach((texture) => texture.dispose());
|
|
2659
|
-
this.matcaps.clear();
|
|
2660
|
-
}
|
|
2661
|
-
updateServiceState(serviceState) {
|
|
2662
|
-
this.eventEmitter.emit("serviceStateUpdated", { type: "matcap", state: serviceState });
|
|
2663
|
-
}
|
|
2664
|
-
}
|
|
2665
2588
|
const _camera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
|
2666
2589
|
class FullscreenTriangleGeometry extends BufferGeometry {
|
|
2667
2590
|
constructor() {
|
|
@@ -3264,6 +3187,122 @@ class TransitionService {
|
|
|
3264
3187
|
this.eventEmitter.emit("transitionFinished", { type });
|
|
3265
3188
|
}
|
|
3266
3189
|
}
|
|
3190
|
+
class AssetService {
|
|
3191
|
+
constructor(eventEmitter) {
|
|
3192
|
+
__publicField(this, "serviceState", "created");
|
|
3193
|
+
__publicField(this, "eventEmitter");
|
|
3194
|
+
__publicField(this, "meshes", /* @__PURE__ */ new Map());
|
|
3195
|
+
__publicField(this, "textures", /* @__PURE__ */ new Map());
|
|
3196
|
+
__publicField(this, "gltfLoader", new GLTFLoader());
|
|
3197
|
+
__publicField(this, "textureLoader", new THREE.TextureLoader());
|
|
3198
|
+
__publicField(this, "dracoLoader", new DRACOLoader());
|
|
3199
|
+
__publicField(this, "solidColorTexture", new THREE.DataTexture(new Uint8Array([127, 127, 127, 255]), 1, 1, THREE.RGBAFormat));
|
|
3200
|
+
this.eventEmitter = eventEmitter;
|
|
3201
|
+
this.dracoLoader.setDecoderPath("https://www.gstatic.com/draco/versioned/decoders/1.5.7/");
|
|
3202
|
+
this.gltfLoader.setDRACOLoader(this.dracoLoader);
|
|
3203
|
+
this.updateServiceState("ready");
|
|
3204
|
+
}
|
|
3205
|
+
/**
|
|
3206
|
+
* Registers an asset.
|
|
3207
|
+
* @param id - The ID of the asset.
|
|
3208
|
+
* @param item - The asset to set.
|
|
3209
|
+
*/
|
|
3210
|
+
register(id, item) {
|
|
3211
|
+
item.name = id;
|
|
3212
|
+
if (item instanceof THREE.Mesh) {
|
|
3213
|
+
const prev = this.meshes.get(id);
|
|
3214
|
+
if (prev) disposeMesh(prev);
|
|
3215
|
+
this.meshes.set(id, item);
|
|
3216
|
+
} else {
|
|
3217
|
+
const prev = this.textures.get(id);
|
|
3218
|
+
if (prev) prev.dispose();
|
|
3219
|
+
this.textures.set(id, item);
|
|
3220
|
+
}
|
|
3221
|
+
this.eventEmitter.emit("assetRegistered", { id });
|
|
3222
|
+
}
|
|
3223
|
+
setSolidColor(color) {
|
|
3224
|
+
this.changeColor(color);
|
|
3225
|
+
}
|
|
3226
|
+
getSolidColorTexture() {
|
|
3227
|
+
return this.solidColorTexture;
|
|
3228
|
+
}
|
|
3229
|
+
getMesh(id) {
|
|
3230
|
+
return this.meshes.get(id) ?? null;
|
|
3231
|
+
}
|
|
3232
|
+
getMatcap(id) {
|
|
3233
|
+
const texture = this.textures.get(id);
|
|
3234
|
+
if (!texture) this.eventEmitter.emit("invalidRequest", { message: `texture with id "${id}" not found. using solid color texture instead...` });
|
|
3235
|
+
return texture ?? this.solidColorTexture;
|
|
3236
|
+
}
|
|
3237
|
+
getMeshIDs() {
|
|
3238
|
+
return Array.from(this.meshes.keys());
|
|
3239
|
+
}
|
|
3240
|
+
getTextureIDs() {
|
|
3241
|
+
return Array.from(this.textures.keys());
|
|
3242
|
+
}
|
|
3243
|
+
getMeshes() {
|
|
3244
|
+
return Array.from(this.meshes.values());
|
|
3245
|
+
}
|
|
3246
|
+
getTextures() {
|
|
3247
|
+
return Array.from(this.textures.values());
|
|
3248
|
+
}
|
|
3249
|
+
/**
|
|
3250
|
+
* Loads a mesh asynchronously.
|
|
3251
|
+
* @param id - The ID of the mesh.
|
|
3252
|
+
* @param url - The URL of the mesh.
|
|
3253
|
+
* @param options - Optional parameters.
|
|
3254
|
+
* @returns The loaded mesh or null.
|
|
3255
|
+
*/
|
|
3256
|
+
async loadMeshAsync(id, url, options = {}) {
|
|
3257
|
+
const gltf = await this.gltfLoader.loadAsync(url);
|
|
3258
|
+
try {
|
|
3259
|
+
if (options.meshName) {
|
|
3260
|
+
const mesh = gltf.scene.getObjectByName(options.meshName);
|
|
3261
|
+
this.register(id, mesh);
|
|
3262
|
+
return mesh;
|
|
3263
|
+
} else {
|
|
3264
|
+
const mesh = gltf.scene.children[0];
|
|
3265
|
+
this.register(id, mesh);
|
|
3266
|
+
return mesh;
|
|
3267
|
+
}
|
|
3268
|
+
} catch (error) {
|
|
3269
|
+
this.eventEmitter.emit("invalidRequest", { message: `failed to load mesh: ${id}. ${error}` });
|
|
3270
|
+
return null;
|
|
3271
|
+
}
|
|
3272
|
+
}
|
|
3273
|
+
/**
|
|
3274
|
+
* Loads a texture asynchronously.
|
|
3275
|
+
* @param id - The ID of the texture.
|
|
3276
|
+
* @param url - The URL of the texture.
|
|
3277
|
+
* @returns The loaded texture or null.
|
|
3278
|
+
*/
|
|
3279
|
+
async loadTextureAsync(id, url) {
|
|
3280
|
+
try {
|
|
3281
|
+
const texture = await this.textureLoader.loadAsync(url);
|
|
3282
|
+
this.register(id, texture);
|
|
3283
|
+
return texture;
|
|
3284
|
+
} catch (error) {
|
|
3285
|
+
this.eventEmitter.emit("invalidRequest", { message: `failed to load texture: ${id}. ${error}` });
|
|
3286
|
+
return null;
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
dispose() {
|
|
3290
|
+
this.updateServiceState("disposed");
|
|
3291
|
+
this.meshes.forEach((mesh) => disposeMesh(mesh));
|
|
3292
|
+
this.meshes.clear();
|
|
3293
|
+
this.textures.forEach((texture) => texture.dispose());
|
|
3294
|
+
this.textures.clear();
|
|
3295
|
+
}
|
|
3296
|
+
changeColor(color) {
|
|
3297
|
+
const actual = new THREE.Color(color);
|
|
3298
|
+
this.solidColorTexture = new THREE.DataTexture(new Uint8Array([actual.r, actual.g, actual.b, 255]), 1, 1, THREE.RGBAFormat);
|
|
3299
|
+
this.solidColorTexture.needsUpdate = true;
|
|
3300
|
+
}
|
|
3301
|
+
updateServiceState(serviceState) {
|
|
3302
|
+
this.serviceState = serviceState;
|
|
3303
|
+
this.eventEmitter.emit("serviceStateUpdated", { type: "asset", state: serviceState });
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3267
3306
|
class ParticlesEngine {
|
|
3268
3307
|
/**
|
|
3269
3308
|
* Creates a new ParticlesEngine instance.
|
|
@@ -3276,8 +3315,8 @@ class ParticlesEngine {
|
|
|
3276
3315
|
__publicField(this, "scene");
|
|
3277
3316
|
__publicField(this, "serviceStates");
|
|
3278
3317
|
// assets
|
|
3318
|
+
__publicField(this, "assetService");
|
|
3279
3319
|
__publicField(this, "dataTextureManager");
|
|
3280
|
-
__publicField(this, "matcapService");
|
|
3281
3320
|
__publicField(this, "instancedMeshManager");
|
|
3282
3321
|
__publicField(this, "transitionService");
|
|
3283
3322
|
__publicField(this, "engineState");
|
|
@@ -3288,9 +3327,9 @@ class ParticlesEngine {
|
|
|
3288
3327
|
this.scene = params.scene;
|
|
3289
3328
|
this.renderer = params.renderer;
|
|
3290
3329
|
this.engineState = this.initialEngineState(params.textureSize);
|
|
3330
|
+
this.assetService = new AssetService(this.eventEmitter);
|
|
3291
3331
|
this.transitionService = new TransitionService(this.eventEmitter);
|
|
3292
|
-
this.dataTextureManager = new DataTextureService(this.eventEmitter, params.textureSize
|
|
3293
|
-
this.matcapService = new MatcapService(this.eventEmitter, params.matcaps);
|
|
3332
|
+
this.dataTextureManager = new DataTextureService(this.eventEmitter, params.textureSize);
|
|
3294
3333
|
this.simulationRendererService = new SimulationRendererService(this.eventEmitter, params.textureSize, this.renderer);
|
|
3295
3334
|
this.instancedMeshManager = new InstancedMeshManager(params.textureSize);
|
|
3296
3335
|
this.instancedMeshManager.useMatcapMaterial();
|
|
@@ -3304,7 +3343,7 @@ class ParticlesEngine {
|
|
|
3304
3343
|
* @param elapsedTime The elapsed time since the last frame.
|
|
3305
3344
|
*/
|
|
3306
3345
|
render(elapsedTime) {
|
|
3307
|
-
this.intersectionService.calculate();
|
|
3346
|
+
this.intersectionService.calculate(this.instancedMeshManager.getMesh());
|
|
3308
3347
|
this.transitionService.compute(elapsedTime);
|
|
3309
3348
|
this.simulationRendererService.compute(elapsedTime);
|
|
3310
3349
|
this.instancedMeshManager.update(elapsedTime);
|
|
@@ -3313,24 +3352,31 @@ class ParticlesEngine {
|
|
|
3313
3352
|
}
|
|
3314
3353
|
setOriginDataTexture(meshID, override = false) {
|
|
3315
3354
|
if (override) this.eventEmitter.emit("transitionCancelled", { type: "data-texture" });
|
|
3316
|
-
this.
|
|
3355
|
+
const mesh = this.assetService.getMesh(meshID);
|
|
3356
|
+
if (!mesh) {
|
|
3357
|
+
this.eventEmitter.emit("invalidRequest", { message: `Mesh with id "${meshID}" does not exist` });
|
|
3358
|
+
return;
|
|
3359
|
+
}
|
|
3360
|
+
this.dataTextureManager.getDataTexture(mesh).then((dataTexture) => {
|
|
3317
3361
|
this.engineState.originMeshID = meshID;
|
|
3318
|
-
this.simulationRendererService.setOriginDataTexture({
|
|
3319
|
-
|
|
3320
|
-
textureSize: this.engineState.textureSize
|
|
3321
|
-
});
|
|
3322
|
-
this.intersectionService.setOriginGeometry(this.dataTextureManager.getMesh(meshID));
|
|
3362
|
+
this.simulationRendererService.setOriginDataTexture({ dataTexture, textureSize: this.engineState.textureSize });
|
|
3363
|
+
this.intersectionService.setOriginGeometry(mesh);
|
|
3323
3364
|
});
|
|
3324
3365
|
}
|
|
3325
3366
|
setDestinationDataTexture(meshID, override = false) {
|
|
3326
3367
|
if (override) this.eventEmitter.emit("transitionCancelled", { type: "data-texture" });
|
|
3327
|
-
this.
|
|
3368
|
+
const mesh = this.assetService.getMesh(meshID);
|
|
3369
|
+
if (!mesh) {
|
|
3370
|
+
this.eventEmitter.emit("invalidRequest", { message: `Mesh with id "${meshID}" does not exist` });
|
|
3371
|
+
return;
|
|
3372
|
+
}
|
|
3373
|
+
this.dataTextureManager.getDataTexture(mesh).then((texture) => {
|
|
3328
3374
|
this.engineState.destinationMeshID = meshID;
|
|
3329
3375
|
this.simulationRendererService.setDestinationDataTexture({
|
|
3330
3376
|
dataTexture: texture,
|
|
3331
3377
|
textureSize: this.engineState.textureSize
|
|
3332
3378
|
});
|
|
3333
|
-
this.intersectionService.setDestinationGeometry(
|
|
3379
|
+
this.intersectionService.setDestinationGeometry(mesh);
|
|
3334
3380
|
});
|
|
3335
3381
|
}
|
|
3336
3382
|
setDataTextureTransitionProgress(progress, override = false) {
|
|
@@ -3342,12 +3388,12 @@ class ParticlesEngine {
|
|
|
3342
3388
|
setOriginMatcap(matcapID, override = false) {
|
|
3343
3389
|
if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
|
|
3344
3390
|
this.engineState.originMatcapID = matcapID;
|
|
3345
|
-
this.instancedMeshManager.setOriginMatcap(this.
|
|
3391
|
+
this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(matcapID));
|
|
3346
3392
|
}
|
|
3347
3393
|
setDestinationMatcap(matcapID, override = false) {
|
|
3348
3394
|
if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
|
|
3349
3395
|
this.engineState.destinationMatcapID = matcapID;
|
|
3350
|
-
this.instancedMeshManager.setDestinationMatcap(this.
|
|
3396
|
+
this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(matcapID));
|
|
3351
3397
|
}
|
|
3352
3398
|
setMatcapProgress(progress, override = false) {
|
|
3353
3399
|
if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
|
|
@@ -3359,8 +3405,18 @@ class ParticlesEngine {
|
|
|
3359
3405
|
this.dataTextureManager.setTextureSize(size);
|
|
3360
3406
|
this.simulationRendererService.setTextureSize(size);
|
|
3361
3407
|
this.instancedMeshManager.resize(size);
|
|
3362
|
-
this.
|
|
3363
|
-
|
|
3408
|
+
const originMesh = this.assetService.getMesh(this.engineState.originMeshID);
|
|
3409
|
+
if (!originMesh) {
|
|
3410
|
+
this.eventEmitter.emit("invalidRequest", { message: `Mesh with id "${this.engineState.originMeshID}" does not exist` });
|
|
3411
|
+
return;
|
|
3412
|
+
}
|
|
3413
|
+
const destinationMesh = this.assetService.getMesh(this.engineState.destinationMeshID);
|
|
3414
|
+
if (!destinationMesh) {
|
|
3415
|
+
this.eventEmitter.emit("invalidRequest", { message: `Mesh with id "${this.engineState.destinationMeshID}" does not exist` });
|
|
3416
|
+
return;
|
|
3417
|
+
}
|
|
3418
|
+
this.dataTextureManager.getDataTexture(originMesh).then((texture) => this.simulationRendererService.setOriginDataTexture({ dataTexture: texture, textureSize: size }));
|
|
3419
|
+
this.dataTextureManager.getDataTexture(destinationMesh).then(
|
|
3364
3420
|
(texture) => this.simulationRendererService.setDestinationDataTexture({
|
|
3365
3421
|
dataTexture: texture,
|
|
3366
3422
|
textureSize: size
|
|
@@ -3369,11 +3425,23 @@ class ParticlesEngine {
|
|
|
3369
3425
|
this.simulationRendererService.setDataTextureTransitionProgress(this.engineState.dataTextureTransitionProgress);
|
|
3370
3426
|
this.simulationRendererService.setVelocityTractionForce(this.engineState.velocityTractionForce);
|
|
3371
3427
|
this.simulationRendererService.setPositionalTractionForce(this.engineState.positionalTractionForce);
|
|
3372
|
-
this.instancedMeshManager.setOriginMatcap(this.
|
|
3373
|
-
this.instancedMeshManager.setDestinationMatcap(this.
|
|
3428
|
+
this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(this.engineState.originMatcapID));
|
|
3429
|
+
this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(this.engineState.destinationMatcapID));
|
|
3374
3430
|
this.instancedMeshManager.setProgress(this.engineState.matcapTransitionProgress);
|
|
3375
3431
|
this.instancedMeshManager.setGeometrySize(this.engineState.instanceGeometryScale);
|
|
3376
3432
|
}
|
|
3433
|
+
registerMesh(id, mesh) {
|
|
3434
|
+
this.assetService.register(id, mesh);
|
|
3435
|
+
}
|
|
3436
|
+
registerMatcap(id, matcap) {
|
|
3437
|
+
this.assetService.register(id, matcap);
|
|
3438
|
+
}
|
|
3439
|
+
async fetchAndRegisterMesh(id, url) {
|
|
3440
|
+
return await this.assetService.loadMeshAsync(id, url);
|
|
3441
|
+
}
|
|
3442
|
+
async fetchAndRegisterMatcap(id, url) {
|
|
3443
|
+
return await this.assetService.loadTextureAsync(id, url);
|
|
3444
|
+
}
|
|
3377
3445
|
setPointerPosition(position) {
|
|
3378
3446
|
this.engineState.pointerPosition = position;
|
|
3379
3447
|
this.intersectionService.setMousePosition(position);
|
|
@@ -3421,19 +3489,27 @@ class ParticlesEngine {
|
|
|
3421
3489
|
);
|
|
3422
3490
|
}
|
|
3423
3491
|
handleServiceStateUpdated({ type, state }) {
|
|
3424
|
-
console.log("service state updated", type, state);
|
|
3425
3492
|
this.serviceStates[type] = state;
|
|
3426
3493
|
}
|
|
3494
|
+
getObject() {
|
|
3495
|
+
return this.instancedMeshManager.getMesh();
|
|
3496
|
+
}
|
|
3497
|
+
getMeshIDs() {
|
|
3498
|
+
return this.assetService.getMeshIDs();
|
|
3499
|
+
}
|
|
3500
|
+
getMatcapIDs() {
|
|
3501
|
+
return this.assetService.getTextureIDs();
|
|
3502
|
+
}
|
|
3427
3503
|
/**
|
|
3428
3504
|
* Disposes the resources used by the engine.
|
|
3429
3505
|
*/
|
|
3430
3506
|
dispose() {
|
|
3431
3507
|
this.scene.remove(this.instancedMeshManager.getMesh());
|
|
3432
|
-
this.matcapService.dispose();
|
|
3433
3508
|
this.simulationRendererService.dispose();
|
|
3434
3509
|
this.instancedMeshManager.dispose();
|
|
3435
3510
|
this.intersectionService.dispose();
|
|
3436
|
-
this.
|
|
3511
|
+
this.assetService.dispose();
|
|
3512
|
+
this.dataTextureManager.dispose();
|
|
3437
3513
|
}
|
|
3438
3514
|
initialEngineState(textureSize) {
|
|
3439
3515
|
return {
|
|
@@ -3456,7 +3532,8 @@ class ParticlesEngine {
|
|
|
3456
3532
|
"data-texture": "created",
|
|
3457
3533
|
"instanced-mesh": "created",
|
|
3458
3534
|
matcap: "created",
|
|
3459
|
-
simulation: "created"
|
|
3535
|
+
simulation: "created",
|
|
3536
|
+
asset: "created"
|
|
3460
3537
|
};
|
|
3461
3538
|
}
|
|
3462
3539
|
handleTransitionProgress({ type, progress }) {
|