@adatechnology/game-vfx-three 0.2.0 → 0.3.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 +3 -1
- package/dist/index.global.js +199 -124
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +102 -71
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -531,6 +531,81 @@ function createMarkLayer(THREE, options) {
|
|
|
531
531
|
};
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
+
// src/mesh-layer.ts
|
|
535
|
+
var SPHERE_DEFAULT_WIDTH = 8;
|
|
536
|
+
var SPHERE_DEFAULT_HEIGHT = 6;
|
|
537
|
+
function geometryOf(THREE, particle) {
|
|
538
|
+
switch (particle.shape) {
|
|
539
|
+
case "cone":
|
|
540
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, false);
|
|
541
|
+
case "cone_open":
|
|
542
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, true);
|
|
543
|
+
case "sphere":
|
|
544
|
+
return new THREE.SphereGeometry(particle.radius, particle.segments || SPHERE_DEFAULT_WIDTH, particle.segments2 || SPHERE_DEFAULT_HEIGHT);
|
|
545
|
+
case "icosahedron":
|
|
546
|
+
return new THREE.IcosahedronGeometry(particle.radius, particle.segments);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
function materialOf(THREE, particle) {
|
|
550
|
+
if (particle.lit) return new THREE.MeshStandardMaterial({ color: particle.color, roughness: 1, metalness: 0, transparent: true, opacity: particle.opacity, depthWrite: false });
|
|
551
|
+
return new THREE.MeshBasicMaterial({ color: particle.color, transparent: true, opacity: particle.opacity, depthWrite: false, ...particle.additive ? { blending: THREE.AdditiveBlending } : {} });
|
|
552
|
+
}
|
|
553
|
+
function createMeshLayerProbes(THREE) {
|
|
554
|
+
const geometry = new THREE.BoxGeometry(1e-3, 1e-3, 1e-3);
|
|
555
|
+
return [{ lit: true, additive: false }, { lit: false, additive: false }, { lit: false, additive: true }].map(
|
|
556
|
+
(kind) => new THREE.Mesh(geometry, materialOf(THREE, { ...kind, color: 8421504, opacity: 0.5 }))
|
|
557
|
+
);
|
|
558
|
+
}
|
|
559
|
+
function createMeshLayer(THREE, pool) {
|
|
560
|
+
const group = new THREE.Group();
|
|
561
|
+
group.name = "workshop-meshes";
|
|
562
|
+
const drawn = /* @__PURE__ */ new Map();
|
|
563
|
+
const frame = new THREE.Quaternion();
|
|
564
|
+
const euler = new THREE.Euler();
|
|
565
|
+
const turn = new THREE.Quaternion();
|
|
566
|
+
const offset = new THREE.Vector3();
|
|
567
|
+
function release(mesh) {
|
|
568
|
+
mesh.removeFromParent();
|
|
569
|
+
mesh.geometry.dispose();
|
|
570
|
+
mesh.material.dispose();
|
|
571
|
+
}
|
|
572
|
+
return {
|
|
573
|
+
group,
|
|
574
|
+
sync() {
|
|
575
|
+
const live = /* @__PURE__ */ new Set();
|
|
576
|
+
for (const particle of pool.particles) {
|
|
577
|
+
live.add(particle.id);
|
|
578
|
+
let mesh = drawn.get(particle.id);
|
|
579
|
+
if (!mesh) {
|
|
580
|
+
mesh = new THREE.Mesh(geometryOf(THREE, particle), materialOf(THREE, particle));
|
|
581
|
+
mesh.frustumCulled = false;
|
|
582
|
+
mesh.renderOrder = particle.additive ? 5 : 3;
|
|
583
|
+
drawn.set(particle.id, mesh);
|
|
584
|
+
group.add(mesh);
|
|
585
|
+
}
|
|
586
|
+
frame.set(particle.frame[0], particle.frame[1], particle.frame[2], particle.frame[3]);
|
|
587
|
+
offset.set(particle.at[0], particle.at[1], particle.at[2]).multiplyScalar(particle.scale).applyQuaternion(frame);
|
|
588
|
+
mesh.position.set(particle.x + offset.x, particle.y + offset.y, particle.z + offset.z);
|
|
589
|
+
turn.setFromEuler(euler.set(particle.rx, particle.ry, particle.rz));
|
|
590
|
+
mesh.quaternion.copy(frame).multiply(turn);
|
|
591
|
+
mesh.scale.setScalar(particle.scale);
|
|
592
|
+
mesh.material.opacity = particle.opacity;
|
|
593
|
+
}
|
|
594
|
+
for (const [id, mesh] of drawn) {
|
|
595
|
+
if (live.has(id)) continue;
|
|
596
|
+
release(mesh);
|
|
597
|
+
drawn.delete(id);
|
|
598
|
+
}
|
|
599
|
+
return pool.count;
|
|
600
|
+
},
|
|
601
|
+
dispose() {
|
|
602
|
+
for (const mesh of drawn.values()) release(mesh);
|
|
603
|
+
drawn.clear();
|
|
604
|
+
group.removeFromParent();
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
534
609
|
// src/screen-overlay.ts
|
|
535
610
|
var clamp = (value, min, max) => value < min ? min : value > max ? max : value;
|
|
536
611
|
function layer(container, name, blend) {
|
|
@@ -710,75 +785,6 @@ function createSpriteLayer(THREE, system, pointScale) {
|
|
|
710
785
|
};
|
|
711
786
|
}
|
|
712
787
|
|
|
713
|
-
// src/mesh-layer.ts
|
|
714
|
-
var SPHERE_DEFAULT_WIDTH = 8;
|
|
715
|
-
var SPHERE_DEFAULT_HEIGHT = 6;
|
|
716
|
-
function geometryOf(THREE, particle) {
|
|
717
|
-
switch (particle.shape) {
|
|
718
|
-
case "cone":
|
|
719
|
-
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, false);
|
|
720
|
-
case "cone_open":
|
|
721
|
-
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, true);
|
|
722
|
-
case "sphere":
|
|
723
|
-
return new THREE.SphereGeometry(particle.radius, particle.segments || SPHERE_DEFAULT_WIDTH, particle.segments2 || SPHERE_DEFAULT_HEIGHT);
|
|
724
|
-
case "icosahedron":
|
|
725
|
-
return new THREE.IcosahedronGeometry(particle.radius, particle.segments);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
function materialOf(THREE, particle) {
|
|
729
|
-
if (particle.lit) return new THREE.MeshStandardMaterial({ color: particle.color, roughness: 1, metalness: 0, transparent: true, opacity: particle.opacity, depthWrite: false });
|
|
730
|
-
return new THREE.MeshBasicMaterial({ color: particle.color, transparent: true, opacity: particle.opacity, depthWrite: false, ...particle.additive ? { blending: THREE.AdditiveBlending } : {} });
|
|
731
|
-
}
|
|
732
|
-
function createMeshLayer(THREE, pool) {
|
|
733
|
-
const group = new THREE.Group();
|
|
734
|
-
group.name = "workshop-meshes";
|
|
735
|
-
const drawn = /* @__PURE__ */ new Map();
|
|
736
|
-
const frame = new THREE.Quaternion();
|
|
737
|
-
const euler = new THREE.Euler();
|
|
738
|
-
const turn = new THREE.Quaternion();
|
|
739
|
-
const offset = new THREE.Vector3();
|
|
740
|
-
function release(mesh) {
|
|
741
|
-
mesh.removeFromParent();
|
|
742
|
-
mesh.geometry.dispose();
|
|
743
|
-
mesh.material.dispose();
|
|
744
|
-
}
|
|
745
|
-
return {
|
|
746
|
-
group,
|
|
747
|
-
sync() {
|
|
748
|
-
const live = /* @__PURE__ */ new Set();
|
|
749
|
-
for (const particle of pool.particles) {
|
|
750
|
-
live.add(particle.id);
|
|
751
|
-
let mesh = drawn.get(particle.id);
|
|
752
|
-
if (!mesh) {
|
|
753
|
-
mesh = new THREE.Mesh(geometryOf(THREE, particle), materialOf(THREE, particle));
|
|
754
|
-
mesh.frustumCulled = false;
|
|
755
|
-
mesh.renderOrder = particle.additive ? 5 : 3;
|
|
756
|
-
drawn.set(particle.id, mesh);
|
|
757
|
-
group.add(mesh);
|
|
758
|
-
}
|
|
759
|
-
frame.set(particle.frame[0], particle.frame[1], particle.frame[2], particle.frame[3]);
|
|
760
|
-
offset.set(particle.at[0], particle.at[1], particle.at[2]).multiplyScalar(particle.scale).applyQuaternion(frame);
|
|
761
|
-
mesh.position.set(particle.x + offset.x, particle.y + offset.y, particle.z + offset.z);
|
|
762
|
-
turn.setFromEuler(euler.set(particle.rx, particle.ry, particle.rz));
|
|
763
|
-
mesh.quaternion.copy(frame).multiply(turn);
|
|
764
|
-
mesh.scale.setScalar(particle.scale);
|
|
765
|
-
mesh.material.opacity = particle.opacity;
|
|
766
|
-
}
|
|
767
|
-
for (const [id, mesh] of drawn) {
|
|
768
|
-
if (live.has(id)) continue;
|
|
769
|
-
release(mesh);
|
|
770
|
-
drawn.delete(id);
|
|
771
|
-
}
|
|
772
|
-
return pool.count;
|
|
773
|
-
},
|
|
774
|
-
dispose() {
|
|
775
|
-
for (const mesh of drawn.values()) release(mesh);
|
|
776
|
-
drawn.clear();
|
|
777
|
-
group.removeFromParent();
|
|
778
|
-
}
|
|
779
|
-
};
|
|
780
|
-
}
|
|
781
|
-
|
|
782
788
|
// src/shaders/workshop-sprite.ts
|
|
783
789
|
var WORKSHOP_SPRITE_VERTEX = `attribute float size;attribute float alpha;attribute vec3 pcol;varying vec3 vC;varying float vA;uniform float uScale;
|
|
784
790
|
void main(){vC=pcol;vA=alpha;vec4 mv=modelViewMatrix*vec4(position,1.);gl_PointSize=clamp(size*uScale/-mv.z,1.,512.);gl_Position=projectionMatrix*mv;}`;
|
|
@@ -1149,6 +1155,13 @@ function createVfxRenderer(THREE, options) {
|
|
|
1149
1155
|
const requested = options.vfx;
|
|
1150
1156
|
const world = isWorld(requested) ? requested : createVfx({ profile: options.quality ?? "medium", reducedMotion, ...requested });
|
|
1151
1157
|
const pools = world.pools();
|
|
1158
|
+
let anchors;
|
|
1159
|
+
const releaseAnchors = () => {
|
|
1160
|
+
if (!anchors) return;
|
|
1161
|
+
anchors.meshes[0]?.geometry.dispose();
|
|
1162
|
+
for (const mesh of anchors.meshes) mesh.material.dispose();
|
|
1163
|
+
anchors = void 0;
|
|
1164
|
+
};
|
|
1152
1165
|
const root = new THREE.Group();
|
|
1153
1166
|
options.scene.add(root);
|
|
1154
1167
|
const direction = new THREE.Vector3(...options.lightDirection ?? LAB_LIGHT_DIRECTION).normalize();
|
|
@@ -1265,6 +1278,16 @@ function createVfxRenderer(THREE, options) {
|
|
|
1265
1278
|
syncAll();
|
|
1266
1279
|
overlay?.update(screenNow());
|
|
1267
1280
|
},
|
|
1281
|
+
warmUpProbes() {
|
|
1282
|
+
releaseAnchors();
|
|
1283
|
+
const meshes = createMeshLayerProbes(THREE);
|
|
1284
|
+
for (const mesh of meshes) mesh.frustumCulled = false;
|
|
1285
|
+
const group = new THREE.Group();
|
|
1286
|
+
group.add(...meshes);
|
|
1287
|
+
anchors = { meshes, group };
|
|
1288
|
+
return { group, dispose: () => {
|
|
1289
|
+
} };
|
|
1290
|
+
},
|
|
1268
1291
|
applyCamera() {
|
|
1269
1292
|
const shake = screenNow().shake;
|
|
1270
1293
|
if (reducedMotion || !(shake > SHAKE_FLOOR)) return () => {
|
|
@@ -1283,6 +1306,7 @@ function createVfxRenderer(THREE, options) {
|
|
|
1283
1306
|
},
|
|
1284
1307
|
screen: screenNow,
|
|
1285
1308
|
dispose() {
|
|
1309
|
+
releaseAnchors();
|
|
1286
1310
|
stopMarks();
|
|
1287
1311
|
overlay?.dispose();
|
|
1288
1312
|
workshopLayers?.dispose();
|
|
@@ -1556,6 +1580,11 @@ function createVfxTestModule(options = {}) {
|
|
|
1556
1580
|
controls,
|
|
1557
1581
|
layers,
|
|
1558
1582
|
metrics,
|
|
1583
|
+
// opening the effects area puts the camera at the bench view (the initial distance does not move it: that would take the player's view on load)
|
|
1584
|
+
area: () => ({
|
|
1585
|
+
placements: [],
|
|
1586
|
+
view: { eye: eyeFor(DEFAULT_DISTANCE), target: [0, 1.2, 0] }
|
|
1587
|
+
}),
|
|
1559
1588
|
attach(host) {
|
|
1560
1589
|
const bench = host.bench;
|
|
1561
1590
|
let own;
|
|
@@ -1575,6 +1604,7 @@ function createVfxTestModule(options = {}) {
|
|
|
1575
1604
|
let phase = 0;
|
|
1576
1605
|
let handle = null;
|
|
1577
1606
|
let sinceRepeat = 0;
|
|
1607
|
+
let live = false;
|
|
1578
1608
|
read = () => {
|
|
1579
1609
|
const def = explosions[effect];
|
|
1580
1610
|
const recipe = recipes[effect];
|
|
@@ -1613,7 +1643,7 @@ function createVfxTestModule(options = {}) {
|
|
|
1613
1643
|
}
|
|
1614
1644
|
);
|
|
1615
1645
|
bench?.sheet?.(sheetFor(id));
|
|
1616
|
-
replay();
|
|
1646
|
+
if (live) replay();
|
|
1617
1647
|
}
|
|
1618
1648
|
function look() {
|
|
1619
1649
|
const eye = eyeFor(distance);
|
|
@@ -1630,7 +1660,7 @@ function createVfxTestModule(options = {}) {
|
|
|
1630
1660
|
choose(change.value);
|
|
1631
1661
|
else if (change.id === "variant" && typeof change.value === "string") {
|
|
1632
1662
|
variant = change.value;
|
|
1633
|
-
if (recipes[effect]?.params) replay();
|
|
1663
|
+
if (live && recipes[effect]?.params) replay();
|
|
1634
1664
|
} else if (change.id === "auto_repeat") auto = change.value === true;
|
|
1635
1665
|
else if (change.id === "distance" && typeof change.value === "number") {
|
|
1636
1666
|
distance = change.value;
|
|
@@ -1640,6 +1670,7 @@ function createVfxTestModule(options = {}) {
|
|
|
1640
1670
|
};
|
|
1641
1671
|
const offChange = bench?.onChange(apply);
|
|
1642
1672
|
const offFrame = host.onFrame((dt) => {
|
|
1673
|
+
live = true;
|
|
1643
1674
|
phase += dt;
|
|
1644
1675
|
sinceRepeat += dt;
|
|
1645
1676
|
own?.update(dt);
|