bucciafico-lib 1.0.7 → 1.0.8

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.
@@ -1,58 +1,164 @@
1
1
  import * as THREE from 'three';
2
- import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js';
2
+
3
+ let cachedCanvas = null;
4
+ let cachedCtx = null;
5
+
6
+ function getImageData(image) {
7
+ if (!cachedCanvas) {
8
+ cachedCanvas = document.createElement('canvas');
9
+ cachedCanvas.width = 64;
10
+ cachedCanvas.height = 64;
11
+ cachedCtx = cachedCanvas.getContext('2d', { willReadFrequently: true });
12
+ }
13
+
14
+ cachedCtx.clearRect(0, 0, 64, 64);
15
+ cachedCtx.drawImage(image, 0, 0);
16
+ return cachedCtx.getImageData(0, 0, 64, 64).data;
17
+ }
18
+
19
+ const CUBE = {
20
+ vertices: [
21
+ // Right
22
+ 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5,
23
+ // Left
24
+ -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, -0.5,
25
+ // Top
26
+ -0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, 0.5, -0.5,
27
+ // Bottom
28
+ -0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5, 0.5, -0.5, 0.5,
29
+ // Front
30
+ -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5, 0.5, 0.5, -0.5, 0.5, 0.5,
31
+ // Back
32
+ -0.5, -0.5, -0.5, -0.5, 0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5
33
+ ],
34
+ normals: [
35
+ // Right
36
+ 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0,
37
+ // Left
38
+ -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0,
39
+ // Top
40
+ 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0,
41
+ // Bottom
42
+ 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0,
43
+ // Front
44
+ 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1,
45
+ // Back
46
+ 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1
47
+ ],
48
+ indices: [
49
+ 0, 1, 2, 0, 2, 3, // Right
50
+ 4, 5, 6, 4, 6, 7, // Left
51
+ 8, 9, 10, 8, 10, 11, // Top
52
+ 12, 13, 14, 12, 14, 15, // Bottom
53
+ 16, 17, 18, 16, 18, 19, // Front
54
+ 20, 21, 22, 20, 22, 23 // Back
55
+ ]
56
+ };
3
57
 
4
58
  /**
5
59
  * Converts the 2nd layer of a skin (Hat, Jacket) into 3D Voxels.
6
- * This gives the skin actual depth instead of flat planes.
60
+ * Optimized version: Direct buffer manipulation instead of object merging.
61
+ *
7
62
  * @param {THREE.Texture} texture
8
63
  * @param {Object} layerDef - Definition of UVs and dimensions.
9
64
  * @returns {THREE.BufferGeometry|null} Merged geometry of all voxels.
10
65
  */
