Add panorama previews and repair beta export rendering

This commit is contained in:
2026-10-04 23:12:34 +05:00
parent 763cf8713c
commit aec0641f87
21 changed files with 802 additions and 60 deletions

View File

@@ -1,5 +1,6 @@
import * as THREE from "/three.js";
import { OpaqueIndex, QuadBuffer } from "./mesh-buffers.mjs";
import { blockTint } from "./block-colors.mjs";
const nonOpaque =
/air|water|lava|leaves|glass|grass(?!_block)|fern|flower|sapling|torch|fence|wall|slab|stairs|door|pane|rail|vine|carpet/;
@@ -16,6 +17,7 @@ async function compileState(
texture,
materials,
unsupported,
biome,
) {
const faces = [];
for (const { m, v = {} } of variants) {
@@ -40,13 +42,7 @@ async function compileState(
continue;
}
const tint =
f.tintindex !== undefined
? state.includes("water")
? "#5b9eb5"
: state.includes("leaves")
? "#7ba54c"
: "#90b650"
: "#ffffff";
f.tintindex !== undefined ? blockTint(state, biome) : "#ffffff";
const key = ref + "|" + tint;
let material = materials.get(key);
if (!material) {
@@ -60,14 +56,30 @@ async function compileState(
alphaTest: 0.3,
transparent: water,
opacity: water ? 0.8 : 1,
// Grass side overlays share a plane with the dirt face.
polygonOffset: ref?.includes("grass_block_side_overlay"),
polygonOffsetFactor: -1,
polygonOffsetUnits: -1,
}),
};
materials.set(key, material);
}
const normal = new THREE.Vector3(...fd.normal).applyMatrix4(rotation);
if (e.rotation) {
const axis = new THREE.Vector3(
e.rotation.axis === "x" ? 1 : 0,
e.rotation.axis === "y" ? 1 : 0,
e.rotation.axis === "z" ? 1 : 0,
);
normal.copy(
new THREE.Vector3(...fd.normal)
.applyAxisAngle(axis, (e.rotation.angle * Math.PI) / 180)
.applyMatrix4(rotation),
);
}
const positions = new Float64Array(12),
uvs = new Float32Array(8);
const uv = f.uv || [0, 0, 16, 16];
const uv = f.uv || defaultUV(dir, e.from, e.to);
const coords = [
[uv[0] / 16, 1 - uv[3] / 16],
[uv[2] / 16, 1 - uv[3] / 16],
@@ -143,6 +155,17 @@ function fluidModel(state, faceData) {
};
}
function defaultUV(dir, from, to) {
const [x, y, z] = from,
[X, Y, Z] = to;
if (dir === "up") return [x, z, X, Z];
if (dir === "down") return [x, 16 - Z, X, 16 - z];
if (dir === "north") return [16 - X, 16 - Y, 16 - x, 16 - y];
if (dir === "south") return [x, 16 - Y, X, 16 - y];
if (dir === "west") return [z, 16 - Y, Z, 16 - y];
return [16 - Z, 16 - Y, 16 - z, 16 - y];
}
export async function buildTerrain(
snapshot,
scene,
@@ -176,8 +199,14 @@ export async function buildTerrain(
const b = snapshot.blocks[i];
if (b[1] < minY) minY = b[1];
if (b[1] > maxY) maxY = b[1];
if (!states.has(b[3]))
states.set(b[3], { opaque: !nonOpaque.test(b[3]), faces: null });
const key = b[3] + "|" + (b[4] || "minecraft:plains");
if (!states.has(key))
states.set(key, {
state: b[3],
biome: b[4],
opaque: !nonOpaque.test(b[3].split("[")[0]),
faces: null,
});
if (i % 16384 === 0)
await progress(
25 + (2 * i) / snapshot.blocks.length,
@@ -187,7 +216,8 @@ export async function buildTerrain(
const occupancy = new OpaqueIndex(snapshot.bounds, minY, maxY);
for (let i = 0; i < snapshot.blocks.length; i++) {
const b = snapshot.blocks[i];
if (states.get(b[3]).opaque) occupancy.add(b[0], b[1], b[2]);
if (states.get(b[3] + "|" + (b[4] || "minecraft:plains")).opaque)
occupancy.add(b[0], b[1], b[2]);
if (i % 16384 === 0)
await progress(
27 + (3 * i) / snapshot.blocks.length,
@@ -203,7 +233,8 @@ export async function buildTerrain(
for (let i = 0; i < entries.length; i += 8) {
const end = Math.min(i + 8, entries.length);
await Promise.all(
entries.slice(i, end).map(async ([state, entry]) => {
entries.slice(i, end).map(async ([, entry]) => {
const state = entry.state;
const variants = fluid.test(state)
? [fluidModel(state, faceData)]
: await stateModels(state);
@@ -215,6 +246,7 @@ export async function buildTerrain(
texture,
materials,
unsupported,
entry.biome,
);
completedModels++;
}),
@@ -261,7 +293,7 @@ export async function buildTerrain(
x = b[0],
y = b[1],
z = b[2];
const entry = states.get(b[3]);
const entry = states.get(b[3] + "|" + (b[4] || "minecraft:plains"));
const region =
Math.floor(x / 64) -
originX +