bucciafico-lib 1.0.6 → 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.
- package/package.json +1 -1
- package/src/core/SkinViewer.js +154 -9
- package/src/managers/EventManager.js +74 -0
- package/src/managers/PostProcessingManager.js +40 -2
- package/src/objects/SceneSetup.js +49 -8
- package/src/objects/SkinModel.js +205 -12
- package/src/plugins/EditorPlugin.js +45 -14
- package/src/plugins/EffectsPlugin.js +45 -20
- package/src/plugins/IOPlugin.js +46 -17
- package/src/plugins/ItemsPlugin.js +121 -2
- package/src/utils/SkinUtils.js +17 -17
- package/src/utils/ThreeUtils.js +27 -0
- package/src/utils/Voxelizer.js +139 -33
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
1
2
|
import { ItemFactory } from '../objects/ItemFactory.js';
|
|
3
|
+
import {disposeObjectTree} from "../utils/ThreeUtils.js";
|
|
4
|
+
import {createGlowMaterial} from "../materials/GlowMaterial.js";
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
* Plugin responsible for managing 3D Items (Swords, Blocks).
|
|
@@ -8,12 +11,68 @@ export class ItemsPlugin {
|
|
|
8
11
|
this.name = 'ItemsPlugin';
|
|
9
12
|
/** @type {Array<THREE.Mesh>} List of current items on scene */
|
|
10
13
|
this.items = [];
|
|
14
|
+
|
|
15
|
+
this.LAYERS_COUNT = 20;
|
|
11
16
|
}
|
|
12
17
|
|
|
13
18
|
init(viewer) {
|
|
14
19
|
this.viewer = viewer;
|
|
15
20
|
}
|
|
16
21
|
|
|
22
|
+
attachItem(itemMesh, partName) {
|
|
23
|
+
const editor = this.viewer.getPlugin('EditorPlugin');
|
|
24
|
+
if (editor) editor.saveHistory();
|
|
25
|
+
|
|
26
|
+
const skinModel = this.viewer.skinModel;
|
|
27
|
+
|
|
28
|
+
if (!partName) {
|
|
29
|
+
this.viewer.scene.attach(itemMesh);
|
|
30
|
+
itemMesh.userData.parentId = null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
else if (skinModel.parts[partName]) {
|
|
34
|
+
const targetGroup = skinModel.parts[partName];
|
|
35
|
+
targetGroup.attach(itemMesh);
|
|
36
|
+
itemMesh.userData.parentId = partName;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (this.viewer.emit) this.viewer.emit('transform:change', itemMesh);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
_addGlowShells(mesh) {
|
|
43
|
+
mesh.geometry.computeBoundingBox();
|
|
44
|
+
const size = new THREE.Vector3();
|
|
45
|
+
mesh.geometry.boundingBox.getSize(size);
|
|
46
|
+
const itemHeight = size.y || 1;
|
|
47
|
+
|
|
48
|
+
const glowLayers = [];
|
|
49
|
+
|
|
50
|
+
const glowGroup = new THREE.Group();
|
|
51
|
+
glowGroup.name = "GlowShells";
|
|
52
|
+
|
|
53
|
+
const shellGeo = mesh.geometry.clone();
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < this.LAYERS_COUNT; i++) {
|
|
56
|
+
const glowMat = createGlowMaterial(itemHeight);
|
|
57
|
+
|
|
58
|
+
glowMat.uniforms.thickness.value = 0;
|
|
59
|
+
glowMat.uniforms.opacity.value = 0;
|
|
60
|
+
|
|
61
|
+
glowMat.polygonOffset = true;
|
|
62
|
+
glowMat.polygonOffsetFactor = i * 0.1;
|
|
63
|
+
|
|
64
|
+
const layerMesh = new THREE.Mesh(shellGeo, glowMat);
|
|
65
|
+
layerMesh.userData.isGlowLayer = true;
|
|
66
|
+
layerMesh.userData.glowMat = glowMat;
|
|
67
|
+
|
|
68
|
+
glowLayers.push(layerMesh);
|
|
69
|
+
glowGroup.add(layerMesh);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
mesh.add(glowGroup);
|
|
73
|
+
mesh.userData.glowLayers = glowLayers;
|
|
74
|
+
}
|
|
75
|
+
|
|
17
76
|
/**
|
|
18
77
|
* Creates and adds an item to the scene.
|
|
19
78
|
* @param {string} url - Texture URL.
|
|
@@ -26,11 +85,22 @@ export class ItemsPlugin {
|
|
|
26
85
|
return ItemFactory.createFromURL(url, name).then(mesh => {
|
|
27
86
|
mesh.position.set(8, 8, 8);
|
|
28
87
|
mesh.userData.sourceUrl = url;
|
|
88
|
+
|
|
89
|
+
this._addGlowShells(mesh);
|
|
90
|
+
|
|
91
|
+
const fx = this.viewer.getPlugin('EffectsPlugin');
|
|
92
|
+
if (fx) {
|
|
93
|
+
const config = fx.getConfig();
|
|
94
|
+
this.updateItemGlow(mesh, config);
|
|
95
|
+
}
|
|
96
|
+
|
|
29
97
|
this.viewer.scene.add(mesh);
|
|
30
98
|
this.items.push(mesh);
|
|
31
99
|
|
|
32
|
-
// Auto-select if editor is present
|
|
33
100
|
if (editor) editor.selectObject(mesh);
|
|
101
|
+
|
|
102
|
+
if (this.viewer.emit) this.viewer.emit('items:added', mesh);
|
|
103
|
+
|
|
34
104
|
return mesh;
|
|
35
105
|
});
|
|
36
106
|
}
|
|
@@ -42,7 +112,44 @@ export class ItemsPlugin {
|
|
|
42
112
|
this.viewer.scene.remove(mesh);
|
|
43
113
|
this.items = this.items.filter(i => i !== mesh);
|
|
44
114
|
|
|
115
|
+
disposeObjectTree(mesh);
|
|
116
|
+
|
|
45
117
|
if (editor) editor.deselect();
|
|
118
|
+
|
|
119
|
+
if (this.viewer.emit) this.viewer.emit('items:removed', mesh);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// --- EFFECTS ---
|
|
123
|
+
|
|
124
|
+
updateAllGlow(config) {
|
|
125
|
+
this.items.forEach(item => {
|
|
126
|
+
this.updateItemGlow(item, config);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
updateItemGlow(item, config) {
|
|
131
|
+
if (!item.userData.glowLayers) return;
|
|
132
|
+
|
|
133
|
+
const maxThickness = (config.thickness || 4) * 0.05;
|
|
134
|
+
const heightLimit = config.height !== undefined ? config.height : 0.5;
|
|
135
|
+
const enabled = config.enabled;
|
|
136
|
+
|
|
137
|
+
item.userData.glowLayers.forEach((layer, i) => {
|
|
138
|
+
const mat = layer.userData.glowMat;
|
|
139
|
+
if (!mat) return;
|
|
140
|
+
|
|
141
|
+
const progress = (i + 1) / this.LAYERS_COUNT;
|
|
142
|
+
mat.uniforms.thickness.value = maxThickness * progress;
|
|
143
|
+
|
|
144
|
+
mat.uniforms.gradientLimit.value = heightLimit;
|
|
145
|
+
|
|
146
|
+
if (!enabled) {
|
|
147
|
+
mat.uniforms.opacity.value = 0.0;
|
|
148
|
+
} else {
|
|
149
|
+
const baseOpacity = 1.2 / this.LAYERS_COUNT;
|
|
150
|
+
mat.uniforms.opacity.value = baseOpacity;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
46
153
|
}
|
|
47
154
|
|
|
48
155
|
// --- SNAPSHOT HELPERS ---
|
|
@@ -51,6 +158,7 @@ export class ItemsPlugin {
|
|
|
51
158
|
return this.items.map(item => ({
|
|
52
159
|
name: item.name,
|
|
53
160
|
uuid: item.uuid,
|
|
161
|
+
parentId: item.userData.parentId || null,
|
|
54
162
|
pos: item.position.toArray(),
|
|
55
163
|
rot: item.rotation.toArray(),
|
|
56
164
|
scale: item.scale.toArray()
|
|
@@ -59,13 +167,24 @@ export class ItemsPlugin {
|
|
|
59
167
|
|
|
60
168
|
restoreSnapshot(itemsState) {
|
|
61
169
|
itemsState.forEach(state => {
|
|
62
|
-
// Try to find the item by UUID first, then Name
|
|
63
170
|
const item = this.items.find(i => i.uuid === state.uuid || i.name === state.name);
|
|
64
171
|
if (item) {
|
|
172
|
+
if (state.parentId !== item.userData.parentId) {
|
|
173
|
+
this.attachItem(item, state.parentId);
|
|
174
|
+
}
|
|
175
|
+
|
|
65
176
|
item.position.fromArray(state.pos);
|
|
66
177
|
item.rotation.fromArray(state.rot);
|
|
67
178
|
item.scale.fromArray(state.scale);
|
|
68
179
|
}
|
|
69
180
|
});
|
|
70
181
|
}
|
|
182
|
+
|
|
183
|
+
dispose() {
|
|
184
|
+
this.items.forEach(mesh => {
|
|
185
|
+
this.viewer.scene.remove(mesh);
|
|
186
|
+
disposeObjectTree(mesh);
|
|
187
|
+
});
|
|
188
|
+
this.items = [];
|
|
189
|
+
}
|
|
71
190
|
}
|
package/src/utils/SkinUtils.js
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Calculates UV coordinates for standard Minecraft skin layout.
|
|
3
3
|
*/
|
|
4
|
-
export function getUV(x, y, w, h) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
export function getUV(x, y, w, h, imgW = 64, imgH = 64) {
|
|
5
|
+
return {
|
|
6
|
+
u0: x / imgW,
|
|
7
|
+
u1: (x + w) / imgW,
|
|
8
|
+
v0: (imgH - y - h) / imgH,
|
|
9
|
+
v1: (imgH - y) / imgH
|
|
10
|
+
};
|
|
8
11
|
}
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Maps UV coordinates to a box geometry (Cube mapping).
|
|
15
|
+
* @param {THREE.BufferGeometry} geometry
|
|
16
|
+
* @param {number} x - Texture X
|
|
17
|
+
* @param {number} y - Texture Y
|
|
18
|
+
* @param {number} w - Width
|
|
19
|
+
* @param {number} h - Height
|
|
20
|
+
* @param {number} d - Depth
|
|
21
|
+
* @param {number} [imgW=64] - Texture Width
|
|
22
|
+
* @param {number} [imgH=64] - Texture Height
|
|
12
23
|
*/
|
|
13
|
-
export function applySkinUVs(geometry, x, y, w, h, d) {
|
|
24
|
+
export function applySkinUVs(geometry, x, y, w, h, d, imgW = 64, imgH = 64) {
|
|
14
25
|
const uvAttr = geometry.attributes.uv;
|
|
15
26
|
|
|
16
|
-
/**
|
|
17
|
-
* Helper to map a single face.
|
|
18
|
-
* @param {number} idx - Face index (0-5).
|
|
19
|
-
* @param {number} uX - Texture X.
|
|
20
|
-
* @param {number} uY - Texture Y.
|
|
21
|
-
* @param {number} uW - Texture Width.
|
|
22
|
-
* @param {number} uH - Texture Height.
|
|
23
|
-
* @param {boolean} flipX - Mirror horizontally.
|
|
24
|
-
* @param {boolean} flipY - Mirror vertically.
|
|
25
|
-
*/
|
|
26
27
|
const map = (idx, uX, uY, uW, uH, flipX = false, flipY = false) => {
|
|
27
|
-
const uv = getUV(uX, uY, uW, uH);
|
|
28
|
+
const uv = getUV(uX, uY, uW, uH, imgW, imgH);
|
|
28
29
|
const i = idx * 4;
|
|
29
30
|
|
|
30
|
-
// Handle flipping
|
|
31
31
|
const u0 = flipX ? uv.u1 : uv.u0;
|
|
32
32
|
const u1 = flipX ? uv.u0 : uv.u1;
|
|
33
33
|
const v0 = flipY ? uv.v1 : uv.v0;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursively disposes of a Three.js object and its children.
|
|
3
|
+
* Frees memory for Geometries, Materials, and Textures.
|
|
4
|
+
* @param {THREE.Object3D} object - The object to clean up.
|
|
5
|
+
*/
|
|
6
|
+
export function disposeObjectTree(object) {
|
|
7
|
+
if (!object) return;
|
|
8
|
+
|
|
9
|
+
object.traverse((child) => {
|
|
10
|
+
if (child.geometry) {
|
|
11
|
+
child.geometry.dispose();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (child.material) {
|
|
15
|
+
const materials = Array.isArray(child.material) ? child.material : [child.material];
|
|
16
|
+
|
|
17
|
+
materials.forEach((mat) => {
|
|
18
|
+
for (const key in mat) {
|
|
19
|
+
if (mat[key] && mat[key].isTexture) {
|
|
20
|
+
mat[key].dispose();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
mat.dispose();
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
package/src/utils/Voxelizer.js
CHANGED
|
@@ -1,58 +1,164 @@
|
|
|
1
1
|
import * as THREE from 'three';
|
|
2
|
-
|
|
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
|
-
*
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
25
|
-
{
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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.
|
|
36
|
-
for(let j=0; j<f.
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
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
|
}
|