minecraft-renderer 0.1.71 → 0.1.73
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/mesher.js +81 -81
- package/dist/mesher.js.map +3 -3
- package/dist/mesherWasm.js +1183 -943
- package/dist/minecraft-renderer.js +250 -79
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +1732 -1001
- package/package.json +3 -3
- package/src/graphicsBackend/rendererDefaultOptions.ts +5 -10
- package/src/graphicsBackend/rendererOptionsSync.ts +1 -1
- package/src/lib/bakeLegacyLight.ts +17 -0
- package/src/lib/blockEntityLightRegistry.test.ts +18 -0
- package/src/lib/blockEntityLightRegistry.ts +75 -0
- package/src/lib/blockEntityLighting.test.ts +30 -0
- package/src/lib/blockEntityLighting.ts +53 -0
- package/src/lib/worldrendererCommon.reconfigure.test.ts +202 -0
- package/src/lib/worldrendererCommon.ts +152 -22
- package/src/mesher-shared/blockEntityMetadata.test.ts +33 -0
- package/src/mesher-shared/blockEntityMetadata.ts +19 -3
- package/src/mesher-shared/exportedGeometryTypes.ts +11 -0
- package/src/mesher-shared/models.ts +161 -92
- package/src/mesher-shared/shared.ts +15 -4
- package/src/mesher-shared/tests/liquidQuadInvariant.test.ts +40 -0
- package/src/mesher-shared/world.ts +12 -0
- package/src/mesher-shared/worldLighting.test.ts +54 -0
- package/src/playground/baseScene.ts +1 -1
- package/src/three/bannerRenderer.ts +10 -3
- package/src/three/chunkMeshManager.ts +663 -69
- package/src/three/cubeDrawSpans.ts +74 -0
- package/src/three/cubeMultiDraw.ts +119 -0
- package/src/three/documentRenderer.ts +0 -2
- package/src/three/entities.ts +5 -6
- package/src/three/entity/EntityMesh.ts +7 -5
- package/src/three/entity/gltfAnimationUtils.ts +5 -3
- package/src/three/globalBlockBuffer.ts +208 -12
- package/src/three/globalLegacyBuffer.ts +701 -0
- package/src/three/graphicsBackendOffThread.ts +16 -1
- package/src/three/itemMesh.ts +5 -2
- package/src/three/legacySectionCull.ts +85 -0
- package/src/three/modules/sciFiWorldReveal.ts +347 -703
- package/src/three/modules/starfield.ts +3 -2
- package/src/three/sectionRaycastAabb.ts +25 -0
- package/src/three/shaders/cubeBlockShader.ts +80 -17
- package/src/three/shaders/legacyBlockShader.ts +292 -0
- package/src/three/skyboxRenderer.ts +1 -1
- package/src/three/tests/chunkMeshManagerLegacy.test.ts +286 -0
- package/src/three/tests/cubeDrawSpans.test.ts +73 -0
- package/src/three/tests/globalLegacyBuffer.test.ts +360 -0
- package/src/three/tests/legacySectionCull.test.ts +80 -0
- package/src/three/tests/signTextureCache.test.ts +83 -0
- package/src/three/threeJsMedia.ts +2 -2
- package/src/three/waypointSprite.ts +2 -2
- package/src/three/world/cursorBlock.ts +1 -0
- package/src/three/world/vr.ts +2 -2
- package/src/three/worldGeometryExport.ts +83 -26
- package/src/three/worldRendererThree.ts +94 -25
- package/src/wasm-mesher/bridge/render-from-wasm.ts +214 -72
- package/src/wasm-mesher/bridge/shaderCubeBridge.ts +18 -6
- package/src/wasm-mesher/runtime-build/wasm_mesher_bg.wasm +0 -0
- package/src/wasm-mesher/tests/sectionRaycastAabb.test.ts +20 -0
- package/src/wasm-mesher/tests/shaderCubeInstances.test.ts +67 -5
- package/src/wasm-mesher/worker/mesherWasm.ts +70 -14
- package/src/wasm-mesher/worker/mesherWasmLightDirty.test.ts +11 -0
- package/src/wasm-mesher/worker/mesherWasmLightDirty.ts +15 -0
- package/src/worldView/worldView.ts +11 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import { test, expect } from 'vitest'
|
|
3
|
+
import * as THREE from 'three'
|
|
4
|
+
import { sectionIntersectsFrustum, setupLegacySectionMatrix, updateLegacySectionCullState } from '../legacySectionCull'
|
|
5
|
+
|
|
6
|
+
test('setupLegacySectionMatrix: translation set once and stable across frames', () => {
|
|
7
|
+
const mesh = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshBasicMaterial())
|
|
8
|
+
mesh.matrixAutoUpdate = false
|
|
9
|
+
|
|
10
|
+
setupLegacySectionMatrix(mesh, 100, 64, -200, { x: 0, y: 0, z: 0 })
|
|
11
|
+
|
|
12
|
+
expect(mesh.matrix.elements[12]).toBe(100)
|
|
13
|
+
expect(mesh.matrix.elements[13]).toBe(64)
|
|
14
|
+
expect(mesh.matrix.elements[14]).toBe(-200)
|
|
15
|
+
expect(mesh.frustumCulled).toBe(false)
|
|
16
|
+
|
|
17
|
+
const before = mesh.matrix.elements.slice()
|
|
18
|
+
// No per-frame matrix write in 2a — matrix must stay unchanged across frames.
|
|
19
|
+
expect(mesh.matrix.elements.slice()).toEqual(before)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('updateLegacySectionCullState: frustum hit sets visible and nearer section sorts later', () => {
|
|
23
|
+
const meshNear = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshBasicMaterial())
|
|
24
|
+
const meshFar = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshBasicMaterial())
|
|
25
|
+
|
|
26
|
+
const frustum = { intersectsBox: () => true } as unknown as THREE.Frustum
|
|
27
|
+
|
|
28
|
+
const box = new THREE.Box3()
|
|
29
|
+
const boxMin = new THREE.Vector3()
|
|
30
|
+
const boxMax = new THREE.Vector3()
|
|
31
|
+
|
|
32
|
+
updateLegacySectionCullState(meshNear, 0, 0, 0, 0, 0, 0, frustum, box, boxMin, boxMax)
|
|
33
|
+
updateLegacySectionCullState(meshFar, 32, 0, 0, 0, 0, 0, frustum, box, boxMin, boxMax)
|
|
34
|
+
|
|
35
|
+
expect(meshNear.visible).toBe(true)
|
|
36
|
+
expect(meshFar.visible).toBe(true)
|
|
37
|
+
expect(meshFar.renderOrder).toBeLessThan(meshNear.renderOrder)
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
test('sectionIntersectsFrustum: returns distSq and visibility', () => {
|
|
41
|
+
const frustum = { intersectsBox: () => true } as unknown as THREE.Frustum
|
|
42
|
+
const box = new THREE.Box3()
|
|
43
|
+
const boxMin = new THREE.Vector3()
|
|
44
|
+
const boxMax = new THREE.Vector3()
|
|
45
|
+
|
|
46
|
+
const result = sectionIntersectsFrustum(10, 0, 0, 0, 0, 0, frustum, box, boxMin, boxMax)
|
|
47
|
+
expect(result.visible).toBe(true)
|
|
48
|
+
expect(result.distSq).toBe(100)
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
test('updateLegacySectionCullState: outside frustum hides mesh', () => {
|
|
52
|
+
const mesh = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshBasicMaterial())
|
|
53
|
+
const frustum = new THREE.Frustum()
|
|
54
|
+
const proj = new THREE.Matrix4()
|
|
55
|
+
const camera = new THREE.PerspectiveCamera(60, 1, 0.1, 100)
|
|
56
|
+
camera.position.set(0, 0, 0)
|
|
57
|
+
camera.lookAt(0, 0, -1)
|
|
58
|
+
camera.updateMatrixWorld()
|
|
59
|
+
proj.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
|
|
60
|
+
frustum.setFromProjectionMatrix(proj)
|
|
61
|
+
|
|
62
|
+
const box = new THREE.Box3()
|
|
63
|
+
const boxMin = new THREE.Vector3()
|
|
64
|
+
const boxMax = new THREE.Vector3()
|
|
65
|
+
|
|
66
|
+
updateLegacySectionCullState(mesh, 500, 0, 0, 0, 0, 0, frustum, box, boxMin, boxMax)
|
|
67
|
+
|
|
68
|
+
expect(mesh.visible).toBe(false)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('setupLegacySectionMatrix: non-zero render origin stores world minus R', () => {
|
|
72
|
+
const mesh = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshBasicMaterial())
|
|
73
|
+
mesh.matrixAutoUpdate = false
|
|
74
|
+
|
|
75
|
+
setupLegacySectionMatrix(mesh, 100, 64, -200, { x: 16, y: 0, z: 16 })
|
|
76
|
+
|
|
77
|
+
expect(mesh.matrix.elements[12]).toBe(84)
|
|
78
|
+
expect(mesh.matrix.elements[13]).toBe(64)
|
|
79
|
+
expect(mesh.matrix.elements[14]).toBe(-216)
|
|
80
|
+
})
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import { test, expect, vi, beforeEach } from 'vitest'
|
|
3
|
+
import * as THREE from 'three'
|
|
4
|
+
import { Vec3 } from 'vec3'
|
|
5
|
+
|
|
6
|
+
vi.mock('../entity/EntityMesh', () => ({
|
|
7
|
+
getMesh: vi.fn(),
|
|
8
|
+
}))
|
|
9
|
+
|
|
10
|
+
const renderSignMock = vi.fn()
|
|
11
|
+
vi.mock('../../sign-renderer', () => ({
|
|
12
|
+
renderSign: (...args: unknown[]) => renderSignMock(...args),
|
|
13
|
+
}))
|
|
14
|
+
|
|
15
|
+
vi.mock('prismarine-chat', () => ({
|
|
16
|
+
default: () => () => ({}),
|
|
17
|
+
}))
|
|
18
|
+
|
|
19
|
+
import { ChunkMeshManager } from '../chunkMeshManager'
|
|
20
|
+
import type { WorldRendererThree } from '../worldRendererThree'
|
|
21
|
+
|
|
22
|
+
function createManager (): ChunkMeshManager {
|
|
23
|
+
const scene = new THREE.Scene()
|
|
24
|
+
const material = new THREE.MeshBasicMaterial()
|
|
25
|
+
const worldRenderer = {
|
|
26
|
+
version: '1.20',
|
|
27
|
+
shaderCubeBlocksEnabled: () => false,
|
|
28
|
+
getModule: () => undefined,
|
|
29
|
+
sceneOrigin: {
|
|
30
|
+
track: () => {},
|
|
31
|
+
removeAndUntrack: () => {},
|
|
32
|
+
removeAndUntrackAll: () => {},
|
|
33
|
+
},
|
|
34
|
+
blockEntities: {},
|
|
35
|
+
worldRendererConfig: {},
|
|
36
|
+
} as unknown as WorldRendererThree
|
|
37
|
+
return new ChunkMeshManager(worldRenderer, scene, material, 256, 1)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function stubCanvas () {
|
|
41
|
+
return { width: 64, height: 32 } as HTMLCanvasElement
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
renderSignMock.mockReset()
|
|
46
|
+
renderSignMock.mockImplementation(() => stubCanvas())
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('getSignTexture: same blockEntity returns cached texture without re-render', () => {
|
|
50
|
+
const manager = createManager()
|
|
51
|
+
const signHeadsRenderer = (manager as unknown as { signHeadsRenderer: { getSignTexture: Function } }).signHeadsRenderer
|
|
52
|
+
const pos = new Vec3(10, 64, 10)
|
|
53
|
+
const blockEntity = { Text1: '{"text":"Hello"}' }
|
|
54
|
+
|
|
55
|
+
const tex1 = signHeadsRenderer.getSignTexture(pos, blockEntity, false)
|
|
56
|
+
const tex2 = signHeadsRenderer.getSignTexture(pos, blockEntity, false)
|
|
57
|
+
|
|
58
|
+
expect(tex1).toBeDefined()
|
|
59
|
+
expect(tex2).toBe(tex1)
|
|
60
|
+
expect(renderSignMock).toHaveBeenCalledTimes(1)
|
|
61
|
+
|
|
62
|
+
manager.dispose()
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('getSignTexture: changed blockEntity disposes old texture and renders anew', () => {
|
|
66
|
+
const manager = createManager()
|
|
67
|
+
const signHeadsRenderer = (manager as unknown as { signHeadsRenderer: { getSignTexture: Function } }).signHeadsRenderer
|
|
68
|
+
const pos = new Vec3(10, 64, 10)
|
|
69
|
+
const blockEntity = { Text1: '{"text":"Hello"}' }
|
|
70
|
+
|
|
71
|
+
const tex1 = signHeadsRenderer.getSignTexture(pos, blockEntity, false)!
|
|
72
|
+
const disposeSpy = vi.spyOn(tex1, 'dispose')
|
|
73
|
+
|
|
74
|
+
const changed = { Text1: '{"text":"World"}' }
|
|
75
|
+
const tex2 = signHeadsRenderer.getSignTexture(pos, changed, false)
|
|
76
|
+
|
|
77
|
+
expect(tex2).toBeDefined()
|
|
78
|
+
expect(tex2).not.toBe(tex1)
|
|
79
|
+
expect(disposeSpy).toHaveBeenCalledTimes(1)
|
|
80
|
+
expect(renderSignMock).toHaveBeenCalledTimes(2)
|
|
81
|
+
|
|
82
|
+
manager.dispose()
|
|
83
|
+
})
|
|
@@ -81,7 +81,7 @@ export class ThreeJsMedia {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
private createErrorTexture(width: number, height: number, background = 0xff_ff_ff, error = 'Failed to load'): THREE.CanvasTexture {
|
|
84
|
+
private createErrorTexture(width: number, height: number, background = 0xff_ff_ff, error = 'Failed to load'): THREE.CanvasTexture<OffscreenCanvas> {
|
|
85
85
|
const canvas = new OffscreenCanvas(100, 100)
|
|
86
86
|
const MAX_DIMENSION = 100
|
|
87
87
|
|
|
@@ -111,7 +111,7 @@ export class ThreeJsMedia {
|
|
|
111
111
|
return texture
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
private createBackgroundTexture(width: number, height: number, color = 0x00_00_00, opacity = 1): THREE.CanvasTexture {
|
|
114
|
+
private createBackgroundTexture(width: number, height: number, color = 0x00_00_00, opacity = 1): THREE.CanvasTexture<OffscreenCanvas> {
|
|
115
115
|
const canvas = new OffscreenCanvas(1, 1)
|
|
116
116
|
canvas.width = 1
|
|
117
117
|
canvas.height = 1
|
|
@@ -89,7 +89,7 @@ export function createWaypointSprite (options: {
|
|
|
89
89
|
const labelCanvas = createCanvas(getLabelCanvasSize(), getLabelCanvasSize())
|
|
90
90
|
drawCombinedOntoCanvas(labelCanvas, displayColor, options.label ?? '', '0m', visualScale)
|
|
91
91
|
|
|
92
|
-
const labelTexture = new THREE.CanvasTexture(labelCanvas)
|
|
92
|
+
const labelTexture: THREE.CanvasTexture<OffscreenCanvas> = new THREE.CanvasTexture(labelCanvas)
|
|
93
93
|
labelTexture.anisotropy = 1
|
|
94
94
|
labelTexture.magFilter = THREE.LinearFilter
|
|
95
95
|
labelTexture.minFilter = THREE.LinearFilter
|
|
@@ -112,7 +112,7 @@ export function createWaypointSprite (options: {
|
|
|
112
112
|
let arrowSprite: THREE.Sprite | undefined
|
|
113
113
|
let arrowCanvas: OffscreenCanvas | undefined
|
|
114
114
|
let arrowCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | undefined
|
|
115
|
-
let arrowTexture: THREE.CanvasTexture | undefined
|
|
115
|
+
let arrowTexture: THREE.CanvasTexture<OffscreenCanvas> | undefined
|
|
116
116
|
let arrowParent: THREE.Object3D | null = null
|
|
117
117
|
let arrowEnabled = WAYPOINT_CONFIG.ARROW.enabledDefault
|
|
118
118
|
|
|
@@ -52,6 +52,7 @@ export class CursorBlock {
|
|
|
52
52
|
const breakMaterial = new THREE.MeshBasicMaterial({
|
|
53
53
|
transparent: true,
|
|
54
54
|
blending: THREE.MultiplyBlending,
|
|
55
|
+
premultipliedAlpha: true,
|
|
55
56
|
alphaTest: 0.5,
|
|
56
57
|
})
|
|
57
58
|
this.blockBreakMesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), breakMaterial)
|
package/src/three/world/vr.ts
CHANGED
|
@@ -124,14 +124,14 @@ export async function initVR(worldRenderer: WorldRendererThree, documentRenderer
|
|
|
124
124
|
let hand1: any = controllerModelFactory.createControllerModel(controller1)
|
|
125
125
|
controller1.addEventListener('connected', (event) => {
|
|
126
126
|
hand1.xrInputSource = event.data
|
|
127
|
-
manageXrInputSource(event.data, 'left')
|
|
127
|
+
manageXrInputSource(event.data as { gamepad: Gamepad | undefined, handedness?: string }, 'left')
|
|
128
128
|
user.add(controller1)
|
|
129
129
|
})
|
|
130
130
|
controller1.add(hand1)
|
|
131
131
|
let hand2: any = controllerModelFactory.createControllerModel(controller2)
|
|
132
132
|
controller2.addEventListener('connected', (event) => {
|
|
133
133
|
hand2.xrInputSource = event.data
|
|
134
|
-
manageXrInputSource(event.data, 'right')
|
|
134
|
+
manageXrInputSource(event.data as { gamepad: Gamepad | undefined, handedness?: string }, 'right')
|
|
135
135
|
user.add(controller2)
|
|
136
136
|
})
|
|
137
137
|
controller2.add(hand2)
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
import * as THREE from 'three'
|
|
3
3
|
import type { WorldRendererThree } from './worldRendererThree'
|
|
4
4
|
import type { ExportedSection, ExportedWorldGeometry } from '../mesher-shared/exportedGeometryTypes'
|
|
5
|
+
import { calculateSkyLightSimple } from '../lib/skyLight'
|
|
6
|
+
import { bakeLegacyVertexColors } from '../lib/bakeLegacyLight'
|
|
5
7
|
import { getShaderCubeResources } from '../wasm-mesher/bridge/shaderCubeBridge'
|
|
6
|
-
import { createCubeBlockMaterial } from './shaders/cubeBlockShader'
|
|
8
|
+
import { createCubeBlockMaterial, setCubeSkyLevel } from './shaders/cubeBlockShader'
|
|
7
9
|
import { createShaderCubeMesh } from './shaderCubeMesh'
|
|
8
10
|
|
|
9
11
|
export type { ExportedSection, ExportedWorldGeometry } from '../mesher-shared/exportedGeometryTypes'
|
|
@@ -20,35 +22,79 @@ export function exportWorldGeometry(
|
|
|
20
22
|
includeTexture = false
|
|
21
23
|
): ExportedWorldGeometry {
|
|
22
24
|
const sections: ExportedSection[] = []
|
|
25
|
+
const skyLevel = calculateSkyLightSimple(worldRenderer.timeOfTheDay) / 15
|
|
26
|
+
|
|
27
|
+
const globalLegacy = worldRenderer.chunkMeshManager.globalLegacyBuffer
|
|
23
28
|
|
|
24
29
|
for (const [key, sectionObject] of Object.entries(worldRenderer.sectionObjects)) {
|
|
25
|
-
const
|
|
26
|
-
|
|
30
|
+
const positions: number[] = []
|
|
31
|
+
const normals: number[] = []
|
|
32
|
+
const colors: number[] = []
|
|
33
|
+
const skyLights: number[] = []
|
|
34
|
+
const blockLights: number[] = []
|
|
35
|
+
const uvs: number[] = []
|
|
36
|
+
const indices: number[] = []
|
|
27
37
|
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
38
|
+
const globalSlot = globalLegacy?.getSectionGeometryData(key)
|
|
39
|
+
if (globalSlot) {
|
|
40
|
+
positions.push(...globalSlot.positions)
|
|
41
|
+
colors.push(...bakeLegacyVertexColors(globalSlot.colors, globalSlot.skyLights, globalSlot.blockLights, skyLevel))
|
|
42
|
+
skyLights.push(...globalSlot.skyLights)
|
|
43
|
+
blockLights.push(...globalSlot.blockLights)
|
|
44
|
+
uvs.push(...globalSlot.uvs)
|
|
45
|
+
indices.push(...globalSlot.indices)
|
|
46
|
+
}
|
|
34
47
|
|
|
35
|
-
|
|
48
|
+
const blendMesh = sectionObject.children.find(child => child.name === 'mesh') as THREE.Mesh | undefined
|
|
49
|
+
if (blendMesh?.geometry) {
|
|
50
|
+
const { geometry } = blendMesh
|
|
51
|
+
const positionAttr = geometry.getAttribute('position') as THREE.BufferAttribute
|
|
52
|
+
const normalAttr = geometry.getAttribute('normal') as THREE.BufferAttribute
|
|
53
|
+
const colorAttr = geometry.getAttribute('color') as THREE.BufferAttribute
|
|
54
|
+
const skyAttr = geometry.getAttribute('a_skyLight') as THREE.BufferAttribute | undefined
|
|
55
|
+
const blockAttr = geometry.getAttribute('a_blockLight') as THREE.BufferAttribute | undefined
|
|
56
|
+
const uvAttr = geometry.getAttribute('uv') as THREE.BufferAttribute
|
|
57
|
+
const indexAttr = geometry.index
|
|
58
|
+
if (positionAttr && indexAttr && colorAttr) {
|
|
59
|
+
const vertOffset = positions.length / 3
|
|
60
|
+
const vertCount = positionAttr.count
|
|
61
|
+
const rawColors = Array.from(colorAttr.array as Float32Array)
|
|
62
|
+
const rawSky = skyAttr
|
|
63
|
+
? Array.from(skyAttr.array as Float32Array)
|
|
64
|
+
: new Array(vertCount).fill(1)
|
|
65
|
+
const rawBlock = blockAttr
|
|
66
|
+
? Array.from(blockAttr.array as Float32Array)
|
|
67
|
+
: new Array(vertCount).fill(0)
|
|
68
|
+
positions.push(...Array.from(positionAttr.array))
|
|
69
|
+
if (normalAttr) normals.push(...Array.from(normalAttr.array))
|
|
70
|
+
colors.push(...bakeLegacyVertexColors(rawColors, rawSky, rawBlock, skyLevel))
|
|
71
|
+
skyLights.push(...rawSky)
|
|
72
|
+
blockLights.push(...rawBlock)
|
|
73
|
+
if (uvAttr) uvs.push(...Array.from(uvAttr.array))
|
|
74
|
+
for (const idx of Array.from(indexAttr.array)) {
|
|
75
|
+
indices.push(idx + vertOffset)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (positions.length === 0 || indices.length === 0) continue
|
|
36
81
|
|
|
37
|
-
const wp = worldRenderer.sceneOrigin.getWorldPosition(mesh)
|
|
38
82
|
sections.push({
|
|
39
83
|
key,
|
|
40
84
|
position: {
|
|
41
|
-
x:
|
|
42
|
-
y:
|
|
43
|
-
z:
|
|
85
|
+
x: sectionObject.worldX ?? 0,
|
|
86
|
+
y: sectionObject.worldY ?? 0,
|
|
87
|
+
z: sectionObject.worldZ ?? 0,
|
|
44
88
|
},
|
|
45
89
|
geometry: {
|
|
46
|
-
positions
|
|
47
|
-
normals
|
|
48
|
-
colors
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
90
|
+
positions,
|
|
91
|
+
normals,
|
|
92
|
+
colors,
|
|
93
|
+
skyLights,
|
|
94
|
+
blockLights,
|
|
95
|
+
uvs,
|
|
96
|
+
indices,
|
|
97
|
+
},
|
|
52
98
|
})
|
|
53
99
|
}
|
|
54
100
|
|
|
@@ -65,7 +111,7 @@ export function exportWorldGeometry(
|
|
|
65
111
|
// Optionally include texture atlas as data URL
|
|
66
112
|
if (includeTexture && worldRenderer.material.map) {
|
|
67
113
|
const canvas = document.createElement('canvas')
|
|
68
|
-
const texture = worldRenderer.material.map
|
|
114
|
+
const texture = worldRenderer.material.map as THREE.Texture<HTMLImageElement | ImageBitmap>
|
|
69
115
|
const { image } = texture
|
|
70
116
|
if (image) {
|
|
71
117
|
canvas.width = image.width
|
|
@@ -117,12 +163,13 @@ export async function loadWorldGeometryFromUrl(url: string): Promise<ExportedWor
|
|
|
117
163
|
* Recreate THREE.js meshes from exported geometry
|
|
118
164
|
* Returns an array of mesh groups that can be added to a scene
|
|
119
165
|
*/
|
|
120
|
-
function shaderMaterialForExport(legacyMaterial: THREE.Material): THREE.ShaderMaterial | null {
|
|
166
|
+
function shaderMaterialForExport(legacyMaterial: THREE.Material, skyLevel: number): THREE.ShaderMaterial | null {
|
|
121
167
|
const atlas = (legacyMaterial as THREE.MeshBasicMaterial).map
|
|
122
168
|
?? (legacyMaterial as THREE.MeshLambertMaterial).map
|
|
123
169
|
if (!atlas) return null
|
|
124
170
|
const shaderMat = createCubeBlockMaterial()
|
|
125
171
|
shaderMat.uniforms.u_atlas.value = atlas
|
|
172
|
+
setCubeSkyLevel(shaderMat, skyLevel)
|
|
126
173
|
const resources = getShaderCubeResources()
|
|
127
174
|
if (!resources) return null
|
|
128
175
|
const { tintPalette } = resources
|
|
@@ -135,9 +182,10 @@ export function createMeshesFromExport(
|
|
|
135
182
|
exportData: ExportedWorldGeometry,
|
|
136
183
|
material: THREE.Material,
|
|
137
184
|
shaderMaterial?: THREE.ShaderMaterial | null,
|
|
185
|
+
skyLevel = 1,
|
|
138
186
|
): THREE.Group[] {
|
|
139
187
|
const groups: THREE.Group[] = []
|
|
140
|
-
const resolvedShaderMat = shaderMaterial ?? shaderMaterialForExport(material)
|
|
188
|
+
const resolvedShaderMat = shaderMaterial ?? shaderMaterialForExport(material, skyLevel)
|
|
141
189
|
|
|
142
190
|
for (const section of exportData.sections) {
|
|
143
191
|
const group = new THREE.Group()
|
|
@@ -151,7 +199,15 @@ export function createMeshesFromExport(
|
|
|
151
199
|
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(section.geometry.normals, 3))
|
|
152
200
|
}
|
|
153
201
|
if (section.geometry.colors.length) {
|
|
154
|
-
|
|
202
|
+
const baked = section.geometry.skyLights?.length
|
|
203
|
+
? bakeLegacyVertexColors(
|
|
204
|
+
section.geometry.colors,
|
|
205
|
+
section.geometry.skyLights,
|
|
206
|
+
section.geometry.blockLights,
|
|
207
|
+
skyLevel,
|
|
208
|
+
)
|
|
209
|
+
: section.geometry.colors
|
|
210
|
+
geometry.setAttribute('color', new THREE.Float32BufferAttribute(baked, 3))
|
|
155
211
|
}
|
|
156
212
|
if (section.geometry.uvs.length) {
|
|
157
213
|
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(section.geometry.uvs, 2))
|
|
@@ -249,10 +305,11 @@ export async function applyWorldGeometryExport(
|
|
|
249
305
|
material = rendererMaterial
|
|
250
306
|
}
|
|
251
307
|
|
|
308
|
+
const skyLevel = calculateSkyLightSimple(worldRenderer.timeOfTheDay) / 15
|
|
252
309
|
const shaderMat = exportData.sections.some(s => (s.shaderCubes?.count ?? 0) > 0)
|
|
253
|
-
? shaderMaterialForExport(material)
|
|
310
|
+
? shaderMaterialForExport(material, skyLevel)
|
|
254
311
|
: null
|
|
255
|
-
const groups = createMeshesFromExport(exportData, material, shaderMat)
|
|
312
|
+
const groups = createMeshesFromExport(exportData, material, shaderMat, skyLevel)
|
|
256
313
|
const container = new THREE.Group()
|
|
257
314
|
container.name = GEOMETRY_EXPORT_GROUP_NAME
|
|
258
315
|
if (hasEmbeddedTexture) {
|
|
@@ -9,6 +9,7 @@ import { renderSign } from '../sign-renderer'
|
|
|
9
9
|
import { DisplayWorldOptions, GraphicsInitOptions } from '../graphicsBackend/types'
|
|
10
10
|
import { chunkPos, sectionPos } from '../lib/simpleUtils'
|
|
11
11
|
import { WorldRendererCommon } from '../lib/worldrendererCommon'
|
|
12
|
+
import { calculateSkyLightSimple } from '../lib/skyLight'
|
|
12
13
|
import { addNewStat, MC_RENDERER_DEBUG_OVERLAY_CLASS } from '../lib/ui/newStats'
|
|
13
14
|
import { MesherGeometryOutput } from '../mesher-shared/shared'
|
|
14
15
|
import { ItemSpecificContextProperties } from '../playerState/types'
|
|
@@ -43,6 +44,9 @@ type SectionKey = string
|
|
|
43
44
|
export class WorldRendererThree extends WorldRendererCommon {
|
|
44
45
|
outputFormat = 'threeJs' as const
|
|
45
46
|
|
|
47
|
+
/** r184 removed useLegacyLights; physical intensities ≈ legacy / π. */
|
|
48
|
+
private static readonly LEGACY_TO_PHYSICAL_LIGHT = Math.PI
|
|
49
|
+
|
|
46
50
|
protected override isShaderCubeBlocksEnabled(): boolean {
|
|
47
51
|
return this.worldRendererConfig.shaderCubeBlocks === true
|
|
48
52
|
&& !!this.renderer?.capabilities?.isWebGL2
|
|
@@ -60,8 +64,8 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
60
64
|
get realScene() {
|
|
61
65
|
return this.scene
|
|
62
66
|
}
|
|
63
|
-
ambientLight = new THREE.AmbientLight(0xcc_cc_cc)
|
|
64
|
-
directionalLight = new THREE.DirectionalLight(0xff_ff_ff, 0.5)
|
|
67
|
+
ambientLight = new THREE.AmbientLight(0xcc_cc_cc, WorldRendererThree.LEGACY_TO_PHYSICAL_LIGHT)
|
|
68
|
+
directionalLight = new THREE.DirectionalLight(0xff_ff_ff, 0.5 * WorldRendererThree.LEGACY_TO_PHYSICAL_LIGHT)
|
|
65
69
|
entities = new Entities(this, (globalThis as any).mcData)
|
|
66
70
|
performanceMonitor!: PerformanceMonitor
|
|
67
71
|
cameraGroupVr?: THREE.Object3D
|
|
@@ -70,6 +74,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
70
74
|
cursorBlock: CursorBlock
|
|
71
75
|
onRender: Array<(deltaTime: number) => void> = []
|
|
72
76
|
private lastRenderTime = 0
|
|
77
|
+
private lastSciFiTickMs = 0
|
|
73
78
|
private animatedFov = 0
|
|
74
79
|
private lastFovAnimTime = 0
|
|
75
80
|
private static readonly FOV_TRANSITION_MS = 200
|
|
@@ -176,6 +181,15 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
176
181
|
this.chunkMeshManager.updateViewDistance(viewDistance)
|
|
177
182
|
}
|
|
178
183
|
|
|
184
|
+
// Final lightmap values TBD — compare against https://v99.mcraft.fun/
|
|
185
|
+
if (typeof window !== 'undefined') {
|
|
186
|
+
(window as any).setBlockLightmap = (params: { curve?: number, minBrightness?: number, gamma?: number }) => {
|
|
187
|
+
this.chunkMeshManager.setBlockLightmapParams(params)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
this.syncSkyLevelFromTime(this.timeOfTheDay)
|
|
192
|
+
|
|
179
193
|
this.cursorBlock = new CursorBlock(this)
|
|
180
194
|
this.holdingBlock = createHoldingBlock(this)
|
|
181
195
|
this.holdingBlockLeft = createHoldingBlock(this, true)
|
|
@@ -431,6 +445,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
431
445
|
|
|
432
446
|
worldSwitchActions() {
|
|
433
447
|
this.onWorldSwitched.push(() => {
|
|
448
|
+
this.getModule<{ onWorldSwitched?: () => void }>('futuristicReveal')?.onWorldSwitched?.()
|
|
434
449
|
// clear custom blocks
|
|
435
450
|
this.protocolCustomBlocks.clear()
|
|
436
451
|
// Reset section animations
|
|
@@ -441,6 +456,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
441
456
|
this.cinimaticScript.stopScript()
|
|
442
457
|
// Clear fireworks
|
|
443
458
|
this.fireworks.clear()
|
|
459
|
+
this.syncSkyLevelFromTime(this.timeOfTheDay)
|
|
444
460
|
})
|
|
445
461
|
}
|
|
446
462
|
|
|
@@ -500,11 +516,11 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
500
516
|
})
|
|
501
517
|
this.onReactivePlayerStateUpdated('ambientLight', (value) => {
|
|
502
518
|
if (!value) return
|
|
503
|
-
this.ambientLight.intensity = value
|
|
519
|
+
this.ambientLight.intensity = value * WorldRendererThree.LEGACY_TO_PHYSICAL_LIGHT
|
|
504
520
|
})
|
|
505
521
|
this.onReactivePlayerStateUpdated('directionalLight', (value) => {
|
|
506
522
|
if (!value) return
|
|
507
|
-
this.directionalLight.intensity = value
|
|
523
|
+
this.directionalLight.intensity = value * WorldRendererThree.LEGACY_TO_PHYSICAL_LIGHT
|
|
508
524
|
})
|
|
509
525
|
this.onReactivePlayerStateUpdated('lookingAtBlock', (value) => {
|
|
510
526
|
this.cursorBlock.setHighlightCursorBlock(value ? new Vec3(value.x, value.y, value.z) : null, value?.shapes)
|
|
@@ -530,6 +546,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
530
546
|
})
|
|
531
547
|
this.onReactiveConfigUpdated('shaderCubeDebugMode', () => {
|
|
532
548
|
this.chunkMeshManager.syncCubeShaderUniforms()
|
|
549
|
+
this.chunkMeshManager.syncLegacyShaderUniforms()
|
|
533
550
|
})
|
|
534
551
|
this.onReactiveConfigUpdated('futuristicReveal', () => {
|
|
535
552
|
this.updateModulesFromConfig()
|
|
@@ -631,6 +648,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
631
648
|
texture.flipY = false
|
|
632
649
|
this.material.map = texture
|
|
633
650
|
this.chunkMeshManager.syncCubeShaderUniforms()
|
|
651
|
+
this.chunkMeshManager.syncLegacyShaderUniforms()
|
|
634
652
|
|
|
635
653
|
const itemsTexture = loadThreeJsTextureFromBitmap(resources.itemsAtlasImage!)
|
|
636
654
|
itemsTexture.needsUpdate = true
|
|
@@ -675,6 +693,16 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
675
693
|
}
|
|
676
694
|
|
|
677
695
|
this.skyboxRenderer.updateTime(newTime)
|
|
696
|
+
this.syncSkyLevelFromTime(newTime)
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
private syncSkyLevelFromTime (timeOfDay: number): void {
|
|
700
|
+
const skyLevel = calculateSkyLightSimple(timeOfDay) / 15
|
|
701
|
+
this.chunkMeshManager.setSkyLevel(skyLevel)
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
protected onDayCycleSkyLightChanged(_skyLight: number): void {
|
|
705
|
+
// Sky cap is driven by u_skyLevel uniform; no remesh on day/night.
|
|
678
706
|
}
|
|
679
707
|
|
|
680
708
|
biomeUpdated(biome: Biome): void {
|
|
@@ -787,6 +815,7 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
787
815
|
// "Batch Chunks Display" (`_renderByChunks`) option. No-op when the
|
|
788
816
|
// option is off — `waitingChunksToDisplay` is empty in that case.
|
|
789
817
|
this.chunkMeshManager.finishChunkDisplay(chunkKey)
|
|
818
|
+
this.getModule<{ onChunkFinished?: () => void }>('futuristicReveal')?.onChunkFinished?.()
|
|
790
819
|
}
|
|
791
820
|
|
|
792
821
|
private applyPendingSectionUpdates() {
|
|
@@ -847,8 +876,12 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
847
876
|
continue
|
|
848
877
|
}
|
|
849
878
|
|
|
850
|
-
this.chunkMeshManager.updateSection(update.key, update.geometry)
|
|
879
|
+
const sectionObject = this.chunkMeshManager.updateSection(update.key, update.geometry)
|
|
851
880
|
this.updatePosDataChunk(update.key)
|
|
881
|
+
if (sectionObject) {
|
|
882
|
+
this.getModule<{ onSectionMeshed?: (key: string, geometry: MesherGeometryOutput, section: typeof sectionObject) => void }>('futuristicReveal')
|
|
883
|
+
?.onSectionMeshed?.(update.key, update.geometry, sectionObject)
|
|
884
|
+
}
|
|
852
885
|
}
|
|
853
886
|
}
|
|
854
887
|
|
|
@@ -885,8 +918,12 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
885
918
|
this.chunkMeshManager.releaseSection(data.key)
|
|
886
919
|
return
|
|
887
920
|
}
|
|
888
|
-
this.chunkMeshManager.updateSection(data.key, data.geometry)
|
|
921
|
+
const sectionObject = this.chunkMeshManager.updateSection(data.key, data.geometry)
|
|
889
922
|
this.updatePosDataChunk(data.key)
|
|
923
|
+
if (sectionObject) {
|
|
924
|
+
this.getModule<{ onSectionMeshed?: (key: string, geometry: MesherGeometryOutput, section: typeof sectionObject) => void }>('futuristicReveal')
|
|
925
|
+
?.onSectionMeshed?.(data.key, data.geometry, sectionObject)
|
|
926
|
+
}
|
|
890
927
|
}
|
|
891
928
|
}
|
|
892
929
|
|
|
@@ -975,17 +1012,9 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
975
1012
|
this.debugRaycast(pos, direction, distance)
|
|
976
1013
|
}
|
|
977
1014
|
|
|
978
|
-
// Convert world position to scene-relative coordinates for raycasting
|
|
979
|
-
const scenePos = this._tpScenePos.set(
|
|
980
|
-
this.sceneOrigin.toSceneX(pos.x),
|
|
981
|
-
this.sceneOrigin.toSceneY(pos.y),
|
|
982
|
-
this.sceneOrigin.toSceneZ(pos.z)
|
|
983
|
-
)
|
|
984
|
-
|
|
985
|
-
// Perform raycast to avoid camera going through blocks
|
|
986
1015
|
const raycaster = this._tpRaycaster
|
|
987
|
-
raycaster.set(
|
|
988
|
-
raycaster.far = distance
|
|
1016
|
+
raycaster.set(pos, direction)
|
|
1017
|
+
raycaster.far = distance
|
|
989
1018
|
|
|
990
1019
|
const maxCenterDistance = 80
|
|
991
1020
|
const maxCenterDistSq = maxCenterDistance * maxCenterDistance
|
|
@@ -993,8 +1022,8 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
993
1022
|
const oy = pos.y
|
|
994
1023
|
const oz = pos.z
|
|
995
1024
|
|
|
996
|
-
// Legacy
|
|
997
|
-
const
|
|
1025
|
+
// Legacy section meshes: world-space raycast (static mesh.matrix translation).
|
|
1026
|
+
const legacyMeshes: THREE.Object3D[] = []
|
|
998
1027
|
for (const obj of Object.values(this.sectionObjects)) {
|
|
999
1028
|
if (obj.name !== 'chunk' || !obj.visible) continue
|
|
1000
1029
|
if (obj.worldX === undefined) continue
|
|
@@ -1002,11 +1031,11 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1002
1031
|
const dcy = obj.worldY! - oy
|
|
1003
1032
|
const dcz = obj.worldZ! - oz
|
|
1004
1033
|
if (dcx * dcx + dcy * dcy + dcz * dcz > maxCenterDistSq) continue
|
|
1005
|
-
const mesh = obj.children.find(child => child.name === 'mesh'
|
|
1006
|
-
if (mesh)
|
|
1034
|
+
const mesh = obj.children.find(child => child.name === 'mesh')
|
|
1035
|
+
if (mesh) legacyMeshes.push(mesh)
|
|
1007
1036
|
}
|
|
1008
1037
|
|
|
1009
|
-
const intersects = raycaster.intersectObjects(
|
|
1038
|
+
const intersects = raycaster.intersectObjects(legacyMeshes, false)
|
|
1010
1039
|
|
|
1011
1040
|
let finalDistance = distance
|
|
1012
1041
|
if (intersects.length > 0) {
|
|
@@ -1024,6 +1053,15 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1024
1053
|
finalDistance = Math.max(0.5, boxHit - 0.2)
|
|
1025
1054
|
}
|
|
1026
1055
|
|
|
1056
|
+
const legacyGlobalHit = this.chunkMeshManager.raycastGlobalLegacySections(
|
|
1057
|
+
raycaster,
|
|
1058
|
+
pos,
|
|
1059
|
+
maxCenterDistance,
|
|
1060
|
+
)
|
|
1061
|
+
if (legacyGlobalHit !== undefined) {
|
|
1062
|
+
finalDistance = Math.max(0.5, legacyGlobalHit - 0.2)
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1027
1065
|
const finalPos = new Vec3(
|
|
1028
1066
|
pos.x + direction.x * finalDistance,
|
|
1029
1067
|
pos.y + direction.y * finalDistance,
|
|
@@ -1280,12 +1318,45 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1280
1318
|
|
|
1281
1319
|
// eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style
|
|
1282
1320
|
const cam = this.cameraGroupVr instanceof THREE.Group ? this.cameraGroupVr.children.find(child => child instanceof THREE.PerspectiveCamera) as THREE.PerspectiveCamera : this.camera
|
|
1321
|
+
// Flush buffered section geometry before reveal tick (calls onSectionMeshed synchronously in handleWorkerMessage).
|
|
1283
1322
|
this.applyPendingSectionUpdates()
|
|
1323
|
+
const sciFiNow = performance.now()
|
|
1324
|
+
const sciFiDeltaMs = sciFiNow - this.lastSciFiTickMs
|
|
1325
|
+
this.lastSciFiTickMs = sciFiNow
|
|
1326
|
+
this.getModule<{ tick?: (deltaMs: number, now?: number) => void }>('futuristicReveal')?.tick?.(sciFiDeltaMs, sciFiNow)
|
|
1327
|
+
const camX = this.cameraWorldPos.x
|
|
1328
|
+
const camY = this.cameraWorldPos.y
|
|
1329
|
+
const camZ = this.cameraWorldPos.z
|
|
1330
|
+
this.chunkMeshManager.maybeRebase({ x: camX, y: camY, z: camZ })
|
|
1331
|
+
const renderOrigin = this.chunkMeshManager.getRenderOrigin()
|
|
1284
1332
|
const globalBuffer = this.chunkMeshManager.globalBlockBuffer
|
|
1285
1333
|
if (globalBuffer) {
|
|
1286
|
-
globalBuffer.setCameraOrigin(
|
|
1334
|
+
globalBuffer.setCameraOrigin(renderOrigin, camX, camY, camZ)
|
|
1335
|
+
globalBuffer.setDebugOverlay(this.displayOptions.inWorldRenderingConfig.enableDebugOverlay)
|
|
1287
1336
|
globalBuffer.compactStep()
|
|
1288
|
-
globalBuffer.
|
|
1337
|
+
if (globalBuffer.hasPendingUploads()) {
|
|
1338
|
+
globalBuffer.uploadDirtyRange()
|
|
1339
|
+
}
|
|
1340
|
+
globalBuffer.suppressThreeDraw()
|
|
1341
|
+
}
|
|
1342
|
+
const globalLegacyBuffer = this.chunkMeshManager.globalLegacyBuffer
|
|
1343
|
+
if (globalLegacyBuffer?.hasPendingUploads()) {
|
|
1344
|
+
globalLegacyBuffer.uploadDirtyRange()
|
|
1345
|
+
}
|
|
1346
|
+
const globalLegacyBlendBuffer = this.chunkMeshManager.globalLegacyBlendBuffer
|
|
1347
|
+
if (globalLegacyBlendBuffer?.hasPendingUploads()) {
|
|
1348
|
+
globalLegacyBlendBuffer.uploadDirtyRange()
|
|
1349
|
+
}
|
|
1350
|
+
this.chunkMeshManager.setLegacyCameraOrigin(camX, camY, camZ)
|
|
1351
|
+
this.chunkMeshManager.updateCullDirtyFromCamera(cam, camX, camY, camZ)
|
|
1352
|
+
if (this.chunkMeshManager.cullDirty) {
|
|
1353
|
+
this.chunkMeshManager.updateSectionCullAndSort(
|
|
1354
|
+
cam,
|
|
1355
|
+
this.cameraWorldPos.x,
|
|
1356
|
+
this.cameraWorldPos.y,
|
|
1357
|
+
this.cameraWorldPos.z,
|
|
1358
|
+
)
|
|
1359
|
+
this.chunkMeshManager.clearCullDirty()
|
|
1289
1360
|
}
|
|
1290
1361
|
this.renderer.render(this.scene, cam)
|
|
1291
1362
|
|
|
@@ -1524,8 +1595,6 @@ export class WorldRendererThree extends WorldRendererCommon {
|
|
|
1524
1595
|
}
|
|
1525
1596
|
|
|
1526
1597
|
setSectionDirty(...args: Parameters<WorldRendererCommon['setSectionDirty']>) {
|
|
1527
|
-
const [pos] = args
|
|
1528
|
-
this.cleanChunkTextures(pos.x, pos.z) // todo don't do this!
|
|
1529
1598
|
super.setSectionDirty(...args)
|
|
1530
1599
|
}
|
|
1531
1600
|
|