minecraft-renderer 0.1.78 → 0.1.80
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 +29 -25
- package/dist/mesher.js +36 -36
- package/dist/mesher.js.map +4 -4
- package/dist/mesherWasm.js +217 -217
- package/dist/minecraft-renderer.js +32 -32
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +415 -415
- package/package.json +5 -2
- package/src/bundler/bundlePrepare.ts +3 -8
- package/src/graphicsBackend/appViewer.ts +10 -7
- package/src/graphicsBackend/config.ts +1 -5
- package/src/graphicsBackend/playerState.ts +35 -34
- package/src/graphicsBackend/preloadWorkers.ts +43 -41
- package/src/graphicsBackend/rendererDefaultOptions.ts +68 -70
- package/src/graphicsBackend/rendererOptionsSync.ts +24 -50
- package/src/graphicsBackend/types.ts +2 -2
- package/src/index.ts +6 -27
- package/src/lib/DebugGui.ts +34 -31
- package/src/lib/animationController.ts +9 -9
- package/src/lib/bakeLegacyLight.ts +1 -6
- package/src/lib/bindAbortableListener.test.ts +32 -12
- package/src/lib/bindAbortableListener.ts +14 -6
- package/src/lib/blockEntityLightRegistry.ts +11 -20
- package/src/lib/blockEntityLighting.test.ts +1 -6
- package/src/lib/blockEntityLighting.ts +5 -5
- package/src/lib/buildSharedConfig.mjs +4 -4
- package/src/lib/buildWorkerMcDataIndexes.test.ts +4 -4
- package/src/lib/buildWorkerMcDataIndexes.ts +11 -19
- package/src/lib/cameraBobbing.ts +1 -1
- package/src/lib/canvas2DOverlay.example.ts +13 -33
- package/src/lib/canvas2DOverlay.quickstart.ts +24 -54
- package/src/lib/canvas2DOverlay.ts +28 -47
- package/src/lib/cleanupDecorator.ts +2 -2
- package/src/lib/createPlayerObject.test.ts +2 -7
- package/src/lib/createPlayerObject.ts +18 -25
- package/src/lib/frameTimingCollector.ts +2 -5
- package/src/lib/guiRenderer.ts +57 -42
- package/src/lib/items.ts +15 -9
- package/src/lib/mesherlogReader.ts +5 -6
- package/src/lib/simpleUtils.ts +5 -5
- package/src/lib/skyLight.ts +3 -3
- package/src/lib/smoothSwitcher.ts +11 -18
- package/src/lib/ui/newStats.ts +10 -12
- package/src/lib/utils/proxy.ts +7 -1
- package/src/lib/utils/skins.ts +4 -4
- package/src/lib/utils.ts +1 -1
- package/src/lib/workerMessageSanitize.ts +5 -12
- package/src/lib/workerProxy.ts +52 -42
- package/src/lib/workerSyncOps.test.ts +58 -41
- package/src/lib/worldrendererCommon.reconfigure.test.ts +24 -21
- package/src/lib/worldrendererCommon.removeColumn.test.ts +11 -13
- package/src/lib/worldrendererCommon.ts +338 -211
- package/src/mesher-legacy/mesher.ts +9 -4
- package/src/mesher-legacy/test/a.ts +1 -1
- package/src/mesher-legacy/test/mesherTester.ts +2 -2
- package/src/mesher-legacy/test/playground.ts +1 -1
- package/src/mesher-legacy/test/run/test-js.ts +1 -1
- package/src/mesher-legacy/test/snapshotUtils.ts +3 -8
- package/src/mesher-legacy/test/test-perf.ts +1 -1
- package/src/mesher-legacy/test/tests.test.ts +2 -2
- package/src/mesher-shared/blockEntityMetadata.test.ts +7 -5
- package/src/mesher-shared/blockEntityMetadata.ts +28 -19
- package/src/mesher-shared/blockPropertiesForMeshing.ts +2 -2
- package/src/mesher-shared/computeHeightmap.ts +2 -4
- package/src/mesher-shared/exportedGeometryTypes.ts +3 -3
- package/src/mesher-shared/faceOcclusion.ts +324 -0
- package/src/mesher-shared/models.ts +80 -131
- package/src/mesher-shared/modelsGeometryCommon.ts +30 -15
- package/src/mesher-shared/shared.ts +46 -46
- package/src/mesher-shared/standaloneRenderer.ts +40 -44
- package/src/mesher-shared/tests/faceOcclusion.test.ts +179 -0
- package/src/mesher-shared/tests/liquidQuadInvariant.test.ts +12 -8
- package/src/mesher-shared/vertexShading.ts +2 -11
- package/src/mesher-shared/world.ts +19 -19
- package/src/mesher-shared/worldLighting.test.ts +2 -2
- package/src/performanceMonitor/PerformanceMonitor.ts +4 -13
- package/src/performanceMonitor/formatPerformanceFactorsDebug.ts +2 -2
- package/src/performanceMonitor/index.ts +1 -5
- package/src/performanceMonitor/types.ts +1 -1
- package/src/playerState/playerState.ts +55 -50
- package/src/playerState/types.ts +2 -8
- package/src/playground/allEntitiesDebug.ts +19 -16
- package/src/playground/baseScene.ts +29 -32
- package/src/playground/mobileControls.tsx +133 -129
- package/src/playground/playground.html +76 -73
- package/src/playground/playground.ts +14 -1
- package/src/playground/playgroundUi.tsx +100 -74
- package/src/playground/reactUtils.ts +3 -7
- package/src/playground/scenes/entities.ts +10 -7
- package/src/playground/scenes/frequentUpdates.ts +5 -5
- package/src/playground/scenes/geometryExport.ts +6 -20
- package/src/playground/scenes/highPosEntityUpdates.ts +2 -10
- package/src/playground/scenes/index.ts +1 -1
- package/src/playground/scenes/lightingStarfield.ts +18 -12
- package/src/playground/scenes/main.ts +15 -11
- package/src/playground/scenes/partialBlockCulling.ts +31 -0
- package/src/playground/scenes/railsCobweb.ts +1 -1
- package/src/playground/scenes/rotationIssue.ts +1 -1
- package/src/playground/scenes/slabsOptimization.ts +1 -2
- package/src/playground/scenes/transparencyIssue.ts +1 -1
- package/src/playground/shared.ts +2 -2
- package/src/resourcesManager/resourcesManager.ts +29 -54
- package/src/resourcesManager/resourcesManager.worker.test.ts +6 -10
- package/src/shims/minecraftData.ts +70 -24
- package/src/sign-renderer/index.html +10 -12
- package/src/sign-renderer/index.ts +29 -29
- package/src/sign-renderer/playground.ts +22 -15
- package/src/sign-renderer/tests.test.ts +16 -13
- package/src/sign-renderer/vite.config.ts +2 -2
- package/src/three/appShared.ts +46 -25
- package/src/three/bannerRenderer.ts +33 -61
- package/src/three/cameraShake.ts +15 -6
- package/src/three/chunkMeshManager.ts +329 -301
- package/src/three/cinimaticScript.ts +26 -15
- package/src/three/cubeDrawSpans.ts +27 -37
- package/src/three/cubeMultiDraw.ts +9 -22
- package/src/three/documentRenderer.ts +15 -18
- package/src/three/entities.ts +175 -150
- package/src/three/entity/EntityMesh.ts +114 -108
- package/src/three/entity/animations.js +3 -3
- package/src/three/entity/armorModels.ts +15 -15
- package/src/three/entity/gltfAnimationUtils.ts +2 -5
- package/src/three/fireworks.ts +34 -32
- package/src/three/fireworksRenderer.ts +32 -29
- package/src/three/globalBlockBuffer.ts +174 -99
- package/src/three/globalLegacyBuffer.ts +465 -136
- package/src/three/graphicsBackendBase.ts +19 -25
- package/src/three/graphicsBackendOffThread.ts +12 -15
- package/src/three/hand.ts +21 -21
- package/src/three/handLegacy.ts +3 -13
- package/src/three/holdingBlock.ts +116 -79
- package/src/three/holdingBlockFactory.ts +1 -4
- package/src/three/holdingBlockItemIdentity.test.ts +25 -17
- package/src/three/holdingBlockItemIdentity.ts +9 -6
- package/src/three/holdingBlockLegacy.ts +113 -132
- package/src/three/itemMesh.ts +20 -29
- package/src/three/legacyMultiDraw.ts +93 -0
- package/src/three/legacySectionCull.ts +8 -14
- package/src/three/menuBackground/activeView.ts +1 -4
- package/src/three/menuBackground/assetUrl.ts +1 -1
- package/src/three/menuBackground/classic.ts +4 -12
- package/src/three/menuBackground/gpuPreference.ts +1 -3
- package/src/three/menuBackground/index.ts +2 -11
- package/src/three/menuBackground/renderer.ts +1 -5
- package/src/three/menuBackground/types.ts +1 -4
- package/src/three/menuBackground/v2.ts +196 -96
- package/src/three/menuBackground/v2Meta.ts +3 -3
- package/src/three/menuBackground/worldBlocks.ts +37 -35
- package/src/three/modules/blockBreakParticles.ts +59 -28
- package/src/three/modules/cameraBobbing.ts +3 -6
- package/src/three/modules/index.ts +1 -1
- package/src/three/modules/rain.ts +10 -23
- package/src/three/modules/sciFiWorldReveal.ts +11 -25
- package/src/three/modules/starfield.ts +7 -13
- package/src/three/renderSlot.ts +28 -16
- package/src/three/rendererModuleSystem.ts +1 -3
- package/src/three/sceneOrigin.ts +96 -33
- package/src/three/sectionRaycastAabb.ts +30 -18
- package/src/three/shaderCubeMesh.ts +6 -17
- package/src/three/shaders/cubeBlockShader.ts +85 -96
- package/src/three/shaders/legacyBlockShader.ts +21 -43
- package/src/three/shaders/textureIndexMapping.ts +89 -95
- package/src/three/shaders/tintPalette.ts +156 -170
- package/src/three/signTextureCache.ts +9 -12
- package/src/three/skyboxRenderer.ts +62 -70
- package/src/three/tests/chunkMeshManagerLegacy.test.ts +133 -25
- package/src/three/tests/cubeDrawSpans.test.ts +55 -25
- package/src/three/tests/globalBlockBuffer.test.ts +217 -0
- package/src/three/tests/globalLegacyBuffer.test.ts +460 -58
- package/src/three/tests/legacyMultiDraw.test.ts +88 -0
- package/src/three/tests/pr3PerFrameCpuCuts.test.ts +370 -0
- package/src/three/tests/signTextureCache.test.ts +4 -4
- package/src/three/threeJsMedia.ts +55 -72
- package/src/three/threeJsParticles.ts +32 -41
- package/src/three/threeJsSound.ts +3 -3
- package/src/three/threeJsUtils.ts +3 -3
- package/src/three/threeWorker.ts +2 -2
- package/src/three/waypointSprite.ts +55 -82
- package/src/three/waypoints.ts +20 -23
- package/src/three/world/cursorBlock.ts +25 -12
- package/src/three/world/vr.ts +11 -17
- package/src/three/worldGeometryExport.ts +15 -34
- package/src/three/worldRendererThree.ts +131 -133
- package/src/wasm-mesher/bridge/convertChunk.ts +3 -9
- package/src/wasm-mesher/bridge/render-from-wasm.ts +204 -229
- package/src/wasm-mesher/bridge/shaderCubeBridge.ts +26 -67
- package/src/wasm-mesher/tests/cullingRegression.test.ts +307 -0
- package/src/wasm-mesher/tests/heightmapParity.test.ts +8 -18
- package/src/wasm-mesher/tests/mesherWasmConversionCache.test.ts +2 -2
- package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +17 -4
- package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +103 -141
- package/src/wasm-mesher/tests/splitColumnWasmOutput.test.ts +14 -22
- package/src/wasm-mesher/worker/mesherWasm.ts +150 -141
- package/src/wasm-mesher/worker/mesherWasmConversionCache.ts +2 -8
- package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +1 -3
- package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +1 -5
- package/src/wasm-mesher/worker/mesherWasmRequestTracker.ts +42 -42
- package/src/worldView/worldView.spiral.test.ts +1 -1
- package/src/worldView/worldView.ts +34 -39
- package/src/worldView/worldViewWorkerBridge.test.ts +4 -4
|
@@ -4,8 +4,24 @@ import * as nbt from 'prismarine-nbt'
|
|
|
4
4
|
import { Vec3 } from 'vec3'
|
|
5
5
|
import { MesherGeometryOutput } from '../mesher-shared/shared'
|
|
6
6
|
import { getShaderCubeResources, SHADER_CUBES_WORDS_PER_FACE } from '../wasm-mesher/bridge/shaderCubeBridge'
|
|
7
|
-
import {
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
createCubeBlockMaterial,
|
|
9
|
+
computeSectionOriginRel,
|
|
10
|
+
setCubeSkyLevel,
|
|
11
|
+
setCubeShadingTheme,
|
|
12
|
+
setCubeLightmapParams,
|
|
13
|
+
type BlockLightmapParams
|
|
14
|
+
} from './shaders/cubeBlockShader'
|
|
15
|
+
import {
|
|
16
|
+
computeCameraRelativeUniforms,
|
|
17
|
+
createGlobalLegacyBlendMaterial,
|
|
18
|
+
createGlobalLegacyBlockMaterial,
|
|
19
|
+
createLegacyBlockMaterial,
|
|
20
|
+
setLegacyCameraOrigin,
|
|
21
|
+
setLegacySkyLevel,
|
|
22
|
+
setLegacyLightmapParams,
|
|
23
|
+
type RenderOrigin
|
|
24
|
+
} from './shaders/legacyBlockShader'
|
|
9
25
|
import { LEGACY_SECTION_HALF_EXTENT, sectionIntersectsFrustum, setupLegacySectionMatrix, updateLegacySectionCullState } from './legacySectionCull'
|
|
10
26
|
import { createShaderCubeMesh, disposeShaderCubeMesh } from './shaderCubeMesh'
|
|
11
27
|
import { GlobalBlockBuffer } from './globalBlockBuffer'
|
|
@@ -17,7 +33,7 @@ import {
|
|
|
17
33
|
raycastAabb,
|
|
18
34
|
raycastShaderBlocksAabb,
|
|
19
35
|
sectionAabbIntersectsRay,
|
|
20
|
-
type ShaderSectionRaycastEntry
|
|
36
|
+
type ShaderSectionRaycastEntry
|
|
21
37
|
} from './sectionRaycastAabb'
|
|
22
38
|
import { getMesh } from './entity/EntityMesh'
|
|
23
39
|
import type { WorldRendererThree } from './worldRendererThree'
|
|
@@ -39,7 +55,7 @@ export interface SectionObject extends THREE.Group {
|
|
|
39
55
|
/** Per-section instanced shader mesh (sci-fi reveal defer only). */
|
|
40
56
|
shaderMesh?: THREE.Mesh<THREE.InstancedBufferGeometry, THREE.ShaderMaterial>
|
|
41
57
|
/** Shader cube words kept for migration to global buffer after reveal. */
|
|
42
|
-
deferredShaderCubes?: { words: Uint32Array
|
|
58
|
+
deferredShaderCubes?: { words: Uint32Array; count: number }
|
|
43
59
|
/** Opaque legacy geometry deferred from global buffer during sci-fi reveal. */
|
|
44
60
|
deferredLegacyOpaque?: LegacySectionGeometry
|
|
45
61
|
/** Blend legacy geometry deferred from global buffer during sci-fi reveal. */
|
|
@@ -139,7 +155,11 @@ export class ChunkMeshManager {
|
|
|
139
155
|
private readonly _legacyCullBox = new THREE.Box3()
|
|
140
156
|
private readonly _legacyCullBoxMin = new THREE.Vector3()
|
|
141
157
|
private readonly _legacyCullBoxMax = new THREE.Vector3()
|
|
142
|
-
private readonly _visibleSectionSpans: Array<{ key: string
|
|
158
|
+
private readonly _visibleSectionSpans: Array<{ key: string; distSq: number }> = []
|
|
159
|
+
/** Sections with geometry in global legacy opaque and/or blend buffers — cull/raycast scan only these. */
|
|
160
|
+
private readonly legacyCullSections = new Map<string, { worldX: number; worldY: number; worldZ: number }>()
|
|
161
|
+
private _lastCullFingerprint = ''
|
|
162
|
+
private lastBufferStateKey = ''
|
|
143
163
|
/** Drives per-frame cull + span rebuild; cleared after updateSectionCullAndSort. */
|
|
144
164
|
cullDirty = true
|
|
145
165
|
private readonly _lastCullCamPos = new THREE.Vector3()
|
|
@@ -170,20 +190,20 @@ export class ChunkMeshManager {
|
|
|
170
190
|
private lastPerformanceCheck = 0
|
|
171
191
|
private readonly performanceCheckInterval = 2000 // Check every 2 seconds
|
|
172
192
|
|
|
173
|
-
get performanceOverrideDistance
|
|
193
|
+
get performanceOverrideDistance() {
|
|
174
194
|
return this._performanceOverrideDistance ?? 0
|
|
175
195
|
}
|
|
176
|
-
set performanceOverrideDistance
|
|
196
|
+
set performanceOverrideDistance(value: number | undefined) {
|
|
177
197
|
this._performanceOverrideDistance = value
|
|
178
198
|
this.updateSectionsVisibility()
|
|
179
199
|
}
|
|
180
200
|
|
|
181
|
-
constructor
|
|
201
|
+
constructor(
|
|
182
202
|
public worldRenderer: WorldRendererThree,
|
|
183
203
|
public scene: THREE.Object3D,
|
|
184
204
|
public material: THREE.Material,
|
|
185
205
|
public worldHeight: number,
|
|
186
|
-
viewDistance = 3
|
|
206
|
+
viewDistance = 3
|
|
187
207
|
) {
|
|
188
208
|
this.updateViewDistance(viewDistance)
|
|
189
209
|
this.signHeadsRenderer = new SignHeadsRenderer(worldRenderer)
|
|
@@ -191,7 +211,7 @@ export class ChunkMeshManager {
|
|
|
191
211
|
this.initializePool()
|
|
192
212
|
}
|
|
193
213
|
|
|
194
|
-
private initializePool
|
|
214
|
+
private initializePool() {
|
|
195
215
|
// Create initial pool
|
|
196
216
|
for (let i = 0; i < this.poolSize; i++) {
|
|
197
217
|
const geometry = new THREE.BufferGeometry()
|
|
@@ -212,18 +232,18 @@ export class ChunkMeshManager {
|
|
|
212
232
|
}
|
|
213
233
|
|
|
214
234
|
/** True when section has legacy vertices and/or GPU shader cube instances. */
|
|
215
|
-
sectionHasRenderableContent
|
|
235
|
+
sectionHasRenderableContent(geometryData: MesherGeometryOutput): boolean {
|
|
216
236
|
if (geometryData.positions.length > 0) return true
|
|
217
237
|
if ((geometryData.blend?.positions.length ?? 0) > 0) return true
|
|
218
238
|
if (!this.isShaderCubesGpuEnabled()) return false
|
|
219
239
|
return (geometryData.shaderCubes?.count ?? 0) > 0
|
|
220
240
|
}
|
|
221
241
|
|
|
222
|
-
isShaderCubesGpuEnabled
|
|
242
|
+
isShaderCubesGpuEnabled(): boolean {
|
|
223
243
|
return this.worldRenderer.shaderCubeBlocksEnabled()
|
|
224
244
|
}
|
|
225
245
|
|
|
226
|
-
syncCubeShaderUniforms
|
|
246
|
+
syncCubeShaderUniforms(): void {
|
|
227
247
|
if (!this.isShaderCubesGpuEnabled()) return
|
|
228
248
|
const mat = this.cubeShaderMaterial ?? this.getCubeShaderMaterial()
|
|
229
249
|
if (!mat) return
|
|
@@ -240,7 +260,7 @@ export class ChunkMeshManager {
|
|
|
240
260
|
mat.needsUpdate = true
|
|
241
261
|
}
|
|
242
262
|
|
|
243
|
-
syncLegacyShaderUniforms
|
|
263
|
+
syncLegacyShaderUniforms(): void {
|
|
244
264
|
const atlas = (this.material as THREE.MeshBasicMaterial).map ?? null
|
|
245
265
|
if (this.legacyShaderMaterial) {
|
|
246
266
|
this.legacyShaderMaterial.uniforms.u_atlas.value = atlas
|
|
@@ -257,7 +277,7 @@ export class ChunkMeshManager {
|
|
|
257
277
|
}
|
|
258
278
|
|
|
259
279
|
/** Render-time sky light cap (0–1, from time-of-day / 15). */
|
|
260
|
-
setSkyLevel
|
|
280
|
+
setSkyLevel(value: number): void {
|
|
261
281
|
const cube = this.cubeShaderMaterial ?? (this.isShaderCubesGpuEnabled() ? this.getCubeShaderMaterial() : null)
|
|
262
282
|
if (cube) setCubeSkyLevel(cube, value)
|
|
263
283
|
if (this.legacyShaderMaterial) setLegacySkyLevel(this.legacyShaderMaterial, value)
|
|
@@ -266,13 +286,13 @@ export class ChunkMeshManager {
|
|
|
266
286
|
this.blockEntityLightRegistry.setSkyLevel(value)
|
|
267
287
|
}
|
|
268
288
|
|
|
269
|
-
setShadingTheme
|
|
289
|
+
setShadingTheme(theme: 'vanilla' | 'high-contrast', cardinalLight: string): void {
|
|
270
290
|
const cube = this.cubeShaderMaterial ?? (this.isShaderCubesGpuEnabled() ? this.getCubeShaderMaterial() : null)
|
|
271
291
|
if (cube) setCubeShadingTheme(cube, theme, cardinalLight)
|
|
272
292
|
}
|
|
273
293
|
|
|
274
294
|
/** Vanilla-like lightmap curve params (live tuning via window.setBlockLightmap). */
|
|
275
|
-
setBlockLightmapParams
|
|
295
|
+
setBlockLightmapParams(params: BlockLightmapParams): void {
|
|
276
296
|
const cube = this.cubeShaderMaterial ?? (this.isShaderCubesGpuEnabled() ? this.getCubeShaderMaterial() : null)
|
|
277
297
|
if (cube) setCubeLightmapParams(cube, params)
|
|
278
298
|
if (this.legacyShaderMaterial) setLegacyLightmapParams(this.legacyShaderMaterial, params)
|
|
@@ -281,7 +301,7 @@ export class ChunkMeshManager {
|
|
|
281
301
|
this.blockEntityLightRegistry.setLightmapParams(params)
|
|
282
302
|
}
|
|
283
303
|
|
|
284
|
-
private getLegacyShaderMaterial
|
|
304
|
+
private getLegacyShaderMaterial(): THREE.ShaderMaterial {
|
|
285
305
|
if (!this.legacyShaderMaterial) {
|
|
286
306
|
this.legacyShaderMaterial = createLegacyBlockMaterial()
|
|
287
307
|
this.syncLegacyShaderUniforms()
|
|
@@ -289,7 +309,7 @@ export class ChunkMeshManager {
|
|
|
289
309
|
return this.legacyShaderMaterial
|
|
290
310
|
}
|
|
291
311
|
|
|
292
|
-
private getGlobalLegacyShaderMaterial
|
|
312
|
+
private getGlobalLegacyShaderMaterial(): THREE.ShaderMaterial {
|
|
293
313
|
if (!this.globalLegacyShaderMaterial) {
|
|
294
314
|
this.globalLegacyShaderMaterial = createGlobalLegacyBlockMaterial()
|
|
295
315
|
this.syncLegacyShaderUniforms()
|
|
@@ -297,18 +317,15 @@ export class ChunkMeshManager {
|
|
|
297
317
|
return this.globalLegacyShaderMaterial
|
|
298
318
|
}
|
|
299
319
|
|
|
300
|
-
private getGlobalLegacyBuffer
|
|
320
|
+
private getGlobalLegacyBuffer(): GlobalLegacyBuffer {
|
|
301
321
|
if (!this.globalLegacyBuffer) {
|
|
302
|
-
this.globalLegacyBuffer = new GlobalLegacyBuffer(
|
|
303
|
-
this.getGlobalLegacyShaderMaterial(),
|
|
304
|
-
this.scene,
|
|
305
|
-
)
|
|
322
|
+
this.globalLegacyBuffer = new GlobalLegacyBuffer(this.getGlobalLegacyShaderMaterial(), this.scene)
|
|
306
323
|
this.globalLegacyBuffer.setRenderOrigin(this.renderOrigin)
|
|
307
324
|
}
|
|
308
325
|
return this.globalLegacyBuffer
|
|
309
326
|
}
|
|
310
327
|
|
|
311
|
-
private getGlobalLegacyBlendShaderMaterial
|
|
328
|
+
private getGlobalLegacyBlendShaderMaterial(): THREE.ShaderMaterial {
|
|
312
329
|
if (!this.globalLegacyBlendShaderMaterial) {
|
|
313
330
|
this.globalLegacyBlendShaderMaterial = createGlobalLegacyBlendMaterial()
|
|
314
331
|
this.syncLegacyShaderUniforms()
|
|
@@ -316,32 +333,28 @@ export class ChunkMeshManager {
|
|
|
316
333
|
return this.globalLegacyBlendShaderMaterial
|
|
317
334
|
}
|
|
318
335
|
|
|
319
|
-
private getGlobalLegacyBlendBuffer
|
|
336
|
+
private getGlobalLegacyBlendBuffer(): GlobalLegacyBuffer {
|
|
320
337
|
if (!this.globalLegacyBlendBuffer) {
|
|
321
|
-
this.globalLegacyBlendBuffer = new GlobalLegacyBuffer(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
initialCapacityQuads: 32_000,
|
|
327
|
-
growthIncrementQuads: 32_000,
|
|
328
|
-
},
|
|
329
|
-
)
|
|
338
|
+
this.globalLegacyBlendBuffer = new GlobalLegacyBuffer(this.getGlobalLegacyBlendShaderMaterial(), this.scene, {
|
|
339
|
+
name: 'globalLegacyBlend',
|
|
340
|
+
initialCapacityQuads: 32_000,
|
|
341
|
+
growthIncrementQuads: 32_000
|
|
342
|
+
})
|
|
330
343
|
this.globalLegacyBlendBuffer.setRenderOrigin(this.renderOrigin)
|
|
331
344
|
}
|
|
332
345
|
return this.globalLegacyBlendBuffer
|
|
333
346
|
}
|
|
334
347
|
|
|
335
|
-
getRenderOrigin
|
|
348
|
+
getRenderOrigin(): Readonly<RenderOrigin> {
|
|
336
349
|
return this.renderOrigin
|
|
337
350
|
}
|
|
338
351
|
|
|
339
|
-
maybeRebase
|
|
352
|
+
maybeRebase(camera: RenderOrigin): void {
|
|
340
353
|
const R = this.renderOrigin
|
|
341
354
|
if (
|
|
342
|
-
Math.abs(camera.x - R.x) <= ChunkMeshManager.REBASE_THRESHOLD
|
|
343
|
-
|
|
344
|
-
|
|
355
|
+
Math.abs(camera.x - R.x) <= ChunkMeshManager.REBASE_THRESHOLD &&
|
|
356
|
+
Math.abs(camera.y - R.y) <= ChunkMeshManager.REBASE_THRESHOLD &&
|
|
357
|
+
Math.abs(camera.z - R.z) <= ChunkMeshManager.REBASE_THRESHOLD
|
|
345
358
|
) {
|
|
346
359
|
return
|
|
347
360
|
}
|
|
@@ -349,12 +362,12 @@ export class ChunkMeshManager {
|
|
|
349
362
|
const newOrigin: RenderOrigin = {
|
|
350
363
|
x: Math.round(camera.x / 16) * 16,
|
|
351
364
|
y: Math.round(camera.y / 16) * 16,
|
|
352
|
-
z: Math.round(camera.z / 16) * 16
|
|
365
|
+
z: Math.round(camera.z / 16) * 16
|
|
353
366
|
}
|
|
354
367
|
const delta: RenderOrigin = {
|
|
355
368
|
x: newOrigin.x - R.x,
|
|
356
369
|
y: newOrigin.y - R.y,
|
|
357
|
-
z: newOrigin.z - R.z
|
|
370
|
+
z: newOrigin.z - R.z
|
|
358
371
|
}
|
|
359
372
|
|
|
360
373
|
this.globalLegacyBuffer?.rebase(delta)
|
|
@@ -365,13 +378,7 @@ export class ChunkMeshManager {
|
|
|
365
378
|
if (!sectionKey) continue
|
|
366
379
|
const sectionObject = this.sectionObjects[sectionKey]
|
|
367
380
|
if (!sectionObject) continue
|
|
368
|
-
setupLegacySectionMatrix(
|
|
369
|
-
poolEntry.mesh,
|
|
370
|
-
sectionObject.worldX ?? 0,
|
|
371
|
-
sectionObject.worldY ?? 0,
|
|
372
|
-
sectionObject.worldZ ?? 0,
|
|
373
|
-
newOrigin,
|
|
374
|
-
)
|
|
381
|
+
setupLegacySectionMatrix(poolEntry.mesh, sectionObject.worldX ?? 0, sectionObject.worldY ?? 0, sectionObject.worldZ ?? 0, newOrigin)
|
|
375
382
|
}
|
|
376
383
|
|
|
377
384
|
this.renderOrigin = newOrigin
|
|
@@ -380,22 +387,58 @@ export class ChunkMeshManager {
|
|
|
380
387
|
}
|
|
381
388
|
|
|
382
389
|
/** Whether a section still holds a pooled legacy mesh (defer / invariant fallback). */
|
|
383
|
-
sectionUsesPooledLegacyMesh
|
|
390
|
+
sectionUsesPooledLegacyMesh(sectionKey: string): boolean {
|
|
384
391
|
return this.activeSections.has(sectionKey)
|
|
385
392
|
}
|
|
386
393
|
|
|
394
|
+
private registerLegacyCullSection(sectionKey: string, worldX: number, worldY: number, worldZ: number): void {
|
|
395
|
+
this.legacyCullSections.set(sectionKey, { worldX, worldY, worldZ })
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private maybeUnregisterLegacyCullSection(sectionKey: string): void {
|
|
399
|
+
const inOpaque = this.globalLegacyBuffer?.hasSection(sectionKey) ?? false
|
|
400
|
+
const inBlend = this.globalLegacyBlendBuffer?.hasSection(sectionKey) ?? false
|
|
401
|
+
if (!inOpaque && !inBlend) {
|
|
402
|
+
this.legacyCullSections.delete(sectionKey)
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
private updatePooledLegacyCullState(cameraWorldX: number, cameraWorldY: number, cameraWorldZ: number): void {
|
|
407
|
+
for (const poolEntry of this.activeSections.values()) {
|
|
408
|
+
const sectionKey = poolEntry.sectionKey
|
|
409
|
+
if (!sectionKey) continue
|
|
410
|
+
const sectionObject = this.sectionObjects[sectionKey]
|
|
411
|
+
if (!sectionObject) continue
|
|
412
|
+
|
|
413
|
+
updateLegacySectionCullState(
|
|
414
|
+
poolEntry.mesh,
|
|
415
|
+
sectionObject.worldX ?? 0,
|
|
416
|
+
sectionObject.worldY ?? 0,
|
|
417
|
+
sectionObject.worldZ ?? 0,
|
|
418
|
+
cameraWorldX,
|
|
419
|
+
cameraWorldY,
|
|
420
|
+
cameraWorldZ,
|
|
421
|
+
this._legacyCullFrustum,
|
|
422
|
+
this._legacyCullBox,
|
|
423
|
+
this._legacyCullBoxMin,
|
|
424
|
+
this._legacyCullBoxMax
|
|
425
|
+
)
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
387
429
|
/**
|
|
388
430
|
* Shared section visibility + span groups for global legacy and cube buffers.
|
|
389
431
|
*/
|
|
390
|
-
updateSectionCullAndSort
|
|
432
|
+
updateSectionCullAndSort(camera: THREE.Camera, cameraWorldX: number, cameraWorldY: number, cameraWorldZ: number): void {
|
|
391
433
|
this._legacyCullProjScreen.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
|
|
392
434
|
this._legacyCullFrustum.setFromProjectionMatrix(this._legacyCullProjScreen)
|
|
393
435
|
|
|
394
436
|
const visible = this._visibleSectionSpans
|
|
395
437
|
visible.length = 0
|
|
396
438
|
|
|
397
|
-
for (const [sectionKey
|
|
398
|
-
|
|
439
|
+
for (const [sectionKey] of this.legacyCullSections) {
|
|
440
|
+
const sectionObject = this.sectionObjects[sectionKey]
|
|
441
|
+
if (!sectionObject?.visible || sectionObject.worldX === undefined) continue
|
|
399
442
|
const { visible: inFrustum, distSq } = sectionIntersectsFrustum(
|
|
400
443
|
sectionObject.worldX,
|
|
401
444
|
sectionObject.worldY ?? 0,
|
|
@@ -406,20 +449,34 @@ export class ChunkMeshManager {
|
|
|
406
449
|
this._legacyCullFrustum,
|
|
407
450
|
this._legacyCullBox,
|
|
408
451
|
this._legacyCullBoxMin,
|
|
409
|
-
this._legacyCullBoxMax
|
|
452
|
+
this._legacyCullBoxMax
|
|
410
453
|
)
|
|
411
454
|
if (inFrustum) {
|
|
412
455
|
visible.push({ key: sectionKey, distSq })
|
|
413
456
|
}
|
|
414
457
|
}
|
|
415
458
|
|
|
416
|
-
this.globalLegacyBuffer
|
|
417
|
-
this.globalLegacyBlendBuffer
|
|
418
|
-
|
|
459
|
+
const opaqueBuf = this.globalLegacyBuffer
|
|
460
|
+
const blendBuf = this.globalLegacyBlendBuffer
|
|
419
461
|
const gb = this.globalBlockBuffer
|
|
462
|
+
|
|
463
|
+
const opaqueKeys: string[] = []
|
|
464
|
+
for (const entry of visible) {
|
|
465
|
+
if (opaqueBuf?.hasSection(entry.key)) opaqueKeys.push(entry.key)
|
|
466
|
+
}
|
|
467
|
+
opaqueKeys.sort()
|
|
468
|
+
|
|
469
|
+
const blendVisible = visible.filter(v => blendBuf?.hasSection(v.key))
|
|
470
|
+
blendVisible.sort((a, b) => b.distSq - a.distSq)
|
|
471
|
+
const blendKeys = blendVisible.map(v => v.key)
|
|
472
|
+
|
|
473
|
+
const cubeVisibleKeys: string[] = []
|
|
474
|
+
const visibleSlots: Array<{ start: number; count: number }> = []
|
|
420
475
|
if (gb) {
|
|
421
|
-
const visibleSlots: Array<{ start: number, count: number }> = []
|
|
422
476
|
gb.forEachSectionSlot((key, slot) => {
|
|
477
|
+
const sectionObject = this.sectionObjects[key]
|
|
478
|
+
// Keep in sync with legacy gate (line 440).
|
|
479
|
+
if (!sectionObject?.visible) return
|
|
423
480
|
const entry = this.shaderSectionRaycastBoxes.get(key)
|
|
424
481
|
if (!entry) {
|
|
425
482
|
return
|
|
@@ -434,48 +491,90 @@ export class ChunkMeshManager {
|
|
|
434
491
|
this._legacyCullFrustum,
|
|
435
492
|
this._legacyCullBox,
|
|
436
493
|
this._legacyCullBoxMin,
|
|
437
|
-
this._legacyCullBoxMax
|
|
494
|
+
this._legacyCullBoxMax
|
|
438
495
|
)
|
|
439
496
|
if (!inFrustum) {
|
|
440
497
|
return
|
|
441
498
|
}
|
|
499
|
+
cubeVisibleKeys.push(key)
|
|
442
500
|
const drawStart = gb.getSectionDrawStart(key)
|
|
443
|
-
|
|
444
|
-
|
|
501
|
+
const drawCount = gb.getSectionDrawCount(key)
|
|
502
|
+
if (drawStart !== undefined && drawCount !== undefined) {
|
|
503
|
+
visibleSlots.push({ start: drawStart, count: drawCount })
|
|
445
504
|
}
|
|
446
505
|
})
|
|
447
|
-
const spans = buildVisibleCubeSpans(visibleSlots, gb.getHighWatermark())
|
|
448
|
-
gb.setVisibleSpans(spans)
|
|
449
506
|
}
|
|
507
|
+
cubeVisibleKeys.sort()
|
|
508
|
+
|
|
509
|
+
const fingerprint = [
|
|
510
|
+
opaqueKeys.join(','),
|
|
511
|
+
blendKeys.join(','),
|
|
512
|
+
cubeVisibleKeys.join(','),
|
|
513
|
+
opaqueBuf?.getLayoutVersion() ?? 0,
|
|
514
|
+
blendBuf?.getLayoutVersion() ?? 0,
|
|
515
|
+
gb?.getLayoutVersion() ?? 0,
|
|
516
|
+
opaqueBuf?.getUploadEpoch() ?? 0,
|
|
517
|
+
blendBuf?.getUploadEpoch() ?? 0,
|
|
518
|
+
gb?.getUploadEpoch() ?? 0
|
|
519
|
+
].join('|')
|
|
520
|
+
|
|
521
|
+
if (fingerprint === this._lastCullFingerprint && !this.hasPendingBufferWork()) {
|
|
522
|
+
this.updatePooledLegacyCullState(cameraWorldX, cameraWorldY, cameraWorldZ)
|
|
523
|
+
return
|
|
524
|
+
}
|
|
525
|
+
this._lastCullFingerprint = fingerprint
|
|
450
526
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
if (!sectionKey) continue
|
|
454
|
-
const sectionObject = this.sectionObjects[sectionKey]
|
|
455
|
-
if (!sectionObject) continue
|
|
527
|
+
opaqueBuf?.updateDrawSpans(visible, 'opaque')
|
|
528
|
+
blendBuf?.updateDrawSpans(visible, 'sortedBlend')
|
|
456
529
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
cameraWorldZ,
|
|
465
|
-
this._legacyCullFrustum,
|
|
466
|
-
this._legacyCullBox,
|
|
467
|
-
this._legacyCullBoxMin,
|
|
468
|
-
this._legacyCullBoxMax,
|
|
530
|
+
if (gb) {
|
|
531
|
+
const spans = buildVisibleCubeSpans(
|
|
532
|
+
visibleSlots,
|
|
533
|
+
gb.getHighWatermark(),
|
|
534
|
+
gb.canUseFullDrawShortcut(),
|
|
535
|
+
(start, end) => gb.isRangeFullyUploaded(start, end),
|
|
536
|
+
gb.getPendingDirtyRanges()
|
|
469
537
|
)
|
|
538
|
+
gb.setVisibleSpans(spans)
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
this.lastBufferStateKey = this.bufferStateKey()
|
|
542
|
+
this.updatePooledLegacyCullState(cameraWorldX, cameraWorldY, cameraWorldZ)
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
private bufferStateKey(): string {
|
|
546
|
+
const b = this.globalBlockBuffer
|
|
547
|
+
const o = this.globalLegacyBuffer
|
|
548
|
+
const bl = this.globalLegacyBlendBuffer
|
|
549
|
+
return [
|
|
550
|
+
o?.getLayoutVersion() ?? 0,
|
|
551
|
+
o?.getUploadEpoch() ?? 0,
|
|
552
|
+
bl?.getLayoutVersion() ?? 0,
|
|
553
|
+
bl?.getUploadEpoch() ?? 0,
|
|
554
|
+
b?.getLayoutVersion() ?? 0,
|
|
555
|
+
b?.getUploadEpoch() ?? 0
|
|
556
|
+
].join('|')
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
/** Mark cull dirty when any buffer's layout or upload state changed since the last cull. */
|
|
560
|
+
markCullDirtyIfBufferStateChanged(): void {
|
|
561
|
+
const key = this.bufferStateKey()
|
|
562
|
+
if (key !== this.lastBufferStateKey) {
|
|
563
|
+
this.markCullDirty()
|
|
470
564
|
}
|
|
471
565
|
}
|
|
472
566
|
|
|
473
|
-
markCullDirty
|
|
567
|
+
markCullDirty(): void {
|
|
474
568
|
this.cullDirty = true
|
|
475
569
|
}
|
|
476
570
|
|
|
571
|
+
hasPendingBufferWork(): boolean {
|
|
572
|
+
const buffers = [this.globalLegacyBuffer, this.globalLegacyBlendBuffer, this.globalBlockBuffer]
|
|
573
|
+
return buffers.some(b => b != null && (b.hasPendingUploads() || b.hasPendingReplace() || b.getPendingMove() != null))
|
|
574
|
+
}
|
|
575
|
+
|
|
477
576
|
/** Compare camera pose; mark cull dirty when position or rotation changed. */
|
|
478
|
-
updateCullDirtyFromCamera
|
|
577
|
+
updateCullDirtyFromCamera(camera: THREE.Camera, cameraWorldX: number, cameraWorldY: number, cameraWorldZ: number): void {
|
|
479
578
|
camera.getWorldQuaternion(this._cullViewQuat)
|
|
480
579
|
if (!this._cullCamInitialized) {
|
|
481
580
|
this._lastCullCamPos.set(cameraWorldX, cameraWorldY, cameraWorldZ)
|
|
@@ -484,10 +583,7 @@ export class ChunkMeshManager {
|
|
|
484
583
|
this.cullDirty = true
|
|
485
584
|
return
|
|
486
585
|
}
|
|
487
|
-
const posChanged =
|
|
488
|
-
this._lastCullCamPos.x !== cameraWorldX ||
|
|
489
|
-
this._lastCullCamPos.y !== cameraWorldY ||
|
|
490
|
-
this._lastCullCamPos.z !== cameraWorldZ
|
|
586
|
+
const posChanged = this._lastCullCamPos.x !== cameraWorldX || this._lastCullCamPos.y !== cameraWorldY || this._lastCullCamPos.z !== cameraWorldZ
|
|
491
587
|
const quatChanged =
|
|
492
588
|
this._lastCullCamQuat.x !== this._cullViewQuat.x ||
|
|
493
589
|
this._lastCullCamQuat.y !== this._cullViewQuat.y ||
|
|
@@ -500,11 +596,11 @@ export class ChunkMeshManager {
|
|
|
500
596
|
}
|
|
501
597
|
}
|
|
502
598
|
|
|
503
|
-
clearCullDirty
|
|
599
|
+
clearCullDirty(): void {
|
|
504
600
|
this.cullDirty = false
|
|
505
601
|
}
|
|
506
602
|
|
|
507
|
-
setLegacyCameraOrigin
|
|
603
|
+
setLegacyCameraOrigin(x: number, y: number, z: number): void {
|
|
508
604
|
const R = this.renderOrigin
|
|
509
605
|
setLegacyCameraOrigin(this.getLegacyShaderMaterial(), R, x, y, z)
|
|
510
606
|
setLegacyCameraOrigin(this.getGlobalLegacyShaderMaterial(), R, x, y, z)
|
|
@@ -531,7 +627,7 @@ export class ChunkMeshManager {
|
|
|
531
627
|
}
|
|
532
628
|
}
|
|
533
629
|
|
|
534
|
-
private getCubeShaderMaterial
|
|
630
|
+
private getCubeShaderMaterial(): THREE.ShaderMaterial | null {
|
|
535
631
|
if (!this.isShaderCubesGpuEnabled()) return null
|
|
536
632
|
if (!this.cubeShaderMaterial) {
|
|
537
633
|
this.cubeShaderMaterial = createCubeBlockMaterial()
|
|
@@ -542,7 +638,7 @@ export class ChunkMeshManager {
|
|
|
542
638
|
return this.cubeShaderMaterial
|
|
543
639
|
}
|
|
544
640
|
|
|
545
|
-
private getGlobalBlockBuffer
|
|
641
|
+
private getGlobalBlockBuffer(): GlobalBlockBuffer | null {
|
|
546
642
|
const mat = this.getCubeShaderMaterial()
|
|
547
643
|
if (!mat) return null
|
|
548
644
|
if (!this.globalBlockBuffer) {
|
|
@@ -551,12 +647,12 @@ export class ChunkMeshManager {
|
|
|
551
647
|
return this.globalBlockBuffer
|
|
552
648
|
}
|
|
553
649
|
|
|
554
|
-
private shouldDeferLegacyOpaqueToPerSection
|
|
650
|
+
private shouldDeferLegacyOpaqueToPerSection(sectionKey: string): boolean {
|
|
555
651
|
return this.shouldDeferShaderToPerSection(sectionKey)
|
|
556
652
|
}
|
|
557
653
|
|
|
558
654
|
/** Sci-fi reveal keeps geometry off global buffers until the section finishes reveal. */
|
|
559
|
-
private shouldDeferShaderToPerSection
|
|
655
|
+
private shouldDeferShaderToPerSection(sectionKey: string): boolean {
|
|
560
656
|
const sciFi = this.worldRenderer.getModule<{
|
|
561
657
|
shouldDeferSectionGeometry?: (key: string) => boolean
|
|
562
658
|
}>('futuristicReveal')
|
|
@@ -566,7 +662,7 @@ export class ChunkMeshManager {
|
|
|
566
662
|
/**
|
|
567
663
|
* Move deferred per-section shader cubes into the global buffer after reveal completes.
|
|
568
664
|
*/
|
|
569
|
-
migrateDeferredShaderToGlobal
|
|
665
|
+
migrateDeferredShaderToGlobal(sectionKey: string): void {
|
|
570
666
|
const section = this.sectionObjects[sectionKey]
|
|
571
667
|
if (!section?.deferredShaderCubes) return
|
|
572
668
|
|
|
@@ -599,7 +695,7 @@ export class ChunkMeshManager {
|
|
|
599
695
|
/**
|
|
600
696
|
* Move deferred per-section opaque legacy into the global buffer after reveal completes.
|
|
601
697
|
*/
|
|
602
|
-
migrateDeferredLegacyToGlobal
|
|
698
|
+
migrateDeferredLegacyToGlobal(sectionKey: string): void {
|
|
603
699
|
const section = this.sectionObjects[sectionKey]
|
|
604
700
|
if (!section) return
|
|
605
701
|
|
|
@@ -609,13 +705,10 @@ export class ChunkMeshManager {
|
|
|
609
705
|
const wy = section.worldY
|
|
610
706
|
const wz = section.worldZ
|
|
611
707
|
if (wx !== undefined && wy !== undefined && wz !== undefined) {
|
|
612
|
-
this.getGlobalLegacyBuffer().addSection(
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
wy,
|
|
617
|
-
wz,
|
|
618
|
-
)
|
|
708
|
+
const added = this.getGlobalLegacyBuffer().addSection(sectionKey, { positions, colors, skyLights, blockLights, uvs, indices }, wx, wy, wz)
|
|
709
|
+
if (added) {
|
|
710
|
+
this.registerLegacyCullSection(sectionKey, wx, wy, wz)
|
|
711
|
+
}
|
|
619
712
|
}
|
|
620
713
|
delete section.deferredLegacyOpaque
|
|
621
714
|
}
|
|
@@ -626,13 +719,10 @@ export class ChunkMeshManager {
|
|
|
626
719
|
const wy = section.worldY
|
|
627
720
|
const wz = section.worldZ
|
|
628
721
|
if (wx !== undefined && wy !== undefined && wz !== undefined) {
|
|
629
|
-
this.getGlobalLegacyBlendBuffer().addSection(
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
wy,
|
|
634
|
-
wz,
|
|
635
|
-
)
|
|
722
|
+
const added = this.getGlobalLegacyBlendBuffer().addSection(sectionKey, { positions, colors, skyLights, blockLights, uvs, indices }, wx, wy, wz)
|
|
723
|
+
if (added) {
|
|
724
|
+
this.registerLegacyCullSection(sectionKey, wx, wy, wz)
|
|
725
|
+
}
|
|
636
726
|
}
|
|
637
727
|
delete section.deferredLegacyBlend
|
|
638
728
|
section.hasBlendMesh = false
|
|
@@ -642,17 +732,13 @@ export class ChunkMeshManager {
|
|
|
642
732
|
const hadLegacyAsPrimary = section.mesh === this.activeSections.get(sectionKey)?.mesh
|
|
643
733
|
this.releasePooledMesh(sectionKey)
|
|
644
734
|
if (hadLegacyAsPrimary) {
|
|
645
|
-
section.mesh = section.shaderMesh as unknown as THREE.Mesh<THREE.BufferGeometry, THREE.Material> | undefined ?? undefined
|
|
735
|
+
section.mesh = (section.shaderMesh as unknown as THREE.Mesh<THREE.BufferGeometry, THREE.Material> | undefined) ?? undefined
|
|
646
736
|
}
|
|
647
737
|
}
|
|
648
738
|
this.markCullDirty()
|
|
649
739
|
}
|
|
650
740
|
|
|
651
|
-
raycastGlobalLegacySections
|
|
652
|
-
raycaster: THREE.Raycaster,
|
|
653
|
-
origin: THREE.Vector3,
|
|
654
|
-
maxCenterDistance: number,
|
|
655
|
-
): number | undefined {
|
|
741
|
+
raycastGlobalLegacySections(raycaster: THREE.Raycaster, origin: THREE.Vector3, maxCenterDistance: number): number | undefined {
|
|
656
742
|
const maxDistSq = maxCenterDistance * maxCenterDistance
|
|
657
743
|
const dirX = raycaster.ray.direction.x
|
|
658
744
|
const dirY = raycaster.ray.direction.y
|
|
@@ -660,28 +746,15 @@ export class ChunkMeshManager {
|
|
|
660
746
|
const far = raycaster.far
|
|
661
747
|
const halfExtent = LEGACY_SECTION_HALF_EXTENT + 0.01
|
|
662
748
|
const candidates: string[] = []
|
|
663
|
-
for (const [key
|
|
664
|
-
|
|
749
|
+
for (const [key] of this.legacyCullSections) {
|
|
750
|
+
const section = this.sectionObjects[key]
|
|
751
|
+
if (!section || section.worldX === undefined) continue
|
|
665
752
|
const dx = section.worldX - origin.x
|
|
666
753
|
const dy = (section.worldY ?? 0) - origin.y
|
|
667
754
|
const dz = (section.worldZ ?? 0) - origin.z
|
|
668
755
|
if (dx * dx + dy * dy + dz * dz > maxDistSq) continue
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
if (!inOpaque && !inBlend) continue
|
|
672
|
-
if (!sectionAabbIntersectsRay(
|
|
673
|
-
section.worldX,
|
|
674
|
-
section.worldY ?? 0,
|
|
675
|
-
section.worldZ ?? 0,
|
|
676
|
-
origin.x,
|
|
677
|
-
origin.y,
|
|
678
|
-
origin.z,
|
|
679
|
-
dirX,
|
|
680
|
-
dirY,
|
|
681
|
-
dirZ,
|
|
682
|
-
far,
|
|
683
|
-
halfExtent,
|
|
684
|
-
)) continue
|
|
756
|
+
if (!sectionAabbIntersectsRay(section.worldX, section.worldY ?? 0, section.worldZ ?? 0, origin.x, origin.y, origin.z, dirX, dirY, dirZ, far, halfExtent))
|
|
757
|
+
continue
|
|
685
758
|
candidates.push(key)
|
|
686
759
|
}
|
|
687
760
|
|
|
@@ -694,13 +767,13 @@ export class ChunkMeshManager {
|
|
|
694
767
|
return hits[0]?.distance
|
|
695
768
|
}
|
|
696
769
|
|
|
697
|
-
registerShaderSectionRaycastBox
|
|
770
|
+
registerShaderSectionRaycastBox(
|
|
698
771
|
sectionKey: string,
|
|
699
772
|
words: Uint32Array,
|
|
700
773
|
faceCount: number,
|
|
701
774
|
sectionCenterX: number,
|
|
702
775
|
sectionCenterY: number,
|
|
703
|
-
sectionCenterZ: number
|
|
776
|
+
sectionCenterZ: number
|
|
704
777
|
): void {
|
|
705
778
|
const box = computeShaderSectionRaycastAabb(words, faceCount, sectionCenterX, sectionCenterY, sectionCenterZ)
|
|
706
779
|
if (box) {
|
|
@@ -708,24 +781,19 @@ export class ChunkMeshManager {
|
|
|
708
781
|
box,
|
|
709
782
|
sectionCenterX,
|
|
710
783
|
sectionCenterY,
|
|
711
|
-
sectionCenterZ
|
|
784
|
+
sectionCenterZ
|
|
712
785
|
})
|
|
713
786
|
} else {
|
|
714
787
|
this.shaderSectionRaycastBoxes.delete(sectionKey)
|
|
715
788
|
}
|
|
716
789
|
}
|
|
717
790
|
|
|
718
|
-
unregisterShaderSectionRaycastBox
|
|
791
|
+
unregisterShaderSectionRaycastBox(sectionKey: string): void {
|
|
719
792
|
this.shaderSectionRaycastBoxes.delete(sectionKey)
|
|
720
793
|
}
|
|
721
794
|
|
|
722
795
|
/** Closest hit against registered shader-cube AABBs (world-space ray). */
|
|
723
|
-
raycastShaderSectionAABBs
|
|
724
|
-
originWorld: THREE.Vector3,
|
|
725
|
-
direction: THREE.Vector3,
|
|
726
|
-
maxDist: number,
|
|
727
|
-
maxCenterDistance = 80,
|
|
728
|
-
): number | undefined {
|
|
796
|
+
raycastShaderSectionAABBs(originWorld: THREE.Vector3, direction: THREE.Vector3, maxDist: number, maxCenterDistance = 80): number | undefined {
|
|
729
797
|
const ox = originWorld.x
|
|
730
798
|
const oy = originWorld.y
|
|
731
799
|
const oz = originWorld.z
|
|
@@ -753,11 +821,7 @@ export class ChunkMeshManager {
|
|
|
753
821
|
const dcz = box.cz - oz
|
|
754
822
|
if (dcx * dcx + dcy * dcy + dcz * dcz > maxCenterDistSq) continue
|
|
755
823
|
|
|
756
|
-
let t = raycastAabb(
|
|
757
|
-
ox, oy, oz, dx, dy, dz,
|
|
758
|
-
box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ,
|
|
759
|
-
closest,
|
|
760
|
-
)
|
|
824
|
+
let t = raycastAabb(ox, oy, oz, dx, dy, dz, box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ, closest)
|
|
761
825
|
if (t === undefined && isPointInsideAabb(ox, oy, oz, box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)) {
|
|
762
826
|
const gb = this.globalBlockBuffer
|
|
763
827
|
const slot = gb?.getSectionSlot(key)
|
|
@@ -770,10 +834,15 @@ export class ChunkMeshManager {
|
|
|
770
834
|
entry.sectionCenterX,
|
|
771
835
|
entry.sectionCenterY,
|
|
772
836
|
entry.sectionCenterZ,
|
|
773
|
-
ox,
|
|
837
|
+
ox,
|
|
838
|
+
oy,
|
|
839
|
+
oz,
|
|
840
|
+
dx,
|
|
841
|
+
dy,
|
|
842
|
+
dz,
|
|
774
843
|
closest,
|
|
775
844
|
this.blockRaycastVisitGen,
|
|
776
|
-
this.blockRaycastVisitStamp
|
|
845
|
+
this.blockRaycastVisitStamp
|
|
777
846
|
)
|
|
778
847
|
} else {
|
|
779
848
|
const def = this.sectionObjects[key]?.deferredShaderCubes
|
|
@@ -786,10 +855,15 @@ export class ChunkMeshManager {
|
|
|
786
855
|
entry.sectionCenterX,
|
|
787
856
|
entry.sectionCenterY,
|
|
788
857
|
entry.sectionCenterZ,
|
|
789
|
-
ox,
|
|
858
|
+
ox,
|
|
859
|
+
oy,
|
|
860
|
+
oz,
|
|
861
|
+
dx,
|
|
862
|
+
dy,
|
|
863
|
+
dz,
|
|
790
864
|
closest,
|
|
791
865
|
this.blockRaycastVisitGen,
|
|
792
|
-
this.blockRaycastVisitStamp
|
|
866
|
+
this.blockRaycastVisitStamp
|
|
793
867
|
)
|
|
794
868
|
}
|
|
795
869
|
}
|
|
@@ -806,12 +880,12 @@ export class ChunkMeshManager {
|
|
|
806
880
|
/**
|
|
807
881
|
* Update or create a section with new geometry data
|
|
808
882
|
*/
|
|
809
|
-
private uploadLegacyPooledMesh
|
|
883
|
+
private uploadLegacyPooledMesh(
|
|
810
884
|
poolEntry: ChunkMeshPool,
|
|
811
885
|
geometryData: MesherGeometryOutput | MesherGeometryOutput['blend'],
|
|
812
886
|
sx: number,
|
|
813
887
|
sy: number,
|
|
814
|
-
sz: number
|
|
888
|
+
sz: number
|
|
815
889
|
): THREE.Mesh<THREE.BufferGeometry, THREE.Material> {
|
|
816
890
|
const { mesh } = poolEntry
|
|
817
891
|
const geo = geometryData!
|
|
@@ -822,14 +896,8 @@ export class ChunkMeshManager {
|
|
|
822
896
|
this.updateGeometryAttribute(mesh.geometry, 'a_blockLight', geo.blockLights, 1)
|
|
823
897
|
this.updateGeometryAttribute(mesh.geometry, 'uv', geo.uvs, 2)
|
|
824
898
|
mesh.geometry.index = new THREE.BufferAttribute(geo.indices as Uint32Array | Uint16Array, 1)
|
|
825
|
-
mesh.geometry.boundingBox = new THREE.Box3(
|
|
826
|
-
|
|
827
|
-
new THREE.Vector3(8, 8, 8),
|
|
828
|
-
)
|
|
829
|
-
mesh.geometry.boundingSphere = new THREE.Sphere(
|
|
830
|
-
new THREE.Vector3(0, 0, 0),
|
|
831
|
-
Math.sqrt(3 * 8 ** 2),
|
|
832
|
-
)
|
|
899
|
+
mesh.geometry.boundingBox = new THREE.Box3(new THREE.Vector3(-8, -8, -8), new THREE.Vector3(8, 8, 8))
|
|
900
|
+
mesh.geometry.boundingSphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0), Math.sqrt(3 * 8 ** 2))
|
|
833
901
|
setupLegacySectionMatrix(mesh, sx, sy, sz, this.renderOrigin)
|
|
834
902
|
mesh.visible = false
|
|
835
903
|
mesh.name = 'mesh'
|
|
@@ -837,7 +905,7 @@ export class ChunkMeshManager {
|
|
|
837
905
|
return mesh as THREE.Mesh<THREE.BufferGeometry, THREE.Material>
|
|
838
906
|
}
|
|
839
907
|
|
|
840
|
-
private acquirePooledSectionMesh
|
|
908
|
+
private acquirePooledSectionMesh(sectionKey: string): ChunkMeshPool | null {
|
|
841
909
|
let poolEntry = this.activeSections.get(sectionKey)
|
|
842
910
|
if (!poolEntry) {
|
|
843
911
|
poolEntry = this.acquireMesh()
|
|
@@ -851,12 +919,18 @@ export class ChunkMeshManager {
|
|
|
851
919
|
return poolEntry
|
|
852
920
|
}
|
|
853
921
|
|
|
854
|
-
updateSection
|
|
922
|
+
updateSection(sectionKey: string, geometryData: MesherGeometryOutput): SectionObject | null {
|
|
855
923
|
const hasOpaque = geometryData.positions.length > 0
|
|
856
924
|
const hasBlend = (geometryData.blend?.positions.length ?? 0) > 0
|
|
857
925
|
const hasLegacy = hasOpaque || hasBlend
|
|
858
926
|
const shaderData = geometryData.shaderCubes
|
|
859
927
|
const hasShader = this.isShaderCubesGpuEnabled() && (shaderData?.count ?? 0) > 0
|
|
928
|
+
const deferOpaque = hasOpaque && this.shouldDeferLegacyOpaqueToPerSection(sectionKey)
|
|
929
|
+
const deferBlend = hasBlend && this.shouldDeferLegacyOpaqueToPerSection(sectionKey)
|
|
930
|
+
const deferShader = hasShader && this.shouldDeferShaderToPerSection(sectionKey)
|
|
931
|
+
const willAddOpaqueGlobal = hasOpaque && !deferOpaque
|
|
932
|
+
const willAddBlendGlobal = hasBlend && !deferBlend
|
|
933
|
+
const willAddCubeGlobal = hasShader && !!shaderData && !deferShader
|
|
860
934
|
|
|
861
935
|
if (!hasLegacy && !hasShader) {
|
|
862
936
|
this.releaseSection(sectionKey)
|
|
@@ -865,10 +939,19 @@ export class ChunkMeshManager {
|
|
|
865
939
|
|
|
866
940
|
// Remove existing section object from scene if it exists
|
|
867
941
|
let sectionObject = this.sectionObjects[sectionKey]
|
|
942
|
+
const wasRemesh = sectionObject != null
|
|
868
943
|
if (sectionObject) {
|
|
869
944
|
this.cleanupSection(sectionKey, { forRemesh: true })
|
|
870
945
|
}
|
|
871
946
|
|
|
947
|
+
if (wasRemesh) {
|
|
948
|
+
if (!willAddCubeGlobal) this.globalBlockBuffer?.removeSection(sectionKey)
|
|
949
|
+
if (!willAddOpaqueGlobal) this.globalLegacyBuffer?.removeSection(sectionKey)
|
|
950
|
+
if (!willAddBlendGlobal) this.globalLegacyBlendBuffer?.removeSection(sectionKey)
|
|
951
|
+
if (!(hasShader && shaderData)) this.unregisterShaderSectionRaycastBox(sectionKey)
|
|
952
|
+
if (!willAddOpaqueGlobal && !willAddBlendGlobal) this.maybeUnregisterLegacyCullSection(sectionKey)
|
|
953
|
+
}
|
|
954
|
+
|
|
872
955
|
if (!hasBlend) {
|
|
873
956
|
this.releasePooledMesh(sectionKey)
|
|
874
957
|
}
|
|
@@ -885,9 +968,8 @@ export class ChunkMeshManager {
|
|
|
885
968
|
skyLights: geometryData.skyLights as Float32Array,
|
|
886
969
|
blockLights: geometryData.blockLights as Float32Array,
|
|
887
970
|
uvs: geometryData.uvs as Float32Array,
|
|
888
|
-
indices: geometryData.indices as Uint32Array | Uint16Array
|
|
971
|
+
indices: geometryData.indices as Uint32Array | Uint16Array
|
|
889
972
|
}
|
|
890
|
-
const deferOpaque = this.shouldDeferLegacyOpaqueToPerSection(sectionKey)
|
|
891
973
|
if (deferOpaque) {
|
|
892
974
|
deferredLegacyOpaque = {
|
|
893
975
|
positions: new Float32Array(opaqueGeo.positions),
|
|
@@ -895,9 +977,7 @@ export class ChunkMeshManager {
|
|
|
895
977
|
skyLights: new Float32Array(opaqueGeo.skyLights),
|
|
896
978
|
blockLights: new Float32Array(opaqueGeo.blockLights),
|
|
897
979
|
uvs: new Float32Array(opaqueGeo.uvs),
|
|
898
|
-
indices: opaqueGeo.indices instanceof Uint32Array
|
|
899
|
-
? new Uint32Array(opaqueGeo.indices)
|
|
900
|
-
: new Uint16Array(opaqueGeo.indices),
|
|
980
|
+
indices: opaqueGeo.indices instanceof Uint32Array ? new Uint32Array(opaqueGeo.indices) : new Uint16Array(opaqueGeo.indices)
|
|
901
981
|
}
|
|
902
982
|
if (!hasBlend) {
|
|
903
983
|
const poolEntry = this.acquirePooledSectionMesh(sectionKey)
|
|
@@ -905,14 +985,10 @@ export class ChunkMeshManager {
|
|
|
905
985
|
legacyMesh = this.uploadLegacyPooledMesh(poolEntry, geometryData, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
906
986
|
}
|
|
907
987
|
} else {
|
|
908
|
-
const added = this.getGlobalLegacyBuffer().addSection(
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
geometryData.sy,
|
|
913
|
-
geometryData.sz,
|
|
914
|
-
)
|
|
915
|
-
if (!added) {
|
|
988
|
+
const added = this.getGlobalLegacyBuffer().addSection(sectionKey, opaqueGeo, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
989
|
+
if (added) {
|
|
990
|
+
this.registerLegacyCullSection(sectionKey, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
991
|
+
} else {
|
|
916
992
|
const poolEntry = this.acquirePooledSectionMesh(sectionKey)
|
|
917
993
|
if (!poolEntry) return null
|
|
918
994
|
legacyMesh = this.uploadLegacyPooledMesh(poolEntry, geometryData, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
@@ -927,9 +1003,8 @@ export class ChunkMeshManager {
|
|
|
927
1003
|
skyLights: geometryData.blend.skyLights as Float32Array,
|
|
928
1004
|
blockLights: geometryData.blend.blockLights as Float32Array,
|
|
929
1005
|
uvs: geometryData.blend.uvs as Float32Array,
|
|
930
|
-
indices: geometryData.blend.indices as Uint32Array | Uint16Array
|
|
1006
|
+
indices: geometryData.blend.indices as Uint32Array | Uint16Array
|
|
931
1007
|
}
|
|
932
|
-
const deferBlend = this.shouldDeferLegacyOpaqueToPerSection(sectionKey)
|
|
933
1008
|
if (deferBlend) {
|
|
934
1009
|
deferredLegacyBlend = {
|
|
935
1010
|
positions: new Float32Array(blendGeo.positions),
|
|
@@ -937,40 +1012,22 @@ export class ChunkMeshManager {
|
|
|
937
1012
|
skyLights: new Float32Array(blendGeo.skyLights),
|
|
938
1013
|
blockLights: new Float32Array(blendGeo.blockLights),
|
|
939
1014
|
uvs: new Float32Array(blendGeo.uvs),
|
|
940
|
-
indices: blendGeo.indices instanceof Uint32Array
|
|
941
|
-
? new Uint32Array(blendGeo.indices)
|
|
942
|
-
: new Uint16Array(blendGeo.indices),
|
|
1015
|
+
indices: blendGeo.indices instanceof Uint32Array ? new Uint32Array(blendGeo.indices) : new Uint16Array(blendGeo.indices)
|
|
943
1016
|
}
|
|
944
1017
|
const poolEntry = this.acquirePooledSectionMesh(sectionKey)
|
|
945
1018
|
if (!poolEntry) return null
|
|
946
|
-
const blendMesh = this.uploadLegacyPooledMesh(
|
|
947
|
-
poolEntry,
|
|
948
|
-
geometryData.blend,
|
|
949
|
-
geometryData.sx,
|
|
950
|
-
geometryData.sy,
|
|
951
|
-
geometryData.sz,
|
|
952
|
-
)
|
|
1019
|
+
const blendMesh = this.uploadLegacyPooledMesh(poolEntry, geometryData.blend, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
953
1020
|
legacyMesh = legacyMesh ?? blendMesh
|
|
954
1021
|
hasBlendMesh = true
|
|
955
1022
|
} else {
|
|
956
|
-
const added = this.getGlobalLegacyBlendBuffer().addSection(
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
geometryData.sy,
|
|
961
|
-
geometryData.sz,
|
|
962
|
-
)
|
|
963
|
-
if (!added) {
|
|
1023
|
+
const added = this.getGlobalLegacyBlendBuffer().addSection(sectionKey, blendGeo, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
1024
|
+
if (added) {
|
|
1025
|
+
this.registerLegacyCullSection(sectionKey, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
1026
|
+
} else {
|
|
964
1027
|
console.warn(`ChunkMeshManager: blend invariant violation for section ${sectionKey}, using pooled mesh fallback`)
|
|
965
1028
|
const poolEntry = this.acquirePooledSectionMesh(sectionKey)
|
|
966
1029
|
if (!poolEntry) return null
|
|
967
|
-
const blendMesh = this.uploadLegacyPooledMesh(
|
|
968
|
-
poolEntry,
|
|
969
|
-
geometryData.blend,
|
|
970
|
-
geometryData.sx,
|
|
971
|
-
geometryData.sy,
|
|
972
|
-
geometryData.sz,
|
|
973
|
-
)
|
|
1030
|
+
const blendMesh = this.uploadLegacyPooledMesh(poolEntry, geometryData.blend, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
974
1031
|
legacyMesh = legacyMesh ?? blendMesh
|
|
975
1032
|
hasBlendMesh = true
|
|
976
1033
|
}
|
|
@@ -979,7 +1036,6 @@ export class ChunkMeshManager {
|
|
|
979
1036
|
|
|
980
1037
|
const cubeMaterial = hasShader ? this.getCubeShaderMaterial() : null
|
|
981
1038
|
let shaderMesh: THREE.Mesh<THREE.InstancedBufferGeometry, THREE.ShaderMaterial> | undefined
|
|
982
|
-
const deferShader = hasShader && this.shouldDeferShaderToPerSection(sectionKey)
|
|
983
1039
|
if (hasShader && shaderData) {
|
|
984
1040
|
if (deferShader && cubeMaterial) {
|
|
985
1041
|
shaderMesh = createShaderCubeMesh(shaderData, cubeMaterial)
|
|
@@ -1000,7 +1056,7 @@ export class ChunkMeshManager {
|
|
|
1000
1056
|
if (shaderData) {
|
|
1001
1057
|
sectionObject.deferredShaderCubes = {
|
|
1002
1058
|
words: shaderData.words,
|
|
1003
|
-
count: shaderData.count
|
|
1059
|
+
count: shaderData.count
|
|
1004
1060
|
}
|
|
1005
1061
|
}
|
|
1006
1062
|
if (!sectionObject.mesh) {
|
|
@@ -1014,14 +1070,7 @@ export class ChunkMeshManager {
|
|
|
1014
1070
|
sectionObject.deferredLegacyBlend = deferredLegacyBlend
|
|
1015
1071
|
}
|
|
1016
1072
|
if (hasShader && shaderData) {
|
|
1017
|
-
this.registerShaderSectionRaycastBox(
|
|
1018
|
-
sectionKey,
|
|
1019
|
-
shaderData.words,
|
|
1020
|
-
shaderData.count,
|
|
1021
|
-
geometryData.sx,
|
|
1022
|
-
geometryData.sy,
|
|
1023
|
-
geometryData.sz,
|
|
1024
|
-
)
|
|
1073
|
+
this.registerShaderSectionRaycastBox(sectionKey, shaderData.words, shaderData.count, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
1025
1074
|
}
|
|
1026
1075
|
|
|
1027
1076
|
let tilesCount = 0
|
|
@@ -1096,20 +1145,12 @@ export class ChunkMeshManager {
|
|
|
1096
1145
|
const bannerTexture = getBannerTexture(this.worldRenderer, blockName, nbt.simplify(bannerBlockEntity))
|
|
1097
1146
|
if (!bannerTexture) continue
|
|
1098
1147
|
const skyLevel = this.blockEntityLightRegistry.getSkyLevel()
|
|
1099
|
-
const banner = createBannerMesh(
|
|
1100
|
-
new Vec3(+x, +y, +z),
|
|
1101
|
-
rotation,
|
|
1102
|
-
isWall,
|
|
1103
|
-
bannerTexture,
|
|
1104
|
-
blockLightNorm,
|
|
1105
|
-
skyLightNorm,
|
|
1106
|
-
skyLevel,
|
|
1107
|
-
)
|
|
1148
|
+
const banner = createBannerMesh(new Vec3(+x, +y, +z), rotation, isWall, bannerTexture, blockLightNorm, skyLightNorm, skyLevel)
|
|
1108
1149
|
if (banner.bannerMaterial) {
|
|
1109
1150
|
this.blockEntityLightRegistry.register({
|
|
1110
1151
|
material: banner.bannerMaterial,
|
|
1111
1152
|
blockLightNorm,
|
|
1112
|
-
skyLightNorm
|
|
1153
|
+
skyLightNorm
|
|
1113
1154
|
})
|
|
1114
1155
|
}
|
|
1115
1156
|
const { x: bwx, y: bwy, z: bwz } = banner.position
|
|
@@ -1143,8 +1184,7 @@ export class ChunkMeshManager {
|
|
|
1143
1184
|
// setting so the near-first reveal gate has sections to hold.
|
|
1144
1185
|
const chunkCoords = sectionKey.split(',')
|
|
1145
1186
|
const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}`
|
|
1146
|
-
const renderByChunks = !!this.worldRenderer.displayOptions
|
|
1147
|
-
?.inWorldRenderingConfig?._renderByChunks
|
|
1187
|
+
const renderByChunks = !!this.worldRenderer.displayOptions?.inWorldRenderingConfig?._renderByChunks
|
|
1148
1188
|
const forceBatchForWasm = !!this.worldRenderer.worldRendererConfig?.wasmMesher
|
|
1149
1189
|
if ((renderByChunks || forceBatchForWasm) && !this.worldRenderer.finishedChunks[chunkKey]) {
|
|
1150
1190
|
sectionObject.visible = false
|
|
@@ -1165,7 +1205,7 @@ export class ChunkMeshManager {
|
|
|
1165
1205
|
* reveal is deferred (parked in `pendingNearReveal`) and re-checked on
|
|
1166
1206
|
* the next chunkFinished / player-move / grace-expiry.
|
|
1167
1207
|
*/
|
|
1168
|
-
finishChunkDisplay
|
|
1208
|
+
finishChunkDisplay(chunkKey: string): void {
|
|
1169
1209
|
const sectionKeys = this.waitingChunksToDisplay[chunkKey]
|
|
1170
1210
|
if (!sectionKeys) {
|
|
1171
1211
|
// No held sections (empty column / non-batched path) — but the
|
|
@@ -1184,7 +1224,7 @@ export class ChunkMeshManager {
|
|
|
1184
1224
|
this.tryRevealPending()
|
|
1185
1225
|
}
|
|
1186
1226
|
|
|
1187
|
-
private flushChunkDisplay
|
|
1227
|
+
private flushChunkDisplay(chunkKey: string): void {
|
|
1188
1228
|
const sectionKeys = this.waitingChunksToDisplay[chunkKey]
|
|
1189
1229
|
this.pendingNearReveal.delete(chunkKey)
|
|
1190
1230
|
this.clearNearRevealTimer(chunkKey)
|
|
@@ -1197,13 +1237,14 @@ export class ChunkMeshManager {
|
|
|
1197
1237
|
sectionObject.visible = true
|
|
1198
1238
|
}
|
|
1199
1239
|
delete this.waitingChunksToDisplay[chunkKey]
|
|
1240
|
+
this.markCullDirty()
|
|
1200
1241
|
}
|
|
1201
1242
|
|
|
1202
1243
|
// Re-check every parked entry; each has its own grace window via `ageMs`.
|
|
1203
1244
|
// Single pass is enough — pending entries are already finished, so flushing
|
|
1204
1245
|
// one cannot un-block another via this code path (cascading happens via
|
|
1205
1246
|
// chunkFinished events and per-pending grace timers).
|
|
1206
|
-
tryRevealPending
|
|
1247
|
+
tryRevealPending(): void {
|
|
1207
1248
|
if (this.pendingNearReveal.size === 0) return
|
|
1208
1249
|
const now = Date.now()
|
|
1209
1250
|
for (const [chunkKey, enqueuedAt] of [...this.pendingNearReveal]) {
|
|
@@ -1215,7 +1256,7 @@ export class ChunkMeshManager {
|
|
|
1215
1256
|
|
|
1216
1257
|
// Drop gate state for an unloaded column and re-evaluate any farther
|
|
1217
1258
|
// chunks that may have been blocked by it.
|
|
1218
|
-
onChunkRemovedFromGate
|
|
1259
|
+
onChunkRemovedFromGate(chunkKey: string): void {
|
|
1219
1260
|
this.pendingNearReveal.delete(chunkKey)
|
|
1220
1261
|
this.clearNearRevealTimer(chunkKey)
|
|
1221
1262
|
this.clearExpectedGraceTimer(chunkKey)
|
|
@@ -1223,7 +1264,7 @@ export class ChunkMeshManager {
|
|
|
1223
1264
|
this.tryRevealPending()
|
|
1224
1265
|
}
|
|
1225
1266
|
|
|
1226
|
-
private isWasmGateActive
|
|
1267
|
+
private isWasmGateActive(): boolean {
|
|
1227
1268
|
return !!this.worldRenderer.worldRendererConfig?.wasmMesher
|
|
1228
1269
|
}
|
|
1229
1270
|
|
|
@@ -1237,7 +1278,7 @@ export class ChunkMeshManager {
|
|
|
1237
1278
|
* - After grace: only actually-loaded-but-not-finished columns block,
|
|
1238
1279
|
* so a never-arriving column does not freeze the view.
|
|
1239
1280
|
*/
|
|
1240
|
-
private isBlockedByNearer
|
|
1281
|
+
private isBlockedByNearer(chunkKey: string, ageMs: number): boolean {
|
|
1241
1282
|
const viewer = this.worldRenderer.viewerChunkPosition
|
|
1242
1283
|
if (!viewer) return false
|
|
1243
1284
|
const ownParts = chunkKey.split(',')
|
|
@@ -1284,7 +1325,7 @@ export class ChunkMeshManager {
|
|
|
1284
1325
|
return false
|
|
1285
1326
|
}
|
|
1286
1327
|
|
|
1287
|
-
private armNearRevealTimer
|
|
1328
|
+
private armNearRevealTimer(chunkKey: string): void {
|
|
1288
1329
|
if (this.nearRevealTimers.has(chunkKey)) return
|
|
1289
1330
|
const timer = setTimeout(() => {
|
|
1290
1331
|
this.nearRevealTimers.delete(chunkKey)
|
|
@@ -1296,7 +1337,7 @@ export class ChunkMeshManager {
|
|
|
1296
1337
|
this.nearRevealTimers.set(chunkKey, timer)
|
|
1297
1338
|
}
|
|
1298
1339
|
|
|
1299
|
-
private clearNearRevealTimer
|
|
1340
|
+
private clearNearRevealTimer(chunkKey: string): void {
|
|
1300
1341
|
const timer = this.nearRevealTimers.get(chunkKey)
|
|
1301
1342
|
if (timer) {
|
|
1302
1343
|
clearTimeout(timer)
|
|
@@ -1309,7 +1350,7 @@ export class ChunkMeshManager {
|
|
|
1309
1350
|
* "expected but never arrived" positions stop blocking promptly,
|
|
1310
1351
|
* without waiting for the next chunkFinished / player-move event.
|
|
1311
1352
|
*/
|
|
1312
|
-
private armExpectedGraceTimer
|
|
1353
|
+
private armExpectedGraceTimer(chunkKey: string): void {
|
|
1313
1354
|
if (this.nearRevealGraceTimers.has(chunkKey)) return
|
|
1314
1355
|
const timer = setTimeout(() => {
|
|
1315
1356
|
this.nearRevealGraceTimers.delete(chunkKey)
|
|
@@ -1319,7 +1360,7 @@ export class ChunkMeshManager {
|
|
|
1319
1360
|
this.nearRevealGraceTimers.set(chunkKey, timer)
|
|
1320
1361
|
}
|
|
1321
1362
|
|
|
1322
|
-
private clearExpectedGraceTimer
|
|
1363
|
+
private clearExpectedGraceTimer(chunkKey: string): void {
|
|
1323
1364
|
const timer = this.nearRevealGraceTimers.get(chunkKey)
|
|
1324
1365
|
if (timer) {
|
|
1325
1366
|
clearTimeout(timer)
|
|
@@ -1327,7 +1368,7 @@ export class ChunkMeshManager {
|
|
|
1327
1368
|
}
|
|
1328
1369
|
}
|
|
1329
1370
|
|
|
1330
|
-
cleanupSection
|
|
1371
|
+
cleanupSection(sectionKey: string, opts?: { forRemesh?: boolean }) {
|
|
1331
1372
|
// Remove section object from scene
|
|
1332
1373
|
const sectionObject = this.sectionObjects[sectionKey]
|
|
1333
1374
|
if (sectionObject) {
|
|
@@ -1346,7 +1387,7 @@ export class ChunkMeshManager {
|
|
|
1346
1387
|
// Cleanup banner textures before disposing
|
|
1347
1388
|
if (sectionObject.bannersContainer) {
|
|
1348
1389
|
for (const child of sectionObject.bannersContainer.children) {
|
|
1349
|
-
const banner = child as THREE.Group & { bannerMaterial?: THREE.MeshBasicMaterial
|
|
1390
|
+
const banner = child as THREE.Group & { bannerMaterial?: THREE.MeshBasicMaterial; bannerTexture?: THREE.Texture }
|
|
1350
1391
|
if (banner.bannerMaterial) {
|
|
1351
1392
|
this.blockEntityLightRegistry.unregister(banner.bannerMaterial)
|
|
1352
1393
|
}
|
|
@@ -1356,10 +1397,13 @@ export class ChunkMeshManager {
|
|
|
1356
1397
|
}
|
|
1357
1398
|
this.disposeContainer(sectionObject.bannersContainer)
|
|
1358
1399
|
}
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1400
|
+
if (!opts?.forRemesh) {
|
|
1401
|
+
this.globalBlockBuffer?.removeSection(sectionKey)
|
|
1402
|
+
this.globalLegacyBuffer?.removeSection(sectionKey)
|
|
1403
|
+
this.globalLegacyBlendBuffer?.removeSection(sectionKey)
|
|
1404
|
+
this.maybeUnregisterLegacyCullSection(sectionKey)
|
|
1405
|
+
this.unregisterShaderSectionRaycastBox(sectionKey)
|
|
1406
|
+
}
|
|
1363
1407
|
this.markCullDirty()
|
|
1364
1408
|
delete sectionObject.deferredLegacyOpaque
|
|
1365
1409
|
delete sectionObject.deferredLegacyBlend
|
|
@@ -1398,8 +1442,7 @@ export class ChunkMeshManager {
|
|
|
1398
1442
|
}
|
|
1399
1443
|
delete this.sectionObjects[sectionKey]
|
|
1400
1444
|
if (!opts?.forRemesh) {
|
|
1401
|
-
this.worldRenderer.getModule<{ onSectionRemoved?: (key: string) => void }>('futuristicReveal')
|
|
1402
|
-
?.onSectionRemoved?.(sectionKey)
|
|
1445
|
+
this.worldRenderer.getModule<{ onSectionRemoved?: (key: string) => void }>('futuristicReveal')?.onSectionRemoved?.(sectionKey)
|
|
1403
1446
|
}
|
|
1404
1447
|
}
|
|
1405
1448
|
}
|
|
@@ -1407,7 +1450,7 @@ export class ChunkMeshManager {
|
|
|
1407
1450
|
/**
|
|
1408
1451
|
* Release a section and return its mesh to the pool
|
|
1409
1452
|
*/
|
|
1410
|
-
private releasePooledMesh
|
|
1453
|
+
private releasePooledMesh(sectionKey: string): void {
|
|
1411
1454
|
const poolEntry = this.activeSections.get(sectionKey)
|
|
1412
1455
|
if (!poolEntry) return
|
|
1413
1456
|
|
|
@@ -1420,7 +1463,7 @@ export class ChunkMeshManager {
|
|
|
1420
1463
|
this.cleanupExcessMeshes()
|
|
1421
1464
|
}
|
|
1422
1465
|
|
|
1423
|
-
releaseSection
|
|
1466
|
+
releaseSection(sectionKey: string): boolean {
|
|
1424
1467
|
this.cleanupSection(sectionKey)
|
|
1425
1468
|
|
|
1426
1469
|
const poolEntry = this.activeSections.get(sectionKey)
|
|
@@ -1448,14 +1491,14 @@ export class ChunkMeshManager {
|
|
|
1448
1491
|
/**
|
|
1449
1492
|
* Get section object if it exists
|
|
1450
1493
|
*/
|
|
1451
|
-
getSectionObject
|
|
1494
|
+
getSectionObject(sectionKey: string): SectionObject | undefined {
|
|
1452
1495
|
return this.sectionObjects[sectionKey]
|
|
1453
1496
|
}
|
|
1454
1497
|
|
|
1455
1498
|
/**
|
|
1456
1499
|
* Update box helper for a section
|
|
1457
1500
|
*/
|
|
1458
|
-
updateBoxHelper
|
|
1501
|
+
updateBoxHelper(sectionKey: string, showChunkBorders: boolean, chunkBoxMaterial: THREE.Material = this.chunkBoxMaterial) {
|
|
1459
1502
|
const sectionObject = this.sectionObjects[sectionKey]
|
|
1460
1503
|
if (!sectionObject) return
|
|
1461
1504
|
|
|
@@ -1491,7 +1534,7 @@ export class ChunkMeshManager {
|
|
|
1491
1534
|
* after the move from `WorldBlockGeometry` (which created the helpers
|
|
1492
1535
|
* eagerly per section) to the pooled `ChunkMeshManager`.
|
|
1493
1536
|
*/
|
|
1494
|
-
updateAllBoxHelpers
|
|
1537
|
+
updateAllBoxHelpers(showChunkBorders: boolean) {
|
|
1495
1538
|
for (const sectionKey of Object.keys(this.sectionObjects)) {
|
|
1496
1539
|
this.updateBoxHelper(sectionKey, showChunkBorders)
|
|
1497
1540
|
}
|
|
@@ -1500,21 +1543,21 @@ export class ChunkMeshManager {
|
|
|
1500
1543
|
/**
|
|
1501
1544
|
* Get mesh for section if it exists
|
|
1502
1545
|
*/
|
|
1503
|
-
getSectionMesh
|
|
1546
|
+
getSectionMesh(sectionKey: string): THREE.Mesh | undefined {
|
|
1504
1547
|
return this.activeSections.get(sectionKey)?.mesh
|
|
1505
1548
|
}
|
|
1506
1549
|
|
|
1507
1550
|
/**
|
|
1508
1551
|
* Check if section is managed by this pool
|
|
1509
1552
|
*/
|
|
1510
|
-
hasSection
|
|
1553
|
+
hasSection(sectionKey: string): boolean {
|
|
1511
1554
|
return this.activeSections.has(sectionKey)
|
|
1512
1555
|
}
|
|
1513
1556
|
|
|
1514
1557
|
/**
|
|
1515
1558
|
* Update pool size based on new view distance
|
|
1516
1559
|
*/
|
|
1517
|
-
updateViewDistance
|
|
1560
|
+
updateViewDistance(maxViewDistance: number) {
|
|
1518
1561
|
// Calculate dynamic pool size based on view distance
|
|
1519
1562
|
const chunksInView = (maxViewDistance * 2 + 1) ** 2
|
|
1520
1563
|
const maxSectionsPerChunk = this.worldHeight / 16
|
|
@@ -1535,7 +1578,7 @@ export class ChunkMeshManager {
|
|
|
1535
1578
|
/**
|
|
1536
1579
|
* Get pool statistics
|
|
1537
1580
|
*/
|
|
1538
|
-
getGlobalBufferStats
|
|
1581
|
+
getGlobalBufferStats(): GlobalBufferStats {
|
|
1539
1582
|
const snapshotLegacy = (buffer: GlobalLegacyBuffer | null): GlobalBufferSlotStats | null => {
|
|
1540
1583
|
if (!buffer) return null
|
|
1541
1584
|
return {
|
|
@@ -1543,7 +1586,7 @@ export class ChunkMeshManager {
|
|
|
1543
1586
|
capacity: buffer.getCapacityQuads(),
|
|
1544
1587
|
sections: buffer.getSectionCount(),
|
|
1545
1588
|
usedBytes: buffer.getUsedMemoryBytes(),
|
|
1546
|
-
capacityBytes: buffer.getMemoryBytes()
|
|
1589
|
+
capacityBytes: buffer.getMemoryBytes()
|
|
1547
1590
|
}
|
|
1548
1591
|
}
|
|
1549
1592
|
|
|
@@ -1555,17 +1598,17 @@ export class ChunkMeshManager {
|
|
|
1555
1598
|
capacity: cubes.getCapacityFaces(),
|
|
1556
1599
|
sections: cubes.getSectionCount(),
|
|
1557
1600
|
usedBytes: cubes.getUsedMemoryBytes(),
|
|
1558
|
-
capacityBytes: cubes.getMemoryBytes()
|
|
1601
|
+
capacityBytes: cubes.getMemoryBytes()
|
|
1559
1602
|
}
|
|
1560
1603
|
: null,
|
|
1561
1604
|
legacyOpaque: snapshotLegacy(this.globalLegacyBuffer),
|
|
1562
|
-
legacyBlend: snapshotLegacy(this.globalLegacyBlendBuffer)
|
|
1605
|
+
legacyBlend: snapshotLegacy(this.globalLegacyBlendBuffer)
|
|
1563
1606
|
}
|
|
1564
1607
|
}
|
|
1565
1608
|
|
|
1566
|
-
getStats
|
|
1609
|
+
getStats() {
|
|
1567
1610
|
const freeCount = this.meshPool.filter(entry => !entry.inUse).length
|
|
1568
|
-
const hitRate = this.hits + this.misses > 0 ? (this.hits / (this.hits + this.misses) * 100).toFixed(1) : '0'
|
|
1611
|
+
const hitRate = this.hits + this.misses > 0 ? ((this.hits / (this.hits + this.misses)) * 100).toFixed(1) : '0'
|
|
1569
1612
|
const memoryUsage = this.getEstimatedMemoryUsage()
|
|
1570
1613
|
|
|
1571
1614
|
return {
|
|
@@ -1582,21 +1625,21 @@ export class ChunkMeshManager {
|
|
|
1582
1625
|
/**
|
|
1583
1626
|
* Get total tiles rendered
|
|
1584
1627
|
*/
|
|
1585
|
-
getTotalTiles
|
|
1628
|
+
getTotalTiles(): number {
|
|
1586
1629
|
return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj.tilesCount || 0), 0)
|
|
1587
1630
|
}
|
|
1588
1631
|
|
|
1589
1632
|
/**
|
|
1590
1633
|
* Get total blocks rendered
|
|
1591
1634
|
*/
|
|
1592
|
-
getTotalBlocks
|
|
1635
|
+
getTotalBlocks(): number {
|
|
1593
1636
|
return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj.blocksCount || 0), 0)
|
|
1594
1637
|
}
|
|
1595
1638
|
|
|
1596
1639
|
/**
|
|
1597
1640
|
* Estimate memory usage in MB
|
|
1598
1641
|
*/
|
|
1599
|
-
getEstimatedMemoryUsage
|
|
1642
|
+
getEstimatedMemoryUsage(): { total: string; breakdown: any } {
|
|
1600
1643
|
let totalBytes = 0
|
|
1601
1644
|
let positionBytes = 0
|
|
1602
1645
|
let normalBytes = 0
|
|
@@ -1685,7 +1728,7 @@ export class ChunkMeshManager {
|
|
|
1685
1728
|
color: `${(colorBytes / (1024 * 1024)).toFixed(2)} MB`,
|
|
1686
1729
|
uv: `${(uvBytes / (1024 * 1024)).toFixed(2)} MB`,
|
|
1687
1730
|
index: `${(indexBytes / (1024 * 1024)).toFixed(2)} MB`,
|
|
1688
|
-
shaderInstances: `${(shaderInstanceBytes / (1024 * 1024)).toFixed(2)} MB
|
|
1731
|
+
shaderInstances: `${(shaderInstanceBytes / (1024 * 1024)).toFixed(2)} MB`
|
|
1689
1732
|
}
|
|
1690
1733
|
}
|
|
1691
1734
|
}
|
|
@@ -1693,7 +1736,7 @@ export class ChunkMeshManager {
|
|
|
1693
1736
|
/**
|
|
1694
1737
|
* Cleanup and dispose resources
|
|
1695
1738
|
*/
|
|
1696
|
-
dispose
|
|
1739
|
+
dispose() {
|
|
1697
1740
|
// Release all active sections (snapshot keys to avoid mutating map during iteration)
|
|
1698
1741
|
const activeKeys = [...this.activeSections.keys()]
|
|
1699
1742
|
for (const sectionKey of activeKeys) {
|
|
@@ -1712,6 +1755,7 @@ export class ChunkMeshManager {
|
|
|
1712
1755
|
this.activeSections.clear()
|
|
1713
1756
|
this.chunkBoxMaterial.dispose()
|
|
1714
1757
|
this.shaderSectionRaycastBoxes.clear()
|
|
1758
|
+
this.lastBufferStateKey = ''
|
|
1715
1759
|
this.globalBlockBuffer?.dispose()
|
|
1716
1760
|
this.globalBlockBuffer = null
|
|
1717
1761
|
this.globalLegacyBuffer?.dispose()
|
|
@@ -1736,7 +1780,7 @@ export class ChunkMeshManager {
|
|
|
1736
1780
|
|
|
1737
1781
|
// Private helper methods
|
|
1738
1782
|
|
|
1739
|
-
private acquireMesh
|
|
1783
|
+
private acquireMesh(): ChunkMeshPool | undefined {
|
|
1740
1784
|
if (this.bypassPooling) {
|
|
1741
1785
|
const entry: ChunkMeshPool = {
|
|
1742
1786
|
mesh: new THREE.Mesh(new THREE.BufferGeometry(), this.getLegacyShaderMaterial()),
|
|
@@ -1783,7 +1827,7 @@ export class ChunkMeshManager {
|
|
|
1783
1827
|
throw new Error('ChunkMeshManager: Failed to acquire mesh after pool expansion')
|
|
1784
1828
|
}
|
|
1785
1829
|
|
|
1786
|
-
private expandPool
|
|
1830
|
+
private expandPool(newSize: number) {
|
|
1787
1831
|
const currentLength = this.meshPool.length
|
|
1788
1832
|
this.poolSize = newSize
|
|
1789
1833
|
|
|
@@ -1806,12 +1850,7 @@ export class ChunkMeshManager {
|
|
|
1806
1850
|
}
|
|
1807
1851
|
}
|
|
1808
1852
|
|
|
1809
|
-
private updateGeometryAttribute
|
|
1810
|
-
geometry: THREE.BufferGeometry,
|
|
1811
|
-
name: string,
|
|
1812
|
-
array: Float32Array,
|
|
1813
|
-
itemSize: number
|
|
1814
|
-
) {
|
|
1853
|
+
private updateGeometryAttribute(geometry: THREE.BufferGeometry, name: string, array: Float32Array, itemSize: number) {
|
|
1815
1854
|
const attribute = geometry.getAttribute(name)
|
|
1816
1855
|
|
|
1817
1856
|
if (attribute && attribute.count === array.length / itemSize) {
|
|
@@ -1824,7 +1863,7 @@ export class ChunkMeshManager {
|
|
|
1824
1863
|
}
|
|
1825
1864
|
}
|
|
1826
1865
|
|
|
1827
|
-
private clearGeometry
|
|
1866
|
+
private clearGeometry(geometry: THREE.BufferGeometry) {
|
|
1828
1867
|
const attributes = ['position', 'normal', 'color', 'a_skyLight', 'a_blockLight', 'uv']
|
|
1829
1868
|
for (const name of attributes) {
|
|
1830
1869
|
if (geometry.hasAttribute(name)) {
|
|
@@ -1838,7 +1877,7 @@ export class ChunkMeshManager {
|
|
|
1838
1877
|
geometry.boundingSphere = null
|
|
1839
1878
|
}
|
|
1840
1879
|
|
|
1841
|
-
private cleanupExcessMeshes
|
|
1880
|
+
private cleanupExcessMeshes() {
|
|
1842
1881
|
// If pool size exceeds max and we have free meshes, remove some
|
|
1843
1882
|
if (this.poolSize > this.maxPoolSize) {
|
|
1844
1883
|
const freeCount = this.meshPool.filter(entry => !entry.inUse).length
|
|
@@ -1858,14 +1897,14 @@ export class ChunkMeshManager {
|
|
|
1858
1897
|
}
|
|
1859
1898
|
}
|
|
1860
1899
|
|
|
1861
|
-
private disposeContainer
|
|
1900
|
+
private disposeContainer(container: THREE.Group, cleanTextures = true) {
|
|
1862
1901
|
disposeObject(container, cleanTextures)
|
|
1863
1902
|
}
|
|
1864
1903
|
|
|
1865
1904
|
/**
|
|
1866
1905
|
* Record render time for performance monitoring
|
|
1867
1906
|
*/
|
|
1868
|
-
recordRenderTime
|
|
1907
|
+
recordRenderTime(renderTime: number): void {
|
|
1869
1908
|
this.renderTimes.push(renderTime)
|
|
1870
1909
|
if (this.renderTimes.length > this.maxRenderTimeSamples) {
|
|
1871
1910
|
this.renderTimes.shift()
|
|
@@ -1882,31 +1921,31 @@ export class ChunkMeshManager {
|
|
|
1882
1921
|
/**
|
|
1883
1922
|
* Get current effective render distance
|
|
1884
1923
|
*/
|
|
1885
|
-
getEffectiveRenderDistance
|
|
1924
|
+
getEffectiveRenderDistance(): number {
|
|
1886
1925
|
return this.performanceOverrideDistance || this.worldRenderer.viewDistance
|
|
1887
1926
|
}
|
|
1888
1927
|
|
|
1889
1928
|
/**
|
|
1890
1929
|
* Force reset performance override
|
|
1891
1930
|
*/
|
|
1892
|
-
resetPerformanceOverride
|
|
1931
|
+
resetPerformanceOverride(): void {
|
|
1893
1932
|
this.performanceOverrideDistance = undefined
|
|
1894
1933
|
this.renderTimes.length = 0
|
|
1895
1934
|
console.log('ChunkMeshManager: Performance override reset')
|
|
1896
1935
|
}
|
|
1897
1936
|
|
|
1898
1937
|
/**
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
getAverageRenderTime
|
|
1938
|
+
* Get average render time
|
|
1939
|
+
*/
|
|
1940
|
+
getAverageRenderTime(): number {
|
|
1902
1941
|
if (this.renderTimes.length === 0) return 0
|
|
1903
1942
|
return this.renderTimes.reduce((sum, time) => sum + time, 0) / this.renderTimes.length
|
|
1904
1943
|
}
|
|
1905
1944
|
|
|
1906
1945
|
/**
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
private checkPerformance
|
|
1946
|
+
* Check if performance is degraded and adjust render distance
|
|
1947
|
+
*/
|
|
1948
|
+
private checkPerformance(): void {
|
|
1910
1949
|
if (this.renderTimes.length < this.maxRenderTimeSamples) return
|
|
1911
1950
|
|
|
1912
1951
|
const avgRenderTime = this.getAverageRenderTime()
|
|
@@ -1937,7 +1976,7 @@ export class ChunkMeshManager {
|
|
|
1937
1976
|
/**
|
|
1938
1977
|
* Hide sections beyond performance override distance
|
|
1939
1978
|
*/
|
|
1940
|
-
updateSectionsVisibility
|
|
1979
|
+
updateSectionsVisibility(): void {
|
|
1941
1980
|
const cameraPos = this.worldRenderer.cameraSectionPos
|
|
1942
1981
|
for (const [sectionKey, sectionObject] of Object.entries(this.sectionObjects)) {
|
|
1943
1982
|
// Don't override "Batch Chunks Display" hiding — those sections must
|
|
@@ -1964,16 +2003,14 @@ export class ChunkMeshManager {
|
|
|
1964
2003
|
}
|
|
1965
2004
|
}
|
|
1966
2005
|
|
|
1967
|
-
|
|
1968
2006
|
class SignHeadsRenderer {
|
|
1969
|
-
constructor
|
|
1970
|
-
}
|
|
2007
|
+
constructor(public worldRendererThree: WorldRendererThree) {}
|
|
1971
2008
|
|
|
1972
|
-
dispose
|
|
2009
|
+
dispose() {
|
|
1973
2010
|
disposeAllSignTextures()
|
|
1974
2011
|
}
|
|
1975
2012
|
|
|
1976
|
-
renderHead
|
|
2013
|
+
renderHead(position: Vec3, rotation: number, isWall: boolean, blockEntity) {
|
|
1977
2014
|
let textureData: string
|
|
1978
2015
|
if (blockEntity.SkullOwner) {
|
|
1979
2016
|
textureData = blockEntity.SkullOwner.Properties?.textures?.[0]?.Value
|
|
@@ -1987,8 +2024,7 @@ class SignHeadsRenderer {
|
|
|
1987
2024
|
let skinUrl = decodedData.textures?.SKIN?.url
|
|
1988
2025
|
const { skinTexturesProxy } = this.worldRendererThree.worldRendererConfig
|
|
1989
2026
|
if (skinTexturesProxy) {
|
|
1990
|
-
skinUrl = skinUrl?.replace('http://textures.minecraft.net/', skinTexturesProxy)
|
|
1991
|
-
.replace('https://textures.minecraft.net/', skinTexturesProxy)
|
|
2027
|
+
skinUrl = skinUrl?.replace('http://textures.minecraft.net/', skinTexturesProxy).replace('https://textures.minecraft.net/', skinTexturesProxy)
|
|
1992
2028
|
}
|
|
1993
2029
|
|
|
1994
2030
|
const mesh = getMesh(this.worldRendererThree, skinUrl, armorModel.head as any)
|
|
@@ -2001,11 +2037,7 @@ class SignHeadsRenderer {
|
|
|
2001
2037
|
group.add(mesh)
|
|
2002
2038
|
this.worldRendererThree.sceneOrigin.track(group)
|
|
2003
2039
|
group.position.set(position.x + 0.5, position.y + 0.045, position.z + 0.5)
|
|
2004
|
-
group.rotation.set(
|
|
2005
|
-
0,
|
|
2006
|
-
-THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)),
|
|
2007
|
-
0
|
|
2008
|
-
)
|
|
2040
|
+
group.rotation.set(0, -THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)), 0)
|
|
2009
2041
|
group.scale.set(0.8, 0.8, 0.8)
|
|
2010
2042
|
return group
|
|
2011
2043
|
} catch (err) {
|
|
@@ -2013,7 +2045,7 @@ class SignHeadsRenderer {
|
|
|
2013
2045
|
}
|
|
2014
2046
|
}
|
|
2015
2047
|
|
|
2016
|
-
renderSign
|
|
2048
|
+
renderSign(position: Vec3, rotation: number, isWall: boolean, isHanging: boolean, blockEntity) {
|
|
2017
2049
|
const tex = getSignTexture(this.worldRendererThree, blockEntity, isHanging)
|
|
2018
2050
|
|
|
2019
2051
|
if (!tex) return
|
|
@@ -2034,11 +2066,7 @@ class SignHeadsRenderer {
|
|
|
2034
2066
|
}
|
|
2035
2067
|
|
|
2036
2068
|
const group = new THREE.Group() as THREE.Group & { signTexture?: THREE.Texture }
|
|
2037
|
-
group.rotation.set(
|
|
2038
|
-
0,
|
|
2039
|
-
-THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)),
|
|
2040
|
-
0
|
|
2041
|
-
)
|
|
2069
|
+
group.rotation.set(0, -THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)), 0)
|
|
2042
2070
|
group.add(mesh)
|
|
2043
2071
|
group.signTexture = tex
|
|
2044
2072
|
const height = (isHanging ? 10 : 8) / 16
|