minecraft-renderer 0.1.72 → 0.1.74

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.
Files changed (70) hide show
  1. package/README.md +1 -1
  2. package/dist/mesher.js +81 -81
  3. package/dist/mesher.js.map +3 -3
  4. package/dist/mesherWasm.js +1183 -943
  5. package/dist/minecraft-renderer.js +253 -80
  6. package/dist/minecraft-renderer.js.meta.json +1 -1
  7. package/dist/threeWorker.js +1735 -1002
  8. package/package.json +3 -3
  9. package/src/graphicsBackend/config.ts +4 -0
  10. package/src/graphicsBackend/rendererDefaultOptions.ts +2 -7
  11. package/src/graphicsBackend/rendererOptionsSync.ts +1 -1
  12. package/src/graphicsBackend/types.ts +1 -0
  13. package/src/lib/bakeLegacyLight.ts +17 -0
  14. package/src/lib/bindAbortableListener.ts +1 -1
  15. package/src/lib/blockEntityLightRegistry.test.ts +18 -0
  16. package/src/lib/blockEntityLightRegistry.ts +75 -0
  17. package/src/lib/blockEntityLighting.test.ts +30 -0
  18. package/src/lib/blockEntityLighting.ts +53 -0
  19. package/src/lib/createPlayerObject.ts +1 -1
  20. package/src/lib/worldrendererCommon.reconfigure.test.ts +4 -1
  21. package/src/lib/worldrendererCommon.removeColumn.test.ts +8 -4
  22. package/src/lib/worldrendererCommon.ts +15 -7
  23. package/src/mesher-shared/blockEntityMetadata.test.ts +33 -0
  24. package/src/mesher-shared/blockEntityMetadata.ts +19 -3
  25. package/src/mesher-shared/exportedGeometryTypes.ts +11 -0
  26. package/src/mesher-shared/models.ts +161 -92
  27. package/src/mesher-shared/shared.ts +15 -4
  28. package/src/mesher-shared/tests/liquidQuadInvariant.test.ts +40 -0
  29. package/src/mesher-shared/world.ts +12 -0
  30. package/src/mesher-shared/worldLighting.test.ts +54 -0
  31. package/src/playground/baseScene.ts +1 -1
  32. package/src/three/bannerRenderer.ts +14 -4
  33. package/src/three/chunkMeshManager.ts +663 -69
  34. package/src/three/cubeDrawSpans.ts +74 -0
  35. package/src/three/cubeMultiDraw.ts +119 -0
  36. package/src/three/documentRenderer.ts +0 -2
  37. package/src/three/entities.ts +7 -7
  38. package/src/three/entity/EntityMesh.ts +7 -5
  39. package/src/three/entity/gltfAnimationUtils.ts +5 -3
  40. package/src/three/globalBlockBuffer.ts +208 -12
  41. package/src/three/globalLegacyBuffer.ts +701 -0
  42. package/src/three/graphicsBackendBase.ts +9 -5
  43. package/src/three/itemMesh.ts +6 -3
  44. package/src/three/legacySectionCull.ts +85 -0
  45. package/src/three/modules/rain.ts +22 -21
  46. package/src/three/modules/sciFiWorldReveal.ts +347 -703
  47. package/src/three/modules/starfield.ts +19 -6
  48. package/src/three/sectionRaycastAabb.ts +25 -0
  49. package/src/three/shaders/cubeBlockShader.ts +80 -17
  50. package/src/three/shaders/legacyBlockShader.ts +292 -0
  51. package/src/three/skyboxRenderer.ts +1 -1
  52. package/src/three/tests/chunkMeshManagerLegacy.test.ts +286 -0
  53. package/src/three/tests/cubeDrawSpans.test.ts +73 -0
  54. package/src/three/tests/globalLegacyBuffer.test.ts +360 -0
  55. package/src/three/tests/legacySectionCull.test.ts +80 -0
  56. package/src/three/tests/signTextureCache.test.ts +83 -0
  57. package/src/three/threeJsMedia.ts +2 -2
  58. package/src/three/waypointSprite.ts +2 -2
  59. package/src/three/world/cursorBlock.ts +1 -0
  60. package/src/three/world/vr.ts +2 -2
  61. package/src/three/worldGeometryExport.ts +83 -26
  62. package/src/three/worldRendererThree.ts +100 -30
  63. package/src/wasm-mesher/bridge/render-from-wasm.ts +214 -72
  64. package/src/wasm-mesher/bridge/shaderCubeBridge.ts +18 -6
  65. package/src/wasm-mesher/runtime-build/wasm_mesher_bg.wasm +0 -0
  66. package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +20 -0
  67. package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +80 -12
  68. package/src/wasm-mesher/worker/mesherWasm.ts +70 -14
  69. package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +11 -0
  70. package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +15 -0
