@polarfront-lab/ionian 1.7.0 → 3.0.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 +17 -32
- package/dist/ionian.iife.js +1 -1
- package/dist/ionian.iife.js.map +1 -1
- package/dist/ionian.js +187 -230
- package/dist/ionian.js.map +1 -1
- package/package.json +15 -15
package/dist/ionian.js
CHANGED
|
@@ -92,10 +92,12 @@ class AssetService {
|
|
|
92
92
|
__publicField(this, "gltfLoader", new GLTFLoader());
|
|
93
93
|
__publicField(this, "textureLoader", new THREE.TextureLoader());
|
|
94
94
|
__publicField(this, "dracoLoader", new DRACOLoader());
|
|
95
|
-
__publicField(this, "
|
|
95
|
+
__publicField(this, "solidColorTextures", /* @__PURE__ */ new Map());
|
|
96
|
+
__publicField(this, "fallbackTexture", new THREE.DataTexture(new Uint8Array([127, 127, 127, 255]), 1, 1, THREE.RGBAFormat));
|
|
96
97
|
this.eventEmitter = eventEmitter;
|
|
97
98
|
this.dracoLoader.setDecoderPath("https://www.gstatic.com/draco/versioned/decoders/1.5.7/");
|
|
98
99
|
this.gltfLoader.setDRACOLoader(this.dracoLoader);
|
|
100
|
+
this.fallbackTexture.name = "default-fallback-texture";
|
|
99
101
|
this.updateServiceState("ready");
|
|
100
102
|
}
|
|
101
103
|
/**
|
|
@@ -116,19 +118,32 @@ class AssetService {
|
|
|
116
118
|
}
|
|
117
119
|
this.eventEmitter.emit("assetRegistered", { id });
|
|
118
120
|
}
|
|
119
|
-
setSolidColor(color) {
|
|
120
|
-
this.changeColor(color);
|
|
121
|
-
}
|
|
122
|
-
getSolidColorTexture() {
|
|
123
|
-
return this.solidColorTexture;
|
|
124
|
-
}
|
|
125
121
|
getMesh(id) {
|
|
126
122
|
return this.meshes.get(id) ?? null;
|
|
127
123
|
}
|
|
128
|
-
|
|
124
|
+
getMatcapTexture(id) {
|
|
129
125
|
const texture = this.textures.get(id);
|
|
130
126
|
if (!texture) this.eventEmitter.emit("invalidRequest", { message: `texture with id "${id}" not found. using solid color texture instead...` });
|
|
131
|
-
return texture ?? this.
|
|
127
|
+
return texture ?? this.fallbackTexture;
|
|
128
|
+
}
|
|
129
|
+
getSolidColorTexture(colorValue) {
|
|
130
|
+
const colorKey = new THREE.Color(colorValue).getHexString();
|
|
131
|
+
let texture = this.solidColorTextures.get(colorKey);
|
|
132
|
+
if (texture) {
|
|
133
|
+
return texture;
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
const texture2 = this.createSolidColorDataTexture(new THREE.Color(colorValue));
|
|
137
|
+
this.solidColorTextures.set(colorKey, texture2);
|
|
138
|
+
return texture2;
|
|
139
|
+
} catch (error) {
|
|
140
|
+
console.error(`Invalid color value provided to getSolidColorTexture: ${colorValue}`, error);
|
|
141
|
+
this.eventEmitter.emit("invalidRequest", { message: `Invalid color value: ${colorValue}. Using fallback texture.` });
|
|
142
|
+
return this.fallbackTexture;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
getFallbackTexture() {
|
|
146
|
+
return this.fallbackTexture;
|
|
132
147
|
}
|
|
133
148
|
getMeshIDs() {
|
|
134
149
|
return Array.from(this.meshes.keys());
|
|
@@ -142,8 +157,29 @@ class AssetService {
|
|
|
142
157
|
getTextures() {
|
|
143
158
|
return Array.from(this.textures.values());
|
|
144
159
|
}
|
|
145
|
-
|
|
146
|
-
|
|
160
|
+
createSolidColorDataTexture(color, size = 16) {
|
|
161
|
+
const col = new THREE.Color(color);
|
|
162
|
+
const width = size;
|
|
163
|
+
const height = size;
|
|
164
|
+
const data = new Uint8Array(width * height * 4);
|
|
165
|
+
const r = Math.floor(col.r * 255);
|
|
166
|
+
const g = Math.floor(col.g * 255);
|
|
167
|
+
const b = Math.floor(col.b * 255);
|
|
168
|
+
for (let i = 0; i < width * height; i++) {
|
|
169
|
+
const index = i * 4;
|
|
170
|
+
data[index] = r;
|
|
171
|
+
data[index + 1] = g;
|
|
172
|
+
data[index + 2] = b;
|
|
173
|
+
data[index + 3] = 255;
|
|
174
|
+
}
|
|
175
|
+
const texture = new THREE.DataTexture(data, width, height, THREE.RGBAFormat);
|
|
176
|
+
texture.type = THREE.UnsignedByteType;
|
|
177
|
+
texture.wrapS = THREE.RepeatWrapping;
|
|
178
|
+
texture.wrapT = THREE.RepeatWrapping;
|
|
179
|
+
texture.minFilter = THREE.NearestFilter;
|
|
180
|
+
texture.magFilter = THREE.NearestFilter;
|
|
181
|
+
texture.needsUpdate = true;
|
|
182
|
+
return texture;
|
|
147
183
|
}
|
|
148
184
|
/**
|
|
149
185
|
* Loads a mesh asynchronously.
|
|
@@ -191,11 +227,9 @@ class AssetService {
|
|
|
191
227
|
this.meshes.clear();
|
|
192
228
|
this.textures.forEach((texture) => texture.dispose());
|
|
193
229
|
this.textures.clear();
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
this.solidColorTexture = new THREE.DataTexture(new Uint8Array([actual.r, actual.g, actual.b, 255]), 1, 1, THREE.RGBAFormat);
|
|
198
|
-
this.solidColorTexture.needsUpdate = true;
|
|
230
|
+
this.solidColorTextures.forEach((texture) => texture.dispose());
|
|
231
|
+
this.solidColorTextures.clear();
|
|
232
|
+
this.fallbackTexture.dispose();
|
|
199
233
|
}
|
|
200
234
|
updateServiceState(serviceState) {
|
|
201
235
|
this.serviceState = serviceState;
|
|
@@ -206,6 +240,11 @@ const _face = new Triangle();
|
|
|
206
240
|
const _color = new Vector3();
|
|
207
241
|
const _uva = new Vector2(), _uvb = new Vector2(), _uvc = new Vector2();
|
|
208
242
|
class MeshSurfaceSampler {
|
|
243
|
+
/**
|
|
244
|
+
* Constructs a mesh surface sampler.
|
|
245
|
+
*
|
|
246
|
+
* @param {Mesh} mesh - Surface mesh from which to sample.
|
|
247
|
+
*/
|
|
209
248
|
constructor(mesh) {
|
|
210
249
|
this.geometry = mesh.geometry;
|
|
211
250
|
this.randomFunction = Math.random;
|
|
@@ -217,10 +256,27 @@ class MeshSurfaceSampler {
|
|
|
217
256
|
this.weightAttribute = null;
|
|
218
257
|
this.distribution = null;
|
|
219
258
|
}
|
|
259
|
+
/**
|
|
260
|
+
* Specifies a vertex attribute to be used as a weight when sampling from the surface.
|
|
261
|
+
* Faces with higher weights are more likely to be sampled, and those with weights of
|
|
262
|
+
* zero will not be sampled at all. For vector attributes, only .x is used in sampling.
|
|
263
|
+
*
|
|
264
|
+
* If no weight attribute is selected, sampling is randomly distributed by area.
|
|
265
|
+
*
|
|
266
|
+
* @param {string} name - The attribute name.
|
|
267
|
+
* @return {MeshSurfaceSampler} A reference to this sampler.
|
|
268
|
+
*/
|
|
220
269
|
setWeightAttribute(name) {
|
|
221
270
|
this.weightAttribute = name ? this.geometry.getAttribute(name) : null;
|
|
222
271
|
return this;
|
|
223
272
|
}
|
|
273
|
+
/**
|
|
274
|
+
* Processes the input geometry and prepares to return samples. Any configuration of the
|
|
275
|
+
* geometry or sampler must occur before this method is called. Time complexity is O(n)
|
|
276
|
+
* for a surface with n faces.
|
|
277
|
+
*
|
|
278
|
+
* @return {MeshSurfaceSampler} A reference to this sampler.
|
|
279
|
+
*/
|
|
224
280
|
build() {
|
|
225
281
|
const indexAttribute = this.indexAttribute;
|
|
226
282
|
const positionAttribute = this.positionAttribute;
|
|
@@ -255,19 +311,37 @@ class MeshSurfaceSampler {
|
|
|
255
311
|
this.distribution = distribution;
|
|
256
312
|
return this;
|
|
257
313
|
}
|
|
314
|
+
/**
|
|
315
|
+
* Allows to set a custom random number generator. Default is `Math.random()`.
|
|
316
|
+
*
|
|
317
|
+
* @param {Function} randomFunction - A random number generator.
|
|
318
|
+
* @return {MeshSurfaceSampler} A reference to this sampler.
|
|
319
|
+
*/
|
|
258
320
|
setRandomGenerator(randomFunction) {
|
|
259
321
|
this.randomFunction = randomFunction;
|
|
260
322
|
return this;
|
|
261
323
|
}
|
|
324
|
+
/**
|
|
325
|
+
* Selects a random point on the surface of the input geometry, returning the
|
|
326
|
+
* position and optionally the normal vector, color and UV Coordinate at that point.
|
|
327
|
+
* Time complexity is O(log n) for a surface with n faces.
|
|
328
|
+
*
|
|
329
|
+
* @param {Vector3} targetPosition - The target object holding the sampled position.
|
|
330
|
+
* @param {Vector3} targetNormal - The target object holding the sampled normal.
|
|
331
|
+
* @param {Color} targetColor - The target object holding the sampled color.
|
|
332
|
+
* @param {Vector2} targetUV - The target object holding the sampled uv coordinates.
|
|
333
|
+
* @return {MeshSurfaceSampler} A reference to this sampler.
|
|
334
|
+
*/
|
|
262
335
|
sample(targetPosition, targetNormal, targetColor, targetUV) {
|
|
263
|
-
const faceIndex = this.
|
|
264
|
-
return this.
|
|
336
|
+
const faceIndex = this._sampleFaceIndex();
|
|
337
|
+
return this._sampleFace(faceIndex, targetPosition, targetNormal, targetColor, targetUV);
|
|
265
338
|
}
|
|
266
|
-
|
|
339
|
+
// private
|
|
340
|
+
_sampleFaceIndex() {
|
|
267
341
|
const cumulativeTotal = this.distribution[this.distribution.length - 1];
|
|
268
|
-
return this.
|
|
342
|
+
return this._binarySearch(this.randomFunction() * cumulativeTotal);
|
|
269
343
|
}
|
|
270
|
-
|
|
344
|
+
_binarySearch(x) {
|
|
271
345
|
const dist = this.distribution;
|
|
272
346
|
let start = 0;
|
|
273
347
|
let end = dist.length - 1;
|
|
@@ -285,7 +359,7 @@ class MeshSurfaceSampler {
|
|
|
285
359
|
}
|
|
286
360
|
return index;
|
|
287
361
|
}
|
|
288
|
-
|
|
362
|
+
_sampleFace(faceIndex, targetPosition, targetNormal, targetColor, targetUV) {
|
|
289
363
|
let u = this.randomFunction();
|
|
290
364
|
let v = this.randomFunction();
|
|
291
365
|
if (u + v > 1) {
|
|
@@ -471,7 +545,6 @@ function sampleMesh(meshData, size) {
|
|
|
471
545
|
}
|
|
472
546
|
const instanceFragmentShader = `
|
|
473
547
|
varying vec2 vUv;
|
|
474
|
-
uniform sampler2D uTexture;
|
|
475
548
|
|
|
476
549
|
uniform sampler2D uOriginTexture;
|
|
477
550
|
uniform sampler2D uDestinationTexture;
|
|
@@ -485,11 +558,11 @@ void main() {
|
|
|
485
558
|
vec3 y = cross( viewDir, x );
|
|
486
559
|
vec2 uv = vec2( dot( x, vNormal ), dot( y, vNormal ) ) * 0.495 + 0.5; // 0.495 to remove artifacts caused by undersized matcap disks
|
|
487
560
|
|
|
488
|
-
vec4
|
|
489
|
-
vec4
|
|
561
|
+
vec4 textureA = texture2D( uOriginTexture, uv );
|
|
562
|
+
vec4 textureB = texture2D( uDestinationTexture, uv );
|
|
490
563
|
|
|
491
|
-
vec4
|
|
492
|
-
gl_FragColor =
|
|
564
|
+
vec4 finalColor = mix(textureA, textureB, uProgress);
|
|
565
|
+
gl_FragColor = finalColor;
|
|
493
566
|
}
|
|
494
567
|
`;
|
|
495
568
|
const instanceVertexShader = `
|
|
@@ -545,11 +618,9 @@ class InstancedMeshManager {
|
|
|
545
618
|
constructor(initialSize) {
|
|
546
619
|
__publicField(this, "size");
|
|
547
620
|
__publicField(this, "mesh");
|
|
548
|
-
__publicField(this, "
|
|
621
|
+
__publicField(this, "shaderMaterial");
|
|
549
622
|
__publicField(this, "fallbackGeometry");
|
|
550
623
|
__publicField(this, "uniforms");
|
|
551
|
-
__publicField(this, "originColor");
|
|
552
|
-
__publicField(this, "destinationColor");
|
|
553
624
|
__publicField(this, "geometries");
|
|
554
625
|
__publicField(this, "uvRefsCache");
|
|
555
626
|
__publicField(this, "previousScale");
|
|
@@ -557,8 +628,6 @@ class InstancedMeshManager {
|
|
|
557
628
|
this.geometries = /* @__PURE__ */ new Map();
|
|
558
629
|
this.uvRefsCache = /* @__PURE__ */ new Map();
|
|
559
630
|
this.previousScale = { x: 1, y: 1, z: 1 };
|
|
560
|
-
this.originColor = "grey";
|
|
561
|
-
this.destinationColor = "grey";
|
|
562
631
|
this.uniforms = {
|
|
563
632
|
uTime: { value: 0 },
|
|
564
633
|
uProgress: { value: 0 },
|
|
@@ -567,15 +636,14 @@ class InstancedMeshManager {
|
|
|
567
636
|
uOriginTexture: { value: null },
|
|
568
637
|
uDestinationTexture: { value: null }
|
|
569
638
|
};
|
|
570
|
-
this.
|
|
639
|
+
this.shaderMaterial = new THREE.ShaderMaterial({
|
|
571
640
|
uniforms: this.uniforms,
|
|
572
641
|
vertexShader: instanceVertexShader,
|
|
573
642
|
fragmentShader: instanceFragmentShader
|
|
574
643
|
});
|
|
575
|
-
this.setOriginColor(this.originColor);
|
|
576
|
-
this.setDestinationColor(this.destinationColor);
|
|
577
644
|
this.fallbackGeometry = new THREE.BoxGeometry(1e-3, 1e-3, 1e-3);
|
|
578
|
-
this.mesh = this.createInstancedMesh(initialSize, this.fallbackGeometry, this.
|
|
645
|
+
this.mesh = this.createInstancedMesh(initialSize, this.fallbackGeometry, this.shaderMaterial);
|
|
646
|
+
this.mesh.material = this.shaderMaterial;
|
|
579
647
|
}
|
|
580
648
|
/**
|
|
581
649
|
* Gets the instanced mesh.
|
|
@@ -594,22 +662,10 @@ class InstancedMeshManager {
|
|
|
594
662
|
material.uniforms.uTime.value = elapsedTime;
|
|
595
663
|
}
|
|
596
664
|
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
setOriginMatcap(matcap) {
|
|
602
|
-
this.disposeSolidColorOriginTexture();
|
|
603
|
-
this.matcapMaterial.uniforms.uOriginTexture.value = matcap;
|
|
604
|
-
}
|
|
605
|
-
setDestinationMatcap(matcap) {
|
|
606
|
-
this.disposeSolidColorDestinationTexture();
|
|
607
|
-
this.matcapMaterial.uniforms.uDestinationTexture.value = matcap;
|
|
608
|
-
}
|
|
609
|
-
setProgress(float) {
|
|
610
|
-
float = Math.max(0, float);
|
|
611
|
-
float = Math.min(1, float);
|
|
612
|
-
this.matcapMaterial.uniforms.uProgress.value = float;
|
|
665
|
+
updateTextureInterpolation(textureA, textureB, progress) {
|
|
666
|
+
this.uniforms.uOriginTexture.value = textureA;
|
|
667
|
+
this.uniforms.uDestinationTexture.value = textureB;
|
|
668
|
+
this.uniforms.uProgress.value = progress;
|
|
613
669
|
}
|
|
614
670
|
setGeometrySize(size) {
|
|
615
671
|
this.mesh.geometry.scale(1 / this.previousScale.x, 1 / this.previousScale.y, 1 / this.previousScale.z);
|
|
@@ -620,7 +676,7 @@ class InstancedMeshManager {
|
|
|
620
676
|
* Use the matcap material for the instanced mesh.
|
|
621
677
|
*/
|
|
622
678
|
useMatcapMaterial() {
|
|
623
|
-
this.mesh.material = this.
|
|
679
|
+
this.mesh.material = this.shaderMaterial;
|
|
624
680
|
}
|
|
625
681
|
/**
|
|
626
682
|
* Use the specified geometry for the instanced mesh.
|
|
@@ -637,14 +693,14 @@ class InstancedMeshManager {
|
|
|
637
693
|
* @param texture The velocity texture to update with.
|
|
638
694
|
*/
|
|
639
695
|
updateVelocityTexture(texture) {
|
|
640
|
-
this.
|
|
696
|
+
this.shaderMaterial.uniforms.uVelocity.value = texture;
|
|
641
697
|
}
|
|
642
698
|
/**
|
|
643
699
|
* Updates the position texture.
|
|
644
700
|
* @param texture The position texture to update with.
|
|
645
701
|
*/
|
|
646
702
|
updatePositionTexture(texture) {
|
|
647
|
-
this.
|
|
703
|
+
this.shaderMaterial.uniforms.uTexture.value = texture;
|
|
648
704
|
}
|
|
649
705
|
/**
|
|
650
706
|
* Resizes or replaces the instanced mesh.
|
|
@@ -664,9 +720,7 @@ class InstancedMeshManager {
|
|
|
664
720
|
dispose() {
|
|
665
721
|
this.mesh.dispose();
|
|
666
722
|
this.geometries.forEach((geometry) => geometry.dispose());
|
|
667
|
-
this.
|
|
668
|
-
this.disposeSolidColorDestinationTexture();
|
|
669
|
-
this.matcapMaterial.dispose();
|
|
723
|
+
this.shaderMaterial.dispose();
|
|
670
724
|
this.uvRefsCache.clear();
|
|
671
725
|
this.geometries.clear();
|
|
672
726
|
}
|
|
@@ -690,16 +744,6 @@ class InstancedMeshManager {
|
|
|
690
744
|
}
|
|
691
745
|
previous == null ? void 0 : previous.dispose();
|
|
692
746
|
}
|
|
693
|
-
setOriginColor(color) {
|
|
694
|
-
this.disposeSolidColorOriginTexture();
|
|
695
|
-
this.originColor = color;
|
|
696
|
-
this.uniforms.uOriginTexture.value = this.createSolidColorDataTexture(color);
|
|
697
|
-
}
|
|
698
|
-
setDestinationColor(color) {
|
|
699
|
-
this.disposeSolidColorDestinationTexture();
|
|
700
|
-
this.destinationColor = color;
|
|
701
|
-
this.uniforms.uDestinationTexture.value = this.createSolidColorDataTexture(color);
|
|
702
|
-
}
|
|
703
747
|
/**
|
|
704
748
|
* Gets the UV references for the specified size.
|
|
705
749
|
* @param size The size for which to generate UV references.
|
|
@@ -735,46 +779,6 @@ class InstancedMeshManager {
|
|
|
735
779
|
const count = size * size;
|
|
736
780
|
return new THREE.InstancedMesh(geometry, material, count);
|
|
737
781
|
}
|
|
738
|
-
createSolidColorDataTexture(color, size = 16) {
|
|
739
|
-
const col = new THREE.Color(color);
|
|
740
|
-
const width = size;
|
|
741
|
-
const height = size;
|
|
742
|
-
const data = new Uint8Array(width * height * 4);
|
|
743
|
-
const r = Math.floor(col.r * 255);
|
|
744
|
-
const g = Math.floor(col.g * 255);
|
|
745
|
-
const b = Math.floor(col.b * 255);
|
|
746
|
-
for (let i = 0; i < width * height; i++) {
|
|
747
|
-
const index = i * 4;
|
|
748
|
-
data[index] = r;
|
|
749
|
-
data[index + 1] = g;
|
|
750
|
-
data[index + 2] = b;
|
|
751
|
-
data[index + 3] = 255;
|
|
752
|
-
}
|
|
753
|
-
const texture = new THREE.DataTexture(data, width, height, THREE.RGBAFormat);
|
|
754
|
-
texture.type = THREE.UnsignedByteType;
|
|
755
|
-
texture.wrapS = THREE.RepeatWrapping;
|
|
756
|
-
texture.wrapT = THREE.RepeatWrapping;
|
|
757
|
-
texture.minFilter = THREE.NearestFilter;
|
|
758
|
-
texture.magFilter = THREE.NearestFilter;
|
|
759
|
-
texture.needsUpdate = true;
|
|
760
|
-
return texture;
|
|
761
|
-
}
|
|
762
|
-
disposeSolidColorOriginTexture() {
|
|
763
|
-
if (this.originColor) {
|
|
764
|
-
this.originColor = null;
|
|
765
|
-
if (this.uniforms.uOriginTexture.value) {
|
|
766
|
-
this.uniforms.uOriginTexture.value.dispose();
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
disposeSolidColorDestinationTexture() {
|
|
771
|
-
if (this.destinationColor) {
|
|
772
|
-
this.destinationColor = null;
|
|
773
|
-
if (this.uniforms.uDestinationTexture.value) {
|
|
774
|
-
this.uniforms.uDestinationTexture.value.dispose();
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
782
|
}
|
|
779
783
|
class IntersectionService {
|
|
780
784
|
/**
|
|
@@ -1012,15 +1016,34 @@ class FullscreenTriangleGeometry extends BufferGeometry {
|
|
|
1012
1016
|
}
|
|
1013
1017
|
const _geometry = new FullscreenTriangleGeometry();
|
|
1014
1018
|
class FullScreenQuad {
|
|
1019
|
+
/**
|
|
1020
|
+
* Constructs a new full screen quad.
|
|
1021
|
+
*
|
|
1022
|
+
* @param {?Material} material - The material to render te full screen quad with.
|
|
1023
|
+
*/
|
|
1015
1024
|
constructor(material) {
|
|
1016
1025
|
this._mesh = new Mesh(_geometry, material);
|
|
1017
1026
|
}
|
|
1027
|
+
/**
|
|
1028
|
+
* Frees the GPU-related resources allocated by this instance. Call this
|
|
1029
|
+
* method whenever the instance is no longer used in your app.
|
|
1030
|
+
*/
|
|
1018
1031
|
dispose() {
|
|
1019
1032
|
this._mesh.geometry.dispose();
|
|
1020
1033
|
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Renders the full screen quad.
|
|
1036
|
+
*
|
|
1037
|
+
* @param {WebGLRenderer} renderer - The renderer.
|
|
1038
|
+
*/
|
|
1021
1039
|
render(renderer) {
|
|
1022
1040
|
renderer.render(this._mesh, _camera);
|
|
1023
1041
|
}
|
|
1042
|
+
/**
|
|
1043
|
+
* The quad's material.
|
|
1044
|
+
*
|
|
1045
|
+
* @type {?Material}
|
|
1046
|
+
*/
|
|
1024
1047
|
get material() {
|
|
1025
1048
|
return this._mesh.material;
|
|
1026
1049
|
}
|
|
@@ -1030,9 +1053,11 @@ class FullScreenQuad {
|
|
|
1030
1053
|
}
|
|
1031
1054
|
class GPUComputationRenderer {
|
|
1032
1055
|
/**
|
|
1033
|
-
*
|
|
1034
|
-
|
|
1035
|
-
|
|
1056
|
+
* Constructs a new GPU computation renderer.
|
|
1057
|
+
*
|
|
1058
|
+
* @param {number} sizeX - Computation problem size is always 2d: sizeX * sizeY elements.
|
|
1059
|
+
* @param {number} sizeY - Computation problem size is always 2d: sizeX * sizeY elements.
|
|
1060
|
+
* @param {WebGLRenderer} renderer - The renderer.
|
|
1036
1061
|
*/
|
|
1037
1062
|
constructor(sizeX, sizeY, renderer) {
|
|
1038
1063
|
this.variables = [];
|
|
@@ -1742,10 +1767,10 @@ class ParticlesEngine {
|
|
|
1742
1767
|
this.dataTextureManager = new DataTextureService(this.eventEmitter, textureSize);
|
|
1743
1768
|
this.simulationRendererService = new SimulationRendererService(this.eventEmitter, textureSize, this.renderer);
|
|
1744
1769
|
this.instancedMeshManager = new InstancedMeshManager(textureSize);
|
|
1745
|
-
this.instancedMeshManager.useMatcapMaterial();
|
|
1746
1770
|
this.scene.add(this.instancedMeshManager.getMesh());
|
|
1747
1771
|
this.intersectionService = new IntersectionService(this.eventEmitter, camera);
|
|
1748
1772
|
if (!useIntersection) this.intersectionService.setActive(false);
|
|
1773
|
+
this.setOverallProgress(0, false);
|
|
1749
1774
|
this.eventEmitter.on("interactionPositionUpdated", this.handleInteractionPositionUpdated.bind(this));
|
|
1750
1775
|
}
|
|
1751
1776
|
/**
|
|
@@ -1761,45 +1786,10 @@ class ParticlesEngine {
|
|
|
1761
1786
|
this.instancedMeshManager.updateVelocityTexture(this.simulationRendererService.getVelocityTexture());
|
|
1762
1787
|
this.instancedMeshManager.updatePositionTexture(this.simulationRendererService.getPositionTexture());
|
|
1763
1788
|
}
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
this.
|
|
1767
|
-
this.
|
|
1768
|
-
}
|
|
1769
|
-
setDestinationMatcap(matcapID, override = false) {
|
|
1770
|
-
if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
|
|
1771
|
-
this.engineState.destinationMatcapID = matcapID;
|
|
1772
|
-
this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(matcapID));
|
|
1773
|
-
}
|
|
1774
|
-
setOriginColor(color, override = false) {
|
|
1775
|
-
if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
|
|
1776
|
-
this.instancedMeshManager.setOriginColor(color);
|
|
1777
|
-
}
|
|
1778
|
-
setDestinationColor(color, override = false) {
|
|
1779
|
-
if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
|
|
1780
|
-
this.instancedMeshManager.setDestinationColor(color);
|
|
1781
|
-
}
|
|
1782
|
-
setOriginTexture(id, override = false) {
|
|
1783
|
-
if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
|
|
1784
|
-
if (typeof id === "string" && this.assetService.hasMatcap(id)) {
|
|
1785
|
-
this.setOriginMatcap(id);
|
|
1786
|
-
} else {
|
|
1787
|
-
this.setOriginColor(id);
|
|
1788
|
-
}
|
|
1789
|
-
}
|
|
1790
|
-
setDestinationTexture(id, override = false) {
|
|
1791
|
-
if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
|
|
1792
|
-
if (typeof id === "string" && this.assetService.hasMatcap(id)) {
|
|
1793
|
-
this.setDestinationMatcap(id);
|
|
1794
|
-
} else {
|
|
1795
|
-
this.setDestinationColor(id);
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
setMatcapProgress(progress, override = false) {
|
|
1799
|
-
const clampedProgress = clamp(progress, 0, 1);
|
|
1800
|
-
if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
|
|
1801
|
-
this.engineState.matcapTransitionProgress = clampedProgress;
|
|
1802
|
-
this.instancedMeshManager.setProgress(clampedProgress);
|
|
1789
|
+
setTextureSequence(sequence) {
|
|
1790
|
+
this.engineState.textureSequence = sequence;
|
|
1791
|
+
this.eventEmitter.emit("textureSequenceUpdated", { sequence });
|
|
1792
|
+
this.setOverallProgress(0, false);
|
|
1803
1793
|
}
|
|
1804
1794
|
// --- Update setTextureSize ---
|
|
1805
1795
|
async setTextureSize(size) {
|
|
@@ -1821,10 +1811,8 @@ class ParticlesEngine {
|
|
|
1821
1811
|
this.simulationRendererService.setMaxRepelDistance(this.engineState.maxRepelDistance);
|
|
1822
1812
|
this.simulationRendererService.setOverallProgress(this.engineState.overallProgress);
|
|
1823
1813
|
this.intersectionService.setOverallProgress(this.engineState.overallProgress);
|
|
1824
|
-
this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(this.engineState.originMatcapID));
|
|
1825
|
-
this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(this.engineState.destinationMatcapID));
|
|
1826
|
-
this.instancedMeshManager.setProgress(this.engineState.matcapTransitionProgress);
|
|
1827
1814
|
this.instancedMeshManager.setGeometrySize(this.engineState.instanceGeometryScale);
|
|
1815
|
+
this.setOverallProgress(this.engineState.overallProgress, false);
|
|
1828
1816
|
}
|
|
1829
1817
|
registerMesh(id, mesh) {
|
|
1830
1818
|
this.assetService.register(id, mesh);
|
|
@@ -1907,6 +1895,7 @@ class ParticlesEngine {
|
|
|
1907
1895
|
this.simulationRendererService.setOverallProgress(this.engineState.overallProgress);
|
|
1908
1896
|
this.intersectionService.setMeshSequence(meshes);
|
|
1909
1897
|
this.intersectionService.setOverallProgress(this.engineState.overallProgress);
|
|
1898
|
+
this.setOverallProgress(0, false);
|
|
1910
1899
|
} catch (error) {
|
|
1911
1900
|
console.error("Failed during mesh sequence setup:", error);
|
|
1912
1901
|
this.meshSequenceAtlasTexture = null;
|
|
@@ -1925,79 +1914,8 @@ class ParticlesEngine {
|
|
|
1925
1914
|
this.engineState.overallProgress = clampedProgress;
|
|
1926
1915
|
this.simulationRendererService.setOverallProgress(clampedProgress);
|
|
1927
1916
|
this.intersectionService.setOverallProgress(clampedProgress);
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
scheduleMatcapTransition(originMatcapID, destinationMatcapID, easing = linear, duration = 1e3, override = false, options = {}) {
|
|
1931
|
-
if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
|
|
1932
|
-
const handleProgressUpdate = (transitionProgress) => {
|
|
1933
|
-
var _a;
|
|
1934
|
-
this.setMatcapProgress(transitionProgress, false);
|
|
1935
|
-
(_a = options.onTransitionProgress) == null ? void 0 : _a.call(options, transitionProgress);
|
|
1936
|
-
};
|
|
1937
|
-
this.transitionService.enqueue(
|
|
1938
|
-
"matcap",
|
|
1939
|
-
{ easing, duration },
|
|
1940
|
-
{
|
|
1941
|
-
...options,
|
|
1942
|
-
onTransitionProgress: handleProgressUpdate,
|
|
1943
|
-
onTransitionBegin: () => {
|
|
1944
|
-
var _a;
|
|
1945
|
-
this.setOriginMatcap(originMatcapID, false);
|
|
1946
|
-
this.setDestinationMatcap(destinationMatcapID, false);
|
|
1947
|
-
this.setMatcapProgress(0, false);
|
|
1948
|
-
(_a = options.onTransitionBegin) == null ? void 0 : _a.call(options);
|
|
1949
|
-
},
|
|
1950
|
-
onTransitionFinished: () => {
|
|
1951
|
-
var _a;
|
|
1952
|
-
this.setMatcapProgress(1, false);
|
|
1953
|
-
(_a = options.onTransitionFinished) == null ? void 0 : _a.call(options);
|
|
1954
|
-
},
|
|
1955
|
-
onTransitionCancelled: options.onTransitionCancelled
|
|
1956
|
-
}
|
|
1957
|
-
);
|
|
1958
|
-
}
|
|
1959
|
-
scheduleTextureTransition(origin, destination, options = {}) {
|
|
1960
|
-
const easing = (options == null ? void 0 : options.easing) ?? linear;
|
|
1961
|
-
const duration = (options == null ? void 0 : options.duration) ?? 1e3;
|
|
1962
|
-
const userCallbacks = {
|
|
1963
|
-
// Extract user callbacks
|
|
1964
|
-
onTransitionBegin: options == null ? void 0 : options.onTransitionBegin,
|
|
1965
|
-
onTransitionProgress: options == null ? void 0 : options.onTransitionProgress,
|
|
1966
|
-
onTransitionFinished: options == null ? void 0 : options.onTransitionFinished,
|
|
1967
|
-
onTransitionCancelled: options == null ? void 0 : options.onTransitionCancelled
|
|
1968
|
-
};
|
|
1969
|
-
if (options == null ? void 0 : options.override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
|
|
1970
|
-
const handleProgressUpdate = (transitionProgress) => {
|
|
1971
|
-
var _a;
|
|
1972
|
-
this.setMatcapProgress(transitionProgress, false);
|
|
1973
|
-
(_a = userCallbacks.onTransitionProgress) == null ? void 0 : _a.call(userCallbacks, transitionProgress);
|
|
1974
|
-
};
|
|
1975
|
-
this.transitionService.enqueue(
|
|
1976
|
-
"matcap",
|
|
1977
|
-
// Still uses matcap type internally
|
|
1978
|
-
{ easing, duration },
|
|
1979
|
-
{
|
|
1980
|
-
...userCallbacks,
|
|
1981
|
-
// Pass user callbacks
|
|
1982
|
-
onTransitionProgress: handleProgressUpdate,
|
|
1983
|
-
onTransitionBegin: () => {
|
|
1984
|
-
var _a;
|
|
1985
|
-
this.setOriginTexture(origin);
|
|
1986
|
-
this.setDestinationTexture(destination);
|
|
1987
|
-
this.setMatcapProgress(0);
|
|
1988
|
-
(_a = userCallbacks.onTransitionBegin) == null ? void 0 : _a.call(userCallbacks);
|
|
1989
|
-
},
|
|
1990
|
-
onTransitionFinished: () => {
|
|
1991
|
-
var _a;
|
|
1992
|
-
this.setMatcapProgress(1);
|
|
1993
|
-
(_a = userCallbacks.onTransitionFinished) == null ? void 0 : _a.call(userCallbacks);
|
|
1994
|
-
},
|
|
1995
|
-
onTransitionCancelled: () => {
|
|
1996
|
-
var _a;
|
|
1997
|
-
(_a = userCallbacks.onTransitionCancelled) == null ? void 0 : _a.call(userCallbacks);
|
|
1998
|
-
}
|
|
1999
|
-
}
|
|
2000
|
-
);
|
|
1917
|
+
const { textureA, textureB, localProgress } = this.calculateTextureInterpolation(progress);
|
|
1918
|
+
this.instancedMeshManager.updateTextureInterpolation(textureA, textureB, localProgress);
|
|
2001
1919
|
}
|
|
2002
1920
|
/**
|
|
2003
1921
|
* Schedules a smooth transition for the overall mesh sequence progress.
|
|
@@ -2080,9 +1998,7 @@ class ParticlesEngine {
|
|
|
2080
1998
|
// ADDED
|
|
2081
1999
|
overallProgress: 0,
|
|
2082
2000
|
// ADDED
|
|
2083
|
-
|
|
2084
|
-
destinationMatcapID: "",
|
|
2085
|
-
matcapTransitionProgress: 0,
|
|
2001
|
+
textureSequence: [],
|
|
2086
2002
|
velocityTractionForce: 0.1,
|
|
2087
2003
|
positionalTractionForce: 0.1,
|
|
2088
2004
|
maxRepelDistance: 0.3,
|
|
@@ -2103,6 +2019,47 @@ class ParticlesEngine {
|
|
|
2103
2019
|
handleInteractionPositionUpdated({ position }) {
|
|
2104
2020
|
this.simulationRendererService.setInteractionPosition(position);
|
|
2105
2021
|
}
|
|
2022
|
+
calculateTextureInterpolation(progress) {
|
|
2023
|
+
const sequence = this.engineState.textureSequence;
|
|
2024
|
+
const numItems = sequence.length;
|
|
2025
|
+
if (numItems === 0) {
|
|
2026
|
+
const defaultTex = this.assetService.getFallbackTexture();
|
|
2027
|
+
return { textureA: defaultTex, textureB: defaultTex, localProgress: 0 };
|
|
2028
|
+
}
|
|
2029
|
+
if (numItems === 1) {
|
|
2030
|
+
const tex = this.getTextureForSequenceItem(sequence[0]);
|
|
2031
|
+
return { textureA: tex, textureB: tex, localProgress: 0 };
|
|
2032
|
+
}
|
|
2033
|
+
const totalSegments = numItems - 1;
|
|
2034
|
+
const progressPerSegment = 1 / totalSegments;
|
|
2035
|
+
const scaledProgress = progress * totalSegments;
|
|
2036
|
+
let indexA = Math.floor(scaledProgress);
|
|
2037
|
+
let indexB = indexA + 1;
|
|
2038
|
+
indexA = Math.max(0, Math.min(indexA, totalSegments));
|
|
2039
|
+
indexB = Math.max(0, Math.min(indexB, totalSegments));
|
|
2040
|
+
let localProgress = 0;
|
|
2041
|
+
if (progressPerSegment > 0) {
|
|
2042
|
+
localProgress = (progress - indexA * progressPerSegment) / progressPerSegment;
|
|
2043
|
+
}
|
|
2044
|
+
if (progress >= 1) {
|
|
2045
|
+
indexA = totalSegments;
|
|
2046
|
+
indexB = totalSegments;
|
|
2047
|
+
localProgress = 1;
|
|
2048
|
+
}
|
|
2049
|
+
localProgress = Math.max(0, Math.min(localProgress, 1));
|
|
2050
|
+
const itemA = sequence[indexA];
|
|
2051
|
+
const itemB = sequence[indexB];
|
|
2052
|
+
const textureA = this.getTextureForSequenceItem(itemA);
|
|
2053
|
+
const textureB = this.getTextureForSequenceItem(itemB);
|
|
2054
|
+
return { textureA, textureB, localProgress };
|
|
2055
|
+
}
|
|
2056
|
+
getTextureForSequenceItem(item) {
|
|
2057
|
+
if (item.type === "matcap") {
|
|
2058
|
+
return this.assetService.getMatcapTexture(item.id);
|
|
2059
|
+
} else {
|
|
2060
|
+
return this.assetService.getSolidColorTexture(item.value);
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2106
2063
|
}
|
|
2107
2064
|
export {
|
|
2108
2065
|
ParticlesEngine
|