11
66
  export function createVoxelLayer(texture, layerDef) {
12
- const canvas = document.createElement('canvas');
13
- canvas.width = 64; canvas.height = 64;
14
- const ctx = canvas.getContext('2d');
15
- ctx.drawImage(texture.image, 0, 0);
16
- const imgData = ctx.getImageData(0, 0, 64, 64).data;
17
-
18
- const geometries = [];
67
+ const imgData = getImageData(texture.image);
19
68
  const { outer } = layerDef.uv;
20
69
  const { w, h, d } = layerDef.size;
21
70
 
22
- // Mapping faces of the body part to UV coordinates
71
+ const positions = [];
72
+ const normals = [];
73
+ const uvs = [];
74
+ const indices = [];
75
+
76
+ let vertexOffset = 0;
77
+
78
+ const addVoxel = (cx, cy, cz, sx, sy, sz, u, v) => {
79
+ const uCoord = (u + 0.5) / 64;
80
+ const vCoord = 1.0 - (v + 0.5) / 64;
81
+
82
+ for (let i = 0; i < 24; i++) {
83
+ const vx = CUBE.vertices[i * 3] * sx + cx;
84
+ const vy = CUBE.vertices[i * 3 + 1] * sy + cy;
85
+ const vz = CUBE.vertices[i * 3 + 2] * sz + cz;
86
+
87
+ positions.push(vx, vy, vz);
88
+ normals.push(CUBE.normals[i * 3], CUBE.normals[i * 3 + 1], CUBE.normals[i * 3 + 2]);
89
+ uvs.push(uCoord, vCoord);
90
+ }
91
+
92
+ for (let i = 0; i < CUBE.indices.length; i++) {
93
+ indices.push(CUBE.indices[i] + vertexOffset);
94
+ }
95
+ vertexOffset += 24;
96
+ };
97
+
23
98
  const faces = [
24
- { u: outer.x+d, v: outer.y+d, w: w, h: h, pos: (i,j) => new THREE.Vector3(i-w/2+0.5, j-h/2+0.5, d/2+0.25) },
25
- { u: outer.x+d+w+d, v: outer.y+d, w: w, h: h, pos: (i,j) => new THREE.Vector3(-(i-w/2+0.5), j-h/2+0.5, -d/2-0.25) },
26
- { u: outer.x, v: outer.y+d, w: d, h: h, pos: (i,j) => new THREE.Vector3(-w/2-0.25, j-h/2+0.5, i-d/2+0.5), sx: 0.5 },
27
- { u: outer.x+d+w, v: outer.y+d, w: d, h: h, pos: (i,j) => new THREE.Vector3(w/2+0.25, j-h/2+0.5, -(i-d/2+0.5)), sx: 0.5 },
28
- { u: outer.x+d, v: outer.y, w: w, h: d, pos: (i,j) => new THREE.Vector3(i-w/2+0.5, h/2+0.25, -(j-d/2+0.5)), sy: 0.5 },
29
- { u: outer.x+d+w, v: outer.y, w: w, h: d, pos: (i,j) => new THREE.Vector3(i-w/2+0.5, -h/2-0.25, (d - 1 - j) - d/2 + 0.5), sy: 0.5 }
99
+ // Face 0: Front (Z+)
100
+ {
101
+ u: outer.x + d, v: outer.y + d, width: w, height: h,
102
+ pos: (i, j) => ({ x: i - w/2 + 0.5, y: j - h/2 + 0.5, z: d/2 + 0.25 }),
103
+ scale: { z: 0.5 }
104
+ },
105
+ // Face 1: Back (Z-)
106
+ {
107
+ u: outer.x + d + w + d, v: outer.y + d, width: w, height: h,
108
+ pos: (i, j) => ({ x: -(i - w/2 + 0.5), y: j - h/2 + 0.5, z: -d/2 - 0.25 }),
109
+ scale: { z: 0.5 }
110
+ },
111
+ // Face 2: Right UV / Left 3D (X-)
112
+ {
113
+ u: outer.x, v: outer.y + d, width: d, height: h,
114
+ pos: (i, j) => ({ x: -w/2 - 0.25, y: j - h/2 + 0.5, z: i - d/2 + 0.5 }),
115
+ scale: { x: 0.5 }
116
+ },
117
+ // Face 3: Left UV / Right 3D (X+)
118
+ {
119
+ u: outer.x + d + w, v: outer.y + d, width: d, height: h,
120
+ pos: (i, j) => ({ x: w/2 + 0.25, y: j - h/2 + 0.5, z: -(i - d/2 + 0.5) }),
121
+ scale: { x: 0.5 }
122
+ },
123
+ // Face 4: Top (Y+)
124
+ {
125
+ u: outer.x + d, v: outer.y, width: w, height: d,
126
+ pos: (i, j) => ({ x: i - w/2 + 0.5, y: h/2 + 0.25, z: -(j - d/2 + 0.5) }),
127
+ scale: { y: 0.5 }
128
+ },
129
+ // Face 5: Bottom (Y-)
130
+ {
131
+ u: outer.x + d + w, v: outer.y, width: w, height: d,
132
+ pos: (i, j) => ({ x: i - w/2 + 0.5, y: -h/2 - 0.25, z: (d - 1 - j) - d/2 + 0.5 }),
133
+ scale: { y: 0.5 }
134
+ }
30
135
  ];
31
136
 
32
- const baseGeo = new THREE.BoxGeometry(1, 1, 1);
33
-
34
137
  faces.forEach(f => {
35
- for(let i=0; i<f.w; i++) {
36
- for(let j=0; j<f.h; j++) {
138
+ for (let i = 0; i < f.width; i++) {
139
+ for (let j = 0; j < f.height; j++) {
37
140
  const u = f.u + i;
38
141
  const v = f.v + j;
39
142
 
40
- if(imgData[(v*64+u)*4+3] > 0) {
41
- const geo = baseGeo.clone();
42
-
43
- const uvAttr = geo.attributes.uv;
44
- for(let k=0; k<uvAttr.count; k++) uvAttr.setXY(k, (u+0.5)/64, 1.0-(v+0.5)/64);
45
-
46
- const m = new THREE.Matrix4();
47
- const scale = new THREE.Vector3(f.sx||1, f.sy||1, f.sz||1);
48
- if(f === faces[0] || f === faces[1]) scale.z = 0.5;
49
- m.compose(f.pos(i, (f.h-1)-j), new THREE.Quaternion(), scale);
50
- geo.applyMatrix4(m);
51
- geometries.push(geo);
143
+ const alphaIndex = (v * 64 + u) * 4 + 3;
144
+ if (imgData[alphaIndex] > 0) {
145
+ const pos = f.pos(i, (f.height - 1) - j);
146
+ const sx = f.scale?.x ?? 1;
147
+ const sy = f.scale?.y ?? 1;
148
+ const sz = f.scale?.z ?? 1;
149
+ addVoxel(pos.x, pos.y, pos.z, sx, sy, sz, u, v);
52
150
  }
53
151
  }
54
152
  }
55
153
  });
56
154
 
57
- return geometries.length > 0 ? BufferGeometryUtils.mergeGeometries(geometries) : null;
155
+ if (positions.length === 0) return null;
156
+
157
+ const geometry = new THREE.BufferGeometry();
158
+ geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
159
+ geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));
160
+ geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));
161
+ geometry.setIndex(indices);
162
+
163
+ return geometry;
58
164
  }