@@ -0,0 +1,80 @@
1
+ //@ts-nocheck
2
+ import { test, expect } from 'vitest'
3
+ import * as THREE from 'three'
4
+ import { sectionIntersectsFrustum, setupLegacySectionMatrix, updateLegacySectionCullState } from '../legacySectionCull'
5
+
6
+ test('setupLegacySectionMatrix: translation set once and stable across frames', () => {
7
+ const mesh = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshBasicMaterial())
8
+ mesh.matrixAutoUpdate = false
9
+
10
+ setupLegacySectionMatrix(mesh, 100, 64, -200, { x: 0, y: 0, z: 0 })
11
+
12
+ expect(mesh.matrix.elements[12]).toBe(100)
13
+ expect(mesh.matrix.elements[13]).toBe(64)
14
+ expect(mesh.matrix.elements[14]).toBe(-200)
15
+ expect(mesh.frustumCulled).toBe(false)
16
+
17
+ const before = mesh.matrix.elements.slice()
18
+ // No per-frame matrix write in 2a — matrix must stay unchanged across frames.
19
+ expect(mesh.matrix.elements.slice()).toEqual(before)
20
+ })
21
+
22
+ test('updateLegacySectionCullState: frustum hit sets visible and nearer section sorts later', () => {
23
+ const meshNear = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshBasicMaterial())
24
+ const meshFar = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshBasicMaterial())
25
+
26
+ const frustum = { intersectsBox: () => true } as unknown as THREE.Frustum
27
+
28
+ const box = new THREE.Box3()
29
+ const boxMin = new THREE.Vector3()
30
+ const boxMax = new THREE.Vector3()
31
+
32
+ updateLegacySectionCullState(meshNear, 0, 0, 0, 0, 0, 0, frustum, box, boxMin, boxMax)
33
+ updateLegacySectionCullState(meshFar, 32, 0, 0, 0, 0, 0, frustum, box, boxMin, boxMax)
34
+
35
+ expect(meshNear.visible).toBe(true)
36
+ expect(meshFar.visible).toBe(true)
37
+ expect(meshFar.renderOrder).toBeLessThan(meshNear.renderOrder)
38
+ })
39
+
40
+ test('sectionIntersectsFrustum: returns distSq and visibility', () => {
41
+ const frustum = { intersectsBox: () => true } as unknown as THREE.Frustum
42
+ const box = new THREE.Box3()
43
+ const boxMin = new THREE.Vector3()
44
+ const boxMax = new THREE.Vector3()
45
+
46
+ const result = sectionIntersectsFrustum(10, 0, 0, 0, 0, 0, frustum, box, boxMin, boxMax)
47
+ expect(result.visible).toBe(true)
48
+ expect(result.distSq).toBe(100)
49
+ })
50
+
51
+ test('updateLegacySectionCullState: outside frustum hides mesh', () => {
52
+ const mesh = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshBasicMaterial())
53
+ const frustum = new THREE.Frustum()
54
+ const proj = new THREE.Matrix4()
55
+ const camera = new THREE.PerspectiveCamera(60, 1, 0.1, 100)
56
+ camera.position.set(0, 0, 0)
57
+ camera.lookAt(0, 0, -1)
58
+ camera.updateMatrixWorld()
59
+ proj.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
60
+ frustum.setFromProjectionMatrix(proj)
61
+
62
+ const box = new THREE.Box3()
63
+ const boxMin = new THREE.Vector3()
64
+ const boxMax = new THREE.Vector3()
65
+
66
+ updateLegacySectionCullState(mesh, 500, 0, 0, 0, 0, 0, frustum, box, boxMin, boxMax)
67
+
68
+ expect(mesh.visible).toBe(false)
69
+ })
70
+
71
+ test('setupLegacySectionMatrix: non-zero render origin stores world minus R', () => {
72
+ const mesh = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshBasicMaterial())
73
+ mesh.matrixAutoUpdate = false
74
+
75
+ setupLegacySectionMatrix(mesh, 100, 64, -200, { x: 16, y: 0, z: 16 })
76
+
77
+ expect(mesh.matrix.elements[12]).toBe(84)
78
+ expect(mesh.matrix.elements[13]).toBe(64)
79
+ expect(mesh.matrix.elements[14]).toBe(-216)
80
+ })
@@ -0,0 +1,83 @@
1
+ //@ts-nocheck
2
+ import { test, expect, vi, beforeEach } from 'vitest'
3
+ import * as THREE from 'three'
4
+ import { Vec3 } from 'vec3'
5
+
6
+ vi.mock('../entity/EntityMesh', () => ({
7
+ getMesh: vi.fn(),
8
+ }))
9
+
10
+ const renderSignMock = vi.fn()
11
+ vi.mock('../../sign-renderer', () => ({
12
+ renderSign: (...args: unknown[]) => renderSignMock(...args),
13
+ }))
14
+
15
+ vi.mock('prismarine-chat', () => ({
16
+ default: () => () => ({}),
17
+ }))
18
+
19
+ import { ChunkMeshManager } from '../chunkMeshManager'
20
+ import type { WorldRendererThree } from '../worldRendererThree'
21
+
22
+ function createManager (): ChunkMeshManager {
23
+ const scene = new THREE.Scene()
24
+ const material = new THREE.MeshBasicMaterial()
25
+ const worldRenderer = {
26
+ version: '1.20',
27
+ shaderCubeBlocksEnabled: () => false,
28
+ getModule: () => undefined,
29
+ sceneOrigin: {
30
+ track: () => {},
31
+ removeAndUntrack: () => {},
32
+ removeAndUntrackAll: () => {},
33
+ },
34
+ blockEntities: {},
35
+ worldRendererConfig: {},
36
+ } as unknown as WorldRendererThree
37
+ return new ChunkMeshManager(worldRenderer, scene, material, 256, 1)
38
+ }
39
+
40
+ function stubCanvas () {
41
+ return { width: 64, height: 32 } as HTMLCanvasElement
42
+ }
43
+
44
+ beforeEach(() => {
45
+ renderSignMock.mockReset()
46
+ renderSignMock.mockImplementation(() => stubCanvas())
47
+ })
48
+
49
+ test('getSignTexture: same blockEntity returns cached texture without re-render', () => {
50
+ const manager = createManager()
51
+ const signHeadsRenderer = (manager as unknown as { signHeadsRenderer: { getSignTexture: Function } }).signHeadsRenderer
52
+ const pos = new Vec3(10, 64, 10)
53
+ const blockEntity = { Text1: '{"text":"Hello"}' }
54
+
55
+ const tex1 = signHeadsRenderer.getSignTexture(pos, blockEntity, false)
56
+ const tex2 = signHeadsRenderer.getSignTexture(pos, blockEntity, false)
57
+
58
+ expect(tex1).toBeDefined()
59
+ expect(tex2).toBe(tex1)
60
+ expect(renderSignMock).toHaveBeenCalledTimes(1)
61
+
62
+ manager.dispose()
63
+ })
64
+
65
+ test('getSignTexture: changed blockEntity disposes old texture and renders anew', () => {
66
+ const manager = createManager()
67
+ const signHeadsRenderer = (manager as unknown as { signHeadsRenderer: { getSignTexture: Function } }).signHeadsRenderer
68
+ const pos = new Vec3(10, 64, 10)
69
+ const blockEntity = { Text1: '{"text":"Hello"}' }
70
+
71
+ const tex1 = signHeadsRenderer.getSignTexture(pos, blockEntity, false)!
72
+ const disposeSpy = vi.spyOn(tex1, 'dispose')
73
+
74
+ const changed = { Text1: '{"text":"World"}' }
75
+ const tex2 = signHeadsRenderer.getSignTexture(pos, changed, false)
76
+
77
+ expect(tex2).toBeDefined()
78
+ expect(tex2).not.toBe(tex1)
79
+ expect(disposeSpy).toHaveBeenCalledTimes(1)
80
+ expect(renderSignMock).toHaveBeenCalledTimes(2)
81
+
82
+ manager.dispose()
83
+ })
@@ -81,7 +81,7 @@ export class ThreeJsMedia {
81
81
  }
