minecraft-renderer 0.1.79 → 0.1.81

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 (205) hide show
  1. package/README.md +66 -26
  2. package/dist/mesher.js +36 -36
  3. package/dist/mesher.js.map +4 -4
  4. package/dist/mesherWasm.js +217 -217
  5. package/dist/minecraft-renderer.js +66 -66
  6. package/dist/minecraft-renderer.js.meta.json +1 -1
  7. package/dist/threeWorker.js +450 -450
  8. package/package.json +5 -2
  9. package/src/bundler/bundlePrepare.ts +3 -8
  10. package/src/graphicsBackend/appViewer.ts +10 -7
  11. package/src/graphicsBackend/config.ts +1 -5
  12. package/src/graphicsBackend/playerState.ts +35 -34
  13. package/src/graphicsBackend/preloadWorkers.ts +43 -41
  14. package/src/graphicsBackend/rendererDefaultOptions.ts +68 -70
  15. package/src/graphicsBackend/rendererOptionsSync.ts +24 -50
  16. package/src/graphicsBackend/types.ts +2 -2
  17. package/src/index.ts +6 -27
  18. package/src/lib/DebugGui.ts +34 -31
  19. package/src/lib/animationController.ts +9 -9
  20. package/src/lib/bakeLegacyLight.ts +1 -6
  21. package/src/lib/bindAbortableListener.test.ts +32 -12
  22. package/src/lib/bindAbortableListener.ts +14 -6
  23. package/src/lib/blockEntityLightRegistry.ts +11 -20
  24. package/src/lib/blockEntityLighting.test.ts +1 -6
  25. package/src/lib/blockEntityLighting.ts +5 -5
  26. package/src/lib/buildSharedConfig.mjs +4 -4
  27. package/src/lib/buildWorkerMcDataIndexes.test.ts +4 -4
  28. package/src/lib/buildWorkerMcDataIndexes.ts +11 -19
  29. package/src/lib/cameraBobbing.ts +1 -1
  30. package/src/lib/canvas2DOverlay.example.ts +13 -33
  31. package/src/lib/canvas2DOverlay.quickstart.ts +24 -54
  32. package/src/lib/canvas2DOverlay.ts +28 -47
  33. package/src/lib/cleanupDecorator.ts +2 -2
  34. package/src/lib/createPlayerObject.test.ts +2 -7
  35. package/src/lib/createPlayerObject.ts +18 -25
  36. package/src/lib/frameTimingCollector.ts +2 -5
  37. package/src/lib/guiRenderer.ts +57 -42
  38. package/src/lib/items.ts +15 -9
  39. package/src/lib/mesherlogReader.ts +5 -6
  40. package/src/lib/simpleUtils.ts +5 -5
  41. package/src/lib/skyLight.ts +3 -3
  42. package/src/lib/smoothSwitcher.ts +11 -18
  43. package/src/lib/ui/newStats.ts +10 -12
  44. package/src/lib/utils/proxy.ts +7 -1
  45. package/src/lib/utils/skins.ts +4 -4
  46. package/src/lib/utils.ts +1 -1
  47. package/src/lib/workerMessageSanitize.ts +5 -12
  48. package/src/lib/workerProxy.ts +52 -42
  49. package/src/lib/workerSyncOps.test.ts +58 -41
  50. package/src/lib/worldrendererCommon.reconfigure.test.ts +24 -21
  51. package/src/lib/worldrendererCommon.removeColumn.test.ts +11 -13
  52. package/src/lib/worldrendererCommon.ts +349 -211
  53. package/src/mesher-legacy/mesher.ts +9 -4
  54. package/src/mesher-legacy/test/a.ts +1 -1
  55. package/src/mesher-legacy/test/mesherTester.ts +2 -2
  56. package/src/mesher-legacy/test/playground.ts +1 -1
  57. package/src/mesher-legacy/test/run/test-js.ts +1 -1
  58. package/src/mesher-legacy/test/snapshotUtils.ts +3 -8
  59. package/src/mesher-legacy/test/test-perf.ts +1 -1
  60. package/src/mesher-legacy/test/tests.test.ts +2 -2
  61. package/src/mesher-shared/blockEntityMetadata.test.ts +7 -5
  62. package/src/mesher-shared/blockEntityMetadata.ts +28 -19
  63. package/src/mesher-shared/blockPropertiesForMeshing.ts +2 -2
  64. package/src/mesher-shared/computeHeightmap.ts +2 -4
  65. package/src/mesher-shared/exportedGeometryTypes.ts +3 -3
  66. package/src/mesher-shared/faceOcclusion.ts +324 -0
  67. package/src/mesher-shared/models.ts +80 -131
  68. package/src/mesher-shared/modelsGeometryCommon.ts +30 -15
  69. package/src/mesher-shared/shared.ts +46 -46
  70. package/src/mesher-shared/standaloneRenderer.ts +40 -44
  71. package/src/mesher-shared/tests/faceOcclusion.test.ts +179 -0
  72. package/src/mesher-shared/tests/liquidQuadInvariant.test.ts +12 -8
  73. package/src/mesher-shared/vertexShading.ts +2 -11
  74. package/src/mesher-shared/world.ts +19 -19
  75. package/src/mesher-shared/worldLighting.test.ts +2 -2
  76. package/src/performanceMonitor/PerformanceMonitor.ts +4 -13
  77. package/src/performanceMonitor/formatPerformanceFactorsDebug.ts +2 -2
  78. package/src/performanceMonitor/index.ts +1 -5
  79. package/src/performanceMonitor/types.ts +1 -1
  80. package/src/playerState/playerState.ts +55 -50
  81. package/src/playerState/types.ts +2 -8
  82. package/src/playground/allEntitiesDebug.ts +19 -16
  83. package/src/playground/baseScene.ts +29 -32
  84. package/src/playground/mobileControls.tsx +133 -129
  85. package/src/playground/playground.html +76 -73
  86. package/src/playground/playground.ts +14 -1
  87. package/src/playground/playgroundUi.tsx +100 -74
  88. package/src/playground/reactUtils.ts +3 -7
  89. package/src/playground/scenes/entities.ts +10 -7
  90. package/src/playground/scenes/frequentUpdates.ts +5 -5
  91. package/src/playground/scenes/geometryExport.ts +6 -20
  92. package/src/playground/scenes/highPosEntityUpdates.ts +2 -10
  93. package/src/playground/scenes/index.ts +1 -1
  94. package/src/playground/scenes/lightingStarfield.ts +18 -12
  95. package/src/playground/scenes/main.ts +15 -11
  96. package/src/playground/scenes/partialBlockCulling.ts +31 -0
  97. package/src/playground/scenes/railsCobweb.ts +1 -1
  98. package/src/playground/scenes/rotationIssue.ts +1 -1
  99. package/src/playground/scenes/slabsOptimization.ts +1 -2
  100. package/src/playground/scenes/transparencyIssue.ts +1 -1
  101. package/src/playground/shared.ts +2 -2
  102. package/src/resourcesManager/resourcesManager.ts +29 -54
  103. package/src/resourcesManager/resourcesManager.worker.test.ts +6 -10
  104. package/src/shims/minecraftData.ts +70 -24
  105. package/src/sign-renderer/index.html +10 -12
  106. package/src/sign-renderer/index.ts +29 -29
  107. package/src/sign-renderer/playground.ts +22 -15
  108. package/src/sign-renderer/tests.test.ts +16 -13
  109. package/src/sign-renderer/vite.config.ts +2 -2
  110. package/src/three/appShared.ts +46 -25
  111. package/src/three/bannerRenderer.ts +33 -61
  112. package/src/three/cameraCollisionBlockCache.ts +156 -0
  113. package/src/three/cameraCollisionSolidity.ts +50 -0
  114. package/src/three/cameraShake.ts +15 -6
  115. package/src/three/chunkMeshManager.ts +223 -390
  116. package/src/three/cinimaticScript.ts +26 -15
  117. package/src/three/cubeDrawSpans.ts +27 -37
  118. package/src/three/cubeMultiDraw.ts +9 -22
  119. package/src/three/documentRenderer.ts +15 -18
  120. package/src/three/entities.ts +175 -150
  121. package/src/three/entity/EntityMesh.ts +114 -108
  122. package/src/three/entity/animations.js +3 -3
  123. package/src/three/entity/armorModels.ts +15 -15
  124. package/src/three/entity/gltfAnimationUtils.ts +2 -5
  125. package/src/three/fireworks.ts +34 -32
  126. package/src/three/fireworksRenderer.ts +32 -29
  127. package/src/three/globalBlockBuffer.ts +167 -100
  128. package/src/three/globalLegacyBuffer.ts +248 -264
  129. package/src/three/graphicsBackendBase.ts +19 -25
  130. package/src/three/graphicsBackendOffThread.ts +12 -15
  131. package/src/three/hand.ts +21 -21
  132. package/src/three/handLegacy.ts +3 -13
  133. package/src/three/holdingBlock.ts +116 -79
  134. package/src/three/holdingBlockFactory.ts +1 -4
  135. package/src/three/holdingBlockItemIdentity.test.ts +25 -17
  136. package/src/three/holdingBlockItemIdentity.ts +9 -6
  137. package/src/three/holdingBlockLegacy.ts +113 -132
  138. package/src/three/itemMesh.ts +20 -29
  139. package/src/three/legacyMultiDraw.ts +10 -16
  140. package/src/three/legacySectionCull.ts +8 -14
  141. package/src/three/menuBackground/activeView.ts +1 -4
  142. package/src/three/menuBackground/assetUrl.ts +1 -1
  143. package/src/three/menuBackground/classic.ts +4 -12
  144. package/src/three/menuBackground/gpuPreference.ts +1 -3
  145. package/src/three/menuBackground/index.ts +2 -11
  146. package/src/three/menuBackground/renderer.ts +1 -5
  147. package/src/three/menuBackground/types.ts +1 -4
  148. package/src/three/menuBackground/v2.ts +196 -96
  149. package/src/three/menuBackground/v2Meta.ts +3 -3
  150. package/src/three/menuBackground/worldBlocks.ts +37 -35
  151. package/src/three/modules/blockBreakParticles.ts +59 -28
  152. package/src/three/modules/cameraBobbing.ts +3 -6
  153. package/src/three/modules/index.ts +1 -1
  154. package/src/three/modules/rain.ts +10 -23
  155. package/src/three/modules/sciFiWorldReveal.ts +11 -25
  156. package/src/three/modules/starfield.ts +7 -13
  157. package/src/three/renderSlot.ts +28 -16
  158. package/src/three/rendererModuleSystem.ts +1 -3
  159. package/src/three/sceneOrigin.ts +96 -33
  160. package/src/three/sectionRaycastAabb.ts +24 -110
  161. package/src/three/shaderCubeMesh.ts +6 -17
  162. package/src/three/shaders/cubeBlockShader.ts +85 -96
  163. package/src/three/shaders/legacyBlockShader.ts +21 -43
  164. package/src/three/shaders/textureIndexMapping.ts +89 -95
  165. package/src/three/shaders/tintPalette.ts +156 -170
  166. package/src/three/signTextureCache.ts +9 -12
  167. package/src/three/skyboxRenderer.ts +62 -70
  168. package/src/three/tests/chunkMeshManagerLegacy.test.ts +34 -64
  169. package/src/three/tests/cubeDrawSpans.test.ts +55 -25
  170. package/src/three/tests/globalBlockBuffer.test.ts +217 -0
  171. package/src/three/tests/globalLegacyBuffer.test.ts +300 -41
  172. package/src/three/tests/legacyMultiDraw.test.ts +8 -29
  173. package/src/three/tests/pr3PerFrameCpuCuts.test.ts +106 -29
  174. package/src/three/tests/signTextureCache.test.ts +4 -4
  175. package/src/three/thirdPersonVoxelRaycast.ts +120 -0
  176. package/src/three/threeJsMedia.ts +55 -72
  177. package/src/three/threeJsParticles.ts +32 -41
  178. package/src/three/threeJsSound.ts +3 -3
  179. package/src/three/threeJsUtils.ts +3 -3
  180. package/src/three/threeWorker.ts +2 -2
  181. package/src/three/waypointSprite.ts +55 -82
  182. package/src/three/waypoints.ts +20 -23
  183. package/src/three/world/cursorBlock.ts +25 -12
  184. package/src/three/world/vr.ts +11 -17
  185. package/src/three/worldGeometryExport.ts +15 -34
  186. package/src/three/worldRendererThree.ts +144 -166
  187. package/src/wasm-mesher/bridge/convertChunk.ts +3 -9
  188. package/src/wasm-mesher/bridge/render-from-wasm.ts +204 -229
  189. package/src/wasm-mesher/bridge/shaderCubeBridge.ts +26 -67
  190. package/src/wasm-mesher/tests/cameraCollisionBlockCache.test.ts +82 -0
  191. package/src/wasm-mesher/tests/cullingRegression.test.ts +307 -0
  192. package/src/wasm-mesher/tests/heightmapParity.test.ts +8 -18
  193. package/src/wasm-mesher/tests/mesherWasmConversionCache.test.ts +2 -2
  194. package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +1 -93
  195. package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +103 -141
  196. package/src/wasm-mesher/tests/splitColumnWasmOutput.test.ts +14 -22
  197. package/src/wasm-mesher/tests/thirdPersonVoxelRaycast.test.ts +63 -0
  198. package/src/wasm-mesher/worker/mesherWasm.ts +150 -141
  199. package/src/wasm-mesher/worker/mesherWasmConversionCache.ts +2 -8
  200. package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +1 -3
  201. package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +1 -5
  202. package/src/wasm-mesher/worker/mesherWasmRequestTracker.ts +42 -42
  203. package/src/worldView/worldView.spiral.test.ts +1 -1
  204. package/src/worldView/worldView.ts +34 -39
  205. package/src/worldView/worldViewWorkerBridge.test.ts +4 -4
