minecraft-renderer 0.1.0
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 +297 -0
- package/dist/index.html +83 -0
- package/dist/static/image/arrow.6f27b59f.png +0 -0
- package/dist/static/image/blocksAtlasLatest.7850afa3.png +0 -0
- package/dist/static/image/blocksAtlasLegacy.5c76823d.png +0 -0
- package/dist/static/image/itemsAtlasLatest.36036f95.png +0 -0
- package/dist/static/image/itemsAtlasLegacy.dcb1b58d.png +0 -0
- package/dist/static/image/tipped_arrow.6f27b59f.png +0 -0
- package/dist/static/js/365.f05233ab.js +8462 -0
- package/dist/static/js/365.f05233ab.js.LICENSE.txt +52 -0
- package/dist/static/js/async/738.efa27644.js +1 -0
- package/dist/static/js/index.092ec5be.js +56 -0
- package/dist/static/js/lib-polyfill.98986ac5.js +1 -0
- package/dist/static/js/lib-react.5c9129e0.js +2 -0
- package/dist/static/js/lib-react.5c9129e0.js.LICENSE.txt +39 -0
- package/package.json +104 -0
- package/src/assets/destroy_stage_0.png +0 -0
- package/src/assets/destroy_stage_1.png +0 -0
- package/src/assets/destroy_stage_2.png +0 -0
- package/src/assets/destroy_stage_3.png +0 -0
- package/src/assets/destroy_stage_4.png +0 -0
- package/src/assets/destroy_stage_5.png +0 -0
- package/src/assets/destroy_stage_6.png +0 -0
- package/src/assets/destroy_stage_7.png +0 -0
- package/src/assets/destroy_stage_8.png +0 -0
- package/src/assets/destroy_stage_9.png +0 -0
- package/src/examples/README.md +146 -0
- package/src/examples/appViewerExample.ts +205 -0
- package/src/examples/initialMenuStart.ts +161 -0
- package/src/graphicsBackend/appViewer.ts +297 -0
- package/src/graphicsBackend/config.ts +119 -0
- package/src/graphicsBackend/index.ts +10 -0
- package/src/graphicsBackend/playerState.ts +61 -0
- package/src/graphicsBackend/types.ts +143 -0
- package/src/index.ts +97 -0
- package/src/lib/DebugGui.ts +190 -0
- package/src/lib/animationController.ts +85 -0
- package/src/lib/buildSharedConfig.mjs +1 -0
- package/src/lib/cameraBobbing.ts +94 -0
- package/src/lib/canvas2DOverlay.example.ts +361 -0
- package/src/lib/canvas2DOverlay.quickstart.ts +242 -0
- package/src/lib/canvas2DOverlay.ts +381 -0
- package/src/lib/cleanupDecorator.ts +29 -0
- package/src/lib/createPlayerObject.ts +55 -0
- package/src/lib/frameTimingCollector.ts +164 -0
- package/src/lib/guiRenderer.ts +283 -0
- package/src/lib/items.ts +140 -0
- package/src/lib/mesherlogReader.ts +131 -0
- package/src/lib/moreBlockDataGenerated.json +714 -0
- package/src/lib/preflatMap.json +1741 -0
- package/src/lib/simpleUtils.ts +40 -0
- package/src/lib/smoothSwitcher.ts +168 -0
- package/src/lib/spiral.ts +29 -0
- package/src/lib/ui/newStats.ts +120 -0
- package/src/lib/utils/proxy.ts +23 -0
- package/src/lib/utils/skins.ts +63 -0
- package/src/lib/utils.ts +76 -0
- package/src/lib/workerProxy.ts +342 -0
- package/src/lib/worldrendererCommon.ts +1088 -0
- package/src/mesher/mesher.ts +253 -0
- package/src/mesher/models.ts +769 -0
- package/src/mesher/modelsGeometryCommon.ts +142 -0
- package/src/mesher/shared.ts +80 -0
- package/src/mesher/standaloneRenderer.ts +270 -0
- package/src/mesher/test/a.ts +3 -0
- package/src/mesher/test/mesherTester.ts +76 -0
- package/src/mesher/test/playground.ts +19 -0
- package/src/mesher/test/test-perf.ts +74 -0
- package/src/mesher/test/tests.test.ts +56 -0
- package/src/mesher/world.ts +294 -0
- package/src/mesher/worldConstants.ts +1 -0
- package/src/modules/index.ts +11 -0
- package/src/modules/starfield.ts +313 -0
- package/src/modules/types.ts +110 -0
- package/src/playerState/playerState.ts +78 -0
- package/src/playerState/types.ts +36 -0
- package/src/playground/allEntitiesDebug.ts +170 -0
- package/src/playground/baseScene.ts +587 -0
- package/src/playground/mobileControls.tsx +268 -0
- package/src/playground/playground.html +83 -0
- package/src/playground/playground.ts +11 -0
- package/src/playground/playgroundUi.tsx +140 -0
- package/src/playground/reactUtils.ts +71 -0
- package/src/playground/scenes/allEntities.ts +13 -0
- package/src/playground/scenes/entities.ts +37 -0
- package/src/playground/scenes/floorRandom.ts +33 -0
- package/src/playground/scenes/frequentUpdates.ts +148 -0
- package/src/playground/scenes/geometryExport.ts +142 -0
- package/src/playground/scenes/index.ts +12 -0
- package/src/playground/scenes/lightingStarfield.ts +40 -0
- package/src/playground/scenes/main.ts +313 -0
- package/src/playground/scenes/railsCobweb.ts +14 -0
- package/src/playground/scenes/rotationIssue.ts +7 -0
- package/src/playground/scenes/slabsOptimization.ts +16 -0
- package/src/playground/scenes/transparencyIssue.ts +11 -0
- package/src/playground/shared.ts +79 -0
- package/src/resourcesManager/index.ts +5 -0
- package/src/resourcesManager/resourcesManager.ts +314 -0
- package/src/shims/minecraftData.ts +41 -0
- package/src/sign-renderer/index.html +21 -0
- package/src/sign-renderer/index.ts +216 -0
- package/src/sign-renderer/noop.js +1 -0
- package/src/sign-renderer/playground.ts +38 -0
- package/src/sign-renderer/tests.test.ts +69 -0
- package/src/sign-renderer/vite.config.ts +10 -0
- package/src/three/appShared.ts +75 -0
- package/src/three/bannerRenderer.ts +275 -0
- package/src/three/cameraShake.ts +120 -0
- package/src/three/cinimaticScript.ts +350 -0
- package/src/three/documentRenderer.ts +491 -0
- package/src/three/entities.ts +1580 -0
- package/src/three/entity/EntityMesh.ts +707 -0
- package/src/three/entity/animations.js +171 -0
- package/src/three/entity/armorModels.json +204 -0
- package/src/three/entity/armorModels.ts +36 -0
- package/src/three/entity/entities.json +6230 -0
- package/src/three/entity/exportedModels.js +38 -0
- package/src/three/entity/externalTextures.json +1 -0
- package/src/three/entity/models/allay.obj +325 -0
- package/src/three/entity/models/arrow.obj +60 -0
- package/src/three/entity/models/axolotl.obj +509 -0
- package/src/three/entity/models/blaze.obj +601 -0
- package/src/three/entity/models/boat.obj +417 -0
- package/src/three/entity/models/camel.obj +1061 -0
- package/src/three/entity/models/cat.obj +509 -0
- package/src/three/entity/models/chicken.obj +371 -0
- package/src/three/entity/models/cod.obj +371 -0
- package/src/three/entity/models/creeper.obj +279 -0
- package/src/three/entity/models/dolphin.obj +371 -0
- package/src/three/entity/models/ender_dragon.obj +2993 -0
- package/src/three/entity/models/enderman.obj +325 -0
- package/src/three/entity/models/endermite.obj +187 -0
- package/src/three/entity/models/fox.obj +463 -0
- package/src/three/entity/models/frog.obj +739 -0
- package/src/three/entity/models/ghast.obj +463 -0
- package/src/three/entity/models/goat.obj +601 -0
- package/src/three/entity/models/guardian.obj +1015 -0
- package/src/three/entity/models/horse.obj +1061 -0
- package/src/three/entity/models/llama.obj +509 -0
- package/src/three/entity/models/minecart.obj +233 -0
- package/src/three/entity/models/parrot.obj +509 -0
- package/src/three/entity/models/piglin.obj +739 -0
- package/src/three/entity/models/pillager.obj +371 -0
- package/src/three/entity/models/rabbit.obj +555 -0
- package/src/three/entity/models/sheep.obj +555 -0
- package/src/three/entity/models/shulker.obj +141 -0
- package/src/three/entity/models/sniffer.obj +693 -0
- package/src/three/entity/models/spider.obj +509 -0
- package/src/three/entity/models/tadpole.obj +95 -0
- package/src/three/entity/models/turtle.obj +371 -0
- package/src/three/entity/models/vex.obj +325 -0
- package/src/three/entity/models/villager.obj +509 -0
- package/src/three/entity/models/warden.obj +463 -0
- package/src/three/entity/models/witch.obj +647 -0
- package/src/three/entity/models/wolf.obj +509 -0
- package/src/three/entity/models/zombie_villager.obj +463 -0
- package/src/three/entity/objModels.js +1 -0
- package/src/three/fireworks.ts +661 -0
- package/src/three/fireworksRenderer.ts +434 -0
- package/src/three/globals.d.ts +7 -0
- package/src/three/graphicsBackend.ts +274 -0
- package/src/three/graphicsBackendOffThread.ts +107 -0
- package/src/three/hand.ts +89 -0
- package/src/three/holdingBlock.ts +926 -0
- package/src/three/index.ts +20 -0
- package/src/three/itemMesh.ts +427 -0
- package/src/three/modules.d.ts +14 -0
- package/src/three/panorama.ts +308 -0
- package/src/three/panoramaShared.ts +1 -0
- package/src/three/renderSlot.ts +82 -0
- package/src/three/skyboxRenderer.ts +406 -0
- package/src/three/starField.ts +13 -0
- package/src/three/threeJsMedia.ts +731 -0
- package/src/three/threeJsMethods.ts +15 -0
- package/src/three/threeJsParticles.ts +160 -0
- package/src/three/threeJsSound.ts +95 -0
- package/src/three/threeJsUtils.ts +90 -0
- package/src/three/waypointSprite.ts +435 -0
- package/src/three/waypoints.ts +163 -0
- package/src/three/world/cursorBlock.ts +172 -0
- package/src/three/world/vr.ts +257 -0
- package/src/three/worldGeometryExport.ts +259 -0
- package/src/three/worldGeometryHandler.ts +279 -0
- package/src/three/worldRendererThree.ts +1381 -0
- package/src/worldView/index.ts +6 -0
- package/src/worldView/types.ts +66 -0
- package/src/worldView/worldView.ts +424 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Three.js Graphics Backend
|
|
3
|
+
*
|
|
4
|
+
* This module provides the Three.js WebGL implementation for the Minecraft renderer.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// Main backend
|
|
8
|
+
export { default as createGraphicsBackend, createGraphicsBackendBase } from './graphicsBackend'
|
|
9
|
+
|
|
10
|
+
// Core components
|
|
11
|
+
export { DocumentRenderer, addCanvasForWorker, isWebWorker } from './documentRenderer'
|
|
12
|
+
export type { ThreeRendererMainData } from './documentRenderer'
|
|
13
|
+
|
|
14
|
+
// World geometry
|
|
15
|
+
export { WorldGeometryHandler, estimateGeometryMemoryUsage, disposeObject } from './worldGeometryHandler'
|
|
16
|
+
export type { WorldGeometryHandlerOptions, SectionObject } from './worldGeometryHandler'
|
|
17
|
+
|
|
18
|
+
// Visual effects
|
|
19
|
+
export { StarField } from './starField'
|
|
20
|
+
export type { StarFieldOptions } from './starField'
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import * as THREE from 'three'
|
|
2
|
+
|
|
3
|
+
export interface Create3DItemMeshOptions {
|
|
4
|
+
depth: number
|
|
5
|
+
pixelSize?: number
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface Create3DItemMeshResult {
|
|
9
|
+
geometry: THREE.BufferGeometry
|
|
10
|
+
totalVertices: number
|
|
11
|
+
totalTriangles: number
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Creates a 3D item geometry with front/back faces and connecting edges
|
|
16
|
+
* from a canvas containing the item texture
|
|
17
|
+
*/
|
|
18
|
+
export function create3DItemMesh (
|
|
19
|
+
canvas: HTMLCanvasElement,
|
|
20
|
+
options: Create3DItemMeshOptions
|
|
21
|
+
): Create3DItemMeshResult {
|
|
22
|
+
const { depth, pixelSize } = options
|
|
23
|
+
|
|
24
|
+
// Validate canvas dimensions
|
|
25
|
+
if (canvas.width <= 0 || canvas.height <= 0) {
|
|
26
|
+
throw new Error(`Invalid canvas dimensions: ${canvas.width}x${canvas.height}`)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const ctx = canvas.getContext('2d')!
|
|
30
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height)
|
|
31
|
+
const { data } = imageData
|
|
32
|
+
|
|
33
|
+
const w = canvas.width
|
|
34
|
+
const h = canvas.height
|
|
35
|
+
const halfDepth = depth / 2
|
|
36
|
+
const actualPixelSize = pixelSize ?? (1 / Math.max(w, h))
|
|
37
|
+
|
|
38
|
+
// Find opaque pixels
|
|
39
|
+
const isOpaque = (x: number, y: number) => {
|
|
40
|
+
if (x < 0 || y < 0 || x >= w || y >= h) return false
|
|
41
|
+
const i = (y * w + x) * 4
|
|
42
|
+
return data[i + 3] > 128 // alpha > 128
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const vertices: number[] = []
|
|
46
|
+
const indices: number[] = []
|
|
47
|
+
const uvs: number[] = []
|
|
48
|
+
const normals: number[] = []
|
|
49
|
+
|
|
50
|
+
let vertexIndex = 0
|
|
51
|
+
|
|
52
|
+
// Helper to add a vertex
|
|
53
|
+
const addVertex = (x: number, y: number, z: number, u: number, v: number, nx: number, ny: number, nz: number) => {
|
|
54
|
+
vertices.push(x, y, z)
|
|
55
|
+
uvs.push(u, v)
|
|
56
|
+
normals.push(nx, ny, nz)
|
|
57
|
+
return vertexIndex++
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Helper to add a quad (two triangles)
|
|
61
|
+
const addQuad = (v0: number, v1: number, v2: number, v3: number) => {
|
|
62
|
+
indices.push(v0, v1, v2, v0, v2, v3)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Convert pixel coordinates to world coordinates
|
|
66
|
+
const pixelToWorld = (px: number, py: number) => {
|
|
67
|
+
const x = (px / w - 0.5) * actualPixelSize * w
|
|
68
|
+
const y = -(py / h - 0.5) * actualPixelSize * h
|
|
69
|
+
return { x, y }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Create a grid of vertices for front and back faces
|
|
73
|
+
const frontVertices: Array<Array<number | null>> = Array.from({ length: h + 1 }, () => Array.from({ length: w + 1 }, () => null))
|
|
74
|
+
const backVertices: Array<Array<number | null>> = Array.from({ length: h + 1 }, () => Array.from({ length: w + 1 }, () => null))
|
|
75
|
+
|
|
76
|
+
// Create vertices at pixel corners
|
|
77
|
+
for (let py = 0; py <= h; py++) {
|
|
78
|
+
for (let px = 0; px <= w; px++) {
|
|
79
|
+
const { x, y } = pixelToWorld(px - 0.5, py - 0.5)
|
|
80
|
+
|
|
81
|
+
// UV coordinates should map to the texture space of the extracted tile
|
|
82
|
+
const u = px / w
|
|
83
|
+
const v = py / h
|
|
84
|
+
|
|
85
|
+
// Check if this vertex is needed for any face or edge
|
|
86
|
+
let needVertex = false
|
|
87
|
+
|
|
88
|
+
// Check all 4 adjacent pixels to see if any are opaque
|
|
89
|
+
const adjacentPixels = [
|
|
90
|
+
[px - 1, py - 1], // top-left pixel
|
|
91
|
+
[px, py - 1], // top-right pixel
|
|
92
|
+
[px - 1, py], // bottom-left pixel
|
|
93
|
+
[px, py] // bottom-right pixel
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
for (const [adjX, adjY] of adjacentPixels) {
|
|
97
|
+
if (isOpaque(adjX, adjY)) {
|
|
98
|
+
needVertex = true
|
|
99
|
+
break
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (needVertex) {
|
|
104
|
+
frontVertices[py][px] = addVertex(x, y, halfDepth, u, v, 0, 0, 1)
|
|
105
|
+
backVertices[py][px] = addVertex(x, y, -halfDepth, u, v, 0, 0, -1)
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Create front and back faces
|
|
111
|
+
for (let py = 0; py < h; py++) {
|
|
112
|
+
for (let px = 0; px < w; px++) {
|
|
113
|
+
if (!isOpaque(px, py)) continue
|
|
114
|
+
|
|
115
|
+
const v00 = frontVertices[py][px]
|
|
116
|
+
const v10 = frontVertices[py][px + 1]
|
|
117
|
+
const v11 = frontVertices[py + 1][px + 1]
|
|
118
|
+
const v01 = frontVertices[py + 1][px]
|
|
119
|
+
|
|
120
|
+
const b00 = backVertices[py][px]
|
|
121
|
+
const b10 = backVertices[py][px + 1]
|
|
122
|
+
const b11 = backVertices[py + 1][px + 1]
|
|
123
|
+
const b01 = backVertices[py + 1][px]
|
|
124
|
+
|
|
125
|
+
if (v00 !== null && v10 !== null && v11 !== null && v01 !== null) {
|
|
126
|
+
// Front face
|
|
127
|
+
addQuad(v00, v10, v11, v01)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (b00 !== null && b10 !== null && b11 !== null && b01 !== null) {
|
|
131
|
+
// Back face (reversed winding)
|
|
132
|
+
addQuad(b10, b00, b01, b11)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Create edge faces for each side of the pixel with proper UVs
|
|
138
|
+
for (let py = 0; py < h; py++) {
|
|
139
|
+
for (let px = 0; px < w; px++) {
|
|
140
|
+
if (!isOpaque(px, py)) continue
|
|
141
|
+
|
|
142
|
+
const pixelU = (px + 0.5) / w // Center of current pixel
|
|
143
|
+
const pixelV = (py + 0.5) / h
|
|
144
|
+
|
|
145
|
+
// Left edge (x = px)
|
|
146
|
+
if (!isOpaque(px - 1, py)) {
|
|
147
|
+
const f0 = frontVertices[py][px]
|
|
148
|
+
const f1 = frontVertices[py + 1][px]
|
|
149
|
+
const b0 = backVertices[py][px]
|
|
150
|
+
const b1 = backVertices[py + 1][px]
|
|
151
|
+
|
|
152
|
+
if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) {
|
|
153
|
+
// Create new vertices for edge with current pixel's UV
|
|
154
|
+
const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, -1, 0, 0)
|
|
155
|
+
const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, -1, 0, 0)
|
|
156
|
+
const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, -1, 0, 0)
|
|
157
|
+
const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, -1, 0, 0)
|
|
158
|
+
addQuad(ef0, ef1, eb1, eb0)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Right edge (x = px + 1)
|
|
163
|
+
if (!isOpaque(px + 1, py)) {
|
|
164
|
+
const f0 = frontVertices[py + 1][px + 1]
|
|
165
|
+
const f1 = frontVertices[py][px + 1]
|
|
166
|
+
const b0 = backVertices[py + 1][px + 1]
|
|
167
|
+
const b1 = backVertices[py][px + 1]
|
|
168
|
+
|
|
169
|
+
if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) {
|
|
170
|
+
const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, 1, 0, 0)
|
|
171
|
+
const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, 1, 0, 0)
|
|
172
|
+
const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, 1, 0, 0)
|
|
173
|
+
const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, 1, 0, 0)
|
|
174
|
+
addQuad(ef0, ef1, eb1, eb0)
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Top edge (y = py)
|
|
179
|
+
if (!isOpaque(px, py - 1)) {
|
|
180
|
+
const f0 = frontVertices[py][px]
|
|
181
|
+
const f1 = frontVertices[py][px + 1]
|
|
182
|
+
const b0 = backVertices[py][px]
|
|
183
|
+
const b1 = backVertices[py][px + 1]
|
|
184
|
+
|
|
185
|
+
if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) {
|
|
186
|
+
const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, 0, -1, 0)
|
|
187
|
+
const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, 0, -1, 0)
|
|
188
|
+
const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, 0, -1, 0)
|
|
189
|
+
const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, 0, -1, 0)
|
|
190
|
+
addQuad(ef0, ef1, eb1, eb0)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Bottom edge (y = py + 1)
|
|
195
|
+
if (!isOpaque(px, py + 1)) {
|
|
196
|
+
const f0 = frontVertices[py + 1][px + 1]
|
|
197
|
+
const f1 = frontVertices[py + 1][px]
|
|
198
|
+
const b0 = backVertices[py + 1][px + 1]
|
|
199
|
+
const b1 = backVertices[py + 1][px]
|
|
200
|
+
|
|
201
|
+
if (f0 !== null && f1 !== null && b0 !== null && b1 !== null) {
|
|
202
|
+
const ef0 = addVertex(vertices[f0 * 3], vertices[f0 * 3 + 1], vertices[f0 * 3 + 2], pixelU, pixelV, 0, 1, 0)
|
|
203
|
+
const ef1 = addVertex(vertices[f1 * 3], vertices[f1 * 3 + 1], vertices[f1 * 3 + 2], pixelU, pixelV, 0, 1, 0)
|
|
204
|
+
const eb1 = addVertex(vertices[b1 * 3], vertices[b1 * 3 + 1], vertices[b1 * 3 + 2], pixelU, pixelV, 0, 1, 0)
|
|
205
|
+
const eb0 = addVertex(vertices[b0 * 3], vertices[b0 * 3 + 1], vertices[b0 * 3 + 2], pixelU, pixelV, 0, 1, 0)
|
|
206
|
+
addQuad(ef0, ef1, eb1, eb0)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const geometry = new THREE.BufferGeometry()
|
|
213
|
+
geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3))
|
|
214
|
+
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2))
|
|
215
|
+
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3))
|
|
216
|
+
geometry.setIndex(indices)
|
|
217
|
+
|
|
218
|
+
// Compute normals properly
|
|
219
|
+
geometry.computeVertexNormals()
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
geometry,
|
|
223
|
+
totalVertices: vertexIndex,
|
|
224
|
+
totalTriangles: indices.length / 3
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export interface ItemTextureInfo {
|
|
229
|
+
u: number
|
|
230
|
+
v: number
|
|
231
|
+
sizeX: number
|
|
232
|
+
sizeY: number
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export interface ItemMeshResult {
|
|
236
|
+
mesh: THREE.Object3D
|
|
237
|
+
itemsTexture?: THREE.Texture
|
|
238
|
+
itemsTextureFlipped?: THREE.Texture
|
|
239
|
+
cleanup?: () => void
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Extracts item texture region to a canvas
|
|
244
|
+
*/
|
|
245
|
+
export function extractItemTextureToCanvas (
|
|
246
|
+
sourceTexture: THREE.Texture,
|
|
247
|
+
textureInfo: ItemTextureInfo
|
|
248
|
+
): HTMLCanvasElement {
|
|
249
|
+
const { u, v, sizeX, sizeY } = textureInfo
|
|
250
|
+
|
|
251
|
+
// Calculate canvas size - fix the calculation
|
|
252
|
+
const canvasWidth = Math.max(1, Math.floor(sizeX * sourceTexture.image.width))
|
|
253
|
+
const canvasHeight = Math.max(1, Math.floor(sizeY * sourceTexture.image.height))
|
|
254
|
+
|
|
255
|
+
const canvas = document.createElement('canvas')
|
|
256
|
+
canvas.width = canvasWidth
|
|
257
|
+
canvas.height = canvasHeight
|
|
258
|
+
|
|
259
|
+
const ctx = canvas.getContext('2d')!
|
|
260
|
+
ctx.imageSmoothingEnabled = false
|
|
261
|
+
|
|
262
|
+
// Draw the item texture region to canvas
|
|
263
|
+
ctx.drawImage(
|
|
264
|
+
sourceTexture.image,
|
|
265
|
+
u * sourceTexture.image.width,
|
|
266
|
+
v * sourceTexture.image.height,
|
|
267
|
+
sizeX * sourceTexture.image.width,
|
|
268
|
+
sizeY * sourceTexture.image.height,
|
|
269
|
+
0,
|
|
270
|
+
0,
|
|
271
|
+
canvas.width,
|
|
272
|
+
canvas.height
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
return canvas
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Creates either a 2D or 3D item mesh based on parameters
|
|
280
|
+
*/
|
|
281
|
+
export function createItemMesh (
|
|
282
|
+
sourceTexture: THREE.Texture,
|
|
283
|
+
textureInfo: ItemTextureInfo,
|
|
284
|
+
options: {
|
|
285
|
+
faceCamera?: boolean
|
|
286
|
+
use3D?: boolean
|
|
287
|
+
depth?: number
|
|
288
|
+
} = {}
|
|
289
|
+
): ItemMeshResult {
|
|
290
|
+
const { faceCamera = false, use3D = true, depth = 0.04 } = options
|
|
291
|
+
const { u, v, sizeX, sizeY } = textureInfo
|
|
292
|
+
|
|
293
|
+
if (faceCamera) {
|
|
294
|
+
// Create sprite for camera-facing items
|
|
295
|
+
const itemsTexture = sourceTexture.clone()
|
|
296
|
+
itemsTexture.flipY = true
|
|
297
|
+
itemsTexture.offset.set(u, 1 - v - sizeY)
|
|
298
|
+
itemsTexture.repeat.set(sizeX, sizeY)
|
|
299
|
+
itemsTexture.needsUpdate = true
|
|
300
|
+
itemsTexture.magFilter = THREE.NearestFilter
|
|
301
|
+
itemsTexture.minFilter = THREE.NearestFilter
|
|
302
|
+
|
|
303
|
+
const spriteMat = new THREE.SpriteMaterial({
|
|
304
|
+
map: itemsTexture,
|
|
305
|
+
transparent: true,
|
|
306
|
+
alphaTest: 0.1,
|
|
307
|
+
})
|
|
308
|
+
const mesh = new THREE.Sprite(spriteMat)
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
mesh,
|
|
312
|
+
itemsTexture,
|
|
313
|
+
cleanup () {
|
|
314
|
+
itemsTexture.dispose()
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (use3D) {
|
|
320
|
+
// Try to create 3D mesh
|
|
321
|
+
try {
|
|
322
|
+
const canvas = extractItemTextureToCanvas(sourceTexture, textureInfo)
|
|
323
|
+
const { geometry } = create3DItemMesh(canvas, { depth })
|
|
324
|
+
|
|
325
|
+
// Create texture from canvas for the 3D mesh
|
|
326
|
+
const itemsTexture = new THREE.CanvasTexture(canvas)
|
|
327
|
+
itemsTexture.magFilter = THREE.NearestFilter
|
|
328
|
+
itemsTexture.minFilter = THREE.NearestFilter
|
|
329
|
+
itemsTexture.wrapS = itemsTexture.wrapT = THREE.ClampToEdgeWrapping
|
|
330
|
+
itemsTexture.flipY = false
|
|
331
|
+
itemsTexture.needsUpdate = true
|
|
332
|
+
|
|
333
|
+
const material = new THREE.MeshStandardMaterial({
|
|
334
|
+
map: itemsTexture,
|
|
335
|
+
side: THREE.DoubleSide,
|
|
336
|
+
transparent: true,
|
|
337
|
+
alphaTest: 0.1,
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
const mesh = new THREE.Mesh(geometry, material)
|
|
341
|
+
|
|
342
|
+
return {
|
|
343
|
+
mesh,
|
|
344
|
+
itemsTexture,
|
|
345
|
+
cleanup () {
|
|
346
|
+
itemsTexture.dispose()
|
|
347
|
+
geometry.dispose()
|
|
348
|
+
if (material.map) material.map.dispose()
|
|
349
|
+
material.dispose()
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
} catch (error) {
|
|
353
|
+
console.warn('Failed to create 3D item mesh, falling back to 2D:', error)
|
|
354
|
+
// Fall through to 2D rendering
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Fallback to 2D flat rendering
|
|
359
|
+
const itemsTexture = sourceTexture.clone()
|
|
360
|
+
itemsTexture.flipY = true
|
|
361
|
+
itemsTexture.offset.set(u, 1 - v - sizeY)
|
|
362
|
+
itemsTexture.repeat.set(sizeX, sizeY)
|
|
363
|
+
itemsTexture.needsUpdate = true
|
|
364
|
+
itemsTexture.magFilter = THREE.NearestFilter
|
|
365
|
+
itemsTexture.minFilter = THREE.NearestFilter
|
|
366
|
+
|
|
367
|
+
const itemsTextureFlipped = itemsTexture.clone()
|
|
368
|
+
itemsTextureFlipped.repeat.x *= -1
|
|
369
|
+
itemsTextureFlipped.needsUpdate = true
|
|
370
|
+
itemsTextureFlipped.offset.set(u + sizeX, 1 - v - sizeY)
|
|
371
|
+
|
|
372
|
+
const material = new THREE.MeshStandardMaterial({
|
|
373
|
+
map: itemsTexture,
|
|
374
|
+
transparent: true,
|
|
375
|
+
alphaTest: 0.1,
|
|
376
|
+
})
|
|
377
|
+
const materialFlipped = new THREE.MeshStandardMaterial({
|
|
378
|
+
map: itemsTextureFlipped,
|
|
379
|
+
transparent: true,
|
|
380
|
+
alphaTest: 0.1,
|
|
381
|
+
})
|
|
382
|
+
const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 0), [
|
|
383
|
+
new THREE.MeshBasicMaterial({ color: 0x00_00_00 }), new THREE.MeshBasicMaterial({ color: 0x00_00_00 }),
|
|
384
|
+
new THREE.MeshBasicMaterial({ color: 0x00_00_00 }), new THREE.MeshBasicMaterial({ color: 0x00_00_00 }),
|
|
385
|
+
material, materialFlipped,
|
|
386
|
+
])
|
|
387
|
+
|
|
388
|
+
return {
|
|
389
|
+
mesh,
|
|
390
|
+
itemsTexture,
|
|
391
|
+
itemsTextureFlipped,
|
|
392
|
+
cleanup () {
|
|
393
|
+
itemsTexture.dispose()
|
|
394
|
+
itemsTextureFlipped.dispose()
|
|
395
|
+
material.dispose()
|
|
396
|
+
materialFlipped.dispose()
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Creates a complete 3D item mesh from a canvas texture
|
|
403
|
+
*/
|
|
404
|
+
export function createItemMeshFromCanvas (
|
|
405
|
+
canvas: HTMLCanvasElement,
|
|
406
|
+
options: Create3DItemMeshOptions
|
|
407
|
+
): THREE.Mesh {
|
|
408
|
+
const { geometry } = create3DItemMesh(canvas, options)
|
|
409
|
+
|
|
410
|
+
// Base color texture for the item
|
|
411
|
+
const colorTexture = new THREE.CanvasTexture(canvas)
|
|
412
|
+
colorTexture.magFilter = THREE.NearestFilter
|
|
413
|
+
colorTexture.minFilter = THREE.NearestFilter
|
|
414
|
+
colorTexture.wrapS = colorTexture.wrapT = THREE.ClampToEdgeWrapping
|
|
415
|
+
colorTexture.flipY = false // Important for canvas textures
|
|
416
|
+
colorTexture.needsUpdate = true
|
|
417
|
+
|
|
418
|
+
// Material - no transparency, no alpha test needed for edges
|
|
419
|
+
const material = new THREE.MeshBasicMaterial({
|
|
420
|
+
map: colorTexture,
|
|
421
|
+
side: THREE.DoubleSide,
|
|
422
|
+
transparent: true,
|
|
423
|
+
alphaTest: 0.1
|
|
424
|
+
})
|
|
425
|
+
|
|
426
|
+
return new THREE.Mesh(geometry, material)
|
|
427
|
+
}
|