minecraft-renderer 0.1.30 → 0.1.32
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/dist/minecraft-renderer.js +56 -56
- package/dist/minecraft-renderer.js.meta.json +1 -1
- package/dist/threeWorker.js +419 -419
- package/package.json +1 -1
- package/src/graphicsBackend/config.ts +1 -0
- package/src/graphicsBackend/playerState.ts +4 -0
- package/src/lib/cameraBobbing.ts +29 -85
- package/src/lib/worldrendererCommon.ts +1 -1
- package/src/playerState/playerState.ts +4 -0
- package/src/three/cameraShake.ts +26 -2
- package/src/three/hand.ts +103 -52
- package/src/three/handLegacy.ts +90 -0
- package/src/three/holdingBlock.ts +269 -335
- package/src/three/holdingBlockFactory.ts +16 -0
- package/src/three/holdingBlockLegacy.ts +957 -0
- package/src/three/holdingBlockTypes.ts +22 -0
- package/src/three/modules/cameraBobbing.ts +59 -0
- package/src/three/modules/index.ts +2 -0
- package/src/three/worldRendererThree.ts +28 -6
- package/src/three/entity/models/sheep.obj +0 -555
package/package.json
CHANGED
|
@@ -45,6 +45,7 @@ export const defaultWorldRendererConfig = {
|
|
|
45
45
|
// Camera visual related settings
|
|
46
46
|
showHand: false,
|
|
47
47
|
viewBobbing: false,
|
|
48
|
+
handRenderer: 'vanilla' as 'vanilla' | 'legacy',
|
|
48
49
|
renderEars: true,
|
|
49
50
|
highlightBlockColor: 'blue' as 'blue' | 'classic' | 'auto' | undefined,
|
|
50
51
|
|
package/src/lib/cameraBobbing.ts
CHANGED
|
@@ -1,95 +1,39 @@
|
|
|
1
1
|
//@ts-nocheck
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
private bobAmount = 0
|
|
6
|
-
private prevBobAmount = 0
|
|
7
|
-
private readonly gameTimer = new GameTimer()
|
|
8
|
-
|
|
9
|
-
// eslint-disable-next-line max-params
|
|
10
|
-
constructor (
|
|
11
|
-
private readonly BOB_FREQUENCY: number = Math.PI, // How fast the bob cycles
|
|
12
|
-
private readonly BOB_BASE_AMPLITUDE: number = 0.5, // Base amplitude of the bob
|
|
13
|
-
private readonly VERTICAL_MULTIPLIER: number = 1, // Vertical movement multiplier
|
|
14
|
-
private readonly ROTATION_MULTIPLIER_Z: number = 3, // Roll rotation multiplier
|
|
15
|
-
private readonly ROTATION_MULTIPLIER_X: number = 5 // Pitch rotation multiplier
|
|
16
|
-
) {}
|
|
17
|
-
|
|
18
|
-
// Call this when player is moving
|
|
19
|
-
public updateWalkDistance (distance: number): void {
|
|
20
|
-
this.prevWalkDistance = this.walkDistance
|
|
21
|
-
this.walkDistance = distance
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Call this when player is moving to update bob amount
|
|
25
|
-
public updateBobAmount (isMoving: boolean): void {
|
|
26
|
-
const targetBob = isMoving ? 1 : 0
|
|
27
|
-
this.prevBobAmount = this.bobAmount
|
|
28
|
-
|
|
29
|
-
// Update timing
|
|
30
|
-
const ticks = this.gameTimer.update()
|
|
31
|
-
const deltaTime = ticks / 20 // Convert ticks to seconds assuming 20 TPS
|
|
32
|
-
|
|
33
|
-
// Smooth transition for bob amount
|
|
34
|
-
const bobDelta = (targetBob - this.bobAmount) * Math.min(1, deltaTime * 10)
|
|
35
|
-
this.bobAmount += bobDelta
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// Call this in your render/animation loop
|
|
39
|
-
public getBobbing (): { position: { x: number, y: number }, rotation: { x: number, z: number } } {
|
|
40
|
-
// Interpolate walk distance
|
|
41
|
-
const walkDist = this.prevWalkDistance +
|
|
42
|
-
(this.walkDistance - this.prevWalkDistance) * this.gameTimer.partialTick
|
|
43
|
-
|
|
44
|
-
// Interpolate bob amount
|
|
45
|
-
const bob = this.prevBobAmount +
|
|
46
|
-
(this.bobAmount - this.prevBobAmount) * this.gameTimer.partialTick
|
|
47
|
-
|
|
48
|
-
// Calculate total distance for bob cycle
|
|
49
|
-
const totalDist = -(walkDist * this.BOB_FREQUENCY)
|
|
50
|
-
|
|
51
|
-
// Calculate offsets
|
|
52
|
-
const xOffset = Math.sin(totalDist) * bob * this.BOB_BASE_AMPLITUDE
|
|
53
|
-
const yOffset = -Math.abs(Math.cos(totalDist) * bob) * this.VERTICAL_MULTIPLIER
|
|
54
|
-
|
|
55
|
-
// Calculate rotations (in radians)
|
|
56
|
-
const zRot = (Math.sin(totalDist) * bob * this.ROTATION_MULTIPLIER_Z) * (Math.PI / 180)
|
|
57
|
-
const xRot = (Math.abs(Math.cos(totalDist - 0.2) * bob) * this.ROTATION_MULTIPLIER_X) * (Math.PI / 180)
|
|
58
|
-
|
|
59
|
-
return {
|
|
60
|
-
position: { x: xOffset, y: yOffset },
|
|
61
|
-
rotation: { x: xRot, z: zRot }
|
|
62
|
-
}
|
|
63
|
-
}
|
|
2
|
+
export interface CameraBobResult {
|
|
3
|
+
position: { x: number; y: number }
|
|
4
|
+
rotation: { x: number; z: number }
|
|
64
5
|
}
|
|
65
6
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
this.lastMs = performance.now()
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
update (): number {
|
|
77
|
-
const currentMs = performance.now()
|
|
78
|
-
const deltaSinceLastTick = currentMs - this.lastMs
|
|
7
|
+
export interface CameraBobInput {
|
|
8
|
+
walkDist: number
|
|
9
|
+
prevWalkDist: number
|
|
10
|
+
bob: number
|
|
11
|
+
prevBob: number
|
|
12
|
+
partialTick: number
|
|
13
|
+
}
|
|
79
14
|
|
|
80
|
-
|
|
81
|
-
const tickDelta = deltaSinceLastTick / this.msPerTick
|
|
82
|
-
this.lastMs = currentMs
|
|
15
|
+
const DEG_TO_RAD = Math.PI / 180
|
|
83
16
|
|
|
84
|
-
|
|
85
|
-
|
|
17
|
+
export function computeCameraBob (input: CameraBobInput): CameraBobResult {
|
|
18
|
+
const { walkDist, prevWalkDist, bob, prevBob, partialTick } = input
|
|
86
19
|
|
|
87
|
-
|
|
88
|
-
|
|
20
|
+
// Vanilla uses "backwards interpolation": -(walkDist + delta * partialTick)
|
|
21
|
+
// See ClientAvatarState.getBackwardsInterpolatedWalkDistance()
|
|
22
|
+
const walkDelta = walkDist - prevWalkDist
|
|
23
|
+
const interpolatedWalkDist = -(walkDist + walkDelta * partialTick)
|
|
24
|
+
const interpolatedBob = prevBob + (bob - prevBob) * partialTick
|
|
89
25
|
|
|
90
|
-
|
|
91
|
-
|
|
26
|
+
const sinWalk = Math.sin(interpolatedWalkDist * Math.PI)
|
|
27
|
+
const cosWalk = Math.cos(interpolatedWalkDist * Math.PI)
|
|
92
28
|
|
|
93
|
-
|
|
29
|
+
return {
|
|
30
|
+
position: {
|
|
31
|
+
x: sinWalk * interpolatedBob * 0.5,
|
|
32
|
+
y: -Math.abs(cosWalk * interpolatedBob)
|
|
33
|
+
},
|
|
34
|
+
rotation: {
|
|
35
|
+
x: Math.abs(Math.cos(interpolatedWalkDist * Math.PI - 0.2) * interpolatedBob) * 5 * DEG_TO_RAD,
|
|
36
|
+
z: sinWalk * interpolatedBob * 3 * DEG_TO_RAD
|
|
37
|
+
}
|
|
94
38
|
}
|
|
95
39
|
}
|
|
@@ -288,7 +288,7 @@ export abstract class WorldRendererCommon<WorkerSend = any, WorkerReceive = any>
|
|
|
288
288
|
if (initial) {
|
|
289
289
|
callback(this.playerStateReactive[key])
|
|
290
290
|
}
|
|
291
|
-
subscribeKey(this.playerStateReactive, key, callback)
|
|
291
|
+
return subscribeKey(this.playerStateReactive, key, callback)
|
|
292
292
|
}
|
|
293
293
|
|
|
294
294
|
onReactiveConfigUpdated<T extends keyof typeof this.worldRendererConfig>(key: T, callback: (value: typeof this.worldRendererConfig[T]) => void) {
|
package/src/three/cameraShake.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
//@ts-nocheck
|
|
2
2
|
import * as THREE from 'three'
|
|
3
|
+
import { computeCameraBob, type CameraBobInput } from '../lib/cameraBobbing'
|
|
3
4
|
import { WorldRendererThree } from './worldRendererThree'
|
|
4
5
|
|
|
5
6
|
export class CameraShake {
|
|
@@ -9,6 +10,11 @@ export class CameraShake {
|
|
|
9
10
|
private rollAnimation?: { startTime: number, startRoll: number, targetRoll: number, duration: number, returnToZero?: boolean }
|
|
10
11
|
private basePitch = 0
|
|
11
12
|
private baseYaw = 0
|
|
13
|
+
private cameraBobInput: CameraBobInput | null = null
|
|
14
|
+
|
|
15
|
+
setCameraBobInput(input: CameraBobInput | null) {
|
|
16
|
+
this.cameraBobInput = input
|
|
17
|
+
}
|
|
12
18
|
|
|
13
19
|
constructor(public worldRenderer: WorldRendererThree, public onRenderCallbacks: Array<(deltaTime: number) => void>) {
|
|
14
20
|
onRenderCallbacks.push(() => {
|
|
@@ -88,8 +94,26 @@ export class CameraShake {
|
|
|
88
94
|
const pitchQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), pitchOffset)
|
|
89
95
|
const yawQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), yawOffset)
|
|
90
96
|
const rollQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 0, 1), THREE.MathUtils.degToRad(this.rollAngle))
|
|
91
|
-
|
|
92
|
-
|
|
97
|
+
|
|
98
|
+
// Camera bobbing rotation
|
|
99
|
+
let bobRollQuat = new THREE.Quaternion()
|
|
100
|
+
let bobPitchQuat = new THREE.Quaternion()
|
|
101
|
+
const perspective = this.worldRenderer.playerStateReactive.perspective
|
|
102
|
+
if (this.cameraBobInput) {
|
|
103
|
+
const bob = computeCameraBob(this.cameraBobInput)
|
|
104
|
+
bobRollQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 0, 1), bob.rotation.z)
|
|
105
|
+
bobPitchQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), bob.rotation.x)
|
|
106
|
+
|
|
107
|
+
// Apply position bobbing to the camera child (not cameraContainer) in first-person only
|
|
108
|
+
if (perspective === 'first_person') {
|
|
109
|
+
this.worldRenderer.camera.position.set(bob.position.x, bob.position.y, 0)
|
|
110
|
+
}
|
|
111
|
+
} else if (perspective === 'first_person') {
|
|
112
|
+
this.worldRenderer.camera.position.set(0, 0, 0)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Combine: yaw * pitch * damageRoll * bobRoll(Z) * bobPitch(X) — vanilla applies Z then X
|
|
116
|
+
const finalQuat = yawQuat.multiply(pitchQuat).multiply(rollQuat).multiply(bobRollQuat).multiply(bobPitchQuat)
|
|
93
117
|
camera.setRotationFromQuaternion(finalQuat)
|
|
94
118
|
}
|
|
95
119
|
}
|
package/src/three/hand.ts
CHANGED
|
@@ -21,70 +21,121 @@ export const getMyHand = async (image?: string, userName?: string) => {
|
|
|
21
21
|
|
|
22
22
|
newMap.magFilter = THREE.NearestFilter
|
|
23
23
|
newMap.minFilter = THREE.NearestFilter
|
|
24
|
-
|
|
25
|
-
const box = new THREE.BoxGeometry()
|
|
26
|
-
const material = new THREE.MeshStandardMaterial()
|
|
24
|
+
|
|
27
25
|
const slim = false
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
const pixelWidth = slim ? 3 : 4
|
|
27
|
+
|
|
28
|
+
// Exact replica of vanilla's Cube: addBox(-3, -2, -2, 4, 12, 4) at texOffs(40, 16)
|
|
29
|
+
const box = createVanillaCubeGeometry(
|
|
30
|
+
40, 16,
|
|
31
|
+
slim ? -2 : -3, -2, -2,
|
|
32
|
+
pixelWidth, 12, 4,
|
|
33
|
+
64, 64
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
const material = new THREE.MeshStandardMaterial()
|
|
33
37
|
material.map = newMap
|
|
34
38
|
material.needsUpdate = true
|
|
39
|
+
|
|
40
|
+
const mesh = new THREE.Mesh(box, material)
|
|
41
|
+
|
|
35
42
|
const group = new THREE.Group()
|
|
36
43
|
group.add(mesh)
|
|
37
|
-
group.scale.set(0.1, 0.1, 0.1)
|
|
38
|
-
mesh.rotation.z = Math.PI
|
|
39
44
|
return group
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
/**
|
|
48
|
+
* Creates a BufferGeometry replicating vanilla Minecraft's ModelPart.Cube exactly.
|
|
49
|
+
* Vertices, face winding, normals, and UV mapping match the decompiled Java source.
|
|
50
|
+
* Position coordinates are in pixels, divided by 16 for block units.
|
|
51
|
+
*/
|
|
52
|
+
function createVanillaCubeGeometry (
|
|
53
|
+
texU: number, texV: number,
|
|
54
|
+
originX: number, originY: number, originZ: number,
|
|
55
|
+
sizeX: number, sizeY: number, sizeZ: number,
|
|
56
|
+
texWidth: number, texHeight: number,
|
|
57
|
+
mirror = false
|
|
58
|
+
): THREE.BufferGeometry {
|
|
59
|
+
let minX = originX / 16
|
|
60
|
+
let minY = originY / 16
|
|
61
|
+
let minZ = originZ / 16
|
|
62
|
+
let maxX = (originX + sizeX) / 16
|
|
63
|
+
let maxY = (originY + sizeY) / 16
|
|
64
|
+
let maxZ = (originZ + sizeZ) / 16
|
|
65
|
+
|
|
66
|
+
if (mirror) {
|
|
67
|
+
[minX, maxX] = [maxX, minX]
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 8 corner vertices matching vanilla's Cube constructor
|
|
71
|
+
const V = [
|
|
72
|
+
[minX, minY, minZ], // 0
|
|
73
|
+
[maxX, minY, minZ], // 1
|
|
74
|
+
[maxX, maxY, minZ], // 2
|
|
75
|
+
[minX, maxY, minZ], // 3
|
|
76
|
+
[minX, minY, maxZ], // 4
|
|
77
|
+
[maxX, minY, maxZ], // 5
|
|
78
|
+
[maxX, maxY, maxZ], // 6
|
|
79
|
+
[minX, maxY, maxZ], // 7
|
|
57
80
|
]
|
|
58
81
|
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
const
|
|
62
|
-
const
|
|
63
|
-
const
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
82
|
+
// UV grid (pixel coords)
|
|
83
|
+
const u0 = texU
|
|
84
|
+
const u1 = texU + sizeZ
|
|
85
|
+
const u2 = texU + sizeZ + sizeX
|
|
86
|
+
const u3 = texU + sizeZ + sizeX + sizeX
|
|
87
|
+
const u4 = texU + sizeZ + sizeX + sizeZ
|
|
88
|
+
const u5 = texU + sizeZ + sizeX + sizeZ + sizeX
|
|
89
|
+
const v0 = texV
|
|
90
|
+
const v1 = texV + sizeZ
|
|
91
|
+
const v2 = texV + sizeZ + sizeY
|
|
92
|
+
|
|
93
|
+
// 6 faces: vanilla vertex order + UV rect + normal
|
|
94
|
+
const faces: { vi: number[]; uv: number[]; n: number[] }[] = [
|
|
95
|
+
{ vi: [5, 4, 0, 1], uv: [u1, v0, u2, v1], n: [0, -1, 0] }, // DOWN
|
|
96
|
+
{ vi: [2, 3, 7, 6], uv: [u2, v1, u3, v0], n: [0, 1, 0] }, // UP
|
|
97
|
+
{ vi: [0, 4, 7, 3], uv: [u0, v1, u1, v2], n: [-1, 0, 0] }, // WEST
|
|
98
|
+
{ vi: [1, 0, 3, 2], uv: [u1, v1, u2, v2], n: [0, 0, -1] }, // NORTH
|
|
99
|
+
{ vi: [5, 1, 2, 6], uv: [u2, v1, u4, v2], n: [1, 0, 0] }, // EAST
|
|
100
|
+
{ vi: [4, 5, 6, 7], uv: [u4, v1, u5, v2], n: [0, 0, 1] }, // SOUTH
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
const positions: number[] = []
|
|
104
|
+
const uvs: number[] = []
|
|
105
|
+
const normals: number[] = []
|
|
106
|
+
const indices: number[] = []
|
|
107
|
+
|
|
108
|
+
for (let fi = 0; fi < faces.length; fi++) {
|
|
109
|
+
const face = faces[fi]
|
|
110
|
+
const base = fi * 4
|
|
111
|
+
|
|
112
|
+
const [uL, vT, uR, vB] = face.uv
|
|
113
|
+
// Vanilla vertex UV order: top-right, top-left, bottom-left, bottom-right
|
|
114
|
+
const fUV = [
|
|
115
|
+
[uR / texWidth, 1 - vT / texHeight],
|
|
116
|
+
[uL / texWidth, 1 - vT / texHeight],
|
|
117
|
+
[uL / texWidth, 1 - vB / texHeight],
|
|
118
|
+
[uR / texWidth, 1 - vB / texHeight],
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
const order = mirror ? [3, 2, 1, 0] : [0, 1, 2, 3]
|
|
122
|
+
const nx = mirror ? -face.n[0] : face.n[0]
|
|
123
|
+
|
|
124
|
+
for (let i = 0; i < 4; i++) {
|
|
125
|
+
const vert = V[face.vi[order[i]]]
|
|
126
|
+
positions.push(vert[0], vert[1], vert[2])
|
|
127
|
+
uvs.push(fUV[i][0], fUV[i][1])
|
|
128
|
+
normals.push(nx, face.n[1], face.n[2])
|
|
81
129
|
}
|
|
130
|
+
|
|
131
|
+
indices.push(base, base + 1, base + 2, base, base + 2, base + 3)
|
|
82
132
|
}
|
|
83
133
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
134
|
+
const geometry = new THREE.BufferGeometry()
|
|
135
|
+
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3))
|
|
136
|
+
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2))
|
|
137
|
+
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3))
|
|
138
|
+
geometry.setIndex(indices)
|
|
87
139
|
|
|
88
|
-
|
|
89
|
-
setUVs(box, u, v, width, height, depth, 64, 64)
|
|
140
|
+
return geometry
|
|
90
141
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import * as THREE from 'three'
|
|
3
|
+
import { loadSkinFromUsername, loadSkinImage } from '../lib/utils/skins'
|
|
4
|
+
import { steveTexture } from './entities'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export const getMyHand = async (image?: string, userName?: string) => {
|
|
8
|
+
let newMap: THREE.Texture
|
|
9
|
+
if (!image && !userName) {
|
|
10
|
+
newMap = await steveTexture
|
|
11
|
+
} else {
|
|
12
|
+
if (!image) {
|
|
13
|
+
image = await loadSkinFromUsername(userName!, 'skin')
|
|
14
|
+
}
|
|
15
|
+
if (!image) {
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
const { canvas } = await loadSkinImage(image)
|
|
19
|
+
newMap = new THREE.CanvasTexture(canvas)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
newMap.magFilter = THREE.NearestFilter
|
|
23
|
+
newMap.minFilter = THREE.NearestFilter
|
|
24
|
+
// right arm
|
|
25
|
+
const box = new THREE.BoxGeometry()
|
|
26
|
+
const material = new THREE.MeshStandardMaterial()
|
|
27
|
+
const slim = false
|
|
28
|
+
const mesh = new THREE.Mesh(box, material)
|
|
29
|
+
mesh.scale.x = slim ? 3 : 4
|
|
30
|
+
mesh.scale.y = 12
|
|
31
|
+
mesh.scale.z = 4
|
|
32
|
+
setSkinUVs(box, 40, 16, slim ? 3 : 4, 12, 4)
|
|
33
|
+
material.map = newMap
|
|
34
|
+
material.needsUpdate = true
|
|
35
|
+
const group = new THREE.Group()
|
|
36
|
+
group.add(mesh)
|
|
37
|
+
group.scale.set(0.1, 0.1, 0.1)
|
|
38
|
+
mesh.rotation.z = Math.PI
|
|
39
|
+
return group
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function setUVs (
|
|
43
|
+
box: THREE.BoxGeometry,
|
|
44
|
+
u: number,
|
|
45
|
+
v: number,
|
|
46
|
+
width: number,
|
|
47
|
+
height: number,
|
|
48
|
+
depth: number,
|
|
49
|
+
textureWidth: number,
|
|
50
|
+
textureHeight: number
|
|
51
|
+
): void {
|
|
52
|
+
const toFaceVertices = (x1: number, y1: number, x2: number, y2: number) => [
|
|
53
|
+
new THREE.Vector2(x1 / textureWidth, 1 - y2 / textureHeight),
|
|
54
|
+
new THREE.Vector2(x2 / textureWidth, 1 - y2 / textureHeight),
|
|
55
|
+
new THREE.Vector2(x2 / textureWidth, 1 - y1 / textureHeight),
|
|
56
|
+
new THREE.Vector2(x1 / textureWidth, 1 - y1 / textureHeight),
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
const top = toFaceVertices(u + depth, v, u + width + depth, v + depth)
|
|
60
|
+
const bottom = toFaceVertices(u + width + depth, v, u + width * 2 + depth, v + depth)
|
|
61
|
+
const left = toFaceVertices(u, v + depth, u + depth, v + depth + height)
|
|
62
|
+
const front = toFaceVertices(u + depth, v + depth, u + width + depth, v + depth + height)
|
|
63
|
+
const right = toFaceVertices(u + width + depth, v + depth, u + width + depth * 2, v + height + depth)
|
|
64
|
+
const back = toFaceVertices(u + width + depth * 2, v + depth, u + width * 2 + depth * 2, v + height + depth)
|
|
65
|
+
|
|
66
|
+
const uvAttr = box.attributes.uv as THREE.BufferAttribute
|
|
67
|
+
const uvRight = [right[3], right[2], right[0], right[1]]
|
|
68
|
+
const uvLeft = [left[3], left[2], left[0], left[1]]
|
|
69
|
+
const uvTop = [top[3], top[2], top[0], top[1]]
|
|
70
|
+
const uvBottom = [bottom[0], bottom[1], bottom[3], bottom[2]]
|
|
71
|
+
const uvFront = [front[3], front[2], front[0], front[1]]
|
|
72
|
+
const uvBack = [back[3], back[2], back[0], back[1]]
|
|
73
|
+
|
|
74
|
+
// Create a new array to hold the modified UV data
|
|
75
|
+
const newUVData = [] as number[]
|
|
76
|
+
|
|
77
|
+
// Iterate over the arrays and copy the data to uvData
|
|
78
|
+
for (const uvArray of [uvRight, uvLeft, uvTop, uvBottom, uvFront, uvBack]) {
|
|
79
|
+
for (const uv of uvArray) {
|
|
80
|
+
newUVData.push(uv.x, uv.y)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
uvAttr.set(new Float32Array(newUVData))
|
|
85
|
+
uvAttr.needsUpdate = true
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function setSkinUVs (box: THREE.BoxGeometry, u: number, v: number, width: number, height: number, depth: number): void {
|
|
89
|
+
setUVs(box, u, v, width, height, depth, 64, 64)
|
|
90
|
+
}
|