minecraft-renderer 0.1.72 → 0.1.73
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/README.md +1 -1
- package/dist/mesher.js +81 -81
- package/dist/mesher.js.map +3 -3
- package/dist/mesherWasm.js +1183 -943
- package/dist/minecraft-renderer.js +249 -78
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +1732 -1001
- package/package.json +3 -3
- package/src/graphicsBackend/rendererDefaultOptions.ts +2 -7
- package/src/graphicsBackend/rendererOptionsSync.ts +1 -1
- package/src/lib/bakeLegacyLight.ts +17 -0
- package/src/lib/blockEntityLightRegistry.test.ts +18 -0
- package/src/lib/blockEntityLightRegistry.ts +75 -0
- package/src/lib/blockEntityLighting.test.ts +30 -0
- package/src/lib/blockEntityLighting.ts +53 -0
- package/src/lib/worldrendererCommon.ts +14 -6
- package/src/mesher-shared/blockEntityMetadata.test.ts +33 -0
- package/src/mesher-shared/blockEntityMetadata.ts +19 -3
- package/src/mesher-shared/exportedGeometryTypes.ts +11 -0
- package/src/mesher-shared/models.ts +161 -92
- package/src/mesher-shared/shared.ts +15 -4
- package/src/mesher-shared/tests/liquidQuadInvariant.test.ts +40 -0
- package/src/mesher-shared/world.ts +12 -0
- package/src/mesher-shared/worldLighting.test.ts +54 -0
- package/src/playground/baseScene.ts +1 -1
- package/src/three/bannerRenderer.ts +10 -3
- package/src/three/chunkMeshManager.ts +663 -69
- package/src/three/cubeDrawSpans.ts +74 -0
- package/src/three/cubeMultiDraw.ts +119 -0
- package/src/three/documentRenderer.ts +0 -2
- package/src/three/entities.ts +5 -6
- package/src/three/entity/EntityMesh.ts +7 -5
- package/src/three/entity/gltfAnimationUtils.ts +5 -3
- package/src/three/globalBlockBuffer.ts +208 -12
- package/src/three/globalLegacyBuffer.ts +701 -0
- package/src/three/itemMesh.ts +5 -2
- package/src/three/legacySectionCull.ts +85 -0
- package/src/three/modules/sciFiWorldReveal.ts +347 -703
- package/src/three/modules/starfield.ts +3 -2
- package/src/three/sectionRaycastAabb.ts +25 -0
- package/src/three/shaders/cubeBlockShader.ts +80 -17
- package/src/three/shaders/legacyBlockShader.ts +292 -0
- package/src/three/skyboxRenderer.ts +1 -1
- package/src/three/tests/chunkMeshManagerLegacy.test.ts +286 -0
- package/src/three/tests/cubeDrawSpans.test.ts +73 -0
- package/src/three/tests/globalLegacyBuffer.test.ts +360 -0
- package/src/three/tests/legacySectionCull.test.ts +80 -0
- package/src/three/tests/signTextureCache.test.ts +83 -0
- package/src/three/threeJsMedia.ts +2 -2
- package/src/three/waypointSprite.ts +2 -2
- package/src/three/world/cursorBlock.ts +1 -0
- package/src/three/world/vr.ts +2 -2
- package/src/three/worldGeometryExport.ts +83 -26
- package/src/three/worldRendererThree.ts +94 -25
- package/src/wasm-mesher/bridge/render-from-wasm.ts +214 -72
- package/src/wasm-mesher/bridge/shaderCubeBridge.ts +18 -6
- package/src/wasm-mesher/runtime-build/wasm_mesher_bg.wasm +0 -0
- package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +20 -0
- package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +67 -5
- package/src/wasm-mesher/worker/mesherWasm.ts +70 -14
- package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +11 -0
- package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +15 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "minecraft-renderer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.73",
|
|
4
4
|
"description": "The most Modular Minecraft world renderer with Three.js WebGL backend",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"skinview3d": "^3.4.1",
|
|
56
56
|
"stats-gl": "^1.0.5",
|
|
57
57
|
"stats.js": "^0.17.0",
|
|
58
|
-
"three": "0.
|
|
58
|
+
"three": "0.184.0",
|
|
59
59
|
"three-stdlib": "^2.36.1",
|
|
60
60
|
"type-fest": "^5.3.0",
|
|
61
61
|
"typed-emitter": "^2.1.0",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@types/lodash": "^4.17.21",
|
|
71
71
|
"@types/react": "^19.2.7",
|
|
72
72
|
"@types/stats.js": "^0.17.1",
|
|
73
|
-
"@types/three": "0.
|
|
73
|
+
"@types/three": "0.184.0",
|
|
74
74
|
"@zardoy/react-util": "^0.2.7",
|
|
75
75
|
"@zardoy/tsconfig": "^1.5.1",
|
|
76
76
|
"contro-max": "*",
|
|
@@ -63,7 +63,6 @@ export const RENDERER_DEFAULT_OPTIONS = {
|
|
|
63
63
|
rendererPerfDebugOverlay: false as boolean,
|
|
64
64
|
disableBlockEntityTextures: false as boolean,
|
|
65
65
|
rendererMesher: 'wasm' as RendererMesherPipeline,
|
|
66
|
-
rendererShaderCubeBlocks: false as boolean,
|
|
67
66
|
rendererShaderCubeDebugMode: 'off' as RendererShaderCubeDebugMode,
|
|
68
67
|
showChunkBorders: false as boolean,
|
|
69
68
|
renderEntities: true as boolean,
|
|
@@ -110,6 +109,7 @@ export function migrateRendererOptions(saved: Record<string, unknown>): void {
|
|
|
110
109
|
}
|
|
111
110
|
delete saved.wasmExperimentalMesher
|
|
112
111
|
delete saved.rendererWasmMesher
|
|
112
|
+
delete saved.rendererShaderCubeBlocks
|
|
113
113
|
|
|
114
114
|
if (saved.menuBackgroundMode === 'futuristic') {
|
|
115
115
|
saved.menuBackgroundMode = 'v2'
|
|
@@ -196,11 +196,6 @@ export const RENDERER_OPTIONS_META: Partial<Record<RendererDefaultOptionKey, Ren
|
|
|
196
196
|
tooltip: 'Browser technology for processing world geometry before render. WASM is the fastest; if you see a dead tab icon, reloads, or other errors, switch to Legacy JS.',
|
|
197
197
|
requiresChunksReload: true,
|
|
198
198
|
},
|
|
199
|
-
rendererShaderCubeBlocks: {
|
|
200
|
-
text: '(UNSTABLE) Instanced shader cubes',
|
|
201
|
-
tooltip: 'Render full blocks through the global GPU instanced path. Requires WASM mesher and WebGL2.',
|
|
202
|
-
requiresChunksReload: true,
|
|
203
|
-
},
|
|
204
199
|
rendererShaderCubeDebugMode: {
|
|
205
200
|
text: 'Shader cube debug',
|
|
206
201
|
tooltip: 'Instanced cube path visualization (requires shader cubes enabled).',
|
|
@@ -341,7 +336,7 @@ export const RENDERER_RENDER_GUI_SECTIONS: ReadonlyArray<{
|
|
|
341
336
|
},
|
|
342
337
|
{
|
|
343
338
|
title: 'Mesher',
|
|
344
|
-
keys: ['rendererMesher'
|
|
339
|
+
keys: ['rendererMesher']
|
|
345
340
|
},
|
|
346
341
|
{
|
|
347
342
|
title: 'Renderer debug',
|
|
@@ -163,7 +163,7 @@ export function applyRendererOptions(
|
|
|
163
163
|
cfg.fetchPlayerSkins = o.loadPlayerSkins
|
|
164
164
|
cfg.highlightBlockColor = o.highlightBlockColor
|
|
165
165
|
cfg.wasmMesher = wasmActive
|
|
166
|
-
cfg.shaderCubeBlocks =
|
|
166
|
+
cfg.shaderCubeBlocks = wasmActive
|
|
167
167
|
cfg.disableMesherConversionCache = !!ctx.isSafari
|
|
168
168
|
|
|
169
169
|
setSkinsConfig({ apiEnabled: o.loadPlayerSkins })
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
/** Bake tint×AO colors with sky/block channels for static export (no live u_skyLevel uniform). */
|
|
3
|
+
export function bakeLegacyVertexColors (
|
|
4
|
+
colors: ArrayLike<number>,
|
|
5
|
+
skyLights: ArrayLike<number>,
|
|
6
|
+
blockLights: ArrayLike<number>,
|
|
7
|
+
skyLevel: number,
|
|
8
|
+
): number[] {
|
|
9
|
+
const vertCount = colors.length / 3
|
|
10
|
+
const out: number[] = []
|
|
11
|
+
for (let v = 0; v < vertCount; v++) {
|
|
12
|
+
const L = Math.max(blockLights[v] ?? 0, Math.min(skyLights[v] ?? 1, skyLevel))
|
|
13
|
+
const i = v * 3
|
|
14
|
+
out.push(colors[i]! * L, colors[i + 1]! * L, colors[i + 2]! * L)
|
|
15
|
+
}
|
|
16
|
+
return out
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
import * as THREE from 'three'
|
|
4
|
+
import { blockEntityBrightness } from './blockEntityLighting'
|
|
5
|
+
import { BlockEntityLightRegistry } from './blockEntityLightRegistry'
|
|
6
|
+
|
|
7
|
+
describe('BlockEntityLightRegistry', () => {
|
|
8
|
+
it('refreshes overlay brightness when sky level changes', () => {
|
|
9
|
+
const registry = new BlockEntityLightRegistry()
|
|
10
|
+
const material = new THREE.MeshBasicMaterial()
|
|
11
|
+
registry.register({ material, blockLightNorm: 0, skyLightNorm: 1 })
|
|
12
|
+
const nightSky = 4 / 15
|
|
13
|
+
registry.setSkyLevel(nightSky)
|
|
14
|
+
expect(material.color.r).toBeCloseTo(blockEntityBrightness(0, 1, nightSky), 5)
|
|
15
|
+
registry.setSkyLevel(1)
|
|
16
|
+
expect(material.color.r).toBe(1)
|
|
17
|
+
})
|
|
18
|
+
})
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import {
|
|
4
|
+
blockEntityBrightness,
|
|
5
|
+
DEFAULT_LIGHTMAP_PARAMS,
|
|
6
|
+
type BlockLightmapParams,
|
|
7
|
+
} from './blockEntityLighting'
|
|
8
|
+
|
|
9
|
+
export type BlockEntityOverlayLight = {
|
|
10
|
+
material: THREE.MeshBasicMaterial
|
|
11
|
+
blockLightNorm: number
|
|
12
|
+
skyLightNorm: number
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class BlockEntityLightRegistry {
|
|
16
|
+
private readonly entries = new Set<BlockEntityOverlayLight>()
|
|
17
|
+
private skyLevel = 1
|
|
18
|
+
private lightmapParams: BlockLightmapParams = { ...DEFAULT_LIGHTMAP_PARAMS }
|
|
19
|
+
|
|
20
|
+
register (entry: BlockEntityOverlayLight): void {
|
|
21
|
+
this.entries.add(entry)
|
|
22
|
+
this.applyBrightness(entry)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
unregister (material: THREE.Material): void {
|
|
26
|
+
for (const entry of this.entries) {
|
|
27
|
+
if (entry.material === material) {
|
|
28
|
+
this.entries.delete(entry)
|
|
29
|
+
break
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
setSkyLevel (value: number): void {
|
|
35
|
+
this.skyLevel = value
|
|
36
|
+
this.refreshAll()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setLightmapParams (params: BlockLightmapParams): void {
|
|
40
|
+
this.lightmapParams = { ...this.lightmapParams, ...params }
|
|
41
|
+
this.refreshAll()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
getSkyLevel (): number {
|
|
45
|
+
return this.skyLevel
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private refreshAll (): void {
|
|
49
|
+
for (const entry of this.entries) {
|
|
50
|
+
this.applyBrightness(entry)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private applyBrightness (entry: BlockEntityOverlayLight): void {
|
|
55
|
+
const brightness = blockEntityBrightness(
|
|
56
|
+
entry.blockLightNorm,
|
|
57
|
+
entry.skyLightNorm,
|
|
58
|
+
this.skyLevel,
|
|
59
|
+
this.lightmapParams,
|
|
60
|
+
)
|
|
61
|
+
entry.material.color.setScalar(brightness)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function tintBannerMaterial (
|
|
66
|
+
material: THREE.MeshBasicMaterial,
|
|
67
|
+
blockLightNorm: number,
|
|
68
|
+
skyLightNorm: number,
|
|
69
|
+
skyLevel: number,
|
|
70
|
+
lightmapParams: BlockLightmapParams = DEFAULT_LIGHTMAP_PARAMS,
|
|
71
|
+
): number {
|
|
72
|
+
const brightness = blockEntityBrightness(blockLightNorm, skyLightNorm, skyLevel, lightmapParams)
|
|
73
|
+
material.color.setScalar(brightness)
|
|
74
|
+
return brightness
|
|
75
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
import {
|
|
4
|
+
applyLightmap,
|
|
5
|
+
blockEntityBrightness,
|
|
6
|
+
combinedBlockLight,
|
|
7
|
+
DEFAULT_LIGHTMAP_PARAMS,
|
|
8
|
+
} from './blockEntityLighting'
|
|
9
|
+
|
|
10
|
+
describe('blockEntityLighting', () => {
|
|
11
|
+
it('applyLightmap(1) === 1 for default params', () => {
|
|
12
|
+
expect(applyLightmap(1, DEFAULT_LIGHTMAP_PARAMS)).toBe(1)
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
it('combinedBlockLight caps sky by skyLevel', () => {
|
|
16
|
+
expect(combinedBlockLight(0, 1, 4 / 15)).toBeCloseTo(4 / 15, 5)
|
|
17
|
+
expect(combinedBlockLight(0.5, 1, 4 / 15)).toBeCloseTo(0.5, 5)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it('night outdoor blockEntityBrightness matches cap + lightmap', () => {
|
|
21
|
+
const skyLevel = 4 / 15
|
|
22
|
+
const L = combinedBlockLight(0, 1, skyLevel)
|
|
23
|
+
expect(blockEntityBrightness(0, 1, skyLevel)).toBeCloseTo(applyLightmap(L), 5)
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
it('linear curve matches raw L at minBrightness 0', () => {
|
|
27
|
+
const p = { curve: 0, minBrightness: 0, gamma: 1 }
|
|
28
|
+
expect(applyLightmap(0.5, p)).toBeCloseTo(0.5, 5)
|
|
29
|
+
})
|
|
30
|
+
})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* Shared block lighting math — keep in sync with APPLY_LIGHTMAP_GLSL in shaders.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export type BlockLightmapParams = {
|
|
7
|
+
curve?: number
|
|
8
|
+
minBrightness?: number
|
|
9
|
+
gamma?: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const DEFAULT_LIGHTMAP_PARAMS: Required<BlockLightmapParams> = {
|
|
13
|
+
curve: 0,
|
|
14
|
+
minBrightness: 0.12,
|
|
15
|
+
gamma: 1,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** GLSL body for applyLightmap — requires u_lightCurve, u_minBrightness, u_lightGamma uniforms. */
|
|
19
|
+
export const APPLY_LIGHTMAP_GLSL = /* glsl */ `
|
|
20
|
+
float applyLightmap(float L) {
|
|
21
|
+
float curved = L / (4.0 - 3.0 * L);
|
|
22
|
+
float shaped = mix(L, curved, u_lightCurve);
|
|
23
|
+
shaped = mix(u_minBrightness, 1.0, shaped);
|
|
24
|
+
return clamp(pow(shaped, u_lightGamma), 0.0, 1.0);
|
|
25
|
+
}
|
|
26
|
+
`
|
|
27
|
+
|
|
28
|
+
export function applyLightmap (L: number, params: BlockLightmapParams = DEFAULT_LIGHTMAP_PARAMS): number {
|
|
29
|
+
const curve = params.curve ?? DEFAULT_LIGHTMAP_PARAMS.curve
|
|
30
|
+
const minBrightness = params.minBrightness ?? DEFAULT_LIGHTMAP_PARAMS.minBrightness
|
|
31
|
+
const gamma = params.gamma ?? DEFAULT_LIGHTMAP_PARAMS.gamma
|
|
32
|
+
|
|
33
|
+
const curved = L / (4 - 3 * L)
|
|
34
|
+
let shaped = L * (1 - curve) + curved * curve
|
|
35
|
+
shaped = minBrightness + shaped * (1 - minBrightness)
|
|
36
|
+
return Math.min(1, Math.max(0, shaped ** gamma))
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Same cap as block shaders: max(block, min(sky, skyLevel)). */
|
|
40
|
+
export function combinedBlockLight (block: number, sky: number, skyLevel: number): number {
|
|
41
|
+
return Math.max(block, Math.min(sky, skyLevel))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** 0..1 brightness for MeshBasicMaterial.color.setScalar on block-entity overlays. */
|
|
45
|
+
export function blockEntityBrightness (
|
|
46
|
+
blockNorm: number,
|
|
47
|
+
skyNorm: number,
|
|
48
|
+
skyLevel: number,
|
|
49
|
+
lightmapParams: BlockLightmapParams = DEFAULT_LIGHTMAP_PARAMS,
|
|
50
|
+
): number {
|
|
51
|
+
const L = combinedBlockLight(blockNorm, skyNorm, skyLevel)
|
|
52
|
+
return applyLightmap(L, lightmapParams)
|
|
53
|
+
}
|
|
@@ -33,6 +33,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
33
33
|
worldReadyResolvers = Promise.withResolvers<void>()
|
|
34
34
|
worldReadyPromise = this.worldReadyResolvers.promise
|
|
35
35
|
timeOfTheDay = 0
|
|
36
|
+
lastMesherSkyLight = 15
|
|
36
37
|
worldSizeParams = { minY: 0, worldHeight: 256 }
|
|
37
38
|
reactiveDebugParams = proxy({
|
|
38
39
|
stopRendering: false,
|
|
@@ -695,6 +696,9 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
695
696
|
|
|
696
697
|
timeUpdated?(newTime: number): void
|
|
697
698
|
|
|
699
|
+
/** Called when day-cycle sky-light bucket changes; Three.js overrides to remesh. */
|
|
700
|
+
protected onDayCycleSkyLightChanged?(_skyLight: number): void
|
|
701
|
+
|
|
698
702
|
biomeUpdated?(biome: any): void
|
|
699
703
|
|
|
700
704
|
biomeReset?(): void
|
|
@@ -1064,16 +1068,20 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
1064
1068
|
}, signal)
|
|
1065
1069
|
|
|
1066
1070
|
bindAbortableListener(worldEmitter, 'time', (timeOfDay) => {
|
|
1067
|
-
if (!this.worldRendererConfig.dayCycle)
|
|
1071
|
+
if (!this.worldRendererConfig.dayCycle) {
|
|
1072
|
+
return
|
|
1073
|
+
}
|
|
1068
1074
|
this.timeUpdated?.(timeOfDay)
|
|
1069
1075
|
|
|
1070
1076
|
this.timeOfTheDay = timeOfDay
|
|
1071
1077
|
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1078
|
+
const skyLight = (timeOfDay < 0 || timeOfDay > 24_000) ? 15 : calculateSkyLightSimple(timeOfDay)
|
|
1079
|
+
if (this.lastMesherSkyLight === skyLight) return
|
|
1080
|
+
this.lastMesherSkyLight = skyLight
|
|
1081
|
+
if (this.workers.length > 0) {
|
|
1082
|
+
this.sendWorkers({ config: { skyLight } } as WorkerSend)
|
|
1083
|
+
}
|
|
1084
|
+
this.onDayCycleSkyLightChanged?.(skyLight)
|
|
1077
1085
|
}, signal)
|
|
1078
1086
|
|
|
1079
1087
|
bindAbortableListener(worldEmitter, 'biomeUpdate', ({ biome }) => {
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
import { Vec3 } from 'vec3'
|
|
4
|
+
import { collectBlockEntityMetadata } from './blockEntityMetadata'
|
|
5
|
+
|
|
6
|
+
describe('collectBlockEntityMetadata', () => {
|
|
7
|
+
it('stores channel light norms on banner metadata', () => {
|
|
8
|
+
const target = { signs: {}, heads: {}, banners: {} }
|
|
9
|
+
const block = {
|
|
10
|
+
name: 'pink_banner',
|
|
11
|
+
getProperties: () => ({ rotation: 0 }),
|
|
12
|
+
}
|
|
13
|
+
collectBlockEntityMetadata(
|
|
14
|
+
block,
|
|
15
|
+
1, 2, 3,
|
|
16
|
+
target,
|
|
17
|
+
{},
|
|
18
|
+
{
|
|
19
|
+
getChannelLightNorm: (pos: Vec3) => {
|
|
20
|
+
expect(pos).toBeInstanceOf(Vec3)
|
|
21
|
+
return { block: 0.4, sky: 0.8 }
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
)
|
|
25
|
+
expect(target.banners['1,2,3']).toEqual({
|
|
26
|
+
isWall: false,
|
|
27
|
+
blockName: 'pink_banner',
|
|
28
|
+
rotation: 0,
|
|
29
|
+
blockLightNorm: 0.4,
|
|
30
|
+
skyLightNorm: 0.8,
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
})
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
//@ts-nocheck
|
|
2
|
+
import { Vec3 } from 'vec3'
|
|
3
|
+
|
|
2
4
|
export interface SignMeta { isWall: boolean; isHanging: boolean; rotation: number }
|
|
3
5
|
export interface HeadMeta { isWall: boolean; rotation: number }
|
|
4
|
-
export interface BannerMeta {
|
|
6
|
+
export interface BannerMeta {
|
|
7
|
+
isWall: boolean
|
|
8
|
+
blockName: string
|
|
9
|
+
rotation: number
|
|
10
|
+
blockLightNorm: number
|
|
11
|
+
skyLightNorm: number
|
|
12
|
+
}
|
|
5
13
|
|
|
6
14
|
export interface BlockEntityMetadataTarget {
|
|
7
15
|
signs: Record<string, SignMeta>
|
|
@@ -15,11 +23,16 @@ export interface BlockEntityMetadataOptions {
|
|
|
15
23
|
|
|
16
24
|
type BlockLike = { name: string; getProperties(): any }
|
|
17
25
|
|
|
26
|
+
type LightSampler = {
|
|
27
|
+
getChannelLightNorm(pos: Vec3): { block: number, sky: number }
|
|
28
|
+
}
|
|
29
|
+
|
|
18
30
|
export function collectBlockEntityMetadata(
|
|
19
31
|
block: BlockLike,
|
|
20
32
|
x: number, y: number, z: number,
|
|
21
33
|
target: BlockEntityMetadataTarget,
|
|
22
|
-
options: BlockEntityMetadataOptions
|
|
34
|
+
options: BlockEntityMetadataOptions,
|
|
35
|
+
world?: LightSampler,
|
|
23
36
|
): void {
|
|
24
37
|
if ((block.name.includes('_sign') || block.name === 'sign') && !options.disableBlockEntityTextures) {
|
|
25
38
|
const key = `${x},${y},${z}`
|
|
@@ -61,10 +74,13 @@ export function collectBlockEntityMetadata(
|
|
|
61
74
|
'east': 3
|
|
62
75
|
}
|
|
63
76
|
const isWall = block.name.endsWith('_wall_banner')
|
|
77
|
+
const light = world?.getChannelLightNorm(new Vec3(x, y, z)) ?? { block: 0, sky: 1 }
|
|
64
78
|
target.banners[key] = {
|
|
65
79
|
isWall,
|
|
66
80
|
blockName: block.name, // Pass block name for base color extraction
|
|
67
|
-
rotation: isWall ? facingRotationMap[props.facing] : (props.rotation === undefined ? 0 : +props.rotation)
|
|
81
|
+
rotation: isWall ? facingRotationMap[props.facing] : (props.rotation === undefined ? 0 : +props.rotation),
|
|
82
|
+
blockLightNorm: light.block,
|
|
83
|
+
skyLightNorm: light.sky,
|
|
68
84
|
}
|
|
69
85
|
}
|
|
70
86
|
}
|
|
@@ -8,6 +8,17 @@ export interface ExportedSection {
|
|
|
8
8
|
positions: number[]
|
|
9
9
|
normals: number[]
|
|
10
10
|
colors: number[]
|
|
11
|
+
skyLights: number[]
|
|
12
|
+
blockLights: number[]
|
|
13
|
+
uvs: number[]
|
|
14
|
+
indices: number[]
|
|
15
|
+
}
|
|
16
|
+
blendGeometry?: {
|
|
17
|
+
positions: number[]
|
|
18
|
+
normals: number[]
|
|
19
|
+
colors: number[]
|
|
20
|
+
skyLights: number[]
|
|
21
|
+
blockLights: number[]
|
|
11
22
|
uvs: number[]
|
|
12
23
|
indices: number[]
|
|
13
24
|
}
|