minerender 2.1.0-alpha.120 → 2.1.0-alpha.121
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/browser/index.d.mts +19 -2
- package/dist/browser/index.d.ts +19 -2
- package/dist/browser/index.js +119 -13
- package/dist/browser/index.js.map +1 -1
- package/dist/browser/index.mjs +119 -13
- package/dist/browser/index.mjs.map +1 -1
- package/dist/browser/section.worker.js +55 -4
- package/dist/browser/section.worker.js.map +1 -1
- package/dist/browser/section.worker.mjs +55 -4
- package/dist/browser/section.worker.mjs.map +1 -1
- package/dist/bundle.js +122 -13
- package/dist/bundle.js.map +1 -1
- package/dist/node/index.d.mts +19 -2
- package/dist/node/index.d.ts +19 -2
- package/dist/node/index.js +119 -13
- package/dist/node/index.js.map +1 -1
- package/dist/node/index.mjs +119 -13
- package/dist/node/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/bundle.js
CHANGED
|
@@ -107752,7 +107752,8 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107752
107752
|
atlas,
|
|
107753
107753
|
cullFaces: new Uint8Array(cullFaces),
|
|
107754
107754
|
occludes: ModelCulling.isOpaqueFullCube(atlas) && ModelCulling.toLocalMask(63, rotation) === 63,
|
|
107755
|
-
layer: atlas.hasTranslucency ? 1 : 0
|
|
107755
|
+
layer: atlas.hasTranslucency ? 1 : 0,
|
|
107756
|
+
ambientOcclusion: model.ambientocclusion !== false
|
|
107756
107757
|
};
|
|
107757
107758
|
this.templates.add(template);
|
|
107758
107759
|
return template;
|
|
@@ -107952,17 +107953,38 @@ gl_FragDepth=readDepth(vUv);
|
|
|
107952
107953
|
this.light = /* @__PURE__ */ new Map();
|
|
107953
107954
|
this.lightValidity = /* @__PURE__ */ new Map();
|
|
107954
107955
|
this.highestSkySection = /* @__PURE__ */ new Map();
|
|
107956
|
+
this.ambientOcclusionPending = false;
|
|
107955
107957
|
this.pendingCulling = /* @__PURE__ */ new Map();
|
|
107956
107958
|
if (options.savedLighting && !options.sectionMeshing) throw new TypeError("savedLighting requires sectionMeshing");
|
|
107959
|
+
if (options.ambientOcclusion && !options.sectionMeshing) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
107957
107960
|
if (options.ambientLight !== void 0 && (!Number.isFinite(options.ambientLight) || options.ambientLight < 0 || options.ambientLight > 1)) {
|
|
107958
107961
|
throw new RangeError("ambientLight must be a number from 0 to 1");
|
|
107959
107962
|
}
|
|
107960
107963
|
this.scene = scene;
|
|
107961
107964
|
this.savedLighting = options.savedLighting ?? false;
|
|
107962
107965
|
this.ambientLight = options.ambientLight ?? 0;
|
|
107966
|
+
this._ambientOcclusion = options.ambientOcclusion ?? false;
|
|
107963
107967
|
if (options.sectionMeshing) this.sectionModels = new SectionModels(options.maxAtlasSize);
|
|
107964
107968
|
if (options.renderEntities) this.entities = new WorldEntities(scene);
|
|
107965
107969
|
}
|
|
107970
|
+
/** Whether neighboring opaque cubes shade block-face corners. Defaults to false. */
|
|
107971
|
+
get ambientOcclusion() {
|
|
107972
|
+
return this._ambientOcclusion;
|
|
107973
|
+
}
|
|
107974
|
+
/** Rebuilds loaded blocks with or without corner shading. Block data and saved lighting are preserved. */
|
|
107975
|
+
async setAmbientOcclusion(enabled) {
|
|
107976
|
+
if (typeof enabled !== "boolean") throw new TypeError("Ambient occlusion must be a boolean");
|
|
107977
|
+
if (enabled && !this.sectionModels) throw new TypeError("ambientOcclusion requires sectionMeshing");
|
|
107978
|
+
if (enabled === this._ambientOcclusion && !this.ambientOcclusionPending) {
|
|
107979
|
+
await this.culling;
|
|
107980
|
+
return;
|
|
107981
|
+
}
|
|
107982
|
+
this._ambientOcclusion = enabled;
|
|
107983
|
+
this.ambientOcclusionPending = true;
|
|
107984
|
+
for (const chunk of this._chunks.values()) this.pendingCulling.set(chunk, "all");
|
|
107985
|
+
await this.updateCulling([]);
|
|
107986
|
+
this.ambientOcclusionPending = false;
|
|
107987
|
+
}
|
|
107966
107988
|
getBlockAt(posOrX, y5, z4) {
|
|
107967
107989
|
if (typeof posOrX == "number") {
|
|
107968
107990
|
return this.getBlockAt(new Vector3(posOrX, y5, z4));
|
|
@@ -108286,7 +108308,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108286
108308
|
const index = (ny & 15) * 256 + (nz & 15) * 16 + (nx & 15);
|
|
108287
108309
|
let pending = this.pendingCulling.get(section);
|
|
108288
108310
|
if (pending === "all" || pending?.has(index)) continue;
|
|
108289
|
-
if (Math.abs(x4) + Math.abs(y5) + Math.abs(z4) > 1 && !section.isFluidIndex(index)) continue;
|
|
108311
|
+
if (Math.abs(x4) + Math.abs(y5) + Math.abs(z4) > 1 && !this._ambientOcclusion && !section.isFluidIndex(index)) continue;
|
|
108290
108312
|
if (!pending) this.pendingCulling.set(section, pending = /* @__PURE__ */ new Set());
|
|
108291
108313
|
pending.add(index);
|
|
108292
108314
|
}
|
|
@@ -108294,6 +108316,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108294
108316
|
}
|
|
108295
108317
|
}
|
|
108296
108318
|
return this.culling ?? (this.culling = Promise.resolve().then(async () => {
|
|
108319
|
+
let sliceStart = performance.now();
|
|
108297
108320
|
try {
|
|
108298
108321
|
while (this.pendingCulling.size) {
|
|
108299
108322
|
const batch = [...this.pendingCulling];
|
|
@@ -108329,6 +108352,11 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108329
108352
|
}
|
|
108330
108353
|
for (const [index, mask] of masks) await chunk.setCullMaskIndex(index, mask);
|
|
108331
108354
|
await chunk.refreshLight(indices === "all" ? void 0 : indices);
|
|
108355
|
+
chunk.refreshAmbientOcclusion(this._ambientOcclusion);
|
|
108356
|
+
if ((this._ambientOcclusion || this.ambientOcclusionPending) && performance.now() - sliceStart > 8) {
|
|
108357
|
+
await yieldToEventLoop();
|
|
108358
|
+
sliceStart = performance.now();
|
|
108359
|
+
}
|
|
108332
108360
|
}
|
|
108333
108361
|
await Promise.all(batch.map(([chunk]) => chunk.rebuildSectionMesh()));
|
|
108334
108362
|
}
|
|
@@ -108441,6 +108469,53 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108441
108469
|
init_process2();
|
|
108442
108470
|
init_FluidQuads();
|
|
108443
108471
|
|
|
108472
|
+
// src/world/_light/AmbientOcclusion.ts
|
|
108473
|
+
init_dirname();
|
|
108474
|
+
init_buffer2();
|
|
108475
|
+
init_process2();
|
|
108476
|
+
var AXIS_STRIDES = [1, 9, 3];
|
|
108477
|
+
function sectionAmbientOcclusionMask(cells, center) {
|
|
108478
|
+
let mask = 0;
|
|
108479
|
+
for (let y5 = -1; y5 <= 1; y5++) for (let z4 = -1; z4 <= 1; z4++) for (let x4 = -1; x4 <= 1; x4++) {
|
|
108480
|
+
if (Math.abs(x4) + Math.abs(y5) + Math.abs(z4) < 2) continue;
|
|
108481
|
+
if (cells[center + y5 * 324 + z4 * 18 + x4]) mask |= 1 << (y5 + 1) * 9 + (z4 + 1) * 3 + x4 + 1;
|
|
108482
|
+
}
|
|
108483
|
+
return mask;
|
|
108484
|
+
}
|
|
108485
|
+
function cornerBrightness(mask, center, u4, v5) {
|
|
108486
|
+
const sideU = mask >>> center + u4 & 1;
|
|
108487
|
+
const sideV = mask >>> center + v5 & 1;
|
|
108488
|
+
const corner = sideU && sideV ? 1 : mask >>> center + u4 + v5 & 1;
|
|
108489
|
+
return 1 - (sideU + sideV + corner) * 0.2;
|
|
108490
|
+
}
|
|
108491
|
+
function quadAmbientOcclusion(positions, normals, quad, mask, output) {
|
|
108492
|
+
output.fill(1);
|
|
108493
|
+
if (!mask) return;
|
|
108494
|
+
const start = quad * 12;
|
|
108495
|
+
let axis = 0;
|
|
108496
|
+
if (Math.abs(normals[start + 1]) > Math.abs(normals[start + axis])) axis = 1;
|
|
108497
|
+
if (Math.abs(normals[start + 2]) > Math.abs(normals[start + axis])) axis = 2;
|
|
108498
|
+
const uAxis = (axis + 1) % 3, vAxis = (axis + 2) % 3;
|
|
108499
|
+
if (Math.abs(Math.abs(normals[start + axis]) - 1) > 1e-6 || Math.abs(normals[start + uAxis]) > 1e-6 || Math.abs(normals[start + vAxis]) > 1e-6) return;
|
|
108500
|
+
const sign = normals[start + axis] > 0 ? 1 : -1;
|
|
108501
|
+
for (let vertex2 = 0; vertex2 < 4; vertex2++) {
|
|
108502
|
+
const offset = start + vertex2 * 3;
|
|
108503
|
+
if (Math.abs(positions[offset + axis] - sign * 8) > 16e-4 || Math.abs(positions[offset + uAxis]) > 8.0016 || Math.abs(positions[offset + vAxis]) > 8.0016) return;
|
|
108504
|
+
}
|
|
108505
|
+
const center = 13 + sign * AXIS_STRIDES[axis];
|
|
108506
|
+
const u4 = AXIS_STRIDES[uAxis], v5 = AXIS_STRIDES[vAxis];
|
|
108507
|
+
const lowLow = cornerBrightness(mask, center, -u4, -v5);
|
|
108508
|
+
const highLow = cornerBrightness(mask, center, u4, -v5);
|
|
108509
|
+
const lowHigh = cornerBrightness(mask, center, -u4, v5);
|
|
108510
|
+
const highHigh = cornerBrightness(mask, center, u4, v5);
|
|
108511
|
+
for (let vertex2 = 0; vertex2 < 4; vertex2++) {
|
|
108512
|
+
const offset = start + vertex2 * 3;
|
|
108513
|
+
const a4 = Math.max(0, Math.min(1, (positions[offset + uAxis] + 8) / 16));
|
|
108514
|
+
const b4 = Math.max(0, Math.min(1, (positions[offset + vAxis] + 8) / 16));
|
|
108515
|
+
output[vertex2] = (lowLow * (1 - a4) + highLow * a4) * (1 - b4) + (lowHigh * (1 - a4) + highHigh * a4) * b4;
|
|
108516
|
+
}
|
|
108517
|
+
}
|
|
108518
|
+
|
|
108444
108519
|
// src/world/_light/FaceLight.ts
|
|
108445
108520
|
init_dirname();
|
|
108446
108521
|
init_buffer2();
|
|
@@ -108469,7 +108544,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108469
108544
|
|
|
108470
108545
|
// src/world/SectionGeometry.ts
|
|
108471
108546
|
function buildSectionGeometry(input) {
|
|
108472
|
-
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight } = input;
|
|
108547
|
+
const { count, indices, templates, cullMasks, templateData, atlases, maxAtlasSize, fluids, light, ambientLight, ambientOcclusion } = input;
|
|
108473
108548
|
if (!Number.isInteger(maxAtlasSize) || maxAtlasSize < 1) throw new RangeError("Section atlas size must be a positive integer");
|
|
108474
108549
|
if (count > indices.length || count > templates.length || count > cullMasks.length) throw new RangeError("Section entry count exceeds its arrays");
|
|
108475
108550
|
if (fluids && fluids.cells.length !== 5832) throw new RangeError("Section fluid cells must cover an 18\xD718\xD718 neighborhood");
|
|
@@ -108480,6 +108555,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108480
108555
|
if (ambientLight !== void 0 && (!Number.isFinite(ambientLight) || ambientLight < 0 || ambientLight > 1)) {
|
|
108481
108556
|
throw new RangeError("Section ambient light must be a number from 0 to 1");
|
|
108482
108557
|
}
|
|
108558
|
+
if (ambientOcclusion && (ambientOcclusion.length !== 5832 || ambientOcclusion.some((value) => value > 1))) {
|
|
108559
|
+
throw new RangeError("Section ambient occlusion must cover an 18\xD718\xD718 neighborhood with zero or one per cell");
|
|
108560
|
+
}
|
|
108561
|
+
const cornerBrightness2 = ambientOcclusion ? new Float32Array(4) : void 0;
|
|
108483
108562
|
for (const template of templateData) {
|
|
108484
108563
|
const { quads } = template;
|
|
108485
108564
|
if (template.positions.length !== quads * 12 || template.normals.length !== quads * 12 || template.uvs.length !== quads * 8 || template.uvBounds.length !== quads * 16 || template.colors.length !== quads * 12 || template.indices.length !== quads * 6 || template.cullFaces.length !== quads) {
|
|
@@ -108585,8 +108664,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108585
108664
|
const offsetY = Math.floor(indices[entry] / 256) * 16;
|
|
108586
108665
|
const offsetZ = Math.floor(indices[entry] / 16) % 16 * 16;
|
|
108587
108666
|
const lightIndex = (offsetY / 16 + 1) * 324 + (offsetZ / 16 + 1) * 18 + offsetX / 16 + 1;
|
|
108667
|
+
const ambientMask = ambientOcclusion && template.ambientOcclusion !== false ? sectionAmbientOcclusionMask(ambientOcclusion, lightIndex) : 0;
|
|
108588
108668
|
for (let quad = 0; quad < template.quads; quad++) {
|
|
108589
108669
|
if (cullMasks[entry] & template.cullFaces[quad]) continue;
|
|
108670
|
+
if (ambientMask) quadAmbientOcclusion(template.positions, template.normals, quad, ambientMask, cornerBrightness2);
|
|
108590
108671
|
const brightness = light ? lightBrightness(light[lightIndex + LIGHT_SAMPLE_OFFSETS[quadLightIndex(template.positions, template.normals, quad)]], ambientLight) : 1;
|
|
108591
108672
|
const start = vertex2;
|
|
108592
108673
|
for (let corner = 0; corner < 4; corner++, vertex2++) {
|
|
@@ -108603,9 +108684,10 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108603
108684
|
uvBounds[vertex2 * 4 + 1] = mapV(template.uvBounds[source * 4 + 1]);
|
|
108604
108685
|
uvBounds[vertex2 * 4 + 2] = mapU(template.uvBounds[source * 4 + 2]);
|
|
108605
108686
|
uvBounds[vertex2 * 4 + 3] = mapV(template.uvBounds[source * 4 + 3]);
|
|
108606
|
-
|
|
108607
|
-
colors[vertex2 * 3
|
|
108608
|
-
colors[vertex2 * 3 +
|
|
108687
|
+
const factor = brightness * (ambientMask ? cornerBrightness2[corner] : 1);
|
|
108688
|
+
colors[vertex2 * 3] = template.colors[source * 3] * factor;
|
|
108689
|
+
colors[vertex2 * 3 + 1] = template.colors[source * 3 + 1] * factor;
|
|
108690
|
+
colors[vertex2 * 3 + 2] = template.colors[source * 3 + 2] * factor;
|
|
108609
108691
|
}
|
|
108610
108692
|
for (let corner = 0; corner < 6; corner++) outputIndices[indexOffset++] = start + template.indices[quad * 6 + corner];
|
|
108611
108693
|
}
|
|
@@ -108756,7 +108838,8 @@ gl_FragDepth=readDepth(vUv);
|
|
|
108756
108838
|
indices: new Uint16Array(quads * 6),
|
|
108757
108839
|
cullFaces: new Uint8Array(template.cullFaces),
|
|
108758
108840
|
atlas: 0,
|
|
108759
|
-
layer: template.layer
|
|
108841
|
+
layer: template.layer,
|
|
108842
|
+
ambientOcclusion: template.ambientOcclusion
|
|
108760
108843
|
};
|
|
108761
108844
|
const normal = template.geometry.getAttribute("normal");
|
|
108762
108845
|
const uv = template.geometry.getAttribute("uv");
|
|
@@ -109186,6 +109269,25 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109186
109269
|
if (this.renderedBlocks.has(index)) this.meshDirty = true;
|
|
109187
109270
|
}
|
|
109188
109271
|
}
|
|
109272
|
+
/** Refreshes baked corner shading after edits or a world setting change. Disabled chunks keep no AO neighborhood. */
|
|
109273
|
+
refreshAmbientOcclusion(enabled) {
|
|
109274
|
+
if (!enabled && !this.ambientOcclusionCells) return;
|
|
109275
|
+
const cells = enabled ? this.buildAmbientOcclusionCells() : void 0;
|
|
109276
|
+
if (cells?.some((value, index) => value !== this.ambientOcclusionCells?.[index]) || !!cells !== !!this.ambientOcclusionCells) this.meshDirty = true;
|
|
109277
|
+
this.ambientOcclusionCells = cells;
|
|
109278
|
+
}
|
|
109279
|
+
buildAmbientOcclusionCells() {
|
|
109280
|
+
const cells = new Uint8Array(18 * 18 * 18);
|
|
109281
|
+
for (let y5 = -1; y5 <= 16; y5++) {
|
|
109282
|
+
for (let z4 = -1; z4 <= 16; z4++) {
|
|
109283
|
+
for (let x4 = -1; x4 <= 16; x4++) {
|
|
109284
|
+
const inner = x4 >= 0 && x4 < 16 && y5 >= 0 && y5 < 16 && z4 >= 0 && z4 < 16;
|
|
109285
|
+
cells[(y5 + 1) * 324 + (z4 + 1) * 18 + x4 + 1] = inner ? Number(this.isOccludingIndex(y5 * 256 + z4 * 16 + x4)) : Number(!!((this.neighborCell?.(this.x * 16 + x4, this.y * 16 + y5, this.z * 16 + z4) ?? 0) & 64));
|
|
109286
|
+
}
|
|
109287
|
+
}
|
|
109288
|
+
}
|
|
109289
|
+
return cells;
|
|
109290
|
+
}
|
|
109189
109291
|
biomePosition(index, blockState3, stored) {
|
|
109190
109292
|
const position = this.positionAt(index), name2 = blockState3.key?.toNamespacedString();
|
|
109191
109293
|
if (stored.properties?.half === "upper" && (name2 === "minecraft:tall_grass" || name2 === "minecraft:large_fern")) position[1]--;
|
|
@@ -109374,12 +109476,18 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109374
109476
|
}
|
|
109375
109477
|
}
|
|
109376
109478
|
}
|
|
109377
|
-
|
|
109378
|
-
|
|
109379
|
-
|
|
109380
|
-
|
|
109381
|
-
|
|
109382
|
-
|
|
109479
|
+
let next;
|
|
109480
|
+
try {
|
|
109481
|
+
next = entries.length || fluids ? await SectionMesh.buildAsync(
|
|
109482
|
+
entries,
|
|
109483
|
+
this.sectionModels.maxAtlasSize,
|
|
109484
|
+
fluids,
|
|
109485
|
+
{ light, ambientLight: this.ambientLight, ambientOcclusion: this.ambientOcclusionCells }
|
|
109486
|
+
) : void 0;
|
|
109487
|
+
} catch (error2) {
|
|
109488
|
+
if (generation === this.meshGeneration) this.meshDirty = true;
|
|
109489
|
+
throw error2;
|
|
109490
|
+
}
|
|
109383
109491
|
if (generation !== this.meshGeneration) {
|
|
109384
109492
|
next?.dispose();
|
|
109385
109493
|
return;
|
|
@@ -109407,6 +109515,7 @@ gl_FragDepth=readDepth(vUv);
|
|
|
109407
109515
|
this.hiddenBlocks.clear();
|
|
109408
109516
|
this.fluidCells.fill(0);
|
|
109409
109517
|
this.waterTints = void 0;
|
|
109518
|
+
this.ambientOcclusionCells = void 0;
|
|
109410
109519
|
this.data.clear();
|
|
109411
109520
|
this.biomes = void 0;
|
|
109412
109521
|
if (notify) {
|