minerender 2.1.0-alpha.125 → 2.1.0-alpha.127

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/bundle.js CHANGED
@@ -43098,6 +43098,11 @@ void main() {
43098
43098
  }
43099
43099
  /** Build a display pose for geometry already centered at the model's [8, 8, 8] pivot. */
43100
43100
  static getMatrix(display, position) {
43101
+ const transform = this.getTransform(display, position);
43102
+ return new Matrix4().compose(transform.position, transform.quaternion, transform.scale);
43103
+ }
43104
+ /** Position, rotation, and scale of a display pose for geometry already centered at the model's [8, 8, 8] pivot. */
43105
+ static getTransform(display, position) {
43101
43106
  const transform = this.withHandFallbacks(display)?.[position] ?? {};
43102
43107
  const left = position === "firstperson_lefthand" /* FIRSTPERSON_LEFTHAND */ || position === "thirdperson_lefthand" /* THIRDPERSON_LEFTHAND */;
43103
43108
  const sign = left ? -1 : 1;
@@ -43106,7 +43111,7 @@ void main() {
43106
43111
  const translation = new Vector3(...transform.translation ?? [0, 0, 0]).clampScalar(-80, 80);
43107
43112
  translation.x *= sign;
43108
43113
  const scale = new Vector3(...transform.scale ?? [1, 1, 1]).clampScalar(-4, 4);
43109
- return new Matrix4().compose(translation, rotation, scale);
43114
+ return { position: translation, quaternion: rotation, scale };
43110
43115
  }
43111
43116
  /** Transforms geometry in place and reverses triangle winding when the matrix reflects it. */
43112
43117
  static apply(geometry, matrix) {
@@ -43300,6 +43305,7 @@ ${key}` : key, async () => {
43300
43305
  if (!object(data)) return false;
43301
43306
  if (dataset === "potionColors") return object(data.effects) && Object.values(data.effects).every(Number.isInteger) && object(data.potions) && Object.values(data.potions).every((effects) => Array.isArray(effects) && effects.every((effect) => object(effect) && typeof effect.id === "string" && Number.isInteger(effect.amplifier)));
43302
43307
  if (dataset === "legacyBlocks") return object(data.blocks) && Object.values(data.blocks).every((value) => typeof value === "string");
43308
+ if (dataset === "blockCulling") return Array.isArray(data.profiles) && data.profiles.every((profile) => object(profile) && typeof profile.type === "string") && object(data.blocks) && Object.values(data.blocks).every((index) => Number.isInteger(index) && index >= 0 && index < data.profiles.length) && (data.groups === void 0 || object(data.groups) && Object.values(data.groups).every((group) => Array.isArray(group) && group.every((type) => typeof type === "string")));
43303
43309
  return Object.values(data).every((value) => {
43304
43310
  if (!object(value)) return false;
43305
43311
  switch (dataset) {
@@ -94784,16 +94790,21 @@ ${shader.fragmentShader}`.replace(
94784
94790
  const special = this.originalModel.special;
94785
94791
  if (special) {
94786
94792
  const parts2 = await SpecialItems.getParts(special, this.originalModel.key?.root, this.originalModel.components);
94787
- const transform = this.options.displayPosition ? DisplayTransforms.getMatrix(this.originalModel.display, this.options.displayPosition) : new Matrix4();
94788
- transform.multiply(new Matrix4().makeTranslation(-8, -8, -8));
94793
+ const display = new SceneObject();
94794
+ if (this.options.displayPosition) {
94795
+ const transform = DisplayTransforms.getTransform(this.originalModel.display, this.options.displayPosition);
94796
+ display.position.copy(transform.position);
94797
+ display.quaternion.copy(transform.quaternion);
94798
+ display.scale.copy(transform.scale);
94799
+ }
94800
+ this.add(display);
94801
+ const offset = new Matrix4().makeTranslation(-8, -8, -8);
94789
94802
  try {
94790
94803
  const targets = [];
94791
94804
  for (const part of parts2) {
94792
94805
  const object4 = new EntityObject(part.model, { flip: false, wireframe: this.options.wireframe, tints: part.tints, faces: part.faces });
94793
- object4.matrix.copy(transform).multiply(part.transform);
94794
- object4.matrixWorldNeedsUpdate = true;
94795
- object4.matrixAutoUpdate = false;
94796
- this.add(object4);
94806
+ object4.matrix.multiplyMatrices(offset, part.transform).decompose(object4.position, object4.quaternion, object4.scale);
94807
+ display.add(object4);
94797
94808
  await object4.init(part.material);
94798
94809
  object4.iterateAllMeshes((mesh) => {
94799
94810
  const source = mesh.material;
@@ -108023,6 +108034,41 @@ gl_FragDepth=readDepth(vUv);
108023
108034
  };
108024
108035
  }
108025
108036
 
108037
+ // src/world/_culling/BlockCulling.ts
108038
+ init_dirname();
108039
+ init_buffer2();
108040
+ init_process2();
108041
+ init_Assets();
108042
+ init_MineRenderData();
108043
+ init_CubeFace();
108044
+ async function loadBlockCulling(root) {
108045
+ const { manifest } = await MineRenderData.resolve(root);
108046
+ return manifest.datasets.blockCulling ? MineRenderData.get("blockCulling", root) : void 0;
108047
+ }
108048
+ function blockCullingRule(data, type) {
108049
+ if (!type.includes(":")) type = `${DEFAULT_NAMESPACE}:${type}`;
108050
+ return Object.prototype.hasOwnProperty.call(data.blocks, type) ? data.profiles[data.blocks[type]] : void 0;
108051
+ }
108052
+ function skipsBlockFace(data, rule, block, neighbor, face) {
108053
+ const type = block.type.includes(":") ? block.type : `${DEFAULT_NAMESPACE}:${block.type}`;
108054
+ const other = neighbor.type.includes(":") ? neighbor.type : `${DEFAULT_NAMESPACE}:${neighbor.type}`;
108055
+ const same = type === other;
108056
+ const vertical = CUBE_FACES[face] === "up" /* UP */ || CUBE_FACES[face] === "down" /* DOWN */;
108057
+ switch (rule.type) {
108058
+ case "same_block":
108059
+ return same;
108060
+ case "same_block_vertical":
108061
+ return same && vertical;
108062
+ case "connected": {
108063
+ if (vertical) return same;
108064
+ const group = rule.group ? data.groups?.[rule.group] : void 0;
108065
+ return (same || !!group?.includes(type) && group.includes(other)) && String(block.properties?.[CUBE_FACES[face]]) === "true" && String(neighbor.properties?.[CUBE_FACES[face ^ 1]]) === "true";
108066
+ }
108067
+ default:
108068
+ return false;
108069
+ }
108070
+ }
108071
+
108026
108072
  // src/world/MineRenderWorld.ts
108027
108073
  var MineRenderWorld = class {
108028
108074
  constructor(scene, options = {}) {
@@ -108411,15 +108457,23 @@ gl_FragDepth=readDepth(vUv);
108411
108457
  return this.culling ?? (this.culling = Promise.resolve().then(async () => {
108412
108458
  let sliceStart = performance.now();
108413
108459
  try {
108460
+ const culling = await loadBlockCulling();
108414
108461
  while (this.pendingCulling.size) {
108415
108462
  const batch = [...this.pendingCulling];
108416
108463
  this.pendingCulling.clear();
108417
108464
  for (const [chunk, indices] of batch) {
108418
108465
  const neighbors = CUBE_FACE_OFFSETS.map(([x4, y5, z4]) => this._chunks.get(`${chunk.x + x4}_${chunk.y + y5}_${chunk.z + z4}`));
108419
- const masks = chunk.updateCullMasks(indices === "all" ? void 0 : indices, (x4, y5, z4) => {
108466
+ const neighborAt = (x4, y5, z4) => {
108420
108467
  const lx = x4 - chunk.x * 16, ly = y5 - chunk.y * 16, lz = z4 - chunk.z * 16;
108421
108468
  const section = neighbors[lx >= 16 ? 0 : lx < 0 ? 1 : ly >= 16 ? 2 : ly < 0 ? 3 : lz >= 16 ? 4 : 5];
108422
- return section?.isOccludingIndex((ly & 15) * 256 + (lz & 15) * 16 + (lx & 15)) ?? false;
108469
+ return [section, (ly & 15) * 256 + (lz & 15) * 16 + (lx & 15)];
108470
+ };
108471
+ const masks = chunk.updateCullMasks(indices === "all" ? void 0 : indices, (x4, y5, z4) => {
108472
+ const [section, i4] = neighborAt(x4, y5, z4);
108473
+ return section?.isOccludingIndex(i4) ?? false;
108474
+ }, culling, (x4, y5, z4) => {
108475
+ const [section, i4] = neighborAt(x4, y5, z4);
108476
+ return section?.visibleBlockIndex(i4);
108423
108477
  });
108424
108478
  const fluidIndices = indices === "all" ? function* () {
108425
108479
  for (let index = 0; index < 4096; index++) yield index;
@@ -109549,6 +109603,10 @@ gl_FragDepth=readDepth(vUv);
109549
109603
  isBlockVisibleIndex(index) {
109550
109604
  return this.renderedBlocks.has(index) && !this.hiddenBlocks.has(index);
109551
109605
  }
109606
+ /** Stored state of a rendered, visible cell, or `undefined`. */
109607
+ visibleBlockIndex(index) {
109608
+ return this.isBlockVisibleIndex(index) ? this.data.stateAt(this.data.idAt(index)) : void 0;
109609
+ }
109552
109610
  /** Fluid kind bits and level of a cell, or 0. Hidden cells report 0. */
109553
109611
  fluidByteIndex(index) {
109554
109612
  return this.hiddenBlocks.has(index) ? 0 : this.fluidCells[index];
@@ -109567,18 +109625,30 @@ gl_FragDepth=readDepth(vUv);
109567
109625
  async setCullMaskAt(pos, mask) {
109568
109626
  await this.setCullMaskIndex(_Chunk.chunkPosToBlockIndex(this.worldPosToChunkPos(pos)), mask);
109569
109627
  }
109570
- /** Recomputes section masks and returns changed per-block masks. Omit indices to visit every cell. */
109571
- updateCullMasks(indices, occludes) {
109628
+ /**
109629
+ * Recomputes section masks and returns changed per-block masks. Omit indices to visit every cell.
109630
+ * `culling` supplies neighbor face rules; `blockAt` supplies visible states outside this chunk.
109631
+ */
109632
+ updateCullMasks(indices, occludes, culling, blockAt) {
109572
109633
  const changed = [];
109634
+ const rules = [];
109573
109635
  for (const index of indices ?? this.fluidCells.keys()) {
109574
109636
  if (!this.isBlockVisibleIndex(index)) continue;
109575
109637
  const x4 = index % 16, y5 = Math.floor(index / 256), z4 = Math.floor(index / 16) % 16;
109638
+ const id = this.data.idAt(index);
109639
+ let rule = rules[id];
109640
+ if (culling && rule === void 0) rules[id] = rule = blockCullingRule(culling, this.data.stateAt(id).type) ?? null;
109641
+ const block = rule ? this.data.stateAt(id) : void 0;
109576
109642
  let mask = 0;
109577
109643
  for (let face = 0; face < CUBE_FACE_OFFSETS.length; face++) {
109578
109644
  const [dx, dy, dz] = CUBE_FACE_OFFSETS[face];
109579
109645
  const nx = x4 + dx, ny = y5 + dy, nz = z4 + dz;
109580
109646
  const inner = nx >= 0 && nx < 16 && ny >= 0 && ny < 16 && nz >= 0 && nz < 16;
109581
109647
  if (inner ? this.isOccludingIndex(ny * 256 + nz * 16 + nx) : occludes(this.x * 16 + nx, this.y * 16 + ny, this.z * 16 + nz)) mask |= 1 << face;
109648
+ else if (rule) {
109649
+ const neighbor = inner ? this.visibleBlockIndex(ny * 256 + nz * 16 + nx) : blockAt?.(this.x * 16 + nx, this.y * 16 + ny, this.z * 16 + nz);
109650
+ if (neighbor && skipsBlockFace(culling, rule, block, neighbor, face)) mask |= 1 << face;
109651
+ }
109582
109652
  }
109583
109653
  if (this.fluidCells[index]) this.meshDirty = true;
109584
109654
  const entries = this.sectionBlocks.get(index);