@@ -17,11 +17,8 @@ import { SECTION_HEIGHT } from '../../mesher-shared/shared'
17
17
  import type { World } from '../../mesher-shared/world'
18
18
  import { resolveBlockPropertiesForMeshing } from '../../mesher-shared/blockPropertiesForMeshing'
19
19
  import { isSemiTransparentBlockName } from '../../mesher-shared/models'
20
- import {
21
- buildShaderCubesFromWords,
22
- getShaderCubeResources,
23
- tryBuildShaderCubeInstances,
24
- } from './shaderCubeBridge'
20
+ import { faceIsCulled } from '../../mesher-shared/faceOcclusion'
21
+ import { buildShaderCubesFromWords, getShaderCubeResources, tryBuildShaderCubeInstances } from './shaderCubeBridge'
25
22
  import { getSideShading, vertexLightFromAo } from '../../mesher-shared/vertexShading'
26
23
  import tintsJson from 'minecraft-data/minecraft-data/data/pc/1.16.2/tints.json'
27
24
 
@@ -131,9 +128,7 @@ export interface WasmGeometryOutput {
131
128
  * shape into a transferable typed array. Tests exercise this same adapter so
132
129
  * future runtime usage and parity assertions cannot drift apart.
133
130
  */
134
- export function extractColumnHeightmap(
135
- wasmOutput: { heightmap?: ArrayLike<number> | null } | null | undefined
136
- ): Int16Array | null {
131
+ export function extractColumnHeightmap(wasmOutput: { heightmap?: ArrayLike<number> | null } | null | undefined): Int16Array | null {
137
132
  const raw = wasmOutput?.heightmap
138
133
  if (!raw || raw.length !== 256) return null
139
134
  if (raw instanceof Int16Array) return new Int16Array(raw)
@@ -142,24 +137,14 @@ export function extractColumnHeightmap(
142
137
  return out
143
138
  }
144
139
 
145
- function computeMesherVertexLight(
146
- world: World | undefined,
147
- ao: number,
148
- cornerLight15: number,
149
- faceDir: [number, number, number]
150
- ): number {
140
+ function computeMesherVertexLight(world: World | undefined, ao: number, cornerLight15: number, faceDir: [number, number, number]): number {
151
141
  const shadingTheme = world?.config.shadingTheme ?? 'high-contrast'
152
142
  const cardinalLight = world?.config.cardinalLight ?? 'default'
153
143
  const sideShading = getSideShading(faceDir, shadingTheme, cardinalLight)
154
144
  return vertexLightFromAo(ao, cornerLight15, sideShading, shadingTheme)
155
145
  }
156
146
 
157
- function vertexTintAoColor (
158
- world: World | undefined,
159
- tint: [number, number, number],
160
- ao: number,
161
- faceDir: [number, number, number],
162
- ): [number, number, number] {
147
+ function vertexTintAoColor(world: World | undefined, tint: [number, number, number], ao: number, faceDir: [number, number, number]): [number, number, number] {
163
148
  const shadingTheme = world?.config.shadingTheme ?? 'high-contrast'
164
149
  const cardinalLight = world?.config.cardinalLight ?? 'default'
165
150
  const sideShading = getSideShading(faceDir, shadingTheme, cardinalLight)
@@ -171,17 +156,17 @@ function vertexTintAoColor (
171
156
  return [tint[0] * f, tint[1] * f, tint[2] * f]
172
157
  }
173
158
 
174
- function sampleChannelLightAt (world: World, pos: Vec3): { block: number, sky: number } {
159
+ function sampleChannelLightAt(world: World, pos: Vec3): { block: number; sky: number } {
175
160
  return world.getChannelLightNorm(pos)
176
161
  }
177
162
 
178
- function smoothChannelLightAt (
163
+ function smoothChannelLightAt(
179
164
  world: World,
180
165
  cursor: Vec3,
181
166
  faceDir: [number, number, number],
182
167
  cornerOffset: [number, number, number],
183
- faceIdx: number,
184
- ): { block: number, sky: number } {
168
+ faceIdx: number
169
+ ): { block: number; sky: number } {
185
170
  const neighbor = cursor.offset(faceDir[0], faceDir[1], faceDir[2])
186
171
  const base = sampleChannelLightAt(world, neighbor)
187
172
 
@@ -190,10 +175,20 @@ function smoothChannelLightAt (
190
175
  }
191
176
 
192
177
  const mask1 = [
193
- [1, 1, 0], [1, 1, 0], [1, 1, 0], [1, 1, 0], [1, 0, 1], [1, 0, 1],
178
+ [1, 1, 0],
179
+ [1, 1, 0],
180
+ [1, 1, 0],
181
+ [1, 1, 0],
182
+ [1, 0, 1],
183
+ [1, 0, 1]
194
184
  ][faceIdx]!
195
185
  const mask2 = [
196
- [0, 1, 1], [0, 1, 1], [1, 0, 1], [1, 0, 1], [0, 1, 1], [0, 1, 1],
186
+ [0, 1, 1],
187
+ [0, 1, 1],
188
+ [1, 0, 1],
189
+ [1, 0, 1],
190
+ [0, 1, 1],
191
+ [0, 1, 1]
197
192
  ][faceIdx]!
198
193
  const [cx, cy, cz] = cornerOffset
199
194
  const [fx, fy, fz] = faceDir
@@ -214,7 +209,7 @@ function smoothChannelLightAt (
214
209
  base,
215
210
  sampleChannelLightAt(world, neighbor.offset(s1[0], s1[1], s1[2])),
216
211
  sampleChannelLightAt(world, neighbor.offset(s2[0], s2[1], s2[2])),
217
- sampleChannelLightAt(world, neighbor.offset(c[0], c[1], c[2])),
212
+ sampleChannelLightAt(world, neighbor.offset(c[0], c[1], c[2]))
218
213
  ]
219
214
 
220
215
  let blockSum = 0
@@ -235,19 +230,13 @@ function getCachedBlockModel(
235
230
  blockProvider: WorldBlockProvider,
236
231
  PrismarineBlock: any,
237
232
  world?: World,
238
- blockPos?: { x: number, y: number, z: number }
233
+ blockPos?: { x: number; y: number; z: number }
239
234
  ): CachedBlockModel | null {
240
235
  const usePreflat = !!(world?.preflat && blockPos)
241
236
  let blockName: string
242
237
  let blockProps: Record<string, unknown>
243
238
  if (usePreflat) {
244
- const resolved = resolveBlockPropertiesForMeshing(
245
- world,
246
- new Vec3(blockPos!.x, blockPos!.y, blockPos!.z),
247
- blockProvider,
248
- blockStateId,
249
- PrismarineBlock
250
- )
239
+ const resolved = resolveBlockPropertiesForMeshing(world, new Vec3(blockPos!.x, blockPos!.y, blockPos!.z), blockProvider, blockStateId, PrismarineBlock)
251
240
  blockName = resolved.name
252
241
  blockProps = resolved.properties
253
242
  } else {
@@ -256,11 +245,9 @@ function getCachedBlockModel(
256
245
  blockProps = blockObj.getProperties()
257
246
  }
258
247
 
259
- const cacheKey = usePreflat
260
- ? `${version}:${blockStateId}:${blockName}:${JSON.stringify(blockProps)}`
261
- : `${version}:${blockStateId}`
248
+ const cacheKey = usePreflat ? `${version}:${blockStateId}:${blockName}:${JSON.stringify(blockProps)}` : `${version}:${blockStateId}`
262
249
  if (!(globalThis as any).__wasmBlockModelCache) {
263
- (globalThis as any).__wasmBlockModelCache = new Map()
250
+ ;(globalThis as any).__wasmBlockModelCache = new Map()
264
251
  }
265
252
  const cache = (globalThis as any).__wasmBlockModelCache
266
253
 
@@ -275,59 +262,54 @@ function getCachedBlockModel(
275
262
  blockProps = blockObj.getProperties()
276
263
  }
277
264
 
278
- const models = blockProvider.getAllResolvedModels0_1(
279
- { name: blockName, properties: blockProps as Record<string, string | number | boolean> },
280
- false
281
- )
265
+ const models = blockProvider.getAllResolvedModels0_1({ name: blockName, properties: blockProps as Record<string, string | number | boolean> }, false)
282
266
 
283
267
  if (!models || models.length === 0) return null
284
268
 
285
269
  // Precompute matrices for all model variants
286
- const modelVariants = models.map((modelVars) => {
287
- return modelVars.map((model) => {
288
- // Calculate global matrix and shift for model rotation
289
- let globalMatrix = null as any
290
- let globalShift = null as any
291
- for (const axis of ['x', 'y', 'z'] as const) {
292
- if (axis in model) {
293
- globalMatrix = globalMatrix
294
- ? matmulmat3(globalMatrix, buildRotationMatrix(axis, -(model[axis] ?? 0)))
295
- : buildRotationMatrix(axis, -(model[axis] ?? 0))
270
+ const modelVariants = models
271
+ .map(modelVars => {
272
+ return modelVars.map(model => {
273
+ // Calculate global matrix and shift for model rotation
274
+ let globalMatrix = null as any
275
+ let globalShift = null as any
276
+ for (const axis of ['x', 'y', 'z'] as const) {
277
+ if (axis in model) {
278
+ globalMatrix = globalMatrix
279
+ ? matmulmat3(globalMatrix, buildRotationMatrix(axis, -(model[axis] ?? 0)))
280
+ : buildRotationMatrix(axis, -(model[axis] ?? 0))
281
+ }
296
282
  }
297
- }
298
- if (globalMatrix) {
299
- globalShift = [8, 8, 8]
300
- globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift))
301
- }
302
-
303
- // Precompute element matrices
304
- const elements = (model.elements ?? []).map((element: any) => {
305
- let localMatrix = null as any
306
- let localShift = null as any
307
- if (element.rotation) {
308
- localMatrix = buildRotationMatrix(
309
- element.rotation.axis,
310
- element.rotation.angle
311
- )
312
- localShift = vecsub3(
313
- element.rotation.origin,
314
- matmul3(localMatrix, element.rotation.origin)
315
- )
283
+ if (globalMatrix) {
284
+ globalShift = [8, 8, 8]
285
+ globalShift = vecsub3(globalShift, matmul3(globalMatrix, globalShift))
316
286
  }
317
- return { element, localMatrix, localShift }
318
- })
319
287
 
320
- return { model, globalMatrix, globalShift, elements }
288
+ // Precompute element matrices
289
+ const elements = (model.elements ?? []).map((element: any) => {
290
+ let localMatrix = null as any
291
+ let localShift = null as any
292
+ if (element.rotation) {
293
+ localMatrix = buildRotationMatrix(element.rotation.axis, element.rotation.angle)
294
+ localShift = vecsub3(element.rotation.origin, matmul3(localMatrix, element.rotation.origin))
295
+ }
296
+ return { element, localMatrix, localShift }
297
+ })
298
+
299
+ return { model, globalMatrix, globalShift, elements }
300
+ })
321
301
  })
322
- }).flat()
302
+ .flat()
323
303
 
324
304
  const isCube = (() => {
325
305
  try {
326
306
  if (!models?.length || models.length !== 1) return false
327
307
  if (blockObj.transparent) return false
328
- return models[0].every((v) => v.elements.every((e) => {
329
- return e.from[0] === 0 && e.from[1] === 0 && e.from[2] === 0 && e.to[0] === 16 && e.to[1] === 16 && e.to[2] === 16
330
- }))
308
+ return models[0].every(v =>
309
+ v.elements.every(e => {
310
+ return e.from[0] === 0 && e.from[1] === 0 && e.from[2] === 0 && e.to[0] === 16 && e.to[1] === 16 && e.to[2] === 16
311
+ })
312
+ )
331
313
  } catch {
332
314
  return false
333
315
  }
@@ -339,7 +321,7 @@ function getCachedBlockModel(
339
321
  models,
340
322
  modelVariants,
341
323
  isCube,
342
- boundingBox: blockObj.boundingBox,
324
+ boundingBox: blockObj.boundingBox
343
325
  }
344
326
 
345
327
  cache.set(cacheKey, cached)
@@ -366,11 +348,7 @@ function getTint(
366
348
  if (blockName === 'redstone_wire') {
367
349
  initializeTints()
368
350
  return tints.redstone[`${blockProps.power}`] || [1, 1, 1]
369
- } else if (
370
- blockName === 'birch_leaves' ||
371
- blockName === 'spruce_leaves' ||
372
- blockName === 'lily_pad'
373
- ) {
351
+ } else if (blockName === 'birch_leaves' || blockName === 'spruce_leaves' || blockName === 'lily_pad') {
374
352
  initializeTints()
375
353
  return tints.constant[blockName] || [1, 1, 1]
376
354
  } else if (blockName.includes('leaves') || blockName === 'vine') {
@@ -385,13 +363,7 @@ function getTint(
385
363
  return [1, 1, 1]
386
364
  }
387
365
 
388
- const ALWAYS_WATERLOGGED = new Set([
389
- 'seagrass',
390
- 'tall_seagrass',
391
- 'kelp',
392
- 'kelp_plant',
393
- 'bubble_column'
394
- ])
366
+ const ALWAYS_WATERLOGGED = new Set(['seagrass', 'tall_seagrass', 'kelp', 'kelp_plant', 'bubble_column'])
395
367
 
396
368
  const isBlockWaterlogged = (block: any) => {
397
369
  const props = block?.getProperties?.()
@@ -430,7 +402,7 @@ const renderLiquidToGeometry = (
430
402
  skyLights: number[],
431
403
  blockLights: number[],
432
404
  uvs: number[],
433
- indices: number[],
405
+ indices: number[]
434
406
  ) => {
435
407
  const heights: number[] = []
436
408
  for (let z = -1; z <= 1; z++) {
@@ -517,14 +489,7 @@ const renderLiquidToGeometry = (
517
489
  blockLights.push(blockNorm)
518
490
  }
519
491
 
520
- indices.push(
521
- baseIndex,
522
- baseIndex + 1,
523
- baseIndex + 2,
524
- baseIndex + 2,
525
- baseIndex + 1,
526
- baseIndex + 3,
527
- )
492
+ indices.push(baseIndex, baseIndex + 1, baseIndex + 2, baseIndex + 2, baseIndex + 1, baseIndex + 3)
528
493
 
529
494
  const dupBase = positions.length / 3
530
495
  for (let v = 0; v < 4; v++) {
@@ -537,14 +502,7 @@ const renderLiquidToGeometry = (
537
502
  skyLights.push(skyLights[src / 3]!)
538
503
  blockLights.push(blockLights[src / 3]!)
539
504
  }
540
- indices.push(
541
- dupBase,
542
- dupBase + 2,
543
- dupBase + 1,
544
- dupBase + 1,
545
- dupBase + 2,
546
- dupBase + 3,
547
- )
505
+ indices.push(dupBase, dupBase + 2, dupBase + 1, dupBase + 1, dupBase + 2, dupBase + 3)
548
506
  }
549
507
  }
550
508
 
@@ -565,9 +523,9 @@ export function renderWasmOutputToGeometry(
565
523
  wasmOutput: WasmGeometryOutput,
566
524
  version: string,
567
525
  sectionKey: string,
568
- sectionPosition: { x: number, y: number, z: number },
526
+ sectionPosition: { x: number; y: number; z: number },
569
527
  world?: World,
570
- options?: RenderWasmOptions,
528
+ options?: RenderWasmOptions
571
529
  ): ExportedSection {
572
530
  const DEBUG = false
573
531
  const log = (...args) => {
@@ -611,16 +569,16 @@ export function renderWasmOutputToGeometry(
611
569
  const blendIndices: number[] = []
612
570
 
613
571
  const liquidQueue: Array<{
614
- pos: Vec3,
615
- type: number,
616
- biome: string,
617
- water: boolean,
618
- isRealWater: boolean,
572
+ pos: Vec3
573
+ type: number
574
+ biome: string
575
+ water: boolean
576
+ isRealWater: boolean
619
577
  }> = []
620
578
 
621
579
  const sectionHeight = options?.sectionHeight ?? SECTION_HEIGHT
622
580
  const shaderCubesEnabled = options?.shaderCubes !== false
623
- const [sectionOx, sectionOy, sectionOz] = sectionKey.split(',').map((v) => parseInt(v, 10))
581
+ const [sectionOx, sectionOy, sectionOz] = sectionKey.split(',').map(v => parseInt(v, 10))
624
582
  const shaderWordBuffer: number[] = []
625
583
  const shaderResources = shaderCubesEnabled ? getShaderCubeResources() : null
626
584
 
@@ -645,7 +603,7 @@ export function renderWasmOutputToGeometry(
645
603
  type: prismBlock.type,
646
604
  biome: biome || 'plains',
647
605
  water: true,
648
- isRealWater: prismBlock.name === 'water' && !waterlogged,
606
+ isRealWater: prismBlock.name === 'water' && !waterlogged
649
607
  })
650
608
  }
651
609
 
@@ -655,7 +613,7 @@ export function renderWasmOutputToGeometry(
655
613
  type: prismBlock.type,
656
614
  biome: biome || 'plains',
657
615
  water: false,
658
- isRealWater: false,
616
+ isRealWater: false
659
617
  })
660
618
  }
661
619
 
@@ -664,29 +622,55 @@ export function renderWasmOutputToGeometry(
664
622
  }
665
623
  }
666
624
 
667
- const cachedModel = getCachedBlockModel(
668
- blockStateId,
669
- version,
670
- blockProvider,
671
- PrismarineBlock,
672
- world,
673
- { x: bx, y: by, z: bz }
674
- )
625
+ const cachedModel = getCachedBlockModel(blockStateId, version, blockProvider, PrismarineBlock, world, { x: bx, y: by, z: bz })
675
626
  if (!cachedModel) continue
676
627
 
628
+ const neighborStateIdCache = new Map<string, number | null>()
629
+
677
630
  if (shaderResources) {
678
631
  const modelVars = cachedModel.models[0]
679
632
  const model = modelVars?.[0]
680
633
  const element = model?.elements?.[0]
681
634
  if (model && element) {
682
635
  const doAO = (model as { ao?: boolean }).ao ?? cachedModel.boundingBox !== 'empty'
636
+
637
+ let forceCullMask = 0
638
+ if (world) {
639
+ const shaderCubeFaceNameToIndex: Record<string, number> = {
640
+ up: 0,
641
+ down: 1,
642
+ east: 2,
643
+ west: 3,
644
+ south: 4,
645
+ north: 5
646
+ }
647
+ for (const faceName of ['up', 'down', 'east', 'west', 'south', 'north'] as const) {
648
+ const faceIdx = shaderCubeFaceNameToIndex[faceName]
649
+ if ((block.visible_faces & (1 << faceIdx)) === 0) continue
650
+ const dir = elemFaces[faceName].dir as [number, number, number]
651
+ const dirKey = `${dir[0]},${dir[1]},${dir[2]}`
652
+ let neighborStateId = neighborStateIdCache.get(dirKey)
653
+ if (neighborStateId === undefined) {
654
+ const neighborBlock = world.getBlock(new Vec3(bx, by, bz).offset(...dir))
655
+ neighborStateId = neighborBlock?.stateId ?? null
656
+ neighborStateIdCache.set(dirKey, neighborStateId)
657
+ }
658
+ if (
659
+ neighborStateId !== null &&
660
+ faceIsCulled(version, element, faceName, neighborStateId, { stateId: blockStateId, name: prismBlock.name }, blockProvider, dir, null)
661
+ ) {
662
+ forceCullMask |= 1 << faceIdx
663
+ }
664
+ }
665
+ }
666
+
683
667
  const emitted = tryBuildShaderCubeInstances(
684
668
  block,
685
669
  {
686
670
  blockName: cachedModel.blockName,
687
671
  blockProps: cachedModel.blockProps,
688
672
  isCube: cachedModel.isCube,
689
- model,
673
+ model
690
674
  },
691
675
  model,
692
676
  {
@@ -696,8 +680,9 @@ export function renderWasmOutputToGeometry(
696
680
  tintPalette: shaderResources.tintPalette,
697
681
  textureIndexMapping: shaderResources.textureIndexMapping,
698
682
  doAO,
683
+ forceCullMask
699
684
  },
700
- shaderWordBuffer,
685
+ shaderWordBuffer
701
686
  )
702
687
  if (emitted) continue
703
688
  }
@@ -716,12 +701,12 @@ export function renderWasmOutputToGeometry(
716
701
  const tgtIdx = routeToBlend ? blendIndices : indices
717
702
 
718
703
  const faceNameToIndex: Record<string, number> = {
719
- 'up': 0,
720
- 'down': 1,
721
- 'east': 2,
722
- 'west': 3,
723
- 'south': 4,
724
- 'north': 5
704
+ up: 0,
705
+ down: 1,
706
+ east: 2,
707
+ west: 3,
708
+ south: 4,
709
+ north: 5
725
710
  }
726
711
 
727
712
  const dirKeyToIndex: Record<string, number> = {
@@ -770,14 +755,8 @@ export function renderWasmOutputToGeometry(
770
755
  let localMatrix = null as any
771
756
  let localShift = null as any
772
757
  if (element.rotation) {
773
- localMatrix = buildRotationMatrix(
774
- element.rotation.axis,
775
- element.rotation.angle
776
- )
777
- localShift = vecsub3(
778
- element.rotation.origin,
779
- matmul3(localMatrix, element.rotation.origin)
780
- )
758
+ localMatrix = buildRotationMatrix(element.rotation.axis, element.rotation.angle)
759
+ localShift = vecsub3(element.rotation.origin, matmul3(localMatrix, element.rotation.origin))
781
760
  }
782
761
 
783
762
  // eslint-disable-next-line guard-for-in
@@ -786,11 +765,7 @@ export function renderWasmOutputToGeometry(
786
765
  const { dir, corners, mask1, mask2 } = elemFaces[faceName]
787
766
 
788
767
  const transformedDir = matmul3(globalMatrix, dir)
789
- const transformedDirI: [number, number, number] = [
790
- Math.round(transformedDir[0]),
791
- Math.round(transformedDir[1]),
792
- Math.round(transformedDir[2]),
793
- ]
768
+ const transformedDirI: [number, number, number] = [Math.round(transformedDir[0]), Math.round(transformedDir[1]), Math.round(transformedDir[2])]
794
769
  const dirKey = `${transformedDirI[0]},${transformedDirI[1]},${transformedDirI[2]}`
795
770
  // faceIdx may be undefined for diagonal-rotated faces (e.g. signs at 45/135/225/315 deg).
796
771
  // Such faces are not representable in the 6-axis WASM visible_faces / ao_data / light_data
@@ -806,8 +781,30 @@ export function renderWasmOutputToGeometry(
806
781
  const maxy = element.to[1]
807
782
  const maxz = element.to[2]
808
783
 
809
- if (matchingEFace.cullface && faceIdx !== undefined) {
810
- if ((block.visible_faces & (1 << faceIdx)) === 0) {
784
+ if (faceIdx !== undefined && (block.visible_faces & (1 << faceIdx)) === 0) {
785
+ continue
786
+ }
787
+
788
+ if (matchingEFace.cullface && world) {
789
+ let neighborStateId = neighborStateIdCache.get(dirKey)
790
+ if (neighborStateId === undefined) {
791
+ const neighborBlock = world.getBlock(new Vec3(bx, by, bz).offset(...transformedDirI))
792
+ neighborStateId = neighborBlock?.stateId ?? null
793
+ neighborStateIdCache.set(dirKey, neighborStateId)
794
+ }
795
+ if (
796
+ neighborStateId !== null &&
797
+ faceIsCulled(
798
+ version,
799
+ element,
800
+ faceName,
801
+ neighborStateId,
802
+ { stateId: blockStateId, name: prismBlock.name },
803
+ blockProvider,
804
+ transformedDirI,
805
+ globalMatrix
806
+ )
807
+ ) {
811
808
  continue
812
809
  }
813
810
  }
@@ -828,8 +825,8 @@ export function renderWasmOutputToGeometry(
828
825
  if (faceName === 'down') {
829
826
  r += 180
830
827
  }
831
- const uvcs = Math.cos(r * Math.PI / 180)
832
- const uvsn = -Math.sin(r * Math.PI / 180)
828
+ const uvcs = Math.cos((r * Math.PI) / 180)
829
+ const uvsn = -Math.sin((r * Math.PI) / 180)
833
830
 
834
831
  const tint = getTint(matchingEFace, cachedModel.blockName, cachedModel.blockProps, biome, world)
835
832
 
@@ -838,21 +835,13 @@ export function renderWasmOutputToGeometry(
838
835
  for (let cornerIdx = 0; cornerIdx < 4; cornerIdx++) {
839
836
  const pos = corners[cornerIdx]
840
837
 
841
- let vertex = [
842
- (pos[0] ? maxx : minx),
843
- (pos[1] ? maxy : miny),
844
- (pos[2] ? maxz : minz)
845
- ]
838
+ let vertex = [pos[0] ? maxx : minx, pos[1] ? maxy : miny, pos[2] ? maxz : minz]
846
839
 
847
840
  vertex = vecadd3(matmul3(localMatrix, vertex), localShift)
848
841
  vertex = vecadd3(matmul3(globalMatrix, vertex), globalShift)
849
842
  vertex = vertex.map(v => v / 16)
850
843
 
851
- const worldPos = [
852
- vertex[0] + (bx & 15) - 8,
853
- vertex[1] + (by & 15) - 8,
854
- vertex[2] + (bz & 15) - 8
855
- ]
844
+ const worldPos = [vertex[0] + (bx & 15) - 8, vertex[1] + (by & 15) - 8, vertex[2] + (bz & 15) - 8]
856
845
 
857
846
  tgtPos.push(...worldPos)
858
847
 
@@ -890,20 +879,12 @@ export function renderWasmOutputToGeometry(
890
879
  const side2Block = world.shouldMakeAo(side2) ? 1 : 0
891
880
  const cornerBlock = world.shouldMakeAo(corner) ? 1 : 0
892
881
 
893
- ao = (side1Block && side2Block) ? 0 : (3 - (side1Block + side2Block + cornerBlock))
882
+ ao = side1Block && side2Block ? 0 : 3 - (side1Block + side2Block + cornerBlock)
894
883
  computedAoValues[cornerIdx] = ao
895
884
 
896
885
  const cornerDirL = matmul3(globalMatrix, [dx, dy, dz])
897
- const cornerOffsetI: [number, number, number] = [
898
- Math.round(cornerDirL[0]), Math.round(cornerDirL[1]), Math.round(cornerDirL[2]),
899
- ]
900
- const channels = smoothChannelLightAt(
901
- world,
902
- cursor,
903
- faceDir,
904
- cornerOffsetI,
905
- faceIdx ?? 0,
906
- )
886
+ const cornerOffsetI: [number, number, number] = [Math.round(cornerDirL[0]), Math.round(cornerDirL[1]), Math.round(cornerDirL[2])]
887
+ const channels = smoothChannelLightAt(world, cursor, faceDir, cornerOffsetI, faceIdx ?? 0)
907
888
  skyLightNorm = channels.sky
908
889
  blockLightNorm = channels.block
909
890
  } else {
@@ -948,7 +929,6 @@ export function renderWasmOutputToGeometry(
948
929
  }
949
930
  }
950
931
  }
951
-
952
932
  }
953
933
 
954
934
  if (world && liquidQueue.length) {
@@ -972,7 +952,7 @@ export function renderWasmOutputToGeometry(
972
952
  blendSkyLights,
973
953
  blendBlockLights,
974
954
  blendUvs,
975
- blendIndices,
955
+ blendIndices
976
956
  )
977
957
  }
978
958
  }
@@ -989,20 +969,22 @@ export function renderWasmOutputToGeometry(
989
969
  skyLights,
990
970
  blockLights,
991
971
  uvs,
992
- indices,
972
+ indices
993
973
  },
994
- ...(blendPositions.length > 0 ? {
995
- blendGeometry: {
996
- positions: blendPositions,
997
- normals: blendNormals,
998
- colors: blendColors,
999
- skyLights: blendSkyLights,
1000
- blockLights: blendBlockLights,
1001
- uvs: blendUvs,
1002
- indices: blendIndices,
1003
- },
1004
- } : {}),
1005
- ...(shaderCubes ? { shaderCubes } : {}),
974
+ ...(blendPositions.length > 0
975
+ ? {
976
+ blendGeometry: {
977
+ positions: blendPositions,
978
+ normals: blendNormals,
979
+ colors: blendColors,
980
+ skyLights: blendSkyLights,
981
+ blockLights: blendBlockLights,
982
+ uvs: blendUvs,
983
+ indices: blendIndices
984
+ }
985
+ }
986
+ : {}),
987
+ ...(shaderCubes ? { shaderCubes } : {})
1006
988
  }
1007
989
 
1008
990
  log(`[WASM] Final geometry summary:`)
@@ -1049,9 +1031,9 @@ export function renderWasmOutputToGeometry(
1049
1031
  */
1050
1032
  export function splitColumnWasmOutputToSections(
1051
1033
  fullColumnOutput: WasmGeometryOutput,
1052
- requestedSectionKeys: Array<{ x: number, y: number, z: number }>,
1053
- ctx: { version: string, world?: World, sectionHeight?: number, shaderCubes?: boolean }
1054
- ): Map<string, { exported: ExportedSection, blocksCount: number }> {
1034
+ requestedSectionKeys: Array<{ x: number; y: number; z: number }>,
1035
+ ctx: { version: string; world?: World; sectionHeight?: number; shaderCubes?: boolean }
1036
+ ): Map<string, { exported: ExportedSection; blocksCount: number }> {
1055
1037
  const { version, world } = ctx
1056
1038
  const sectionHeight = ctx.sectionHeight ?? SECTION_HEIGHT
1057
1039
 
@@ -1070,7 +1052,7 @@ export function splitColumnWasmOutputToSections(
1070
1052
  bucket.push(block)
1071
1053
  }
1072
1054
 
1073
- const out = new Map<string, { exported: ExportedSection, blocksCount: number }>()
1055
+ const out = new Map<string, { exported: ExportedSection; blocksCount: number }>()
1074
1056
  for (const { x, y, z } of requestedSectionKeys) {
1075
1057
  // `y` here is the section's world-Y origin (multiple of sectionHeight),
1076
1058
  // matching the convention used by `mesherWasm.ts` (section keys are
@@ -1082,19 +1064,12 @@ export function splitColumnWasmOutputToSections(
1082
1064
  const sectionView: WasmGeometryOutput = {
1083
1065
  blocks: sectionBlocks,
1084
1066
  block_count: sectionBlocks.length,
1085
- block_iterations: fullColumnOutput.block_iterations,
1067
+ block_iterations: fullColumnOutput.block_iterations
1086
1068
  }
1087
1069
 
1088
1070
  const sectionKey = `${x},${y},${z}`
1089
1071
  const sectionPosition = { x: x + 8, y: y + 8, z: z + 8 }
1090
- const exported = renderWasmOutputToGeometry(
1091
- sectionView,
1092
- version,
1093
- sectionKey,
1094
- sectionPosition,
1095
- world,
1096
- { sectionHeight, shaderCubes: ctx.shaderCubes },
1097
- )
1072
+ const exported = renderWasmOutputToGeometry(sectionView, version, sectionKey, sectionPosition, world, { sectionHeight, shaderCubes: ctx.shaderCubes })
1098
1073
  out.set(sectionKey, { exported, blocksCount: sectionBlocks.length })
1099
1074
  }
1100
1075
 
@@ -1108,13 +1083,13 @@ export function wasmOutputToExportFormat(
1108
1083
  wasmOutput: WasmGeometryOutput,
1109
1084
  version: string,
1110
1085
  sectionKey: string,
1111
- sectionPosition: { x: number, y: number, z: number },
1086
+ sectionPosition: { x: number; y: number; z: number },
1112
1087
  cameraPosition = { x: 0, y: 0, z: 0 },
1113
1088
  cameraRotation = { pitch: 0, yaw: 0 },
1114
1089
  world?: World
1115
1090
  ): ExportedWorldGeometry {
1116
1091
  const section = renderWasmOutputToGeometry(wasmOutput, version, sectionKey, sectionPosition, world, {
1117
- shaderCubes: true,
1092
+ shaderCubes: true
1118
1093
  })
1119
1094
 
1120
1095
  return {
@@ -1122,9 +1097,9 @@ export function wasmOutputToExportFormat(
1122
1097
  exportedAt: new Date().toISOString(),
1123
1098
  camera: {
1124
1099
  position: cameraPosition,
1125
- rotation: cameraRotation,
1100
+ rotation: cameraRotation
1126
1101
  },
1127
- sections: [section],
1102
+ sections: [section]
1128
1103
  }
1129
1104
  }
1130
1105
 
@@ -1137,16 +1112,14 @@ export function mesherGeometryToExportFormat(
1137
1112
  version: string,
1138
1113
  cameraPosition = { x: 0, y: 0, z: 0 },
1139
1114
  cameraRotation = { pitch: 0, yaw: 0 },
1140
- skyLevel = 1,
1115
+ skyLevel = 1
1141
1116
  ): ExportedWorldGeometry {
1142
1117
  const positions = Array.from(mesherGeometry.positions) as number[]
1143
1118
  const normals = mesherGeometry.normals ? (Array.from(mesherGeometry.normals) as number[]) : []
1144
1119
  const tintColors = mesherGeometry.colors ? (Array.from(mesherGeometry.colors) as number[]) : []
1145
1120
  const skyLights = mesherGeometry.skyLights ? (Array.from(mesherGeometry.skyLights) as number[]) : []
1146
1121
  const blockLights = mesherGeometry.blockLights ? (Array.from(mesherGeometry.blockLights) as number[]) : []
1147
- const colors = skyLights.length
1148
- ? bakeLegacyVertexColors(tintColors, skyLights, blockLights, skyLevel)
1149
- : tintColors
1122
+ const colors = skyLights.length ? bakeLegacyVertexColors(tintColors, skyLights, blockLights, skyLevel) : tintColors
1150
1123
  const uvs = mesherGeometry.uvs ? (Array.from(mesherGeometry.uvs) as number[]) : []
1151
1124
  const indices = Array.from(mesherGeometry.indices) as number[]
1152
1125
 
@@ -1157,7 +1130,7 @@ export function mesherGeometryToExportFormat(
1157
1130
  const sectionPosition = {
1158
1131
  x: mesherGeometry.sx,
1159
1132
  y: mesherGeometry.sy,
1160
- z: mesherGeometry.sz,
1133
+ z: mesherGeometry.sz
1161
1134
  }
1162
1135
 
1163
1136
  const section: ExportedSection = {
@@ -1170,24 +1143,26 @@ export function mesherGeometryToExportFormat(
1170
1143
  skyLights,
1171
1144
  blockLights,
1172
1145
  uvs,
1173
- indices,
1146
+ indices
1174
1147
  },
1175
- ...(mesherGeometry.blend ? {
1176
- blendGeometry: {
1177
- positions: Array.from(mesherGeometry.blend.positions),
1178
- normals: Array.from(mesherGeometry.blend.normals),
1179
- colors: bakeLegacyVertexColors(
1180
- Array.from(mesherGeometry.blend.colors),
1181
- Array.from(mesherGeometry.blend.skyLights),
1182
- Array.from(mesherGeometry.blend.blockLights),
1183
- skyLevel,
1184
- ),
1185
- skyLights: Array.from(mesherGeometry.blend.skyLights),
1186
- blockLights: Array.from(mesherGeometry.blend.blockLights),
1187
- uvs: Array.from(mesherGeometry.blend.uvs),
1188
- indices: Array.from(mesherGeometry.blend.indices),
1189
- },
1190
- } : {}),
1148
+ ...(mesherGeometry.blend
1149
+ ? {
1150
+ blendGeometry: {
1151
+ positions: Array.from(mesherGeometry.blend.positions),
1152
+ normals: Array.from(mesherGeometry.blend.normals),
1153
+ colors: bakeLegacyVertexColors(
1154
+ Array.from(mesherGeometry.blend.colors),
1155
+ Array.from(mesherGeometry.blend.skyLights),
1156
+ Array.from(mesherGeometry.blend.blockLights),
1157
+ skyLevel
1158
+ ),
1159
+ skyLights: Array.from(mesherGeometry.blend.skyLights),
1160
+ blockLights: Array.from(mesherGeometry.blend.blockLights),
1161
+ uvs: Array.from(mesherGeometry.blend.uvs),
1162
+ indices: Array.from(mesherGeometry.blend.indices)
1163
+ }
1164
+ }
1165
+ : {})
1191
1166
  }
1192
1167
 
1193
1168
  return {
@@ -1195,8 +1170,8 @@ export function mesherGeometryToExportFormat(
1195
1170
  exportedAt: new Date().toISOString(),
1196
1171
  camera: {
1197
1172
  position: cameraPosition,
1198
- rotation: cameraRotation,
1173
+ rotation: cameraRotation
1199
1174
  },
1200
- sections: [section],
1175
+ sections: [section]
1201
1176
  }
1202
1177
  }