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.
- package/README.md +66 -26
- package/dist/mesher.js +36 -36
- package/dist/mesher.js.map +4 -4
- package/dist/mesherWasm.js +217 -217
- package/dist/minecraft-renderer.js +66 -66
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +450 -450
- 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 +349 -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/cameraCollisionBlockCache.ts +156 -0
- package/src/three/cameraCollisionSolidity.ts +50 -0
- package/src/three/cameraShake.ts +15 -6
- package/src/three/chunkMeshManager.ts +223 -390
- 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 +167 -100
- package/src/three/globalLegacyBuffer.ts +248 -264
- 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 +10 -16
- 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 +24 -110
- 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 +34 -64
- 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 +300 -41
- package/src/three/tests/legacyMultiDraw.test.ts +8 -29
- package/src/three/tests/pr3PerFrameCpuCuts.test.ts +106 -29
- package/src/three/tests/signTextureCache.test.ts +4 -4
- package/src/three/thirdPersonVoxelRaycast.ts +120 -0
- 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 +144 -166
- 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/cameraCollisionBlockCache.test.ts +82 -0
- 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 +1 -93
- package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +103 -141
- package/src/wasm-mesher/tests/splitColumnWasmOutput.test.ts +14 -22
- package/src/wasm-mesher/tests/thirdPersonVoxelRaycast.test.ts +63 -0
- 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
|
@@ -3,22 +3,31 @@ import * as THREE from 'three'
|
|
|
3
3
|
import * as nbt from 'prismarine-nbt'
|
|
4
4
|
import { Vec3 } from 'vec3'
|
|
5
5
|
import { MesherGeometryOutput } from '../mesher-shared/shared'
|
|
6
|
-
import { getShaderCubeResources
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
import { getShaderCubeResources } from '../wasm-mesher/bridge/shaderCubeBridge'
|
|
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'
|
|
25
|
+
import { sectionIntersectsFrustum, setupLegacySectionMatrix, updateLegacySectionCullState } from './legacySectionCull'
|
|
10
26
|
import { createShaderCubeMesh, disposeShaderCubeMesh } from './shaderCubeMesh'
|
|
11
27
|
import { GlobalBlockBuffer } from './globalBlockBuffer'
|
|
12
28
|
import { buildVisibleCubeSpans } from './cubeDrawSpans'
|
|
13
29
|
import { GlobalLegacyBuffer, type LegacySectionGeometry } from './globalLegacyBuffer'
|
|
14
|
-
import {
|
|
15
|
-
computeShaderSectionRaycastAabb,
|
|
16
|
-
isPointInsideAabb,
|
|
17
|
-
raycastAabb,
|
|
18
|
-
raycastShaderBlocksAabb,
|
|
19
|
-
sectionAabbIntersectsRay,
|
|
20
|
-
type ShaderSectionRaycastEntry,
|
|
21
|
-
} from './sectionRaycastAabb'
|
|
30
|
+
import { computeShaderSectionRaycastAabb, type ShaderSectionRaycastEntry } from './sectionRaycastAabb'
|
|
22
31
|
import { getMesh } from './entity/EntityMesh'
|
|
23
32
|
import type { WorldRendererThree } from './worldRendererThree'
|
|
24
33
|
import { armorModel } from './entity/armorModels'
|
|
@@ -39,7 +48,7 @@ export interface SectionObject extends THREE.Group {
|
|
|
39
48
|
/** Per-section instanced shader mesh (sci-fi reveal defer only). */
|
|
40
49
|
shaderMesh?: THREE.Mesh<THREE.InstancedBufferGeometry, THREE.ShaderMaterial>
|
|
41
50
|
/** Shader cube words kept for migration to global buffer after reveal. */
|
|
42
|
-
deferredShaderCubes?: { words: Uint32Array
|
|
51
|
+
deferredShaderCubes?: { words: Uint32Array; count: number }
|
|
43
52
|
/** Opaque legacy geometry deferred from global buffer during sci-fi reveal. */
|
|
44
53
|
deferredLegacyOpaque?: LegacySectionGeometry
|
|
45
54
|
/** Blend legacy geometry deferred from global buffer during sci-fi reveal. */
|
|
@@ -139,10 +148,11 @@ export class ChunkMeshManager {
|
|
|
139
148
|
private readonly _legacyCullBox = new THREE.Box3()
|
|
140
149
|
private readonly _legacyCullBoxMin = new THREE.Vector3()
|
|
141
150
|
private readonly _legacyCullBoxMax = new THREE.Vector3()
|
|
142
|
-
private readonly _visibleSectionSpans: Array<{ key: string
|
|
151
|
+
private readonly _visibleSectionSpans: Array<{ key: string; distSq: number }> = []
|
|
143
152
|
/** Sections with geometry in global legacy opaque and/or blend buffers — cull/raycast scan only these. */
|
|
144
|
-
private readonly legacyCullSections = new Map<string, { worldX: number
|
|
153
|
+
private readonly legacyCullSections = new Map<string, { worldX: number; worldY: number; worldZ: number }>()
|
|
145
154
|
private _lastCullFingerprint = ''
|
|
155
|
+
private lastBufferStateKey = ''
|
|
146
156
|
/** Drives per-frame cull + span rebuild; cleared after updateSectionCullAndSort. */
|
|
147
157
|
cullDirty = true
|
|
148
158
|
private readonly _lastCullCamPos = new THREE.Vector3()
|
|
@@ -153,11 +163,8 @@ export class ChunkMeshManager {
|
|
|
153
163
|
globalBlockBuffer: GlobalBlockBuffer | null = null
|
|
154
164
|
globalLegacyBuffer: GlobalLegacyBuffer | null = null
|
|
155
165
|
globalLegacyBlendBuffer: GlobalLegacyBuffer | null = null
|
|
156
|
-
/** Tight world AABBs for
|
|
166
|
+
/** Tight world AABBs for shader-cube frustum culling (section centers). */
|
|
157
167
|
private readonly shaderSectionRaycastBoxes = new Map<string, ShaderSectionRaycastEntry>()
|
|
158
|
-
/** Per-raycast block dedup; safe while the eye is inside at most one section aggregate AABB per call. */
|
|
159
|
-
private readonly blockRaycastVisitGen = new Uint16Array(4096)
|
|
160
|
-
private blockRaycastVisitStamp = 1
|
|
161
168
|
|
|
162
169
|
// Performance tracking
|
|
163
170
|
private hits = 0
|
|
@@ -173,20 +180,20 @@ export class ChunkMeshManager {
|
|
|
173
180
|
private lastPerformanceCheck = 0
|
|
174
181
|
private readonly performanceCheckInterval = 2000 // Check every 2 seconds
|
|
175
182
|
|
|
176
|
-
get performanceOverrideDistance
|
|
183
|
+
get performanceOverrideDistance() {
|
|
177
184
|
return this._performanceOverrideDistance ?? 0
|
|
178
185
|
}
|
|
179
|
-
set performanceOverrideDistance
|
|
186
|
+
set performanceOverrideDistance(value: number | undefined) {
|
|
180
187
|
this._performanceOverrideDistance = value
|
|
181
188
|
this.updateSectionsVisibility()
|
|
182
189
|
}
|
|
183
190
|
|
|
184
|
-
constructor
|
|
191
|
+
constructor(
|
|
185
192
|
public worldRenderer: WorldRendererThree,
|
|
186
193
|
public scene: THREE.Object3D,
|
|
187
194
|
public material: THREE.Material,
|
|
188
195
|
public worldHeight: number,
|
|
189
|
-
viewDistance = 3
|
|
196
|
+
viewDistance = 3
|
|
190
197
|
) {
|
|
191
198
|
this.updateViewDistance(viewDistance)
|
|
192
199
|
this.signHeadsRenderer = new SignHeadsRenderer(worldRenderer)
|
|
@@ -194,7 +201,7 @@ export class ChunkMeshManager {
|
|
|
194
201
|
this.initializePool()
|
|
195
202
|
}
|
|
196
203
|
|
|
197
|
-
private initializePool
|
|
204
|
+
private initializePool() {
|
|
198
205
|
// Create initial pool
|
|
199
206
|
for (let i = 0; i < this.poolSize; i++) {
|
|
200
207
|
const geometry = new THREE.BufferGeometry()
|
|
@@ -215,18 +222,18 @@ export class ChunkMeshManager {
|
|
|
215
222
|
}
|
|
216
223
|
|
|
217
224
|
/** True when section has legacy vertices and/or GPU shader cube instances. */
|
|
218
|
-
sectionHasRenderableContent
|
|
225
|
+
sectionHasRenderableContent(geometryData: MesherGeometryOutput): boolean {
|
|
219
226
|
if (geometryData.positions.length > 0) return true
|
|
220
227
|
if ((geometryData.blend?.positions.length ?? 0) > 0) return true
|
|
221
228
|
if (!this.isShaderCubesGpuEnabled()) return false
|
|
222
229
|
return (geometryData.shaderCubes?.count ?? 0) > 0
|
|
223
230
|
}
|
|
224
231
|
|
|
225
|
-
isShaderCubesGpuEnabled
|
|
232
|
+
isShaderCubesGpuEnabled(): boolean {
|
|
226
233
|
return this.worldRenderer.shaderCubeBlocksEnabled()
|
|
227
234
|
}
|
|
228
235
|
|
|
229
|
-
syncCubeShaderUniforms
|
|
236
|
+
syncCubeShaderUniforms(): void {
|
|
230
237
|
if (!this.isShaderCubesGpuEnabled()) return
|
|
231
238
|
const mat = this.cubeShaderMaterial ?? this.getCubeShaderMaterial()
|
|
232
239
|
if (!mat) return
|
|
@@ -243,7 +250,7 @@ export class ChunkMeshManager {
|
|
|
243
250
|
mat.needsUpdate = true
|
|
244
251
|
}
|
|
245
252
|
|
|
246
|
-
syncLegacyShaderUniforms
|
|
253
|
+
syncLegacyShaderUniforms(): void {
|
|
247
254
|
const atlas = (this.material as THREE.MeshBasicMaterial).map ?? null
|
|
248
255
|
if (this.legacyShaderMaterial) {
|
|
249
256
|
this.legacyShaderMaterial.uniforms.u_atlas.value = atlas
|
|
@@ -260,7 +267,7 @@ export class ChunkMeshManager {
|
|
|
260
267
|
}
|
|
261
268
|
|
|
262
269
|
/** Render-time sky light cap (0–1, from time-of-day / 15). */
|
|
263
|
-
setSkyLevel
|
|
270
|
+
setSkyLevel(value: number): void {
|
|
264
271
|
const cube = this.cubeShaderMaterial ?? (this.isShaderCubesGpuEnabled() ? this.getCubeShaderMaterial() : null)
|
|
265
272
|
if (cube) setCubeSkyLevel(cube, value)
|
|
266
273
|
if (this.legacyShaderMaterial) setLegacySkyLevel(this.legacyShaderMaterial, value)
|
|
@@ -269,13 +276,13 @@ export class ChunkMeshManager {
|
|
|
269
276
|
this.blockEntityLightRegistry.setSkyLevel(value)
|
|
270
277
|
}
|
|
271
278
|
|
|
272
|
-
setShadingTheme
|
|
279
|
+
setShadingTheme(theme: 'vanilla' | 'high-contrast', cardinalLight: string): void {
|
|
273
280
|
const cube = this.cubeShaderMaterial ?? (this.isShaderCubesGpuEnabled() ? this.getCubeShaderMaterial() : null)
|
|
274
281
|
if (cube) setCubeShadingTheme(cube, theme, cardinalLight)
|
|
275
282
|
}
|
|
276
283
|
|
|
277
284
|
/** Vanilla-like lightmap curve params (live tuning via window.setBlockLightmap). */
|
|
278
|
-
setBlockLightmapParams
|
|
285
|
+
setBlockLightmapParams(params: BlockLightmapParams): void {
|
|
279
286
|
const cube = this.cubeShaderMaterial ?? (this.isShaderCubesGpuEnabled() ? this.getCubeShaderMaterial() : null)
|
|
280
287
|
if (cube) setCubeLightmapParams(cube, params)
|
|
281
288
|
if (this.legacyShaderMaterial) setLegacyLightmapParams(this.legacyShaderMaterial, params)
|
|
@@ -284,7 +291,7 @@ export class ChunkMeshManager {
|
|
|
284
291
|
this.blockEntityLightRegistry.setLightmapParams(params)
|
|
285
292
|
}
|
|
286
293
|
|
|
287
|
-
private getLegacyShaderMaterial
|
|
294
|
+
private getLegacyShaderMaterial(): THREE.ShaderMaterial {
|
|
288
295
|
if (!this.legacyShaderMaterial) {
|
|
289
296
|
this.legacyShaderMaterial = createLegacyBlockMaterial()
|
|
290
297
|
this.syncLegacyShaderUniforms()
|
|
@@ -292,7 +299,7 @@ export class ChunkMeshManager {
|
|
|
292
299
|
return this.legacyShaderMaterial
|
|
293
300
|
}
|
|
294
301
|
|
|
295
|
-
private getGlobalLegacyShaderMaterial
|
|
302
|
+
private getGlobalLegacyShaderMaterial(): THREE.ShaderMaterial {
|
|
296
303
|
if (!this.globalLegacyShaderMaterial) {
|
|
297
304
|
this.globalLegacyShaderMaterial = createGlobalLegacyBlockMaterial()
|
|
298
305
|
this.syncLegacyShaderUniforms()
|
|
@@ -300,18 +307,15 @@ export class ChunkMeshManager {
|
|
|
300
307
|
return this.globalLegacyShaderMaterial
|
|
301
308
|
}
|
|
302
309
|
|
|
303
|
-
private getGlobalLegacyBuffer
|
|
310
|
+
private getGlobalLegacyBuffer(): GlobalLegacyBuffer {
|
|
304
311
|
if (!this.globalLegacyBuffer) {
|
|
305
|
-
this.globalLegacyBuffer = new GlobalLegacyBuffer(
|
|
306
|
-
this.getGlobalLegacyShaderMaterial(),
|
|
307
|
-
this.scene,
|
|
308
|
-
)
|
|
312
|
+
this.globalLegacyBuffer = new GlobalLegacyBuffer(this.getGlobalLegacyShaderMaterial(), this.scene)
|
|
309
313
|
this.globalLegacyBuffer.setRenderOrigin(this.renderOrigin)
|
|
310
314
|
}
|
|
311
315
|
return this.globalLegacyBuffer
|
|
312
316
|
}
|
|
313
317
|
|
|
314
|
-
private getGlobalLegacyBlendShaderMaterial
|
|
318
|
+
private getGlobalLegacyBlendShaderMaterial(): THREE.ShaderMaterial {
|
|
315
319
|
if (!this.globalLegacyBlendShaderMaterial) {
|
|
316
320
|
this.globalLegacyBlendShaderMaterial = createGlobalLegacyBlendMaterial()
|
|
317
321
|
this.syncLegacyShaderUniforms()
|
|
@@ -319,32 +323,28 @@ export class ChunkMeshManager {
|
|
|
319
323
|
return this.globalLegacyBlendShaderMaterial
|
|
320
324
|
}
|
|
321
325
|
|
|
322
|
-
private getGlobalLegacyBlendBuffer
|
|
326
|
+
private getGlobalLegacyBlendBuffer(): GlobalLegacyBuffer {
|
|
323
327
|
if (!this.globalLegacyBlendBuffer) {
|
|
324
|
-
this.globalLegacyBlendBuffer = new GlobalLegacyBuffer(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
initialCapacityQuads: 32_000,
|
|
330
|
-
growthIncrementQuads: 32_000,
|
|
331
|
-
},
|
|
332
|
-
)
|
|
328
|
+
this.globalLegacyBlendBuffer = new GlobalLegacyBuffer(this.getGlobalLegacyBlendShaderMaterial(), this.scene, {
|
|
329
|
+
name: 'globalLegacyBlend',
|
|
330
|
+
initialCapacityQuads: 32_000,
|
|
331
|
+
growthIncrementQuads: 32_000
|
|
332
|
+
})
|
|
333
333
|
this.globalLegacyBlendBuffer.setRenderOrigin(this.renderOrigin)
|
|
334
334
|
}
|
|
335
335
|
return this.globalLegacyBlendBuffer
|
|
336
336
|
}
|
|
337
337
|
|
|
338
|
-
getRenderOrigin
|
|
338
|
+
getRenderOrigin(): Readonly<RenderOrigin> {
|
|
339
339
|
return this.renderOrigin
|
|
340
340
|
}
|
|
341
341
|
|
|
342
|
-
maybeRebase
|
|
342
|
+
maybeRebase(camera: RenderOrigin): void {
|
|
343
343
|
const R = this.renderOrigin
|
|
344
344
|
if (
|
|
345
|
-
Math.abs(camera.x - R.x) <= ChunkMeshManager.REBASE_THRESHOLD
|
|
346
|
-
|
|
347
|
-
|
|
345
|
+
Math.abs(camera.x - R.x) <= ChunkMeshManager.REBASE_THRESHOLD &&
|
|
346
|
+
Math.abs(camera.y - R.y) <= ChunkMeshManager.REBASE_THRESHOLD &&
|
|
347
|
+
Math.abs(camera.z - R.z) <= ChunkMeshManager.REBASE_THRESHOLD
|
|
348
348
|
) {
|
|
349
349
|
return
|
|
350
350
|
}
|
|
@@ -352,12 +352,12 @@ export class ChunkMeshManager {
|
|
|
352
352
|
const newOrigin: RenderOrigin = {
|
|
353
353
|
x: Math.round(camera.x / 16) * 16,
|
|
354
354
|
y: Math.round(camera.y / 16) * 16,
|
|
355
|
-
z: Math.round(camera.z / 16) * 16
|
|
355
|
+
z: Math.round(camera.z / 16) * 16
|
|
356
356
|
}
|
|
357
357
|
const delta: RenderOrigin = {
|
|
358
358
|
x: newOrigin.x - R.x,
|
|
359
359
|
y: newOrigin.y - R.y,
|
|
360
|
-
z: newOrigin.z - R.z
|
|
360
|
+
z: newOrigin.z - R.z
|
|
361
361
|
}
|
|
362
362
|
|
|
363
363
|
this.globalLegacyBuffer?.rebase(delta)
|
|
@@ -368,13 +368,7 @@ export class ChunkMeshManager {
|
|
|
368
368
|
if (!sectionKey) continue
|
|
369
369
|
const sectionObject = this.sectionObjects[sectionKey]
|
|
370
370
|
if (!sectionObject) continue
|
|
371
|
-
setupLegacySectionMatrix(
|
|
372
|
-
poolEntry.mesh,
|
|
373
|
-
sectionObject.worldX ?? 0,
|
|
374
|
-
sectionObject.worldY ?? 0,
|
|
375
|
-
sectionObject.worldZ ?? 0,
|
|
376
|
-
newOrigin,
|
|
377
|
-
)
|
|
371
|
+
setupLegacySectionMatrix(poolEntry.mesh, sectionObject.worldX ?? 0, sectionObject.worldY ?? 0, sectionObject.worldZ ?? 0, newOrigin)
|
|
378
372
|
}
|
|
379
373
|
|
|
380
374
|
this.renderOrigin = newOrigin
|
|
@@ -383,15 +377,15 @@ export class ChunkMeshManager {
|
|
|
383
377
|
}
|
|
384
378
|
|
|
385
379
|
/** Whether a section still holds a pooled legacy mesh (defer / invariant fallback). */
|
|
386
|
-
sectionUsesPooledLegacyMesh
|
|
380
|
+
sectionUsesPooledLegacyMesh(sectionKey: string): boolean {
|
|
387
381
|
return this.activeSections.has(sectionKey)
|
|
388
382
|
}
|
|
389
383
|
|
|
390
|
-
private registerLegacyCullSection
|
|
384
|
+
private registerLegacyCullSection(sectionKey: string, worldX: number, worldY: number, worldZ: number): void {
|
|
391
385
|
this.legacyCullSections.set(sectionKey, { worldX, worldY, worldZ })
|
|
392
386
|
}
|
|
393
387
|
|
|
394
|
-
private maybeUnregisterLegacyCullSection
|
|
388
|
+
private maybeUnregisterLegacyCullSection(sectionKey: string): void {
|
|
395
389
|
const inOpaque = this.globalLegacyBuffer?.hasSection(sectionKey) ?? false
|
|
396
390
|
const inBlend = this.globalLegacyBlendBuffer?.hasSection(sectionKey) ?? false
|
|
397
391
|
if (!inOpaque && !inBlend) {
|
|
@@ -399,11 +393,7 @@ export class ChunkMeshManager {
|
|
|
399
393
|
}
|
|
400
394
|
}
|
|
401
395
|
|
|
402
|
-
private updatePooledLegacyCullState
|
|
403
|
-
cameraWorldX: number,
|
|
404
|
-
cameraWorldY: number,
|
|
405
|
-
cameraWorldZ: number,
|
|
406
|
-
): void {
|
|
396
|
+
private updatePooledLegacyCullState(cameraWorldX: number, cameraWorldY: number, cameraWorldZ: number): void {
|
|
407
397
|
for (const poolEntry of this.activeSections.values()) {
|
|
408
398
|
const sectionKey = poolEntry.sectionKey
|
|
409
399
|
if (!sectionKey) continue
|
|
@@ -421,7 +411,7 @@ export class ChunkMeshManager {
|
|
|
421
411
|
this._legacyCullFrustum,
|
|
422
412
|
this._legacyCullBox,
|
|
423
413
|
this._legacyCullBoxMin,
|
|
424
|
-
this._legacyCullBoxMax
|
|
414
|
+
this._legacyCullBoxMax
|
|
425
415
|
)
|
|
426
416
|
}
|
|
427
417
|
}
|
|
@@ -429,7 +419,7 @@ export class ChunkMeshManager {
|
|
|
429
419
|
/**
|
|
430
420
|
* Shared section visibility + span groups for global legacy and cube buffers.
|
|
431
421
|
*/
|
|
432
|
-
updateSectionCullAndSort
|
|
422
|
+
updateSectionCullAndSort(camera: THREE.Camera, cameraWorldX: number, cameraWorldY: number, cameraWorldZ: number): void {
|
|
433
423
|
this._legacyCullProjScreen.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
|
|
434
424
|
this._legacyCullFrustum.setFromProjectionMatrix(this._legacyCullProjScreen)
|
|
435
425
|
|
|
@@ -449,7 +439,7 @@ export class ChunkMeshManager {
|
|
|
449
439
|
this._legacyCullFrustum,
|
|
450
440
|
this._legacyCullBox,
|
|
451
441
|
this._legacyCullBoxMin,
|
|
452
|
-
this._legacyCullBoxMax
|
|
442
|
+
this._legacyCullBoxMax
|
|
453
443
|
)
|
|
454
444
|
if (inFrustum) {
|
|
455
445
|
visible.push({ key: sectionKey, distSq })
|
|
@@ -471,7 +461,7 @@ export class ChunkMeshManager {
|
|
|
471
461
|
const blendKeys = blendVisible.map(v => v.key)
|
|
472
462
|
|
|
473
463
|
const cubeVisibleKeys: string[] = []
|
|
474
|
-
const visibleSlots: Array<{ start: number
|
|
464
|
+
const visibleSlots: Array<{ start: number; count: number }> = []
|
|
475
465
|
if (gb) {
|
|
476
466
|
gb.forEachSectionSlot((key, slot) => {
|
|
477
467
|
const sectionObject = this.sectionObjects[key]
|
|
@@ -491,15 +481,16 @@ export class ChunkMeshManager {
|
|
|
491
481
|
this._legacyCullFrustum,
|
|
492
482
|
this._legacyCullBox,
|
|
493
483
|
this._legacyCullBoxMin,
|
|
494
|
-
this._legacyCullBoxMax
|
|
484
|
+
this._legacyCullBoxMax
|
|
495
485
|
)
|
|
496
486
|
if (!inFrustum) {
|
|
497
487
|
return
|
|
498
488
|
}
|
|
499
489
|
cubeVisibleKeys.push(key)
|
|
500
490
|
const drawStart = gb.getSectionDrawStart(key)
|
|
501
|
-
|
|
502
|
-
|
|
491
|
+
const drawCount = gb.getSectionDrawCount(key)
|
|
492
|
+
if (drawStart !== undefined && drawCount !== undefined) {
|
|
493
|
+
visibleSlots.push({ start: drawStart, count: drawCount })
|
|
503
494
|
}
|
|
504
495
|
})
|
|
505
496
|
}
|
|
@@ -512,9 +503,12 @@ export class ChunkMeshManager {
|
|
|
512
503
|
opaqueBuf?.getLayoutVersion() ?? 0,
|
|
513
504
|
blendBuf?.getLayoutVersion() ?? 0,
|
|
514
505
|
gb?.getLayoutVersion() ?? 0,
|
|
506
|
+
opaqueBuf?.getUploadEpoch() ?? 0,
|
|
507
|
+
blendBuf?.getUploadEpoch() ?? 0,
|
|
508
|
+
gb?.getUploadEpoch() ?? 0
|
|
515
509
|
].join('|')
|
|
516
510
|
|
|
517
|
-
if (fingerprint === this._lastCullFingerprint) {
|
|
511
|
+
if (fingerprint === this._lastCullFingerprint && !this.hasPendingBufferWork()) {
|
|
518
512
|
this.updatePooledLegacyCullState(cameraWorldX, cameraWorldY, cameraWorldZ)
|
|
519
513
|
return
|
|
520
514
|
}
|
|
@@ -524,19 +518,53 @@ export class ChunkMeshManager {
|
|
|
524
518
|
blendBuf?.updateDrawSpans(visible, 'sortedBlend')
|
|
525
519
|
|
|
526
520
|
if (gb) {
|
|
527
|
-
const spans = buildVisibleCubeSpans(
|
|
521
|
+
const spans = buildVisibleCubeSpans(
|
|
522
|
+
visibleSlots,
|
|
523
|
+
gb.getHighWatermark(),
|
|
524
|
+
gb.canUseFullDrawShortcut(),
|
|
525
|
+
(start, end) => gb.isRangeFullyUploaded(start, end),
|
|
526
|
+
gb.getPendingDirtyRanges()
|
|
527
|
+
)
|
|
528
528
|
gb.setVisibleSpans(spans)
|
|
529
529
|
}
|
|
530
530
|
|
|
531
|
+
this.lastBufferStateKey = this.bufferStateKey()
|
|
531
532
|
this.updatePooledLegacyCullState(cameraWorldX, cameraWorldY, cameraWorldZ)
|
|
532
533
|
}
|
|
533
534
|
|
|
534
|
-
|
|
535
|
+
private bufferStateKey(): string {
|
|
536
|
+
const b = this.globalBlockBuffer
|
|
537
|
+
const o = this.globalLegacyBuffer
|
|
538
|
+
const bl = this.globalLegacyBlendBuffer
|
|
539
|
+
return [
|
|
540
|
+
o?.getLayoutVersion() ?? 0,
|
|
541
|
+
o?.getUploadEpoch() ?? 0,
|
|
542
|
+
bl?.getLayoutVersion() ?? 0,
|
|
543
|
+
bl?.getUploadEpoch() ?? 0,
|
|
544
|
+
b?.getLayoutVersion() ?? 0,
|
|
545
|
+
b?.getUploadEpoch() ?? 0
|
|
546
|
+
].join('|')
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
/** Mark cull dirty when any buffer's layout or upload state changed since the last cull. */
|
|
550
|
+
markCullDirtyIfBufferStateChanged(): void {
|
|
551
|
+
const key = this.bufferStateKey()
|
|
552
|
+
if (key !== this.lastBufferStateKey) {
|
|
553
|
+
this.markCullDirty()
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
markCullDirty(): void {
|
|
535
558
|
this.cullDirty = true
|
|
536
559
|
}
|
|
537
560
|
|
|
561
|
+
hasPendingBufferWork(): boolean {
|
|
562
|
+
const buffers = [this.globalLegacyBuffer, this.globalLegacyBlendBuffer, this.globalBlockBuffer]
|
|
563
|
+
return buffers.some(b => b != null && (b.hasPendingUploads() || b.hasPendingReplace() || b.getPendingMove() != null))
|
|
564
|
+
}
|
|
565
|
+
|
|
538
566
|
/** Compare camera pose; mark cull dirty when position or rotation changed. */
|
|
539
|
-
updateCullDirtyFromCamera
|
|
567
|
+
updateCullDirtyFromCamera(camera: THREE.Camera, cameraWorldX: number, cameraWorldY: number, cameraWorldZ: number): void {
|
|
540
568
|
camera.getWorldQuaternion(this._cullViewQuat)
|
|
541
569
|
if (!this._cullCamInitialized) {
|
|
542
570
|
this._lastCullCamPos.set(cameraWorldX, cameraWorldY, cameraWorldZ)
|
|
@@ -545,10 +573,7 @@ export class ChunkMeshManager {
|
|
|
545
573
|
this.cullDirty = true
|
|
546
574
|
return
|
|
547
575
|
}
|
|
548
|
-
const posChanged =
|
|
549
|
-
this._lastCullCamPos.x !== cameraWorldX ||
|
|
550
|
-
this._lastCullCamPos.y !== cameraWorldY ||
|
|
551
|
-
this._lastCullCamPos.z !== cameraWorldZ
|
|
576
|
+
const posChanged = this._lastCullCamPos.x !== cameraWorldX || this._lastCullCamPos.y !== cameraWorldY || this._lastCullCamPos.z !== cameraWorldZ
|
|
552
577
|
const quatChanged =
|
|
553
578
|
this._lastCullCamQuat.x !== this._cullViewQuat.x ||
|
|
554
579
|
this._lastCullCamQuat.y !== this._cullViewQuat.y ||
|
|
@@ -561,11 +586,11 @@ export class ChunkMeshManager {
|
|
|
561
586
|
}
|
|
562
587
|
}
|
|
563
588
|
|
|
564
|
-
clearCullDirty
|
|
589
|
+
clearCullDirty(): void {
|
|
565
590
|
this.cullDirty = false
|
|
566
591
|
}
|
|
567
592
|
|
|
568
|
-
setLegacyCameraOrigin
|
|
593
|
+
setLegacyCameraOrigin(x: number, y: number, z: number): void {
|
|
569
594
|
const R = this.renderOrigin
|
|
570
595
|
setLegacyCameraOrigin(this.getLegacyShaderMaterial(), R, x, y, z)
|
|
571
596
|
setLegacyCameraOrigin(this.getGlobalLegacyShaderMaterial(), R, x, y, z)
|
|
@@ -592,7 +617,7 @@ export class ChunkMeshManager {
|
|
|
592
617
|
}
|
|
593
618
|
}
|
|
594
619
|
|
|
595
|
-
private getCubeShaderMaterial
|
|
620
|
+
private getCubeShaderMaterial(): THREE.ShaderMaterial | null {
|
|
596
621
|
if (!this.isShaderCubesGpuEnabled()) return null
|
|
597
622
|
if (!this.cubeShaderMaterial) {
|
|
598
623
|
this.cubeShaderMaterial = createCubeBlockMaterial()
|
|
@@ -603,7 +628,7 @@ export class ChunkMeshManager {
|
|
|
603
628
|
return this.cubeShaderMaterial
|
|
604
629
|
}
|
|
605
630
|
|
|
606
|
-
private getGlobalBlockBuffer
|
|
631
|
+
private getGlobalBlockBuffer(): GlobalBlockBuffer | null {
|
|
607
632
|
const mat = this.getCubeShaderMaterial()
|
|
608
633
|
if (!mat) return null
|
|
609
634
|
if (!this.globalBlockBuffer) {
|
|
@@ -612,12 +637,12 @@ export class ChunkMeshManager {
|
|
|
612
637
|
return this.globalBlockBuffer
|
|
613
638
|
}
|
|
614
639
|
|
|
615
|
-
private shouldDeferLegacyOpaqueToPerSection
|
|
640
|
+
private shouldDeferLegacyOpaqueToPerSection(sectionKey: string): boolean {
|
|
616
641
|
return this.shouldDeferShaderToPerSection(sectionKey)
|
|
617
642
|
}
|
|
618
643
|
|
|
619
644
|
/** Sci-fi reveal keeps geometry off global buffers until the section finishes reveal. */
|
|
620
|
-
private shouldDeferShaderToPerSection
|
|
645
|
+
private shouldDeferShaderToPerSection(sectionKey: string): boolean {
|
|
621
646
|
const sciFi = this.worldRenderer.getModule<{
|
|
622
647
|
shouldDeferSectionGeometry?: (key: string) => boolean
|
|
623
648
|
}>('futuristicReveal')
|
|
@@ -627,7 +652,7 @@ export class ChunkMeshManager {
|
|
|
627
652
|
/**
|
|
628
653
|
* Move deferred per-section shader cubes into the global buffer after reveal completes.
|
|
629
654
|
*/
|
|
630
|
-
migrateDeferredShaderToGlobal
|
|
655
|
+
migrateDeferredShaderToGlobal(sectionKey: string): void {
|
|
631
656
|
const section = this.sectionObjects[sectionKey]
|
|
632
657
|
if (!section?.deferredShaderCubes) return
|
|
633
658
|
|
|
@@ -660,7 +685,7 @@ export class ChunkMeshManager {
|
|
|
660
685
|
/**
|
|
661
686
|
* Move deferred per-section opaque legacy into the global buffer after reveal completes.
|
|
662
687
|
*/
|
|
663
|
-
migrateDeferredLegacyToGlobal
|
|
688
|
+
migrateDeferredLegacyToGlobal(sectionKey: string): void {
|
|
664
689
|
const section = this.sectionObjects[sectionKey]
|
|
665
690
|
if (!section) return
|
|
666
691
|
|
|
@@ -670,13 +695,7 @@ export class ChunkMeshManager {
|
|
|
670
695
|
const wy = section.worldY
|
|
671
696
|
const wz = section.worldZ
|
|
672
697
|
if (wx !== undefined && wy !== undefined && wz !== undefined) {
|
|
673
|
-
const added = this.getGlobalLegacyBuffer().addSection(
|
|
674
|
-
sectionKey,
|
|
675
|
-
{ positions, colors, skyLights, blockLights, uvs, indices },
|
|
676
|
-
wx,
|
|
677
|
-
wy,
|
|
678
|
-
wz,
|
|
679
|
-
)
|
|
698
|
+
const added = this.getGlobalLegacyBuffer().addSection(sectionKey, { positions, colors, skyLights, blockLights, uvs, indices }, wx, wy, wz)
|
|
680
699
|
if (added) {
|
|
681
700
|
this.registerLegacyCullSection(sectionKey, wx, wy, wz)
|
|
682
701
|
}
|
|
@@ -690,13 +709,7 @@ export class ChunkMeshManager {
|
|
|
690
709
|
const wy = section.worldY
|
|
691
710
|
const wz = section.worldZ
|
|
692
711
|
if (wx !== undefined && wy !== undefined && wz !== undefined) {
|
|
693
|
-
const added = this.getGlobalLegacyBlendBuffer().addSection(
|
|
694
|
-
sectionKey,
|
|
695
|
-
{ positions, colors, skyLights, blockLights, uvs, indices },
|
|
696
|
-
wx,
|
|
697
|
-
wy,
|
|
698
|
-
wz,
|
|
699
|
-
)
|
|
712
|
+
const added = this.getGlobalLegacyBlendBuffer().addSection(sectionKey, { positions, colors, skyLights, blockLights, uvs, indices }, wx, wy, wz)
|
|
700
713
|
if (added) {
|
|
701
714
|
this.registerLegacyCullSection(sectionKey, wx, wy, wz)
|
|
702
715
|
}
|
|
@@ -709,63 +722,19 @@ export class ChunkMeshManager {
|
|
|
709
722
|
const hadLegacyAsPrimary = section.mesh === this.activeSections.get(sectionKey)?.mesh
|
|
710
723
|
this.releasePooledMesh(sectionKey)
|
|
711
724
|
if (hadLegacyAsPrimary) {
|
|
712
|
-
section.mesh = section.shaderMesh as unknown as THREE.Mesh<THREE.BufferGeometry, THREE.Material> | undefined ?? undefined
|
|
725
|
+
section.mesh = (section.shaderMesh as unknown as THREE.Mesh<THREE.BufferGeometry, THREE.Material> | undefined) ?? undefined
|
|
713
726
|
}
|
|
714
727
|
}
|
|
715
728
|
this.markCullDirty()
|
|
716
729
|
}
|
|
717
730
|
|
|
718
|
-
|
|
719
|
-
raycaster: THREE.Raycaster,
|
|
720
|
-
origin: THREE.Vector3,
|
|
721
|
-
maxCenterDistance: number,
|
|
722
|
-
): number | undefined {
|
|
723
|
-
const maxDistSq = maxCenterDistance * maxCenterDistance
|
|
724
|
-
const dirX = raycaster.ray.direction.x
|
|
725
|
-
const dirY = raycaster.ray.direction.y
|
|
726
|
-
const dirZ = raycaster.ray.direction.z
|
|
727
|
-
const far = raycaster.far
|
|
728
|
-
const halfExtent = LEGACY_SECTION_HALF_EXTENT + 0.01
|
|
729
|
-
const candidates: string[] = []
|
|
730
|
-
for (const [key] of this.legacyCullSections) {
|
|
731
|
-
const section = this.sectionObjects[key]
|
|
732
|
-
if (!section || section.worldX === undefined) continue
|
|
733
|
-
const dx = section.worldX - origin.x
|
|
734
|
-
const dy = (section.worldY ?? 0) - origin.y
|
|
735
|
-
const dz = (section.worldZ ?? 0) - origin.z
|
|
736
|
-
if (dx * dx + dy * dy + dz * dz > maxDistSq) continue
|
|
737
|
-
if (!sectionAabbIntersectsRay(
|
|
738
|
-
section.worldX,
|
|
739
|
-
section.worldY ?? 0,
|
|
740
|
-
section.worldZ ?? 0,
|
|
741
|
-
origin.x,
|
|
742
|
-
origin.y,
|
|
743
|
-
origin.z,
|
|
744
|
-
dirX,
|
|
745
|
-
dirY,
|
|
746
|
-
dirZ,
|
|
747
|
-
far,
|
|
748
|
-
halfExtent,
|
|
749
|
-
)) continue
|
|
750
|
-
candidates.push(key)
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
if (candidates.length === 0) return undefined
|
|
754
|
-
|
|
755
|
-
const hits: THREE.Intersection[] = []
|
|
756
|
-
this.globalLegacyBuffer?.raycastSections(raycaster, candidates, hits)
|
|
757
|
-
this.globalLegacyBlendBuffer?.raycastSections(raycaster, candidates, hits)
|
|
758
|
-
|
|
759
|
-
return hits[0]?.distance
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
registerShaderSectionRaycastBox (
|
|
731
|
+
registerShaderSectionRaycastBox(
|
|
763
732
|
sectionKey: string,
|
|
764
733
|
words: Uint32Array,
|
|
765
734
|
faceCount: number,
|
|
766
735
|
sectionCenterX: number,
|
|
767
736
|
sectionCenterY: number,
|
|
768
|
-
sectionCenterZ: number
|
|
737
|
+
sectionCenterZ: number
|
|
769
738
|
): void {
|
|
770
739
|
const box = computeShaderSectionRaycastAabb(words, faceCount, sectionCenterX, sectionCenterY, sectionCenterZ)
|
|
771
740
|
if (box) {
|
|
@@ -773,110 +742,26 @@ export class ChunkMeshManager {
|
|
|
773
742
|
box,
|
|
774
743
|
sectionCenterX,
|
|
775
744
|
sectionCenterY,
|
|
776
|
-
sectionCenterZ
|
|
745
|
+
sectionCenterZ
|
|
777
746
|
})
|
|
778
747
|
} else {
|
|
779
748
|
this.shaderSectionRaycastBoxes.delete(sectionKey)
|
|
780
749
|
}
|
|
781
750
|
}
|
|
782
751
|
|
|
783
|
-
unregisterShaderSectionRaycastBox
|
|
752
|
+
unregisterShaderSectionRaycastBox(sectionKey: string): void {
|
|
784
753
|
this.shaderSectionRaycastBoxes.delete(sectionKey)
|
|
785
754
|
}
|
|
786
755
|
|
|
787
|
-
/** Closest hit against registered shader-cube AABBs (world-space ray). */
|
|
788
|
-
raycastShaderSectionAABBs (
|
|
789
|
-
originWorld: THREE.Vector3,
|
|
790
|
-
direction: THREE.Vector3,
|
|
791
|
-
maxDist: number,
|
|
792
|
-
maxCenterDistance = 80,
|
|
793
|
-
): number | undefined {
|
|
794
|
-
const ox = originWorld.x
|
|
795
|
-
const oy = originWorld.y
|
|
796
|
-
const oz = originWorld.z
|
|
797
|
-
const dx = direction.x
|
|
798
|
-
const dy = direction.y
|
|
799
|
-
const dz = direction.z
|
|
800
|
-
const maxCenterDistSq = maxCenterDistance * maxCenterDistance
|
|
801
|
-
|
|
802
|
-
let closest = maxDist
|
|
803
|
-
let found = false
|
|
804
|
-
|
|
805
|
-
this.blockRaycastVisitStamp++
|
|
806
|
-
if (this.blockRaycastVisitStamp >= 65535) {
|
|
807
|
-
this.blockRaycastVisitGen.fill(0)
|
|
808
|
-
this.blockRaycastVisitStamp = 1
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
for (const [key, entry] of this.shaderSectionRaycastBoxes) {
|
|
812
|
-
const section = this.sectionObjects[key]
|
|
813
|
-
if (section && !section.visible) continue
|
|
814
|
-
|
|
815
|
-
const { box } = entry
|
|
816
|
-
const dcx = box.cx - ox
|
|
817
|
-
const dcy = box.cy - oy
|
|
818
|
-
const dcz = box.cz - oz
|
|
819
|
-
if (dcx * dcx + dcy * dcy + dcz * dcz > maxCenterDistSq) continue
|
|
820
|
-
|
|
821
|
-
let t = raycastAabb(
|
|
822
|
-
ox, oy, oz, dx, dy, dz,
|
|
823
|
-
box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ,
|
|
824
|
-
closest,
|
|
825
|
-
)
|
|
826
|
-
if (t === undefined && isPointInsideAabb(ox, oy, oz, box.minX, box.minY, box.minZ, box.maxX, box.maxY, box.maxZ)) {
|
|
827
|
-
const gb = this.globalBlockBuffer
|
|
828
|
-
const slot = gb?.getSectionSlot(key)
|
|
829
|
-
if (gb && slot) {
|
|
830
|
-
t = raycastShaderBlocksAabb(
|
|
831
|
-
gb.getW0(),
|
|
832
|
-
slot.start,
|
|
833
|
-
slot.count,
|
|
834
|
-
1,
|
|
835
|
-
entry.sectionCenterX,
|
|
836
|
-
entry.sectionCenterY,
|
|
837
|
-
entry.sectionCenterZ,
|
|
838
|
-
ox, oy, oz, dx, dy, dz,
|
|
839
|
-
closest,
|
|
840
|
-
this.blockRaycastVisitGen,
|
|
841
|
-
this.blockRaycastVisitStamp,
|
|
842
|
-
)
|
|
843
|
-
} else {
|
|
844
|
-
const def = this.sectionObjects[key]?.deferredShaderCubes
|
|
845
|
-
if (def) {
|
|
846
|
-
t = raycastShaderBlocksAabb(
|
|
847
|
-
def.words,
|
|
848
|
-
0,
|
|
849
|
-
def.count,
|
|
850
|
-
SHADER_CUBES_WORDS_PER_FACE,
|
|
851
|
-
entry.sectionCenterX,
|
|
852
|
-
entry.sectionCenterY,
|
|
853
|
-
entry.sectionCenterZ,
|
|
854
|
-
ox, oy, oz, dx, dy, dz,
|
|
855
|
-
closest,
|
|
856
|
-
this.blockRaycastVisitGen,
|
|
857
|
-
this.blockRaycastVisitStamp,
|
|
858
|
-
)
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
}
|
|
862
|
-
if (t !== undefined && t < closest) {
|
|
863
|
-
closest = t
|
|
864
|
-
found = true
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
return found ? closest : undefined
|
|
869
|
-
}
|
|
870
|
-
|
|
871
756
|
/**
|
|
872
757
|
* Update or create a section with new geometry data
|
|
873
758
|
*/
|
|
874
|
-
private uploadLegacyPooledMesh
|
|
759
|
+
private uploadLegacyPooledMesh(
|
|
875
760
|
poolEntry: ChunkMeshPool,
|
|
876
761
|
geometryData: MesherGeometryOutput | MesherGeometryOutput['blend'],
|
|
877
762
|
sx: number,
|
|
878
763
|
sy: number,
|
|
879
|
-
sz: number
|
|
764
|
+
sz: number
|
|
880
765
|
): THREE.Mesh<THREE.BufferGeometry, THREE.Material> {
|
|
881
766
|
const { mesh } = poolEntry
|
|
882
767
|
const geo = geometryData!
|
|
@@ -887,14 +772,8 @@ export class ChunkMeshManager {
|
|
|
887
772
|
this.updateGeometryAttribute(mesh.geometry, 'a_blockLight', geo.blockLights, 1)
|
|
888
773
|
this.updateGeometryAttribute(mesh.geometry, 'uv', geo.uvs, 2)
|
|
889
774
|
mesh.geometry.index = new THREE.BufferAttribute(geo.indices as Uint32Array | Uint16Array, 1)
|
|
890
|
-
mesh.geometry.boundingBox = new THREE.Box3(
|
|
891
|
-
|
|
892
|
-
new THREE.Vector3(8, 8, 8),
|
|
893
|
-
)
|
|
894
|
-
mesh.geometry.boundingSphere = new THREE.Sphere(
|
|
895
|
-
new THREE.Vector3(0, 0, 0),
|
|
896
|
-
Math.sqrt(3 * 8 ** 2),
|
|
897
|
-
)
|
|
775
|
+
mesh.geometry.boundingBox = new THREE.Box3(new THREE.Vector3(-8, -8, -8), new THREE.Vector3(8, 8, 8))
|
|
776
|
+
mesh.geometry.boundingSphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0), Math.sqrt(3 * 8 ** 2))
|
|
898
777
|
setupLegacySectionMatrix(mesh, sx, sy, sz, this.renderOrigin)
|
|
899
778
|
mesh.visible = false
|
|
900
779
|
mesh.name = 'mesh'
|
|
@@ -902,7 +781,7 @@ export class ChunkMeshManager {
|
|
|
902
781
|
return mesh as THREE.Mesh<THREE.BufferGeometry, THREE.Material>
|
|
903
782
|
}
|
|
904
783
|
|
|
905
|
-
private acquirePooledSectionMesh
|
|
784
|
+
private acquirePooledSectionMesh(sectionKey: string): ChunkMeshPool | null {
|
|
906
785
|
let poolEntry = this.activeSections.get(sectionKey)
|
|
907
786
|
if (!poolEntry) {
|
|
908
787
|
poolEntry = this.acquireMesh()
|
|
@@ -916,12 +795,18 @@ export class ChunkMeshManager {
|
|
|
916
795
|
return poolEntry
|
|
917
796
|
}
|
|
918
797
|
|
|
919
|
-
updateSection
|
|
798
|
+
updateSection(sectionKey: string, geometryData: MesherGeometryOutput): SectionObject | null {
|
|
920
799
|
const hasOpaque = geometryData.positions.length > 0
|
|
921
800
|
const hasBlend = (geometryData.blend?.positions.length ?? 0) > 0
|
|
922
801
|
const hasLegacy = hasOpaque || hasBlend
|
|
923
802
|
const shaderData = geometryData.shaderCubes
|
|
924
803
|
const hasShader = this.isShaderCubesGpuEnabled() && (shaderData?.count ?? 0) > 0
|
|
804
|
+
const deferOpaque = hasOpaque && this.shouldDeferLegacyOpaqueToPerSection(sectionKey)
|
|
805
|
+
const deferBlend = hasBlend && this.shouldDeferLegacyOpaqueToPerSection(sectionKey)
|
|
806
|
+
const deferShader = hasShader && this.shouldDeferShaderToPerSection(sectionKey)
|
|
807
|
+
const willAddOpaqueGlobal = hasOpaque && !deferOpaque
|
|
808
|
+
const willAddBlendGlobal = hasBlend && !deferBlend
|
|
809
|
+
const willAddCubeGlobal = hasShader && !!shaderData && !deferShader
|
|
925
810
|
|
|
926
811
|
if (!hasLegacy && !hasShader) {
|
|
927
812
|
this.releaseSection(sectionKey)
|
|
@@ -930,10 +815,19 @@ export class ChunkMeshManager {
|
|
|
930
815
|
|
|
931
816
|
// Remove existing section object from scene if it exists
|
|
932
817
|
let sectionObject = this.sectionObjects[sectionKey]
|
|
818
|
+
const wasRemesh = sectionObject != null
|
|
933
819
|
if (sectionObject) {
|
|
934
820
|
this.cleanupSection(sectionKey, { forRemesh: true })
|
|
935
821
|
}
|
|
936
822
|
|
|
823
|
+
if (wasRemesh) {
|
|
824
|
+
if (!willAddCubeGlobal) this.globalBlockBuffer?.removeSection(sectionKey)
|
|
825
|
+
if (!willAddOpaqueGlobal) this.globalLegacyBuffer?.removeSection(sectionKey)
|
|
826
|
+
if (!willAddBlendGlobal) this.globalLegacyBlendBuffer?.removeSection(sectionKey)
|
|
827
|
+
if (!(hasShader && shaderData)) this.unregisterShaderSectionRaycastBox(sectionKey)
|
|
828
|
+
if (!willAddOpaqueGlobal && !willAddBlendGlobal) this.maybeUnregisterLegacyCullSection(sectionKey)
|
|
829
|
+
}
|
|
830
|
+
|
|
937
831
|
if (!hasBlend) {
|
|
938
832
|
this.releasePooledMesh(sectionKey)
|
|
939
833
|
}
|
|
@@ -950,9 +844,8 @@ export class ChunkMeshManager {
|
|
|
950
844
|
skyLights: geometryData.skyLights as Float32Array,
|
|
951
845
|
blockLights: geometryData.blockLights as Float32Array,
|
|
952
846
|
uvs: geometryData.uvs as Float32Array,
|
|
953
|
-
indices: geometryData.indices as Uint32Array | Uint16Array
|
|
847
|
+
indices: geometryData.indices as Uint32Array | Uint16Array
|
|
954
848
|
}
|
|
955
|
-
const deferOpaque = this.shouldDeferLegacyOpaqueToPerSection(sectionKey)
|
|
956
849
|
if (deferOpaque) {
|
|
957
850
|
deferredLegacyOpaque = {
|
|
958
851
|
positions: new Float32Array(opaqueGeo.positions),
|
|
@@ -960,9 +853,7 @@ export class ChunkMeshManager {
|
|
|
960
853
|
skyLights: new Float32Array(opaqueGeo.skyLights),
|
|
961
854
|
blockLights: new Float32Array(opaqueGeo.blockLights),
|
|
962
855
|
uvs: new Float32Array(opaqueGeo.uvs),
|
|
963
|
-
indices: opaqueGeo.indices instanceof Uint32Array
|
|
964
|
-
? new Uint32Array(opaqueGeo.indices)
|
|
965
|
-
: new Uint16Array(opaqueGeo.indices),
|
|
856
|
+
indices: opaqueGeo.indices instanceof Uint32Array ? new Uint32Array(opaqueGeo.indices) : new Uint16Array(opaqueGeo.indices)
|
|
966
857
|
}
|
|
967
858
|
if (!hasBlend) {
|
|
968
859
|
const poolEntry = this.acquirePooledSectionMesh(sectionKey)
|
|
@@ -970,13 +861,7 @@ export class ChunkMeshManager {
|
|
|
970
861
|
legacyMesh = this.uploadLegacyPooledMesh(poolEntry, geometryData, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
971
862
|
}
|
|
972
863
|
} else {
|
|
973
|
-
const added = this.getGlobalLegacyBuffer().addSection(
|
|
974
|
-
sectionKey,
|
|
975
|
-
opaqueGeo,
|
|
976
|
-
geometryData.sx,
|
|
977
|
-
geometryData.sy,
|
|
978
|
-
geometryData.sz,
|
|
979
|
-
)
|
|
864
|
+
const added = this.getGlobalLegacyBuffer().addSection(sectionKey, opaqueGeo, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
980
865
|
if (added) {
|
|
981
866
|
this.registerLegacyCullSection(sectionKey, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
982
867
|
} else {
|
|
@@ -994,9 +879,8 @@ export class ChunkMeshManager {
|
|
|
994
879
|
skyLights: geometryData.blend.skyLights as Float32Array,
|
|
995
880
|
blockLights: geometryData.blend.blockLights as Float32Array,
|
|
996
881
|
uvs: geometryData.blend.uvs as Float32Array,
|
|
997
|
-
indices: geometryData.blend.indices as Uint32Array | Uint16Array
|
|
882
|
+
indices: geometryData.blend.indices as Uint32Array | Uint16Array
|
|
998
883
|
}
|
|
999
|
-
const deferBlend = this.shouldDeferLegacyOpaqueToPerSection(sectionKey)
|
|
1000
884
|
if (deferBlend) {
|
|
1001
885
|
deferredLegacyBlend = {
|
|
1002
886
|
positions: new Float32Array(blendGeo.positions),
|
|
@@ -1004,42 +888,22 @@ export class ChunkMeshManager {
|
|
|
1004
888
|
skyLights: new Float32Array(blendGeo.skyLights),
|
|
1005
889
|
blockLights: new Float32Array(blendGeo.blockLights),
|
|
1006
890
|
uvs: new Float32Array(blendGeo.uvs),
|
|
1007
|
-
indices: blendGeo.indices instanceof Uint32Array
|
|
1008
|
-
? new Uint32Array(blendGeo.indices)
|
|
1009
|
-
: new Uint16Array(blendGeo.indices),
|
|
891
|
+
indices: blendGeo.indices instanceof Uint32Array ? new Uint32Array(blendGeo.indices) : new Uint16Array(blendGeo.indices)
|
|
1010
892
|
}
|
|
1011
893
|
const poolEntry = this.acquirePooledSectionMesh(sectionKey)
|
|
1012
894
|
if (!poolEntry) return null
|
|
1013
|
-
const blendMesh = this.uploadLegacyPooledMesh(
|
|
1014
|
-
poolEntry,
|
|
1015
|
-
geometryData.blend,
|
|
1016
|
-
geometryData.sx,
|
|
1017
|
-
geometryData.sy,
|
|
1018
|
-
geometryData.sz,
|
|
1019
|
-
)
|
|
895
|
+
const blendMesh = this.uploadLegacyPooledMesh(poolEntry, geometryData.blend, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
1020
896
|
legacyMesh = legacyMesh ?? blendMesh
|
|
1021
897
|
hasBlendMesh = true
|
|
1022
898
|
} else {
|
|
1023
|
-
const added = this.getGlobalLegacyBlendBuffer().addSection(
|
|
1024
|
-
sectionKey,
|
|
1025
|
-
blendGeo,
|
|
1026
|
-
geometryData.sx,
|
|
1027
|
-
geometryData.sy,
|
|
1028
|
-
geometryData.sz,
|
|
1029
|
-
)
|
|
899
|
+
const added = this.getGlobalLegacyBlendBuffer().addSection(sectionKey, blendGeo, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
1030
900
|
if (added) {
|
|
1031
901
|
this.registerLegacyCullSection(sectionKey, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
1032
902
|
} else {
|
|
1033
903
|
console.warn(`ChunkMeshManager: blend invariant violation for section ${sectionKey}, using pooled mesh fallback`)
|
|
1034
904
|
const poolEntry = this.acquirePooledSectionMesh(sectionKey)
|
|
1035
905
|
if (!poolEntry) return null
|
|
1036
|
-
const blendMesh = this.uploadLegacyPooledMesh(
|
|
1037
|
-
poolEntry,
|
|
1038
|
-
geometryData.blend,
|
|
1039
|
-
geometryData.sx,
|
|
1040
|
-
geometryData.sy,
|
|
1041
|
-
geometryData.sz,
|
|
1042
|
-
)
|
|
906
|
+
const blendMesh = this.uploadLegacyPooledMesh(poolEntry, geometryData.blend, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
1043
907
|
legacyMesh = legacyMesh ?? blendMesh
|
|
1044
908
|
hasBlendMesh = true
|
|
1045
909
|
}
|
|
@@ -1048,7 +912,6 @@ export class ChunkMeshManager {
|
|
|
1048
912
|
|
|
1049
913
|
const cubeMaterial = hasShader ? this.getCubeShaderMaterial() : null
|
|
1050
914
|
let shaderMesh: THREE.Mesh<THREE.InstancedBufferGeometry, THREE.ShaderMaterial> | undefined
|
|
1051
|
-
const deferShader = hasShader && this.shouldDeferShaderToPerSection(sectionKey)
|
|
1052
915
|
if (hasShader && shaderData) {
|
|
1053
916
|
if (deferShader && cubeMaterial) {
|
|
1054
917
|
shaderMesh = createShaderCubeMesh(shaderData, cubeMaterial)
|
|
@@ -1069,7 +932,7 @@ export class ChunkMeshManager {
|
|
|
1069
932
|
if (shaderData) {
|
|
1070
933
|
sectionObject.deferredShaderCubes = {
|
|
1071
934
|
words: shaderData.words,
|
|
1072
|
-
count: shaderData.count
|
|
935
|
+
count: shaderData.count
|
|
1073
936
|
}
|
|
1074
937
|
}
|
|
1075
938
|
if (!sectionObject.mesh) {
|
|
@@ -1083,14 +946,7 @@ export class ChunkMeshManager {
|
|
|
1083
946
|
sectionObject.deferredLegacyBlend = deferredLegacyBlend
|
|
1084
947
|
}
|
|
1085
948
|
if (hasShader && shaderData) {
|
|
1086
|
-
this.registerShaderSectionRaycastBox(
|
|
1087
|
-
sectionKey,
|
|
1088
|
-
shaderData.words,
|
|
1089
|
-
shaderData.count,
|
|
1090
|
-
geometryData.sx,
|
|
1091
|
-
geometryData.sy,
|
|
1092
|
-
geometryData.sz,
|
|
1093
|
-
)
|
|
949
|
+
this.registerShaderSectionRaycastBox(sectionKey, shaderData.words, shaderData.count, geometryData.sx, geometryData.sy, geometryData.sz)
|
|
1094
950
|
}
|
|
1095
951
|
|
|
1096
952
|
let tilesCount = 0
|
|
@@ -1165,20 +1021,12 @@ export class ChunkMeshManager {
|
|
|
1165
1021
|
const bannerTexture = getBannerTexture(this.worldRenderer, blockName, nbt.simplify(bannerBlockEntity))
|
|
1166
1022
|
if (!bannerTexture) continue
|
|
1167
1023
|
const skyLevel = this.blockEntityLightRegistry.getSkyLevel()
|
|
1168
|
-
const banner = createBannerMesh(
|
|
1169
|
-
new Vec3(+x, +y, +z),
|
|
1170
|
-
rotation,
|
|
1171
|
-
isWall,
|
|
1172
|
-
bannerTexture,
|
|
1173
|
-
blockLightNorm,
|
|
1174
|
-
skyLightNorm,
|
|
1175
|
-
skyLevel,
|
|
1176
|
-
)
|
|
1024
|
+
const banner = createBannerMesh(new Vec3(+x, +y, +z), rotation, isWall, bannerTexture, blockLightNorm, skyLightNorm, skyLevel)
|
|
1177
1025
|
if (banner.bannerMaterial) {
|
|
1178
1026
|
this.blockEntityLightRegistry.register({
|
|
1179
1027
|
material: banner.bannerMaterial,
|
|
1180
1028
|
blockLightNorm,
|
|
1181
|
-
skyLightNorm
|
|
1029
|
+
skyLightNorm
|
|
1182
1030
|
})
|
|
1183
1031
|
}
|
|
1184
1032
|
const { x: bwx, y: bwy, z: bwz } = banner.position
|
|
@@ -1212,8 +1060,7 @@ export class ChunkMeshManager {
|
|
|
1212
1060
|
// setting so the near-first reveal gate has sections to hold.
|
|
1213
1061
|
const chunkCoords = sectionKey.split(',')
|
|
1214
1062
|
const chunkKey = `${chunkCoords[0]},${chunkCoords[2]}`
|
|
1215
|
-
const renderByChunks = !!this.worldRenderer.displayOptions
|
|
1216
|
-
?.inWorldRenderingConfig?._renderByChunks
|
|
1063
|
+
const renderByChunks = !!this.worldRenderer.displayOptions?.inWorldRenderingConfig?._renderByChunks
|
|
1217
1064
|
const forceBatchForWasm = !!this.worldRenderer.worldRendererConfig?.wasmMesher
|
|
1218
1065
|
if ((renderByChunks || forceBatchForWasm) && !this.worldRenderer.finishedChunks[chunkKey]) {
|
|
1219
1066
|
sectionObject.visible = false
|
|
@@ -1234,7 +1081,7 @@ export class ChunkMeshManager {
|
|
|
1234
1081
|
* reveal is deferred (parked in `pendingNearReveal`) and re-checked on
|
|
1235
1082
|
* the next chunkFinished / player-move / grace-expiry.
|
|
1236
1083
|
*/
|
|
1237
|
-
finishChunkDisplay
|
|
1084
|
+
finishChunkDisplay(chunkKey: string): void {
|
|
1238
1085
|
const sectionKeys = this.waitingChunksToDisplay[chunkKey]
|
|
1239
1086
|
if (!sectionKeys) {
|
|
1240
1087
|
// No held sections (empty column / non-batched path) — but the
|
|
@@ -1253,7 +1100,7 @@ export class ChunkMeshManager {
|
|
|
1253
1100
|
this.tryRevealPending()
|
|
1254
1101
|
}
|
|
1255
1102
|
|
|
1256
|
-
private flushChunkDisplay
|
|
1103
|
+
private flushChunkDisplay(chunkKey: string): void {
|
|
1257
1104
|
const sectionKeys = this.waitingChunksToDisplay[chunkKey]
|
|
1258
1105
|
this.pendingNearReveal.delete(chunkKey)
|
|
1259
1106
|
this.clearNearRevealTimer(chunkKey)
|
|
@@ -1273,7 +1120,7 @@ export class ChunkMeshManager {
|
|
|
1273
1120
|
// Single pass is enough — pending entries are already finished, so flushing
|
|
1274
1121
|
// one cannot un-block another via this code path (cascading happens via
|
|
1275
1122
|
// chunkFinished events and per-pending grace timers).
|
|
1276
|
-
tryRevealPending
|
|
1123
|
+
tryRevealPending(): void {
|
|
1277
1124
|
if (this.pendingNearReveal.size === 0) return
|
|
1278
1125
|
const now = Date.now()
|
|
1279
1126
|
for (const [chunkKey, enqueuedAt] of [...this.pendingNearReveal]) {
|
|
@@ -1285,7 +1132,7 @@ export class ChunkMeshManager {
|
|
|
1285
1132
|
|
|
1286
1133
|
// Drop gate state for an unloaded column and re-evaluate any farther
|
|
1287
1134
|
// chunks that may have been blocked by it.
|
|
1288
|
-
onChunkRemovedFromGate
|
|
1135
|
+
onChunkRemovedFromGate(chunkKey: string): void {
|
|
1289
1136
|
this.pendingNearReveal.delete(chunkKey)
|
|
1290
1137
|
this.clearNearRevealTimer(chunkKey)
|
|
1291
1138
|
this.clearExpectedGraceTimer(chunkKey)
|
|
@@ -1293,7 +1140,7 @@ export class ChunkMeshManager {
|
|
|
1293
1140
|
this.tryRevealPending()
|
|
1294
1141
|
}
|
|
1295
1142
|
|
|
1296
|
-
private isWasmGateActive
|
|
1143
|
+
private isWasmGateActive(): boolean {
|
|
1297
1144
|
return !!this.worldRenderer.worldRendererConfig?.wasmMesher
|
|
1298
1145
|
}
|
|
1299
1146
|
|
|
@@ -1307,7 +1154,7 @@ export class ChunkMeshManager {
|
|
|
1307
1154
|
* - After grace: only actually-loaded-but-not-finished columns block,
|
|
1308
1155
|
* so a never-arriving column does not freeze the view.
|
|
1309
1156
|
*/
|
|
1310
|
-
private isBlockedByNearer
|
|
1157
|
+
private isBlockedByNearer(chunkKey: string, ageMs: number): boolean {
|
|
1311
1158
|
const viewer = this.worldRenderer.viewerChunkPosition
|
|
1312
1159
|
if (!viewer) return false
|
|
1313
1160
|
const ownParts = chunkKey.split(',')
|
|
@@ -1354,7 +1201,7 @@ export class ChunkMeshManager {
|
|
|
1354
1201
|
return false
|
|
1355
1202
|
}
|
|
1356
1203
|
|
|
1357
|
-
private armNearRevealTimer
|
|
1204
|
+
private armNearRevealTimer(chunkKey: string): void {
|
|
1358
1205
|
if (this.nearRevealTimers.has(chunkKey)) return
|
|
1359
1206
|
const timer = setTimeout(() => {
|
|
1360
1207
|
this.nearRevealTimers.delete(chunkKey)
|
|
@@ -1366,7 +1213,7 @@ export class ChunkMeshManager {
|
|
|
1366
1213
|
this.nearRevealTimers.set(chunkKey, timer)
|
|
1367
1214
|
}
|
|
1368
1215
|
|
|
1369
|
-
private clearNearRevealTimer
|
|
1216
|
+
private clearNearRevealTimer(chunkKey: string): void {
|
|
1370
1217
|
const timer = this.nearRevealTimers.get(chunkKey)
|
|
1371
1218
|
if (timer) {
|
|
1372
1219
|
clearTimeout(timer)
|
|
@@ -1379,7 +1226,7 @@ export class ChunkMeshManager {
|
|
|
1379
1226
|
* "expected but never arrived" positions stop blocking promptly,
|
|
1380
1227
|
* without waiting for the next chunkFinished / player-move event.
|
|
1381
1228
|
*/
|
|
1382
|
-
private armExpectedGraceTimer
|
|
1229
|
+
private armExpectedGraceTimer(chunkKey: string): void {
|
|
1383
1230
|
if (this.nearRevealGraceTimers.has(chunkKey)) return
|
|
1384
1231
|
const timer = setTimeout(() => {
|
|
1385
1232
|
this.nearRevealGraceTimers.delete(chunkKey)
|
|
@@ -1389,7 +1236,7 @@ export class ChunkMeshManager {
|
|
|
1389
1236
|
this.nearRevealGraceTimers.set(chunkKey, timer)
|
|
1390
1237
|
}
|
|
1391
1238
|
|
|
1392
|
-
private clearExpectedGraceTimer
|
|
1239
|
+
private clearExpectedGraceTimer(chunkKey: string): void {
|
|
1393
1240
|
const timer = this.nearRevealGraceTimers.get(chunkKey)
|
|
1394
1241
|
if (timer) {
|
|
1395
1242
|
clearTimeout(timer)
|
|
@@ -1397,7 +1244,7 @@ export class ChunkMeshManager {
|
|
|
1397
1244
|
}
|
|
1398
1245
|
}
|
|
1399
1246
|
|
|
1400
|
-
cleanupSection
|
|
1247
|
+
cleanupSection(sectionKey: string, opts?: { forRemesh?: boolean }) {
|
|
1401
1248
|
// Remove section object from scene
|
|
1402
1249
|
const sectionObject = this.sectionObjects[sectionKey]
|
|
1403
1250
|
if (sectionObject) {
|
|
@@ -1416,7 +1263,7 @@ export class ChunkMeshManager {
|
|
|
1416
1263
|
// Cleanup banner textures before disposing
|
|
1417
1264
|
if (sectionObject.bannersContainer) {
|
|
1418
1265
|
for (const child of sectionObject.bannersContainer.children) {
|
|
1419
|
-
const banner = child as THREE.Group & { bannerMaterial?: THREE.MeshBasicMaterial
|
|
1266
|
+
const banner = child as THREE.Group & { bannerMaterial?: THREE.MeshBasicMaterial; bannerTexture?: THREE.Texture }
|
|
1420
1267
|
if (banner.bannerMaterial) {
|
|
1421
1268
|
this.blockEntityLightRegistry.unregister(banner.bannerMaterial)
|
|
1422
1269
|
}
|
|
@@ -1426,11 +1273,13 @@ export class ChunkMeshManager {
|
|
|
1426
1273
|
}
|
|
1427
1274
|
this.disposeContainer(sectionObject.bannersContainer)
|
|
1428
1275
|
}
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1276
|
+
if (!opts?.forRemesh) {
|
|
1277
|
+
this.globalBlockBuffer?.removeSection(sectionKey)
|
|
1278
|
+
this.globalLegacyBuffer?.removeSection(sectionKey)
|
|
1279
|
+
this.globalLegacyBlendBuffer?.removeSection(sectionKey)
|
|
1280
|
+
this.maybeUnregisterLegacyCullSection(sectionKey)
|
|
1281
|
+
this.unregisterShaderSectionRaycastBox(sectionKey)
|
|
1282
|
+
}
|
|
1434
1283
|
this.markCullDirty()
|
|
1435
1284
|
delete sectionObject.deferredLegacyOpaque
|
|
1436
1285
|
delete sectionObject.deferredLegacyBlend
|
|
@@ -1469,8 +1318,7 @@ export class ChunkMeshManager {
|
|
|
1469
1318
|
}
|
|
1470
1319
|
delete this.sectionObjects[sectionKey]
|
|
1471
1320
|
if (!opts?.forRemesh) {
|
|
1472
|
-
this.worldRenderer.getModule<{ onSectionRemoved?: (key: string) => void }>('futuristicReveal')
|
|
1473
|
-
?.onSectionRemoved?.(sectionKey)
|
|
1321
|
+
this.worldRenderer.getModule<{ onSectionRemoved?: (key: string) => void }>('futuristicReveal')?.onSectionRemoved?.(sectionKey)
|
|
1474
1322
|
}
|
|
1475
1323
|
}
|
|
1476
1324
|
}
|
|
@@ -1478,7 +1326,7 @@ export class ChunkMeshManager {
|
|
|
1478
1326
|
/**
|
|
1479
1327
|
* Release a section and return its mesh to the pool
|
|
1480
1328
|
*/
|
|
1481
|
-
private releasePooledMesh
|
|
1329
|
+
private releasePooledMesh(sectionKey: string): void {
|
|
1482
1330
|
const poolEntry = this.activeSections.get(sectionKey)
|
|
1483
1331
|
if (!poolEntry) return
|
|
1484
1332
|
|
|
@@ -1491,7 +1339,7 @@ export class ChunkMeshManager {
|
|
|
1491
1339
|
this.cleanupExcessMeshes()
|
|
1492
1340
|
}
|
|
1493
1341
|
|
|
1494
|
-
releaseSection
|
|
1342
|
+
releaseSection(sectionKey: string): boolean {
|
|
1495
1343
|
this.cleanupSection(sectionKey)
|
|
1496
1344
|
|
|
1497
1345
|
const poolEntry = this.activeSections.get(sectionKey)
|
|
@@ -1519,14 +1367,14 @@ export class ChunkMeshManager {
|
|
|
1519
1367
|
/**
|
|
1520
1368
|
* Get section object if it exists
|
|
1521
1369
|
*/
|
|
1522
|
-
getSectionObject
|
|
1370
|
+
getSectionObject(sectionKey: string): SectionObject | undefined {
|
|
1523
1371
|
return this.sectionObjects[sectionKey]
|
|
1524
1372
|
}
|
|
1525
1373
|
|
|
1526
1374
|
/**
|
|
1527
1375
|
* Update box helper for a section
|
|
1528
1376
|
*/
|
|
1529
|
-
updateBoxHelper
|
|
1377
|
+
updateBoxHelper(sectionKey: string, showChunkBorders: boolean, chunkBoxMaterial: THREE.Material = this.chunkBoxMaterial) {
|
|
1530
1378
|
const sectionObject = this.sectionObjects[sectionKey]
|
|
1531
1379
|
if (!sectionObject) return
|
|
1532
1380
|
|
|
@@ -1562,7 +1410,7 @@ export class ChunkMeshManager {
|
|
|
1562
1410
|
* after the move from `WorldBlockGeometry` (which created the helpers
|
|
1563
1411
|
* eagerly per section) to the pooled `ChunkMeshManager`.
|
|
1564
1412
|
*/
|
|
1565
|
-
updateAllBoxHelpers
|
|
1413
|
+
updateAllBoxHelpers(showChunkBorders: boolean) {
|
|
1566
1414
|
for (const sectionKey of Object.keys(this.sectionObjects)) {
|
|
1567
1415
|
this.updateBoxHelper(sectionKey, showChunkBorders)
|
|
1568
1416
|
}
|
|
@@ -1571,21 +1419,21 @@ export class ChunkMeshManager {
|
|
|
1571
1419
|
/**
|
|
1572
1420
|
* Get mesh for section if it exists
|
|
1573
1421
|
*/
|
|
1574
|
-
getSectionMesh
|
|
1422
|
+
getSectionMesh(sectionKey: string): THREE.Mesh | undefined {
|
|
1575
1423
|
return this.activeSections.get(sectionKey)?.mesh
|
|
1576
1424
|
}
|
|
1577
1425
|
|
|
1578
1426
|
/**
|
|
1579
1427
|
* Check if section is managed by this pool
|
|
1580
1428
|
*/
|
|
1581
|
-
hasSection
|
|
1429
|
+
hasSection(sectionKey: string): boolean {
|
|
1582
1430
|
return this.activeSections.has(sectionKey)
|
|
1583
1431
|
}
|
|
1584
1432
|
|
|
1585
1433
|
/**
|
|
1586
1434
|
* Update pool size based on new view distance
|
|
1587
1435
|
*/
|
|
1588
|
-
updateViewDistance
|
|
1436
|
+
updateViewDistance(maxViewDistance: number) {
|
|
1589
1437
|
// Calculate dynamic pool size based on view distance
|
|
1590
1438
|
const chunksInView = (maxViewDistance * 2 + 1) ** 2
|
|
1591
1439
|
const maxSectionsPerChunk = this.worldHeight / 16
|
|
@@ -1606,7 +1454,7 @@ export class ChunkMeshManager {
|
|
|
1606
1454
|
/**
|
|
1607
1455
|
* Get pool statistics
|
|
1608
1456
|
*/
|
|
1609
|
-
getGlobalBufferStats
|
|
1457
|
+
getGlobalBufferStats(): GlobalBufferStats {
|
|
1610
1458
|
const snapshotLegacy = (buffer: GlobalLegacyBuffer | null): GlobalBufferSlotStats | null => {
|
|
1611
1459
|
if (!buffer) return null
|
|
1612
1460
|
return {
|
|
@@ -1614,7 +1462,7 @@ export class ChunkMeshManager {
|
|
|
1614
1462
|
capacity: buffer.getCapacityQuads(),
|
|
1615
1463
|
sections: buffer.getSectionCount(),
|
|
1616
1464
|
usedBytes: buffer.getUsedMemoryBytes(),
|
|
1617
|
-
capacityBytes: buffer.getMemoryBytes()
|
|
1465
|
+
capacityBytes: buffer.getMemoryBytes()
|
|
1618
1466
|
}
|
|
1619
1467
|
}
|
|
1620
1468
|
|
|
@@ -1626,17 +1474,17 @@ export class ChunkMeshManager {
|
|
|
1626
1474
|
capacity: cubes.getCapacityFaces(),
|
|
1627
1475
|
sections: cubes.getSectionCount(),
|
|
1628
1476
|
usedBytes: cubes.getUsedMemoryBytes(),
|
|
1629
|
-
capacityBytes: cubes.getMemoryBytes()
|
|
1477
|
+
capacityBytes: cubes.getMemoryBytes()
|
|
1630
1478
|
}
|
|
1631
1479
|
: null,
|
|
1632
1480
|
legacyOpaque: snapshotLegacy(this.globalLegacyBuffer),
|
|
1633
|
-
legacyBlend: snapshotLegacy(this.globalLegacyBlendBuffer)
|
|
1481
|
+
legacyBlend: snapshotLegacy(this.globalLegacyBlendBuffer)
|
|
1634
1482
|
}
|
|
1635
1483
|
}
|
|
1636
1484
|
|
|
1637
|
-
getStats
|
|
1485
|
+
getStats() {
|
|
1638
1486
|
const freeCount = this.meshPool.filter(entry => !entry.inUse).length
|
|
1639
|
-
const hitRate = this.hits + this.misses > 0 ? (this.hits / (this.hits + this.misses) * 100).toFixed(1) : '0'
|
|
1487
|
+
const hitRate = this.hits + this.misses > 0 ? ((this.hits / (this.hits + this.misses)) * 100).toFixed(1) : '0'
|
|
1640
1488
|
const memoryUsage = this.getEstimatedMemoryUsage()
|
|
1641
1489
|
|
|
1642
1490
|
return {
|
|
@@ -1653,21 +1501,21 @@ export class ChunkMeshManager {
|
|
|
1653
1501
|
/**
|
|
1654
1502
|
* Get total tiles rendered
|
|
1655
1503
|
*/
|
|
1656
|
-
getTotalTiles
|
|
1504
|
+
getTotalTiles(): number {
|
|
1657
1505
|
return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj.tilesCount || 0), 0)
|
|
1658
1506
|
}
|
|
1659
1507
|
|
|
1660
1508
|
/**
|
|
1661
1509
|
* Get total blocks rendered
|
|
1662
1510
|
*/
|
|
1663
|
-
getTotalBlocks
|
|
1511
|
+
getTotalBlocks(): number {
|
|
1664
1512
|
return Object.values(this.sectionObjects).reduce((acc, obj) => acc + (obj.blocksCount || 0), 0)
|
|
1665
1513
|
}
|
|
1666
1514
|
|
|
1667
1515
|
/**
|
|
1668
1516
|
* Estimate memory usage in MB
|
|
1669
1517
|
*/
|
|
1670
|
-
getEstimatedMemoryUsage
|
|
1518
|
+
getEstimatedMemoryUsage(): { total: string; breakdown: any } {
|
|
1671
1519
|
let totalBytes = 0
|
|
1672
1520
|
let positionBytes = 0
|
|
1673
1521
|
let normalBytes = 0
|
|
@@ -1756,7 +1604,7 @@ export class ChunkMeshManager {
|
|
|
1756
1604
|
color: `${(colorBytes / (1024 * 1024)).toFixed(2)} MB`,
|
|
1757
1605
|
uv: `${(uvBytes / (1024 * 1024)).toFixed(2)} MB`,
|
|
1758
1606
|
index: `${(indexBytes / (1024 * 1024)).toFixed(2)} MB`,
|
|
1759
|
-
shaderInstances: `${(shaderInstanceBytes / (1024 * 1024)).toFixed(2)} MB
|
|
1607
|
+
shaderInstances: `${(shaderInstanceBytes / (1024 * 1024)).toFixed(2)} MB`
|
|
1760
1608
|
}
|
|
1761
1609
|
}
|
|
1762
1610
|
}
|
|
@@ -1764,7 +1612,7 @@ export class ChunkMeshManager {
|
|
|
1764
1612
|
/**
|
|
1765
1613
|
* Cleanup and dispose resources
|
|
1766
1614
|
*/
|
|
1767
|
-
dispose
|
|
1615
|
+
dispose() {
|
|
1768
1616
|
// Release all active sections (snapshot keys to avoid mutating map during iteration)
|
|
1769
1617
|
const activeKeys = [...this.activeSections.keys()]
|
|
1770
1618
|
for (const sectionKey of activeKeys) {
|
|
@@ -1783,6 +1631,7 @@ export class ChunkMeshManager {
|
|
|
1783
1631
|
this.activeSections.clear()
|
|
1784
1632
|
this.chunkBoxMaterial.dispose()
|
|
1785
1633
|
this.shaderSectionRaycastBoxes.clear()
|
|
1634
|
+
this.lastBufferStateKey = ''
|
|
1786
1635
|
this.globalBlockBuffer?.dispose()
|
|
1787
1636
|
this.globalBlockBuffer = null
|
|
1788
1637
|
this.globalLegacyBuffer?.dispose()
|
|
@@ -1807,7 +1656,7 @@ export class ChunkMeshManager {
|
|
|
1807
1656
|
|
|
1808
1657
|
// Private helper methods
|
|
1809
1658
|
|
|
1810
|
-
private acquireMesh
|
|
1659
|
+
private acquireMesh(): ChunkMeshPool | undefined {
|
|
1811
1660
|
if (this.bypassPooling) {
|
|
1812
1661
|
const entry: ChunkMeshPool = {
|
|
1813
1662
|
mesh: new THREE.Mesh(new THREE.BufferGeometry(), this.getLegacyShaderMaterial()),
|
|
@@ -1854,7 +1703,7 @@ export class ChunkMeshManager {
|
|
|
1854
1703
|
throw new Error('ChunkMeshManager: Failed to acquire mesh after pool expansion')
|
|
1855
1704
|
}
|
|
1856
1705
|
|
|
1857
|
-
private expandPool
|
|
1706
|
+
private expandPool(newSize: number) {
|
|
1858
1707
|
const currentLength = this.meshPool.length
|
|
1859
1708
|
this.poolSize = newSize
|
|
1860
1709
|
|
|
@@ -1877,12 +1726,7 @@ export class ChunkMeshManager {
|
|
|
1877
1726
|
}
|
|
1878
1727
|
}
|
|
1879
1728
|
|
|
1880
|
-
private updateGeometryAttribute
|
|
1881
|
-
geometry: THREE.BufferGeometry,
|
|
1882
|
-
name: string,
|
|
1883
|
-
array: Float32Array,
|
|
1884
|
-
itemSize: number
|
|
1885
|
-
) {
|
|
1729
|
+
private updateGeometryAttribute(geometry: THREE.BufferGeometry, name: string, array: Float32Array, itemSize: number) {
|
|
1886
1730
|
const attribute = geometry.getAttribute(name)
|
|
1887
1731
|
|
|
1888
1732
|
if (attribute && attribute.count === array.length / itemSize) {
|
|
@@ -1895,7 +1739,7 @@ export class ChunkMeshManager {
|
|
|
1895
1739
|
}
|
|
1896
1740
|
}
|
|
1897
1741
|
|
|
1898
|
-
private clearGeometry
|
|
1742
|
+
private clearGeometry(geometry: THREE.BufferGeometry) {
|
|
1899
1743
|
const attributes = ['position', 'normal', 'color', 'a_skyLight', 'a_blockLight', 'uv']
|
|
1900
1744
|
for (const name of attributes) {
|
|
1901
1745
|
if (geometry.hasAttribute(name)) {
|
|
@@ -1909,7 +1753,7 @@ export class ChunkMeshManager {
|
|
|
1909
1753
|
geometry.boundingSphere = null
|
|
1910
1754
|
}
|
|
1911
1755
|
|
|
1912
|
-
private cleanupExcessMeshes
|
|
1756
|
+
private cleanupExcessMeshes() {
|
|
1913
1757
|
// If pool size exceeds max and we have free meshes, remove some
|
|
1914
1758
|
if (this.poolSize > this.maxPoolSize) {
|
|
1915
1759
|
const freeCount = this.meshPool.filter(entry => !entry.inUse).length
|
|
@@ -1929,14 +1773,14 @@ export class ChunkMeshManager {
|
|
|
1929
1773
|
}
|
|
1930
1774
|
}
|
|
1931
1775
|
|
|
1932
|
-
private disposeContainer
|
|
1776
|
+
private disposeContainer(container: THREE.Group, cleanTextures = true) {
|
|
1933
1777
|
disposeObject(container, cleanTextures)
|
|
1934
1778
|
}
|
|
1935
1779
|
|
|
1936
1780
|
/**
|
|
1937
1781
|
* Record render time for performance monitoring
|
|
1938
1782
|
*/
|
|
1939
|
-
recordRenderTime
|
|
1783
|
+
recordRenderTime(renderTime: number): void {
|
|
1940
1784
|
this.renderTimes.push(renderTime)
|
|
1941
1785
|
if (this.renderTimes.length > this.maxRenderTimeSamples) {
|
|
1942
1786
|
this.renderTimes.shift()
|
|
@@ -1953,31 +1797,31 @@ export class ChunkMeshManager {
|
|
|
1953
1797
|
/**
|
|
1954
1798
|
* Get current effective render distance
|
|
1955
1799
|
*/
|
|
1956
|
-
getEffectiveRenderDistance
|
|
1800
|
+
getEffectiveRenderDistance(): number {
|
|
1957
1801
|
return this.performanceOverrideDistance || this.worldRenderer.viewDistance
|
|
1958
1802
|
}
|
|
1959
1803
|
|
|
1960
1804
|
/**
|
|
1961
1805
|
* Force reset performance override
|
|
1962
1806
|
*/
|
|
1963
|
-
resetPerformanceOverride
|
|
1807
|
+
resetPerformanceOverride(): void {
|
|
1964
1808
|
this.performanceOverrideDistance = undefined
|
|
1965
1809
|
this.renderTimes.length = 0
|
|
1966
1810
|
console.log('ChunkMeshManager: Performance override reset')
|
|
1967
1811
|
}
|
|
1968
1812
|
|
|
1969
1813
|
/**
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
getAverageRenderTime
|
|
1814
|
+
* Get average render time
|
|
1815
|
+
*/
|
|
1816
|
+
getAverageRenderTime(): number {
|
|
1973
1817
|
if (this.renderTimes.length === 0) return 0
|
|
1974
1818
|
return this.renderTimes.reduce((sum, time) => sum + time, 0) / this.renderTimes.length
|
|
1975
1819
|
}
|
|
1976
1820
|
|
|
1977
1821
|
/**
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
private checkPerformance
|
|
1822
|
+
* Check if performance is degraded and adjust render distance
|
|
1823
|
+
*/
|
|
1824
|
+
private checkPerformance(): void {
|
|
1981
1825
|
if (this.renderTimes.length < this.maxRenderTimeSamples) return
|
|
1982
1826
|
|
|
1983
1827
|
const avgRenderTime = this.getAverageRenderTime()
|
|
@@ -2008,7 +1852,7 @@ export class ChunkMeshManager {
|
|
|
2008
1852
|
/**
|
|
2009
1853
|
* Hide sections beyond performance override distance
|
|
2010
1854
|
*/
|
|
2011
|
-
updateSectionsVisibility
|
|
1855
|
+
updateSectionsVisibility(): void {
|
|
2012
1856
|
const cameraPos = this.worldRenderer.cameraSectionPos
|
|
2013
1857
|
for (const [sectionKey, sectionObject] of Object.entries(this.sectionObjects)) {
|
|
2014
1858
|
// Don't override "Batch Chunks Display" hiding — those sections must
|
|
@@ -2035,16 +1879,14 @@ export class ChunkMeshManager {
|
|
|
2035
1879
|
}
|
|
2036
1880
|
}
|
|
2037
1881
|
|
|
2038
|
-
|
|
2039
1882
|
class SignHeadsRenderer {
|
|
2040
|
-
constructor
|
|
2041
|
-
}
|
|
1883
|
+
constructor(public worldRendererThree: WorldRendererThree) {}
|
|
2042
1884
|
|
|
2043
|
-
dispose
|
|
1885
|
+
dispose() {
|
|
2044
1886
|
disposeAllSignTextures()
|
|
2045
1887
|
}
|
|
2046
1888
|
|
|
2047
|
-
renderHead
|
|
1889
|
+
renderHead(position: Vec3, rotation: number, isWall: boolean, blockEntity) {
|
|
2048
1890
|
let textureData: string
|
|
2049
1891
|
if (blockEntity.SkullOwner) {
|
|
2050
1892
|
textureData = blockEntity.SkullOwner.Properties?.textures?.[0]?.Value
|
|
@@ -2058,8 +1900,7 @@ class SignHeadsRenderer {
|
|
|
2058
1900
|
let skinUrl = decodedData.textures?.SKIN?.url
|
|
2059
1901
|
const { skinTexturesProxy } = this.worldRendererThree.worldRendererConfig
|
|
2060
1902
|
if (skinTexturesProxy) {
|
|
2061
|
-
skinUrl = skinUrl?.replace('http://textures.minecraft.net/', skinTexturesProxy)
|
|
2062
|
-
.replace('https://textures.minecraft.net/', skinTexturesProxy)
|
|
1903
|
+
skinUrl = skinUrl?.replace('http://textures.minecraft.net/', skinTexturesProxy).replace('https://textures.minecraft.net/', skinTexturesProxy)
|
|
2063
1904
|
}
|
|
2064
1905
|
|
|
2065
1906
|
const mesh = getMesh(this.worldRendererThree, skinUrl, armorModel.head as any)
|
|
@@ -2072,11 +1913,7 @@ class SignHeadsRenderer {
|
|
|
2072
1913
|
group.add(mesh)
|
|
2073
1914
|
this.worldRendererThree.sceneOrigin.track(group)
|
|
2074
1915
|
group.position.set(position.x + 0.5, position.y + 0.045, position.z + 0.5)
|
|
2075
|
-
group.rotation.set(
|
|
2076
|
-
0,
|
|
2077
|
-
-THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)),
|
|
2078
|
-
0
|
|
2079
|
-
)
|
|
1916
|
+
group.rotation.set(0, -THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)), 0)
|
|
2080
1917
|
group.scale.set(0.8, 0.8, 0.8)
|
|
2081
1918
|
return group
|
|
2082
1919
|
} catch (err) {
|
|
@@ -2084,7 +1921,7 @@ class SignHeadsRenderer {
|
|
|
2084
1921
|
}
|
|
2085
1922
|
}
|
|
2086
1923
|
|
|
2087
|
-
renderSign
|
|
1924
|
+
renderSign(position: Vec3, rotation: number, isWall: boolean, isHanging: boolean, blockEntity) {
|
|
2088
1925
|
const tex = getSignTexture(this.worldRendererThree, blockEntity, isHanging)
|
|
2089
1926
|
|
|
2090
1927
|
if (!tex) return
|
|
@@ -2105,11 +1942,7 @@ class SignHeadsRenderer {
|
|
|
2105
1942
|
}
|
|
2106
1943
|
|
|
2107
1944
|
const group = new THREE.Group() as THREE.Group & { signTexture?: THREE.Texture }
|
|
2108
|
-
group.rotation.set(
|
|
2109
|
-
0,
|
|
2110
|
-
-THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)),
|
|
2111
|
-
0
|
|
2112
|
-
)
|
|
1945
|
+
group.rotation.set(0, -THREE.MathUtils.degToRad(rotation * (isWall ? 90 : 45 / 2)), 0)
|
|
2113
1946
|
group.add(mesh)
|
|
2114
1947
|
group.signTexture = tex
|
|
2115
1948
|
const height = (isHanging ? 10 : 8) / 16
|