@adatechnology/game-fluids-three 0.3.1 → 0.4.1
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 -0
- package/dist/index.global.js +213 -96
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +49 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as THREE_NS from 'three';
|
|
2
|
+
import { WarmUpProbes } from '@adatechnology/game-contracts';
|
|
2
3
|
import { VfxWorld } from '@adatechnology/game-vfx';
|
|
3
4
|
import { ThreeLib as ThreeLib$1 } from '@adatechnology/game-vfx-three';
|
|
4
5
|
import { Vec3, FluidWorld, Film, StainTint, FilmLayout, FilmProfile, FilmRandom, LiquidId, SurfaceSpec, FilmLook, FilmRegion } from '@adatechnology/game-fluids';
|
|
@@ -56,6 +57,8 @@ interface FluidRenderer {
|
|
|
56
57
|
/** Draw the liquid of a world container inside `object` (a volume clipped by the liquid surface, plus steam). */
|
|
57
58
|
bindContainer(containerId: string, object: THREE_NS.Object3D, options?: BindOptions): void;
|
|
58
59
|
unbindContainer(containerId: string): void;
|
|
60
|
+
/** Meshes that use the materials of the liquid bodies, streams and stains, to render once so that the first leak does not build their shader programs in the middle of a frame. */
|
|
61
|
+
warmUpProbes(): WarmUpProbes;
|
|
59
62
|
/** Advance the visuals (call it after `fluids.update(dt)`). */
|
|
60
63
|
update(dt: number): void;
|
|
61
64
|
/** Remove every stain, stream and particle (the bindings stay). */
|
package/dist/index.global.js
CHANGED
|
@@ -3088,6 +3088,17 @@ var GameFluidsThree = (() => {
|
|
|
3088
3088
|
])
|
|
3089
3089
|
]
|
|
3090
3090
|
};
|
|
3091
|
+
var FUEL_LEAK_ONLY = {
|
|
3092
|
+
id: "fuel_leak_only",
|
|
3093
|
+
pageId: "vazamento",
|
|
3094
|
+
team: "vehicles",
|
|
3095
|
+
budget: { particles: 200, lights: 0 },
|
|
3096
|
+
loop: 11,
|
|
3097
|
+
view: FUEL_LEAK.view,
|
|
3098
|
+
setup: FUEL_LEAK.setup,
|
|
3099
|
+
timeline: [decal(POOL[0], 0, POOL[2], 2.2, 2040368, { grow: 3, life: 60, ar: 0.6, fluid: "oil" })],
|
|
3100
|
+
tick: [emit("drip", "normal", 12, { p: TANK, box: [0.05, 0, 0.05], sp: 0, life: 1, size: 0.03, c0: 5921402, a: 0.9, g: 9.8, fi: 0, gnd: 1 })]
|
|
3101
|
+
};
|
|
3091
3102
|
var CAR_EXPLOSION = {
|
|
3092
3103
|
id: "car_explosion",
|
|
3093
3104
|
pageId: "explosao",
|
|
@@ -3441,6 +3452,8 @@ var GameFluidsThree = (() => {
|
|
|
3441
3452
|
];
|
|
3442
3453
|
var PI = Math.PI;
|
|
3443
3454
|
var SMOKE = { color: 9079430, width: 10, height: 8, gravity: -0.08, drag: 2.2, growth: 2.1 };
|
|
3455
|
+
var DEFAULT_SMOKE = { puffs: 2, radius: 0.01, opacity: 0.14, life: 0.7, drift: 0.2, rise: 0.06, growth: 2.1, flash: 1 };
|
|
3456
|
+
var DEFAULT_SPREAD = { drift: 0.1, rise: 0.04, side: 0.06 };
|
|
3444
3457
|
var FLASH_SECONDS = 0.055;
|
|
3445
3458
|
var FLASH_RAMP = [0.6, 0.9];
|
|
3446
3459
|
var FLASH_OPACITY = 0.95;
|
|
@@ -3448,8 +3461,10 @@ var GameFluidsThree = (() => {
|
|
|
3448
3461
|
var FLAME_ADDITIVE = 3;
|
|
3449
3462
|
var ORIGIN2 = [0, 0, 0];
|
|
3450
3463
|
var SIZE = variable("size");
|
|
3464
|
+
var FLASH_SCALE = variable("flash");
|
|
3465
|
+
var fallback = (name, defaultValue) => ite(ne(variable(name), void 0), variable(name), defaultValue);
|
|
3451
3466
|
var wide = (width) => mul(sub(rand(), 0.5), width);
|
|
3452
|
-
var puff2 = (point, velocity, world, radius, life, opacity) => mesh({
|
|
3467
|
+
var puff2 = (point, velocity, world, radius, life, opacity, growth = SMOKE.growth) => mesh({
|
|
3453
3468
|
shape: "sphere",
|
|
3454
3469
|
p: point,
|
|
3455
3470
|
v: velocity,
|
|
@@ -3464,7 +3479,7 @@ var GameFluidsThree = (() => {
|
|
|
3464
3479
|
lit: true,
|
|
3465
3480
|
g: SMOKE.gravity,
|
|
3466
3481
|
drag: SMOKE.drag,
|
|
3467
|
-
grow:
|
|
3482
|
+
grow: growth
|
|
3468
3483
|
});
|
|
3469
3484
|
var flameBit = (point, velocity, world, radius, life) => [
|
|
3470
3485
|
set("bitPoint", point),
|
|
@@ -3497,37 +3512,55 @@ var GameFluidsThree = (() => {
|
|
|
3497
3512
|
id: "viewmodel_muzzle_flash",
|
|
3498
3513
|
pageId: "event:viewmodel_muzzle_flash",
|
|
3499
3514
|
team: "weapons",
|
|
3500
|
-
budget: { particles:
|
|
3515
|
+
budget: { particles: 14, lights: 1 },
|
|
3501
3516
|
loop: 0.1,
|
|
3517
|
+
setup: [
|
|
3518
|
+
set("size", fallback("size", 1)),
|
|
3519
|
+
set("puffs", fallback("puffs", DEFAULT_SMOKE.puffs)),
|
|
3520
|
+
set("radius", fallback("radius", DEFAULT_SMOKE.radius)),
|
|
3521
|
+
set("opacity", fallback("opacity", DEFAULT_SMOKE.opacity)),
|
|
3522
|
+
set("life", fallback("life", DEFAULT_SMOKE.life)),
|
|
3523
|
+
set("drift", fallback("drift", DEFAULT_SMOKE.drift)),
|
|
3524
|
+
set("rise", fallback("rise", DEFAULT_SMOKE.rise)),
|
|
3525
|
+
set("growth", fallback("growth", DEFAULT_SMOKE.growth)),
|
|
3526
|
+
set("flash", fallback("flash", DEFAULT_SMOKE.flash)),
|
|
3527
|
+
set("driftSpread", fallback("driftSpread", DEFAULT_SPREAD.drift)),
|
|
3528
|
+
set("riseSpread", fallback("riseSpread", DEFAULT_SPREAD.rise)),
|
|
3529
|
+
set("sideSpread", fallback("sideSpread", DEFAULT_SPREAD.side)),
|
|
3530
|
+
set("lifeSpread", ite(ne(variable("lifeSpread"), void 0), variable("lifeSpread"), mul(variable("life"), 0.3)))
|
|
3531
|
+
],
|
|
3502
3532
|
timeline: [
|
|
3503
3533
|
set("angles", []),
|
|
3504
3534
|
repeat(4, append("angles", add(div(mul(INDEX, PI), 2), mul(rand(), 0.6)))),
|
|
3505
3535
|
set("roll", mul(rand(), PI)),
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3536
|
+
when(gt(FLASH_SCALE, 0), [
|
|
3537
|
+
flash(ORIGIN2, 16756832, mul(4, SIZE, FLASH_SCALE), FLASH_SECONDS, mul(2, SIZE, FLASH_SCALE), true, true),
|
|
3538
|
+
flashPiece("cone_open", mul(0.013, SIZE, FLASH_SCALE), mul(0.085, SIZE, FLASH_SCALE), 10, [mul(0.042, SIZE, FLASH_SCALE), 0, 0], [0, 0, -PI / 2], 16757575),
|
|
3539
|
+
repeat(
|
|
3540
|
+
4,
|
|
3541
|
+
set("angle", pick(variable("angles"), INDEX)),
|
|
3542
|
+
flashPiece(
|
|
3543
|
+
"cone",
|
|
3544
|
+
mul(5e-3, SIZE, FLASH_SCALE),
|
|
3545
|
+
mul(0.04, SIZE, FLASH_SCALE),
|
|
3546
|
+
6,
|
|
3547
|
+
[mul(0.012, SIZE, FLASH_SCALE), mul(cos(variable("angle")), 0.016, SIZE, FLASH_SCALE), mul(sin(variable("angle")), 0.016, SIZE, FLASH_SCALE)],
|
|
3548
|
+
[variable("angle"), 0, -PI / 2],
|
|
3549
|
+
16757575
|
|
3550
|
+
)
|
|
3551
|
+
),
|
|
3552
|
+
flashPiece("sphere", mul(0.016, SIZE, FLASH_SCALE), void 0, 12, [mul(8e-3, SIZE, FLASH_SCALE), 0, 0], [0, 0, 0], 16773568)
|
|
3553
|
+
]),
|
|
3522
3554
|
repeat(
|
|
3523
|
-
|
|
3555
|
+
variable("puffs"),
|
|
3524
3556
|
puff2(
|
|
3525
3557
|
ORIGIN2,
|
|
3526
|
-
[add(
|
|
3558
|
+
[add(variable("drift"), mul(rand(), variable("driftSpread"))), add(variable("rise"), mul(rand(), variable("riseSpread"))), mul(sub(rand(), 0.5), variable("sideSpread"))],
|
|
3527
3559
|
[0, 0, 0],
|
|
3528
|
-
mul(
|
|
3529
|
-
add(
|
|
3530
|
-
|
|
3560
|
+
mul(variable("radius"), SIZE),
|
|
3561
|
+
add(variable("life"), mul(rand(), variable("lifeSpread"))),
|
|
3562
|
+
variable("opacity"),
|
|
3563
|
+
variable("growth")
|
|
3531
3564
|
)
|
|
3532
3565
|
)
|
|
3533
3566
|
]
|
|
@@ -3581,8 +3614,10 @@ var GameFluidsThree = (() => {
|
|
|
3581
3614
|
aliasOf(ENGINE_SMOKE, "vehicle_fire", { params: { id: "condition", options: ["100", "60", "30", "10"], default: 3 }, loop: 12 }),
|
|
3582
3615
|
/** The exhaust of a car under way: `engine_smoke` in the best condition, for half a second so a moving car asks again. */
|
|
3583
3616
|
aliasOf(ENGINE_SMOKE, "vehicle_exhaust", { params: { id: "condition", options: ["100", "60", "30", "10"], default: 0 }, loop: 0.5 }),
|
|
3584
|
-
/** A hole in the tank: the page's
|
|
3585
|
-
aliasOf(
|
|
3617
|
+
/** A hole in the tank: the page's petrol leak without the fire and the blast (the pool and the drips). A normal bullet does only this. */
|
|
3618
|
+
aliasOf(FUEL_LEAK_ONLY, "vehicle_leak", {}),
|
|
3619
|
+
/** The leak caught fire (an incendiary or tracer round, a spark, a fire near): the page's whole sequence, the fire running along the pool to the tank and the blast. */
|
|
3620
|
+
aliasOf(FUEL_LEAK, "vehicle_leak_ignited", {})
|
|
3586
3621
|
];
|
|
3587
3622
|
var ALL_EFFECTS = [BLOOD_HIT, HEADSHOT, DISMEMBER, BLOATER_CLOUD, SCREAMER_SHRIEK, CORPSE_DECAY, REANIMATION, EYES_IN_FOG, MUZZLE_FLASH, IMPACT_BY_MATERIAL, PENETRATION, CASINGS_AND_MAGAZINE, MOLOTOV, GRENADE, EXPLOSIVE_BARREL, SHOPFRONT_GLASS, DOOR_STAGES, BUILDING_COLLAPSE, BLOCK_WALL, METAL_DOOR_EFFECT, IRON_RAILING, WOODEN_FENCE, HIT_POINT_BREAKAGE, PRESSURE_CYLINDERS, BUILDING_FIRE, RAIN_AND_PUDDLES, FOG_AND_ASH, SCRAPING_SPARKS, ENGINE_SMOKE, FUEL_LEAK, CAR_EXPLOSION, WINDSHIELD, HEADLIGHTS_IN_RAIN, DAMAGE_AND_BITE, INFECTION_PHASES, PANIC, BLOATER_BLINDNESS, CAMPFIRE, COUGH_AND_BREATH];
|
|
3588
3623
|
var WORKSHOP_EFFECTS = Object.fromEntries(ALL_EFFECTS.map((effect) => [effect.id, effect]));
|
|
@@ -7225,6 +7260,15 @@ var GameFluidsThree = (() => {
|
|
|
7225
7260
|
};
|
|
7226
7261
|
}
|
|
7227
7262
|
|
|
7263
|
+
// ../game-contracts/dist/index.js
|
|
7264
|
+
var KIT_ORIGIN_KEY = "kitOrigin";
|
|
7265
|
+
function markKitOrigin(object, origin) {
|
|
7266
|
+
const node = object;
|
|
7267
|
+
node.userData = node.userData ?? {};
|
|
7268
|
+
node.userData[KIT_ORIGIN_KEY] = { ...origin };
|
|
7269
|
+
return object;
|
|
7270
|
+
}
|
|
7271
|
+
|
|
7228
7272
|
// ../game-vfx-three/dist/index.js
|
|
7229
7273
|
var GLOW_VERTEX = `attribute vec4 aP;attribute vec4 aC;varying vec2 vU;varying vec4 vC;
|
|
7230
7274
|
void main(){vec3 R=vec3(viewMatrix[0][0],viewMatrix[1][0],viewMatrix[2][0]);vec3 Up=vec3(viewMatrix[0][1],viewMatrix[1][1],viewMatrix[2][1]);
|
|
@@ -7739,6 +7783,79 @@ void main(){
|
|
|
7739
7783
|
}
|
|
7740
7784
|
};
|
|
7741
7785
|
}
|
|
7786
|
+
var SPHERE_DEFAULT_WIDTH = 8;
|
|
7787
|
+
var SPHERE_DEFAULT_HEIGHT = 6;
|
|
7788
|
+
function geometryOf(THREE, particle) {
|
|
7789
|
+
switch (particle.shape) {
|
|
7790
|
+
case "cone":
|
|
7791
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, false);
|
|
7792
|
+
case "cone_open":
|
|
7793
|
+
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, true);
|
|
7794
|
+
case "sphere":
|
|
7795
|
+
return new THREE.SphereGeometry(particle.radius, particle.segments || SPHERE_DEFAULT_WIDTH, particle.segments2 || SPHERE_DEFAULT_HEIGHT);
|
|
7796
|
+
case "icosahedron":
|
|
7797
|
+
return new THREE.IcosahedronGeometry(particle.radius, particle.segments);
|
|
7798
|
+
}
|
|
7799
|
+
}
|
|
7800
|
+
function materialOf(THREE, particle) {
|
|
7801
|
+
if (particle.lit) return new THREE.MeshStandardMaterial({ color: particle.color, roughness: 1, metalness: 0, transparent: true, opacity: particle.opacity, depthWrite: false });
|
|
7802
|
+
return new THREE.MeshBasicMaterial({ color: particle.color, transparent: true, opacity: particle.opacity, depthWrite: false, ...particle.additive ? { blending: THREE.AdditiveBlending } : {} });
|
|
7803
|
+
}
|
|
7804
|
+
function createMeshLayerProbes(THREE) {
|
|
7805
|
+
const geometry = new THREE.BoxGeometry(1e-3, 1e-3, 1e-3);
|
|
7806
|
+
return [{ lit: true, additive: false }, { lit: false, additive: false }, { lit: false, additive: true }].map(
|
|
7807
|
+
(kind) => new THREE.Mesh(geometry, materialOf(THREE, { ...kind, color: 8421504, opacity: 0.5 }))
|
|
7808
|
+
);
|
|
7809
|
+
}
|
|
7810
|
+
function createMeshLayer(THREE, pool) {
|
|
7811
|
+
const group = new THREE.Group();
|
|
7812
|
+
group.name = "workshop-meshes";
|
|
7813
|
+
const drawn = /* @__PURE__ */ new Map();
|
|
7814
|
+
const frame = new THREE.Quaternion();
|
|
7815
|
+
const euler = new THREE.Euler();
|
|
7816
|
+
const turn = new THREE.Quaternion();
|
|
7817
|
+
const offset = new THREE.Vector3();
|
|
7818
|
+
function release(mesh2) {
|
|
7819
|
+
mesh2.removeFromParent();
|
|
7820
|
+
mesh2.geometry.dispose();
|
|
7821
|
+
mesh2.material.dispose();
|
|
7822
|
+
}
|
|
7823
|
+
return {
|
|
7824
|
+
group,
|
|
7825
|
+
sync() {
|
|
7826
|
+
const live = /* @__PURE__ */ new Set();
|
|
7827
|
+
for (const particle of pool.particles) {
|
|
7828
|
+
live.add(particle.id);
|
|
7829
|
+
let mesh2 = drawn.get(particle.id);
|
|
7830
|
+
if (!mesh2) {
|
|
7831
|
+
mesh2 = new THREE.Mesh(geometryOf(THREE, particle), materialOf(THREE, particle));
|
|
7832
|
+
mesh2.frustumCulled = false;
|
|
7833
|
+
mesh2.renderOrder = particle.additive ? 5 : 3;
|
|
7834
|
+
drawn.set(particle.id, mesh2);
|
|
7835
|
+
group.add(mesh2);
|
|
7836
|
+
}
|
|
7837
|
+
frame.set(particle.frame[0], particle.frame[1], particle.frame[2], particle.frame[3]);
|
|
7838
|
+
offset.set(particle.at[0], particle.at[1], particle.at[2]).multiplyScalar(particle.scale).applyQuaternion(frame);
|
|
7839
|
+
mesh2.position.set(particle.x + offset.x, particle.y + offset.y, particle.z + offset.z);
|
|
7840
|
+
turn.setFromEuler(euler.set(particle.rx, particle.ry, particle.rz));
|
|
7841
|
+
mesh2.quaternion.copy(frame).multiply(turn);
|
|
7842
|
+
mesh2.scale.setScalar(particle.scale);
|
|
7843
|
+
mesh2.material.opacity = particle.opacity;
|
|
7844
|
+
}
|
|
7845
|
+
for (const [id, mesh2] of drawn) {
|
|
7846
|
+
if (live.has(id)) continue;
|
|
7847
|
+
release(mesh2);
|
|
7848
|
+
drawn.delete(id);
|
|
7849
|
+
}
|
|
7850
|
+
return pool.count;
|
|
7851
|
+
},
|
|
7852
|
+
dispose() {
|
|
7853
|
+
for (const mesh2 of drawn.values()) release(mesh2);
|
|
7854
|
+
drawn.clear();
|
|
7855
|
+
group.removeFromParent();
|
|
7856
|
+
}
|
|
7857
|
+
};
|
|
7858
|
+
}
|
|
7742
7859
|
var clamp5 = (value, min2, max2) => value < min2 ? min2 : value > max2 ? max2 : value;
|
|
7743
7860
|
function layer(container, name, blend) {
|
|
7744
7861
|
const element = container.ownerDocument.createElement("div");
|
|
@@ -7908,73 +8025,6 @@ void main() {
|
|
|
7908
8025
|
}
|
|
7909
8026
|
};
|
|
7910
8027
|
}
|
|
7911
|
-
var SPHERE_DEFAULT_WIDTH = 8;
|
|
7912
|
-
var SPHERE_DEFAULT_HEIGHT = 6;
|
|
7913
|
-
function geometryOf(THREE, particle) {
|
|
7914
|
-
switch (particle.shape) {
|
|
7915
|
-
case "cone":
|
|
7916
|
-
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, false);
|
|
7917
|
-
case "cone_open":
|
|
7918
|
-
return new THREE.ConeGeometry(particle.radius, particle.height, particle.segments || void 0, particle.segments2 || 1, true);
|
|
7919
|
-
case "sphere":
|
|
7920
|
-
return new THREE.SphereGeometry(particle.radius, particle.segments || SPHERE_DEFAULT_WIDTH, particle.segments2 || SPHERE_DEFAULT_HEIGHT);
|
|
7921
|
-
case "icosahedron":
|
|
7922
|
-
return new THREE.IcosahedronGeometry(particle.radius, particle.segments);
|
|
7923
|
-
}
|
|
7924
|
-
}
|
|
7925
|
-
function materialOf(THREE, particle) {
|
|
7926
|
-
if (particle.lit) return new THREE.MeshStandardMaterial({ color: particle.color, roughness: 1, metalness: 0, transparent: true, opacity: particle.opacity, depthWrite: false });
|
|
7927
|
-
return new THREE.MeshBasicMaterial({ color: particle.color, transparent: true, opacity: particle.opacity, depthWrite: false, ...particle.additive ? { blending: THREE.AdditiveBlending } : {} });
|
|
7928
|
-
}
|
|
7929
|
-
function createMeshLayer(THREE, pool) {
|
|
7930
|
-
const group = new THREE.Group();
|
|
7931
|
-
group.name = "workshop-meshes";
|
|
7932
|
-
const drawn = /* @__PURE__ */ new Map();
|
|
7933
|
-
const frame = new THREE.Quaternion();
|
|
7934
|
-
const euler = new THREE.Euler();
|
|
7935
|
-
const turn = new THREE.Quaternion();
|
|
7936
|
-
const offset = new THREE.Vector3();
|
|
7937
|
-
function release(mesh2) {
|
|
7938
|
-
mesh2.removeFromParent();
|
|
7939
|
-
mesh2.geometry.dispose();
|
|
7940
|
-
mesh2.material.dispose();
|
|
7941
|
-
}
|
|
7942
|
-
return {
|
|
7943
|
-
group,
|
|
7944
|
-
sync() {
|
|
7945
|
-
const live = /* @__PURE__ */ new Set();
|
|
7946
|
-
for (const particle of pool.particles) {
|
|
7947
|
-
live.add(particle.id);
|
|
7948
|
-
let mesh2 = drawn.get(particle.id);
|
|
7949
|
-
if (!mesh2) {
|
|
7950
|
-
mesh2 = new THREE.Mesh(geometryOf(THREE, particle), materialOf(THREE, particle));
|
|
7951
|
-
mesh2.frustumCulled = false;
|
|
7952
|
-
mesh2.renderOrder = particle.additive ? 5 : 3;
|
|
7953
|
-
drawn.set(particle.id, mesh2);
|
|
7954
|
-
group.add(mesh2);
|
|
7955
|
-
}
|
|
7956
|
-
frame.set(particle.frame[0], particle.frame[1], particle.frame[2], particle.frame[3]);
|
|
7957
|
-
offset.set(particle.at[0], particle.at[1], particle.at[2]).multiplyScalar(particle.scale).applyQuaternion(frame);
|
|
7958
|
-
mesh2.position.set(particle.x + offset.x, particle.y + offset.y, particle.z + offset.z);
|
|
7959
|
-
turn.setFromEuler(euler.set(particle.rx, particle.ry, particle.rz));
|
|
7960
|
-
mesh2.quaternion.copy(frame).multiply(turn);
|
|
7961
|
-
mesh2.scale.setScalar(particle.scale);
|
|
7962
|
-
mesh2.material.opacity = particle.opacity;
|
|
7963
|
-
}
|
|
7964
|
-
for (const [id, mesh2] of drawn) {
|
|
7965
|
-
if (live.has(id)) continue;
|
|
7966
|
-
release(mesh2);
|
|
7967
|
-
drawn.delete(id);
|
|
7968
|
-
}
|
|
7969
|
-
return pool.count;
|
|
7970
|
-
},
|
|
7971
|
-
dispose() {
|
|
7972
|
-
for (const mesh2 of drawn.values()) release(mesh2);
|
|
7973
|
-
drawn.clear();
|
|
7974
|
-
group.removeFromParent();
|
|
7975
|
-
}
|
|
7976
|
-
};
|
|
7977
|
-
}
|
|
7978
8028
|
var WORKSHOP_SPRITE_VERTEX = `attribute float size;attribute float alpha;attribute vec3 pcol;varying vec3 vC;varying float vA;uniform float uScale;
|
|
7979
8029
|
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;}`;
|
|
7980
8030
|
var WORKSHOP_SPRITE_FRAGMENT = `uniform float uSoft;varying vec3 vC;varying float vA;
|
|
@@ -8339,7 +8389,14 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8339
8389
|
const requested = options.vfx;
|
|
8340
8390
|
const world = isWorld(requested) ? requested : createVfx({ profile: options.quality ?? "medium", reducedMotion, ...requested });
|
|
8341
8391
|
const pools = world.pools();
|
|
8342
|
-
|
|
8392
|
+
let anchors;
|
|
8393
|
+
const releaseAnchors = () => {
|
|
8394
|
+
if (!anchors) return;
|
|
8395
|
+
anchors.meshes[0]?.geometry.dispose();
|
|
8396
|
+
for (const mesh2 of anchors.meshes) mesh2.material.dispose();
|
|
8397
|
+
anchors = void 0;
|
|
8398
|
+
};
|
|
8399
|
+
const root = markKitOrigin(new THREE.Group(), { owner: "game-vfx-three", kind: "effect" });
|
|
8343
8400
|
options.scene.add(root);
|
|
8344
8401
|
const direction = new THREE.Vector3(...options.lightDirection ?? LAB_LIGHT_DIRECTION).normalize();
|
|
8345
8402
|
const sky = hexToLinearRgb(SKY_COLOR);
|
|
@@ -8455,6 +8512,16 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8455
8512
|
syncAll();
|
|
8456
8513
|
overlay?.update(screenNow());
|
|
8457
8514
|
},
|
|
8515
|
+
warmUpProbes() {
|
|
8516
|
+
releaseAnchors();
|
|
8517
|
+
const meshes = createMeshLayerProbes(THREE);
|
|
8518
|
+
for (const mesh2 of meshes) mesh2.frustumCulled = false;
|
|
8519
|
+
const group = new THREE.Group();
|
|
8520
|
+
group.add(...meshes);
|
|
8521
|
+
anchors = { meshes, group };
|
|
8522
|
+
return { group, dispose: () => {
|
|
8523
|
+
} };
|
|
8524
|
+
},
|
|
8458
8525
|
applyCamera() {
|
|
8459
8526
|
const shake = screenNow().shake;
|
|
8460
8527
|
if (reducedMotion || !(shake > SHAKE_FLOOR)) return () => {
|
|
@@ -8473,6 +8540,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8473
8540
|
},
|
|
8474
8541
|
screen: screenNow,
|
|
8475
8542
|
dispose() {
|
|
8543
|
+
releaseAnchors();
|
|
8476
8544
|
stopMarks();
|
|
8477
8545
|
overlay?.dispose();
|
|
8478
8546
|
workshopLayers?.dispose();
|
|
@@ -8685,6 +8753,11 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8685
8753
|
this.vertices = 0;
|
|
8686
8754
|
return;
|
|
8687
8755
|
}
|
|
8756
|
+
if (state.closed && this.isShellOpaque()) {
|
|
8757
|
+
if (this.mesh) this.mesh.visible = false;
|
|
8758
|
+
this.vertices = 0;
|
|
8759
|
+
return;
|
|
8760
|
+
}
|
|
8688
8761
|
this.build(state, quality);
|
|
8689
8762
|
if (!this.mesh || !this.solid) return;
|
|
8690
8763
|
this.mesh.material = materials.liquidBody(def);
|
|
@@ -8710,6 +8783,17 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8710
8783
|
}
|
|
8711
8784
|
} else this.steamAcc = 0;
|
|
8712
8785
|
}
|
|
8786
|
+
/** Every mesh of the bound object (the liquid itself aside) is drawn with an opaque material. */
|
|
8787
|
+
isShellOpaque() {
|
|
8788
|
+
let opaque = true;
|
|
8789
|
+
this.object.traverse((child) => {
|
|
8790
|
+
const mesh2 = child;
|
|
8791
|
+
if (!opaque || !mesh2.isMesh || child === this.mesh) return;
|
|
8792
|
+
const materials = Array.isArray(mesh2.material) ? mesh2.material : [mesh2.material];
|
|
8793
|
+
if (materials.some((material) => material.transparent || material.opacity < 1)) opaque = false;
|
|
8794
|
+
});
|
|
8795
|
+
return opaque;
|
|
8796
|
+
}
|
|
8713
8797
|
get triangles() {
|
|
8714
8798
|
return this.visible ? Math.floor(this.vertices / 3) : 0;
|
|
8715
8799
|
}
|
|
@@ -8835,6 +8919,16 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8835
8919
|
}
|
|
8836
8920
|
return m;
|
|
8837
8921
|
}
|
|
8922
|
+
/** One material per role, in a clear and in an opaque liquid, which are the shader programs a leak will need (the colour is not part of a program). */
|
|
8923
|
+
probes() {
|
|
8924
|
+
const base = { id: "warm_up", color: 8421504, viscosity: 1, density: 1e3, dryTime: 60, gloss: 0.5 };
|
|
8925
|
+
const defs = [{ ...base, opacity: 0.5 }, { ...base, opacity: 1 }];
|
|
8926
|
+
return {
|
|
8927
|
+
plain: defs.flatMap((def) => [this.liquidBody(def), this.liquidStream(def)]),
|
|
8928
|
+
instanced: defs.map((def) => this.liquidStream(def)),
|
|
8929
|
+
coloured: defs.flatMap((def) => [this.stainFilm(def), this.stainWet(def)])
|
|
8930
|
+
};
|
|
8931
|
+
}
|
|
8838
8932
|
dispose() {
|
|
8839
8933
|
for (const map of [this.body, this.stream, this.film, this.wet]) {
|
|
8840
8934
|
for (const m of map.values()) m.dispose();
|
|
@@ -8910,9 +9004,9 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
8910
9004
|
var dot2 = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
8911
9005
|
var cross3 = (a, b) => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
8912
9006
|
var length = (a) => Math.hypot(a[0], a[1], a[2]);
|
|
8913
|
-
var normalize2 = (a,
|
|
9007
|
+
var normalize2 = (a, fallback2 = [0, 1, 0]) => {
|
|
8914
9008
|
const l = length(a);
|
|
8915
|
-
return l < 1e-9 ? [
|
|
9009
|
+
return l < 1e-9 ? [fallback2[0], fallback2[1], fallback2[2]] : [a[0] / l, a[1] / l, a[2] / l];
|
|
8916
9010
|
};
|
|
8917
9011
|
var ballistic = (origin, velocity, gravity, t) => [
|
|
8918
9012
|
origin[0] + velocity[0] * t,
|
|
@@ -10348,6 +10442,29 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
10348
10442
|
body.dispose();
|
|
10349
10443
|
bodies.delete(containerId);
|
|
10350
10444
|
},
|
|
10445
|
+
warmUpProbes() {
|
|
10446
|
+
const plainGeometry = new THREE.BufferGeometry();
|
|
10447
|
+
plainGeometry.setAttribute("position", new THREE.BufferAttribute(new Float32Array(9), 3));
|
|
10448
|
+
plainGeometry.setAttribute("normal", new THREE.BufferAttribute(new Float32Array(9), 3));
|
|
10449
|
+
const stainGeometry = plainGeometry.clone();
|
|
10450
|
+
stainGeometry.setAttribute("color", new THREE.BufferAttribute(new Float32Array(12), 4));
|
|
10451
|
+
const { plain, instanced, coloured } = materials.probes();
|
|
10452
|
+
const meshes = [
|
|
10453
|
+
...plain.map((material) => new THREE.Mesh(plainGeometry, material)),
|
|
10454
|
+
...instanced.map((material) => new THREE.InstancedMesh(dropGeometry, material, 1)),
|
|
10455
|
+
...coloured.map((material) => new THREE.Mesh(stainGeometry, material))
|
|
10456
|
+
];
|
|
10457
|
+
const group = new THREE.Group();
|
|
10458
|
+
for (const mesh2 of meshes) mesh2.frustumCulled = false;
|
|
10459
|
+
group.add(...meshes);
|
|
10460
|
+
return {
|
|
10461
|
+
group,
|
|
10462
|
+
dispose() {
|
|
10463
|
+
plainGeometry.dispose();
|
|
10464
|
+
stainGeometry.dispose();
|
|
10465
|
+
}
|
|
10466
|
+
};
|
|
10467
|
+
},
|
|
10351
10468
|
update(dt) {
|
|
10352
10469
|
if (disposed) return;
|
|
10353
10470
|
time += dt;
|