82
82
  }
83
83
 
84
- private createErrorTexture(width: number, height: number, background = 0xff_ff_ff, error = 'Failed to load'): THREE.CanvasTexture {
84
+ private createErrorTexture(width: number, height: number, background = 0xff_ff_ff, error = 'Failed to load'): THREE.CanvasTexture<OffscreenCanvas> {
85
85
  const canvas = new OffscreenCanvas(100, 100)
86
86
  const MAX_DIMENSION = 100
87
87
 
@@ -111,7 +111,7 @@ export class ThreeJsMedia {
111
111
  return texture
112
112
  }
113
113
 
114
- private createBackgroundTexture(width: number, height: number, color = 0x00_00_00, opacity = 1): THREE.CanvasTexture {
114
+ private createBackgroundTexture(width: number, height: number, color = 0x00_00_00, opacity = 1): THREE.CanvasTexture<OffscreenCanvas> {
115
115
  const canvas = new OffscreenCanvas(1, 1)
116
116
  canvas.width = 1
117
117
  canvas.height = 1
@@ -89,7 +89,7 @@ export function createWaypointSprite (options: {
89
89
  const labelCanvas = createCanvas(getLabelCanvasSize(), getLabelCanvasSize())
90
90
  drawCombinedOntoCanvas(labelCanvas, displayColor, options.label ?? '', '0m', visualScale)
91
91
 
92
- const labelTexture = new THREE.CanvasTexture(labelCanvas)
92
+ const labelTexture: THREE.CanvasTexture<OffscreenCanvas> = new THREE.CanvasTexture(labelCanvas)
93
93
  labelTexture.anisotropy = 1
94
94
  labelTexture.magFilter = THREE.LinearFilter
95
95
  labelTexture.minFilter = THREE.LinearFilter
@@ -112,7 +112,7 @@ export function createWaypointSprite (options: {
112
112
  let arrowSprite: THREE.Sprite | undefined
113
113
  let arrowCanvas: OffscreenCanvas | undefined
114
114
  let arrowCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | undefined
115
- let arrowTexture: THREE.CanvasTexture | undefined
115
+ let arrowTexture: THREE.CanvasTexture<OffscreenCanvas> | undefined
116
116
  let arrowParent: THREE.Object3D | null = null
117
117
  let arrowEnabled = WAYPOINT_CONFIG.ARROW.enabledDefault
118
118
 
@@ -52,6 +52,7 @@ export class CursorBlock {
52
52
  const breakMaterial = new THREE.MeshBasicMaterial({
53
53
  transparent: true,
54
54
  blending: THREE.MultiplyBlending,
55
+ premultipliedAlpha: true,
55
56
  alphaTest: 0.5,
56
57
  })
57
58
  this.blockBreakMesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), breakMaterial)
@@ -124,14 +124,14 @@ export async function initVR(worldRenderer: WorldRendererThree, documentRenderer
124
124
  let hand1: any = controllerModelFactory.createControllerModel(controller1)
125
125
  controller1.addEventListener('connected', (event) => {
126
126
  hand1.xrInputSource = event.data
127
- manageXrInputSource(event.data, 'left')
127
+ manageXrInputSource(event.data as { gamepad: Gamepad | undefined, handedness?: string }, 'left')
128
128
  user.add(controller1)
129
129
  })
130
130
  controller1.add(hand1)
131
131
  let hand2: any = controllerModelFactory.createControllerModel(controller2)
132
132
  controller2.addEventListener('connected', (event) => {
133
133
  hand2.xrInputSource = event.data
134
- manageXrInputSource(event.data, 'right')
134
+ manageXrInputSource(event.data as { gamepad: Gamepad | undefined, handedness?: string }, 'right')
135
135
  user.add(controller2)
136
136
  })
137
137
  controller2.add(hand2)
@@ -2,8 +2,10 @@
2
2
  import * as THREE from 'three'
3
3
  import type { WorldRendererThree } from './worldRendererThree'
4
4
  import type { ExportedSection, ExportedWorldGeometry } from '../mesher-shared/exportedGeometryTypes'
5
+ import { calculateSkyLightSimple } from '../lib/skyLight'
6
+ import { bakeLegacyVertexColors } from '../lib/bakeLegacyLight'
5
7
  import { getShaderCubeResources } from '../wasm-mesher/bridge/shaderCubeBridge'
6
- import { createCubeBlockMaterial } from './shaders/cubeBlockShader'
8
+ import { createCubeBlockMaterial, setCubeSkyLevel } from './shaders/cubeBlockShader'
7
9
  import { createShaderCubeMesh } from './shaderCubeMesh'
8
10
 
9
11
  export type { ExportedSection, ExportedWorldGeometry } from '../mesher-shared/exportedGeometryTypes'
@@ -20,35 +22,79 @@ export function exportWorldGeometry(
20
22
  includeTexture = false
21
23
  ): ExportedWorldGeometry {
22
24
  const sections: ExportedSection[] = []
25
+ const skyLevel = calculateSkyLightSimple(worldRenderer.timeOfTheDay) / 15
26
+
27
+ const globalLegacy = worldRenderer.chunkMeshManager.globalLegacyBuffer
23
28
 
24
29
  for (const [key, sectionObject] of Object.entries(worldRenderer.sectionObjects)) {
25
- const mesh = sectionObject.children.find(child => child.name === 'mesh') as THREE.Mesh | undefined
26
- if (!mesh?.geometry) continue
30
+ const positions: number[] = []
31
+ const normals: number[] = []
32
+ const colors: number[] = []
33
+ const skyLights: number[] = []
34
+ const blockLights: number[] = []
35
+ const uvs: number[] = []
36
+ const indices: number[] = []
27
37
 
28
- const { geometry } = mesh
29
- const positionAttr = geometry.getAttribute('position') as THREE.BufferAttribute
30
- const normalAttr = geometry.getAttribute('normal') as THREE.BufferAttribute
31
- const colorAttr = geometry.getAttribute('color') as THREE.BufferAttribute
32
- const uvAttr = geometry.getAttribute('uv') as THREE.BufferAttribute
33
- const indexAttr = geometry.index!
38
+ const globalSlot = globalLegacy?.getSectionGeometryData(key)
39
+ if (globalSlot) {
40
+ positions.push(...globalSlot.positions)
41
+ colors.push(...bakeLegacyVertexColors(globalSlot.colors, globalSlot.skyLights, globalSlot.blockLights, skyLevel))
42
+ skyLights.push(...globalSlot.skyLights)
43
+ blockLights.push(...globalSlot.blockLights)
44
+ uvs.push(...globalSlot.uvs)
45
+ indices.push(...globalSlot.indices)
46
+ }
34
47
 
35
- if (!positionAttr || !indexAttr) continue
48
+ const blendMesh = sectionObject.children.find(child => child.name === 'mesh') as THREE.Mesh | undefined
49
+ if (blendMesh?.geometry) {
50
+ const { geometry } = blendMesh
51
+ const positionAttr = geometry.getAttribute('position') as THREE.BufferAttribute
52
+ const normalAttr = geometry.getAttribute('normal') as THREE.BufferAttribute
53
+ const colorAttr = geometry.getAttribute('color') as THREE.BufferAttribute
54
+ const skyAttr = geometry.getAttribute('a_skyLight') as THREE.BufferAttribute | undefined
55
+ const blockAttr = geometry.getAttribute('a_blockLight') as THREE.BufferAttribute | undefined
56
+ const uvAttr = geometry.getAttribute('uv') as THREE.BufferAttribute
57
+ const indexAttr = geometry.index
58
+ if (positionAttr && indexAttr && colorAttr) {
59
+ const vertOffset = positions.length / 3
60
+ const vertCount = positionAttr.count
61
+ const rawColors = Array.from(colorAttr.array as Float32Array)
62
+ const rawSky = skyAttr
63
+ ? Array.from(skyAttr.array as Float32Array)
64
+ : new Array(vertCount).fill(1)
65
+ const rawBlock = blockAttr
66
+ ? Array.from(blockAttr.array as Float32Array)
67
+ : new Array(vertCount).fill(0)
68
+ positions.push(...Array.from(positionAttr.array))
69
+ if (normalAttr) normals.push(...Array.from(normalAttr.array))
70
+ colors.push(...bakeLegacyVertexColors(rawColors, rawSky, rawBlock, skyLevel))
71
+ skyLights.push(...rawSky)
72
+ blockLights.push(...rawBlock)
73
+ if (uvAttr) uvs.push(...Array.from(uvAttr.array))
74
+ for (const idx of Array.from(indexAttr.array)) {
75
+ indices.push(idx + vertOffset)
76
+ }
77
+ }
78
+ }
79
+
80
+ if (positions.length === 0 || indices.length === 0) continue
36
81
 
37
- const wp = worldRenderer.sceneOrigin.getWorldPosition(mesh)
38
82
  sections.push({
39
83
  key,
40
84
  position: {
41
- x: wp?.x ?? worldRenderer.sceneOrigin.toWorldX(mesh.position.x),
42
- y: wp?.y ?? worldRenderer.sceneOrigin.toWorldY(mesh.position.y),
43
- z: wp?.z ?? worldRenderer.sceneOrigin.toWorldZ(mesh.position.z)
85
+ x: sectionObject.worldX ?? 0,
86
+ y: sectionObject.worldY ?? 0,
87
+ z: sectionObject.worldZ ?? 0,
44
88
  },
45
89
  geometry: {
46
- positions: [...positionAttr.array],
47
- normals: normalAttr ? [...normalAttr.array] : [],
48
- colors: colorAttr ? [...colorAttr.array] : [],
49
- uvs: uvAttr ? [...uvAttr.array] : [],
50
- indices: [...indexAttr.array]
51
- }
90
+ positions,
91
+ normals,
92
+ colors,
93
+ skyLights,
94
+ blockLights,
95
+ uvs,
96
+ indices,
97
+ },
52
98
  })
53
99
  }
54
100
 
@@ -65,7 +111,7 @@ export function exportWorldGeometry(
65
111
  // Optionally include texture atlas as data URL
66
112
  if (includeTexture && worldRenderer.material.map) {
67
113
  const canvas = document.createElement('canvas')
68
- const texture = worldRenderer.material.map
114
+ const texture = worldRenderer.material.map as THREE.Texture<HTMLImageElement | ImageBitmap>
69
115
  const { image } = texture
70
116
  if (image) {
71
117
  canvas.width = image.width
@@ -117,12 +163,13 @@ export async function loadWorldGeometryFromUrl(url: string): Promise<ExportedWor
117
163
  * Recreate THREE.js meshes from exported geometry
118
164
  * Returns an array of mesh groups that can be added to a scene
119
165
  */
120
- function shaderMaterialForExport(legacyMaterial: THREE.Material): THREE.ShaderMaterial | null {
166
+ function shaderMaterialForExport(legacyMaterial: THREE.Material, skyLevel: number): THREE.ShaderMaterial | null {
121
167
  const atlas = (legacyMaterial as THREE.MeshBasicMaterial).map
122
168
  ?? (legacyMaterial as THREE.MeshLambertMaterial).map
123
169
  if (!atlas) return null
124
170
  const shaderMat = createCubeBlockMaterial()
125
171
  shaderMat.uniforms.u_atlas.value = atlas
172
+ setCubeSkyLevel(shaderMat, skyLevel)
126
173
  const resources = getShaderCubeResources()
127
174
  if (!resources) return null
128
175
  const { tintPalette } = resources
@@ -135,9 +182,10 @@ export function createMeshesFromExport(
135
182
  exportData: ExportedWorldGeometry,
136
183
  material: THREE.Material,
137
184
  shaderMaterial?: THREE.ShaderMaterial | null,
185
+ skyLevel = 1,
138
186
  ): THREE.Group[] {
139
187
  const groups: THREE.Group[] = []
140
- const resolvedShaderMat = shaderMaterial ?? shaderMaterialForExport(material)
188
+ const resolvedShaderMat = shaderMaterial ?? shaderMaterialForExport(material, skyLevel)
141
189
 
142
190
  for (const section of exportData.sections) {
143
191
  const group = new THREE.Group()
@@ -151,7 +199,15 @@ export function createMeshesFromExport(
151
199
  geometry.setAttribute('normal', new THREE.Float32BufferAttribute(section.geometry.normals, 3))
152
200
  }
153
201
  if (section.geometry.colors.length) {
154
- geometry.setAttribute('color', new THREE.Float32BufferAttribute(section.geometry.colors, 3))
202
+ const baked = section.geometry.skyLights?.length
203
+ ? bakeLegacyVertexColors(
204
+ section.geometry.colors,
205
+ section.geometry.skyLights,
206
+ section.geometry.blockLights,
207
+ skyLevel,
208
+ )
209
+ : section.geometry.colors
210
+ geometry.setAttribute('color', new THREE.Float32BufferAttribute(baked, 3))
155
211
  }
156
212
  if (section.geometry.uvs.length) {
157
213
  geometry.setAttribute('uv', new THREE.Float32BufferAttribute(section.geometry.uvs, 2))
@@ -249,10 +305,11 @@ export async function applyWorldGeometryExport(
249
305
  material = rendererMaterial
250
306
  }
251
307
 
308
+ const skyLevel = calculateSkyLightSimple(worldRenderer.timeOfTheDay) / 15
252
309
  const shaderMat = exportData.sections.some(s => (s.shaderCubes?.count ?? 0) > 0)
253
- ? shaderMaterialForExport(material)
310
+ ? shaderMaterialForExport(material, skyLevel)
254
311
  : null
255
- const groups = createMeshesFromExport(exportData, material, shaderMat)
312
+ const groups = createMeshesFromExport(exportData, material, shaderMat, skyLevel)
256
313
  const container = new THREE.Group()
257
314
  container.name = GEOMETRY_EXPORT_GROUP_NAME
258
315
  if (hasEmbeddedTexture) {