@adatechnology/game-vfx-three 0.3.5 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +15 -1
- package/dist/index.global.js +187 -88
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +186 -87
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -418,6 +418,11 @@ function createMarkTextures(THREE, createCanvas) {
|
|
|
418
418
|
var MAX_CONFORM_STEPS = 48;
|
|
419
419
|
var MIN_CONFORM_STEPS = 16;
|
|
420
420
|
var BLOOD_GROW_RATE = 1.2;
|
|
421
|
+
var BLOOD_START_GROWTH = 0.05;
|
|
422
|
+
var DEFAULT_MAX_GROUND_MARKS = 64;
|
|
423
|
+
var DEFAULT_MAX_ROCKS = 512;
|
|
424
|
+
var DEFAULT_MAX_BLOOD = 256;
|
|
425
|
+
var MAX_SPARE_GROUND_GEOMETRIES = 16;
|
|
421
426
|
function createMarkLayer(THREE, options) {
|
|
422
427
|
const group = new THREE.Group();
|
|
423
428
|
const textures = createMarkTextures(THREE, options.createCanvas);
|
|
@@ -441,92 +446,146 @@ function createMarkLayer(THREE, options) {
|
|
|
441
446
|
const bloodMaterial = new THREE.MeshStandardMaterial({ color: 6031882, roughness: 0.15, metalness: 0.1, polygonOffset: true, polygonOffsetFactor: -3, polygonOffsetUnits: -3 });
|
|
442
447
|
const bloodGeometry = new THREE.CircleGeometry(0.5, 9).rotateX(-Math.PI / 2);
|
|
443
448
|
owned.push(bloodMaterial, bloodGeometry);
|
|
444
|
-
const
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
material = new THREE.MeshStandardMaterial({ color, roughness: 0.9, metalness: 0, flatShading: true });
|
|
451
|
-
rockMaterials.set(color, material);
|
|
452
|
-
owned.push(material);
|
|
449
|
+
const maxGroundMarks = options.maxGroundMarks ?? DEFAULT_MAX_GROUND_MARKS;
|
|
450
|
+
const instanced = {};
|
|
451
|
+
function rockMaterial() {
|
|
452
|
+
if (!instanced.rockMaterial) {
|
|
453
|
+
instanced.rockMaterial = new THREE.MeshStandardMaterial({ color: 16777215, roughness: 0.9, metalness: 0, flatShading: true });
|
|
454
|
+
owned.push(instanced.rockMaterial);
|
|
453
455
|
}
|
|
454
|
-
return
|
|
456
|
+
return instanced.rockMaterial;
|
|
457
|
+
}
|
|
458
|
+
function bloodMesh() {
|
|
459
|
+
return instanced.blood ?? (instanced.blood = attach(createInstanced(bloodGeometry, bloodMaterial, options.maxBlood ?? DEFAULT_MAX_BLOOD)));
|
|
460
|
+
}
|
|
461
|
+
function rockMesh() {
|
|
462
|
+
return instanced.rock ?? (instanced.rock = attach(createInstanced(options.rockGeometry, rockMaterial(), options.maxRocks ?? DEFAULT_MAX_ROCKS), true));
|
|
463
|
+
}
|
|
464
|
+
function plateMesh() {
|
|
465
|
+
return instanced.plate ?? (instanced.plate = attach(createInstanced(options.plateGeometry, rockMaterial(), options.maxRocks ?? DEFAULT_MAX_ROCKS), true));
|
|
466
|
+
}
|
|
467
|
+
function attach(mesh, castShadow = false) {
|
|
468
|
+
mesh.castShadow = castShadow;
|
|
469
|
+
group.add(mesh);
|
|
470
|
+
return mesh;
|
|
471
|
+
}
|
|
472
|
+
const groundMarks = [];
|
|
473
|
+
const spareGeometries = [];
|
|
474
|
+
const blood = [];
|
|
475
|
+
const placed = { blood: 0, rock: 0, plate: 0 };
|
|
476
|
+
const matrix = new THREE.Matrix4();
|
|
477
|
+
const position = new THREE.Vector3();
|
|
478
|
+
const quaternion = new THREE.Quaternion();
|
|
479
|
+
const euler = new THREE.Euler();
|
|
480
|
+
const scale = new THREE.Vector3();
|
|
481
|
+
const color = new THREE.Color();
|
|
482
|
+
const up = new THREE.Vector3(0, 1, 0);
|
|
483
|
+
function createInstanced(geometry, material, capacity) {
|
|
484
|
+
const mesh = new THREE.InstancedMesh(geometry, material, capacity);
|
|
485
|
+
mesh.count = 0;
|
|
486
|
+
mesh.frustumCulled = false;
|
|
487
|
+
mesh.receiveShadow = true;
|
|
488
|
+
return mesh;
|
|
489
|
+
}
|
|
490
|
+
function takeSpare(vertexCount) {
|
|
491
|
+
const found = spareGeometries.findIndex((geometry) => geometry.getAttribute("position").count === vertexCount);
|
|
492
|
+
return found < 0 ? void 0 : spareGeometries.splice(found, 1)[0];
|
|
493
|
+
}
|
|
494
|
+
function evictOldestGroundMark() {
|
|
495
|
+
const oldest = groundMarks.shift();
|
|
496
|
+
group.remove(oldest.mesh);
|
|
497
|
+
spareGeometries.push(oldest.mesh.geometry);
|
|
498
|
+
if (spareGeometries.length > MAX_SPARE_GROUND_GEOMETRIES) spareGeometries.shift().dispose();
|
|
455
499
|
}
|
|
456
500
|
function conform(mark, material) {
|
|
457
501
|
const radius = mark.radius;
|
|
458
502
|
const steps = Math.max(MIN_CONFORM_STEPS, Math.min(MAX_CONFORM_STEPS, Math.round(radius * 8)));
|
|
459
|
-
|
|
460
|
-
const
|
|
503
|
+
if (groundMarks.length >= maxGroundMarks) evictOldestGroundMark();
|
|
504
|
+
const geometry = takeSpare((steps + 1) * (steps + 1)) ?? new THREE.PlaneGeometry(2, 2, steps, steps).rotateX(-Math.PI / 2);
|
|
505
|
+
const grid = geometry.attributes.position;
|
|
506
|
+
const cell = 2 / steps;
|
|
461
507
|
const cos = Math.cos(mark.rotation);
|
|
462
508
|
const sin = Math.sin(mark.rotation);
|
|
463
|
-
for (let index = 0; index <
|
|
464
|
-
const localX =
|
|
465
|
-
const localZ =
|
|
509
|
+
for (let index = 0; index < grid.count; index++) {
|
|
510
|
+
const localX = Math.fround(index % (steps + 1) * cell - 1) * radius;
|
|
511
|
+
const localZ = Math.fround(Math.floor(index / (steps + 1)) * cell - 1) * radius;
|
|
466
512
|
const worldX = mark.x + localX * cos - localZ * sin;
|
|
467
513
|
const worldZ = mark.z + localX * sin + localZ * cos;
|
|
468
|
-
|
|
514
|
+
grid.setXYZ(index, worldX, (options.ground?.heightAt(worldX, worldZ) ?? 0) + mark.lift, worldZ);
|
|
469
515
|
}
|
|
516
|
+
grid.needsUpdate = true;
|
|
470
517
|
geometry.computeVertexNormals();
|
|
518
|
+
geometry.attributes.normal.needsUpdate = true;
|
|
519
|
+
geometry.boundingSphere = null;
|
|
520
|
+
geometry.boundingBox = null;
|
|
471
521
|
const mesh = new THREE.Mesh(geometry, material);
|
|
472
522
|
mesh.receiveShadow = true;
|
|
473
|
-
|
|
523
|
+
group.add(mesh);
|
|
524
|
+
groundMarks.push({ mesh, steps });
|
|
474
525
|
}
|
|
475
526
|
function addRock(mark) {
|
|
476
|
-
const mesh =
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
mesh.
|
|
481
|
-
mesh.
|
|
482
|
-
|
|
527
|
+
const mesh = mark.plate ? plateMesh() : rockMesh();
|
|
528
|
+
const slot = mark.plate ? "plate" : "rock";
|
|
529
|
+
const index = placed[slot]++ % mesh.instanceMatrix.count;
|
|
530
|
+
quaternion.setFromEuler(euler.set(mark.rotation[0], mark.rotation[1], mark.rotation[2]));
|
|
531
|
+
mesh.setMatrixAt(index, matrix.compose(position.set(mark.x, mark.y, mark.z), quaternion, scale.set(mark.scale[0], mark.scale[1], mark.scale[2])));
|
|
532
|
+
mesh.setColorAt(index, color.set(mark.color));
|
|
533
|
+
mesh.count = Math.min(placed[slot], mesh.instanceMatrix.count);
|
|
534
|
+
mesh.instanceMatrix.needsUpdate = true;
|
|
535
|
+
mesh.instanceColor.needsUpdate = true;
|
|
536
|
+
}
|
|
537
|
+
function writeBlood(index, drawn, growth) {
|
|
538
|
+
quaternion.setFromAxisAngle(up, drawn.rotation);
|
|
539
|
+
const mesh = bloodMesh();
|
|
540
|
+
mesh.setMatrixAt(index, matrix.compose(position.set(drawn.position[0], drawn.position[1], drawn.position[2]), quaternion, scale.set(drawn.scaleX * growth, 1, drawn.scaleZ * growth)));
|
|
541
|
+
mesh.instanceMatrix.needsUpdate = true;
|
|
483
542
|
}
|
|
484
543
|
function addBlood(mark) {
|
|
485
|
-
const
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
mesh.scale.multiplyScalar(0.05);
|
|
491
|
-
blood.push({ mesh, scaleX: mark.scaleX, scaleZ: mark.scaleZ, age: 0 });
|
|
492
|
-
return mesh;
|
|
544
|
+
const index = placed.blood++ % bloodMesh().instanceMatrix.count;
|
|
545
|
+
const drawn = { position: [mark.x, mark.y, mark.z], rotation: mark.rotation, scaleX: mark.scaleX, scaleZ: mark.scaleZ, age: 0 };
|
|
546
|
+
blood[index] = drawn;
|
|
547
|
+
writeBlood(index, drawn, BLOOD_START_GROWTH);
|
|
548
|
+
bloodMesh().count = Math.min(placed.blood, bloodMesh().instanceMatrix.count);
|
|
493
549
|
}
|
|
494
550
|
function build(mark) {
|
|
495
|
-
if (mark.kind === "scorch")
|
|
496
|
-
if (mark.kind === "dirt")
|
|
497
|
-
if (mark.kind === "rock")
|
|
498
|
-
|
|
551
|
+
if (mark.kind === "scorch") conform(mark, scorchMaterials[mark.variant]);
|
|
552
|
+
else if (mark.kind === "dirt") conform(mark, dirtMaterial);
|
|
553
|
+
else if (mark.kind === "rock") addRock(mark);
|
|
554
|
+
else addBlood(mark);
|
|
499
555
|
}
|
|
500
|
-
function
|
|
501
|
-
for (const
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
556
|
+
function clearMarks() {
|
|
557
|
+
for (const drawn of groundMarks) group.remove(drawn.mesh);
|
|
558
|
+
for (const drawn of groundMarks) drawn.mesh.geometry.dispose();
|
|
559
|
+
groundMarks.length = 0;
|
|
560
|
+
for (const geometry of spareGeometries) geometry.dispose();
|
|
561
|
+
spareGeometries.length = 0;
|
|
506
562
|
blood.length = 0;
|
|
507
|
-
|
|
563
|
+
placed.blood = placed.rock = placed.plate = 0;
|
|
564
|
+
for (const mesh of [instanced.blood, instanced.rock, instanced.plate]) if (mesh) mesh.count = 0;
|
|
508
565
|
}
|
|
509
566
|
return {
|
|
510
567
|
group,
|
|
511
568
|
handle(event) {
|
|
512
|
-
if (event.type === "clear")
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
569
|
+
if (event.type === "clear") clearMarks();
|
|
570
|
+
else build(event.mark);
|
|
571
|
+
},
|
|
572
|
+
prepare() {
|
|
573
|
+
bloodMesh();
|
|
574
|
+
rockMesh();
|
|
575
|
+
plateMesh();
|
|
518
576
|
},
|
|
519
577
|
update(dt) {
|
|
520
|
-
for (
|
|
521
|
-
|
|
578
|
+
for (let index = 0; index < blood.length; index++) {
|
|
579
|
+
const drawn = blood[index];
|
|
580
|
+
if (!drawn || drawn.age > 1) continue;
|
|
522
581
|
drawn.age += dt * BLOOD_GROW_RATE;
|
|
523
|
-
|
|
524
|
-
drawn.mesh.scale.set(drawn.scaleX * Math.max(0.05, ease), 1, drawn.scaleZ * Math.max(0.05, ease));
|
|
582
|
+
writeBlood(index, drawn, Math.max(BLOOD_START_GROWTH, 1 - Math.pow(1 - Math.min(1, drawn.age), 2.5)));
|
|
525
583
|
}
|
|
526
584
|
},
|
|
527
|
-
count: () =>
|
|
585
|
+
count: () => groundMarks.length + [instanced.blood, instanced.rock, instanced.plate].filter((mesh) => mesh && mesh.count > 0).length,
|
|
528
586
|
dispose() {
|
|
529
|
-
|
|
587
|
+
clearMarks();
|
|
588
|
+
for (const mesh of [instanced.blood, instanced.rock, instanced.plate]) mesh?.dispose();
|
|
530
589
|
for (const item of owned) item.dispose();
|
|
531
590
|
}
|
|
532
591
|
};
|
|
@@ -535,18 +594,22 @@ function createMarkLayer(THREE, options) {
|
|
|
535
594
|
// src/mesh-layer.ts
|
|
536
595
|
var SPHERE_DEFAULT_WIDTH = 8;
|
|
537
596
|
var SPHERE_DEFAULT_HEIGHT = 6;
|
|
597
|
+
var MAX_PARKED_MESHES_PER_KIND = 256;
|
|
538
598
|
function geometryOf(THREE, particle) {
|
|
539
599
|
switch (particle.shape) {
|
|
540
600
|
case "cone":
|
|
541
|
-
return new THREE.ConeGeometry(
|
|
601
|
+
return new THREE.ConeGeometry(1, 1, particle.segments || void 0, particle.segments2 || 1, false);
|
|
542
602
|
case "cone_open":
|
|
543
|
-
return new THREE.ConeGeometry(
|
|
603
|
+
return new THREE.ConeGeometry(1, 1, particle.segments || void 0, particle.segments2 || 1, true);
|
|
544
604
|
case "sphere":
|
|
545
|
-
return new THREE.SphereGeometry(
|
|
605
|
+
return new THREE.SphereGeometry(1, particle.segments || SPHERE_DEFAULT_WIDTH, particle.segments2 || SPHERE_DEFAULT_HEIGHT);
|
|
546
606
|
case "icosahedron":
|
|
547
|
-
return new THREE.IcosahedronGeometry(
|
|
607
|
+
return new THREE.IcosahedronGeometry(1, particle.segments);
|
|
548
608
|
}
|
|
549
609
|
}
|
|
610
|
+
function isCone(particle) {
|
|
611
|
+
return particle.shape === "cone" || particle.shape === "cone_open";
|
|
612
|
+
}
|
|
550
613
|
function materialOf(THREE, particle) {
|
|
551
614
|
if (particle.lit) return new THREE.MeshStandardMaterial({ color: particle.color, roughness: 1, metalness: 0, transparent: true, opacity: particle.opacity, depthWrite: false });
|
|
552
615
|
return new THREE.MeshBasicMaterial({ color: particle.color, transparent: true, opacity: particle.opacity, depthWrite: false, ...particle.additive ? { blending: THREE.AdditiveBlending } : {} });
|
|
@@ -557,51 +620,82 @@ function createMeshLayerProbes(THREE) {
|
|
|
557
620
|
(kind) => new THREE.Mesh(geometry, materialOf(THREE, { ...kind, color: 8421504, opacity: 0.5 }))
|
|
558
621
|
);
|
|
559
622
|
}
|
|
623
|
+
function geometryKeyOf(particle) {
|
|
624
|
+
return `${particle.shape}:${particle.segments}:${particle.segments2}`;
|
|
625
|
+
}
|
|
560
626
|
function createMeshLayer(THREE, pool) {
|
|
561
627
|
const group = new THREE.Group();
|
|
562
628
|
group.name = "workshop-meshes";
|
|
563
629
|
const drawn = /* @__PURE__ */ new Map();
|
|
630
|
+
const geometries = /* @__PURE__ */ new Map();
|
|
631
|
+
const parked = /* @__PURE__ */ new Map();
|
|
564
632
|
const frame = new THREE.Quaternion();
|
|
565
633
|
const euler = new THREE.Euler();
|
|
566
634
|
const turn = new THREE.Quaternion();
|
|
567
635
|
const offset = new THREE.Vector3();
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
636
|
+
let stamp = 0;
|
|
637
|
+
function geometryFor(particle) {
|
|
638
|
+
const key = geometryKeyOf(particle);
|
|
639
|
+
let geometry = geometries.get(key);
|
|
640
|
+
if (!geometry) {
|
|
641
|
+
geometry = geometryOf(THREE, particle);
|
|
642
|
+
geometries.set(key, geometry);
|
|
643
|
+
}
|
|
644
|
+
return geometry;
|
|
645
|
+
}
|
|
646
|
+
function acquire(particle) {
|
|
647
|
+
const parkingKey = `${geometryKeyOf(particle)}|${particle.lit}|${particle.additive}`;
|
|
648
|
+
const mesh = parked.get(parkingKey)?.pop() ?? new THREE.Mesh(geometryFor(particle), materialOf(THREE, particle));
|
|
649
|
+
mesh.material.color.set(particle.color);
|
|
650
|
+
mesh.frustumCulled = false;
|
|
651
|
+
mesh.renderOrder = particle.additive ? 5 : 3;
|
|
652
|
+
group.add(mesh);
|
|
653
|
+
return { mesh, parkingKey, stamp };
|
|
654
|
+
}
|
|
655
|
+
function park(entry) {
|
|
656
|
+
entry.mesh.removeFromParent();
|
|
657
|
+
let free = parked.get(entry.parkingKey);
|
|
658
|
+
if (!free) {
|
|
659
|
+
free = [];
|
|
660
|
+
parked.set(entry.parkingKey, free);
|
|
661
|
+
}
|
|
662
|
+
if (free.length < MAX_PARKED_MESHES_PER_KIND) free.push(entry.mesh);
|
|
663
|
+
else entry.mesh.material.dispose();
|
|
572
664
|
}
|
|
573
665
|
return {
|
|
574
666
|
group,
|
|
575
667
|
sync() {
|
|
576
|
-
|
|
668
|
+
stamp++;
|
|
577
669
|
for (const particle of pool.particles) {
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
mesh.frustumCulled = false;
|
|
583
|
-
mesh.renderOrder = particle.additive ? 5 : 3;
|
|
584
|
-
drawn.set(particle.id, mesh);
|
|
585
|
-
group.add(mesh);
|
|
670
|
+
let entry = drawn.get(particle.id);
|
|
671
|
+
if (!entry) {
|
|
672
|
+
entry = acquire(particle);
|
|
673
|
+
drawn.set(particle.id, entry);
|
|
586
674
|
}
|
|
675
|
+
entry.stamp = stamp;
|
|
676
|
+
const mesh = entry.mesh;
|
|
587
677
|
frame.set(particle.frame[0], particle.frame[1], particle.frame[2], particle.frame[3]);
|
|
588
678
|
offset.set(particle.at[0], particle.at[1], particle.at[2]).multiplyScalar(particle.scale).applyQuaternion(frame);
|
|
589
679
|
mesh.position.set(particle.x + offset.x, particle.y + offset.y, particle.z + offset.z);
|
|
590
680
|
turn.setFromEuler(euler.set(particle.rx, particle.ry, particle.rz));
|
|
591
681
|
mesh.quaternion.copy(frame).multiply(turn);
|
|
592
|
-
mesh.scale.
|
|
682
|
+
mesh.scale.set(particle.radius * particle.scale, (isCone(particle) ? particle.height : particle.radius) * particle.scale, particle.radius * particle.scale);
|
|
593
683
|
mesh.material.opacity = particle.opacity;
|
|
594
684
|
}
|
|
595
|
-
for (const [id,
|
|
596
|
-
if (
|
|
597
|
-
|
|
685
|
+
for (const [id, entry] of drawn) {
|
|
686
|
+
if (entry.stamp === stamp) continue;
|
|
687
|
+
park(entry);
|
|
598
688
|
drawn.delete(id);
|
|
599
689
|
}
|
|
600
690
|
return pool.count;
|
|
601
691
|
},
|
|
602
692
|
dispose() {
|
|
603
|
-
for (const
|
|
693
|
+
for (const entry of drawn.values()) park(entry);
|
|
604
694
|
drawn.clear();
|
|
695
|
+
for (const free of parked.values()) for (const mesh of free) mesh.material.dispose();
|
|
696
|
+
parked.clear();
|
|
697
|
+
for (const geometry of geometries.values()) geometry.dispose();
|
|
698
|
+
geometries.clear();
|
|
605
699
|
group.removeFromParent();
|
|
606
700
|
}
|
|
607
701
|
};
|
|
@@ -1186,7 +1280,7 @@ function createVfxRenderer(THREE, options) {
|
|
|
1186
1280
|
const shocks = createShockLayer(THREE, pools.shocks);
|
|
1187
1281
|
const sprites = createSpriteLayer(THREE, world.sprites(), options.pointScale ?? 700);
|
|
1188
1282
|
const lights = createLightLayer(THREE, pools.lights, options.lightScale ?? Math.PI);
|
|
1189
|
-
const marks = createMarkLayer(THREE, { ground: pools.ground, createCanvas: options.createCanvas, rockGeometry, plateGeometry });
|
|
1283
|
+
const marks = createMarkLayer(THREE, { ground: pools.ground, createCanvas: options.createCanvas, rockGeometry, plateGeometry, ...options.markLimits });
|
|
1190
1284
|
root.add(puffs.mesh, sparks.mesh, glows.mesh, chunks.rocks, chunks.plates, shocks.group, lights.group, sprites.additive, sprites.normal, marks.group);
|
|
1191
1285
|
const stopMarks = world.onMarks((event) => marks.handle(event));
|
|
1192
1286
|
const overlay = options.overlay ? createScreenOverlay(options.overlay) : void 0;
|
|
@@ -1212,6 +1306,16 @@ function createVfxRenderer(THREE, options) {
|
|
|
1212
1306
|
const position = options.camera.position;
|
|
1213
1307
|
world.setCamera([position.x, position.y, position.z]);
|
|
1214
1308
|
}
|
|
1309
|
+
function attachWorkshopLayers() {
|
|
1310
|
+
const engine = world.peekWorkshop();
|
|
1311
|
+
if (!engine || engine === workshopEngine) return;
|
|
1312
|
+
workshopLayers?.dispose();
|
|
1313
|
+
if (workshopLayers) root.remove(workshopLayers.group);
|
|
1314
|
+
workshopEngine = engine;
|
|
1315
|
+
workshopLayers = createWorkshopLayers(THREE, engine, options.pointScale ?? 700, 1);
|
|
1316
|
+
root.add(workshopLayers.group);
|
|
1317
|
+
applyLayers();
|
|
1318
|
+
}
|
|
1215
1319
|
function syncAll() {
|
|
1216
1320
|
lastDrawn.puffs = puffs.sync();
|
|
1217
1321
|
lastDrawn.sparks = sparks.sync();
|
|
@@ -1220,15 +1324,7 @@ function createVfxRenderer(THREE, options) {
|
|
|
1220
1324
|
lastDrawn.shocks = shocks.sync();
|
|
1221
1325
|
lastDrawn.sprites = sprites.sync();
|
|
1222
1326
|
lights.sync();
|
|
1223
|
-
|
|
1224
|
-
if (engine && engine !== workshopEngine) {
|
|
1225
|
-
workshopLayers?.dispose();
|
|
1226
|
-
if (workshopLayers) root.remove(workshopLayers.group);
|
|
1227
|
-
workshopEngine = engine;
|
|
1228
|
-
workshopLayers = createWorkshopLayers(THREE, engine, options.pointScale ?? 700, 1);
|
|
1229
|
-
root.add(workshopLayers.group);
|
|
1230
|
-
applyLayers();
|
|
1231
|
-
}
|
|
1327
|
+
attachWorkshopLayers();
|
|
1232
1328
|
const workshopCalls = workshopLayers?.sync() ?? 0;
|
|
1233
1329
|
const glow = pools.lights.glow;
|
|
1234
1330
|
uniforms.uGlowPos.value.set(glow.x, glow.y, glow.z);
|
|
@@ -1281,6 +1377,9 @@ function createVfxRenderer(THREE, options) {
|
|
|
1281
1377
|
},
|
|
1282
1378
|
warmUpProbes() {
|
|
1283
1379
|
releaseAnchors();
|
|
1380
|
+
marks.prepare();
|
|
1381
|
+
world.workshop();
|
|
1382
|
+
attachWorkshopLayers();
|
|
1284
1383
|
const meshes = createMeshLayerProbes(THREE);
|
|
1285
1384
|
for (const mesh of meshes) mesh.frustumCulled = false;
|
|
1286
1385
|
const group = new THREE.Group();
|