@triforge/uv-core 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.
Files changed (53) hide show
  1. package/dist/core/BaseUnwrapper.d.ts +24 -0
  2. package/dist/core/BaseUnwrapper.d.ts.map +1 -0
  3. package/dist/core/BaseUnwrapper.js +16 -0
  4. package/dist/core/BaseUnwrapper.js.map +1 -0
  5. package/dist/index.d.ts +19 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +15 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/operations/AverageIslandScale.d.ts +15 -0
  10. package/dist/operations/AverageIslandScale.d.ts.map +1 -0
  11. package/dist/operations/AverageIslandScale.js +109 -0
  12. package/dist/operations/AverageIslandScale.js.map +1 -0
  13. package/dist/operations/MarkSeams.d.ts +34 -0
  14. package/dist/operations/MarkSeams.d.ts.map +1 -0
  15. package/dist/operations/MarkSeams.js +41 -0
  16. package/dist/operations/MarkSeams.js.map +1 -0
  17. package/dist/operations/PackIslands.d.ts +22 -0
  18. package/dist/operations/PackIslands.d.ts.map +1 -0
  19. package/dist/operations/PackIslands.js +129 -0
  20. package/dist/operations/PackIslands.js.map +1 -0
  21. package/dist/unwrappers/AngleBasedABF.d.ts +30 -0
  22. package/dist/unwrappers/AngleBasedABF.d.ts.map +1 -0
  23. package/dist/unwrappers/AngleBasedABF.js +162 -0
  24. package/dist/unwrappers/AngleBasedABF.js.map +1 -0
  25. package/dist/unwrappers/ConformalLSCM.d.ts +29 -0
  26. package/dist/unwrappers/ConformalLSCM.d.ts.map +1 -0
  27. package/dist/unwrappers/ConformalLSCM.js +165 -0
  28. package/dist/unwrappers/ConformalLSCM.js.map +1 -0
  29. package/dist/unwrappers/CubeProjection.d.ts +22 -0
  30. package/dist/unwrappers/CubeProjection.d.ts.map +1 -0
  31. package/dist/unwrappers/CubeProjection.js +57 -0
  32. package/dist/unwrappers/CubeProjection.js.map +1 -0
  33. package/dist/unwrappers/CylinderProjection.d.ts +25 -0
  34. package/dist/unwrappers/CylinderProjection.d.ts.map +1 -0
  35. package/dist/unwrappers/CylinderProjection.js +50 -0
  36. package/dist/unwrappers/CylinderProjection.js.map +1 -0
  37. package/dist/unwrappers/SmartUVProject.d.ts +30 -0
  38. package/dist/unwrappers/SmartUVProject.d.ts.map +1 -0
  39. package/dist/unwrappers/SmartUVProject.js +212 -0
  40. package/dist/unwrappers/SmartUVProject.js.map +1 -0
  41. package/dist/unwrappers/SphereProjection.d.ts +24 -0
  42. package/dist/unwrappers/SphereProjection.d.ts.map +1 -0
  43. package/dist/unwrappers/SphereProjection.js +40 -0
  44. package/dist/unwrappers/SphereProjection.js.map +1 -0
  45. package/dist/utils/linearSolver.d.ts +19 -0
  46. package/dist/utils/linearSolver.d.ts.map +1 -0
  47. package/dist/utils/linearSolver.js +73 -0
  48. package/dist/utils/linearSolver.js.map +1 -0
  49. package/dist/utils/meshGraph.d.ts +71 -0
  50. package/dist/utils/meshGraph.d.ts.map +1 -0
  51. package/dist/utils/meshGraph.js +315 -0
  52. package/dist/utils/meshGraph.js.map +1 -0
  53. package/package.json +45 -0
@@ -0,0 +1,24 @@
1
+ import type { BufferGeometry } from 'three';
2
+ /**
3
+ * Abstract base for all UV unwrappers.
4
+ * Mirrors Blender's UV unwrap operations: non-destructive, parameterized.
5
+ *
6
+ * Every unwrapper:
7
+ * - Takes a BufferGeometry in, returns a new BufferGeometry with updated UV attribute
8
+ * - Never mutates the input geometry
9
+ * - Exposes a plain `parameters` object for GSAP/keyframe compatibility
10
+ */
11
+ export declare abstract class BaseUnwrapper {
12
+ /** When false, apply() returns a clone of the input with no UV changes. */
13
+ enabled: boolean;
14
+ /** All scalar inputs as plain numbers. GSAP-compatible. */
15
+ abstract parameters: Record<string, number>;
16
+ /** Human-readable name matching Blender's operation name. */
17
+ abstract readonly unwrapType: string;
18
+ /**
19
+ * Apply this unwrapper to the input geometry.
20
+ * NEVER mutates the input — always returns a new BufferGeometry.
21
+ */
22
+ abstract apply(geometry: BufferGeometry): BufferGeometry;
23
+ }
24
+ //# sourceMappingURL=BaseUnwrapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseUnwrapper.d.ts","sourceRoot":"","sources":["../../src/core/BaseUnwrapper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAE3C;;;;;;;;GAQG;AACH,8BAAsB,aAAa;IACjC,2EAA2E;IAC3E,OAAO,UAAO;IAEd,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAE3C,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAEpC;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,cAAc,GAAG,cAAc;CACzD"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Abstract base for all UV unwrappers.
3
+ * Mirrors Blender's UV unwrap operations: non-destructive, parameterized.
4
+ *
5
+ * Every unwrapper:
6
+ * - Takes a BufferGeometry in, returns a new BufferGeometry with updated UV attribute
7
+ * - Never mutates the input geometry
8
+ * - Exposes a plain `parameters` object for GSAP/keyframe compatibility
9
+ */
10
+ export class BaseUnwrapper {
11
+ constructor() {
12
+ /** When false, apply() returns a clone of the input with no UV changes. */
13
+ this.enabled = true;
14
+ }
15
+ }
16
+ //# sourceMappingURL=BaseUnwrapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BaseUnwrapper.js","sourceRoot":"","sources":["../../src/core/BaseUnwrapper.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,MAAM,OAAgB,aAAa;IAAnC;QACE,2EAA2E;QAC3E,YAAO,GAAG,IAAI,CAAA;IAahB,CAAC;CAAA"}
@@ -0,0 +1,19 @@
1
+ export { BaseUnwrapper } from './core/BaseUnwrapper.js';
2
+ export { CubeProjection } from './unwrappers/CubeProjection.js';
3
+ export { CylinderProjection } from './unwrappers/CylinderProjection.js';
4
+ export { SphereProjection } from './unwrappers/SphereProjection.js';
5
+ export { SmartUVProject } from './unwrappers/SmartUVProject.js';
6
+ export { ConformalLSCM } from './unwrappers/ConformalLSCM.js';
7
+ export { AngleBasedABF } from './unwrappers/AngleBasedABF.js';
8
+ export { PackIslands } from './operations/PackIslands.js';
9
+ export { AverageIslandScale } from './operations/AverageIslandScale.js';
10
+ export { MarkSeams } from './operations/MarkSeams.js';
11
+ export type { CubeProjectionOptions } from './unwrappers/CubeProjection.js';
12
+ export type { CylinderProjectionOptions } from './unwrappers/CylinderProjection.js';
13
+ export type { SphereProjectionOptions } from './unwrappers/SphereProjection.js';
14
+ export type { SmartUVProjectOptions } from './unwrappers/SmartUVProject.js';
15
+ export type { ConformalLSCMOptions } from './unwrappers/ConformalLSCM.js';
16
+ export type { AngleBasedABFOptions } from './unwrappers/AngleBasedABF.js';
17
+ export type { PackIslandsOptions } from './operations/PackIslands.js';
18
+ export type { SeamEdge } from './operations/MarkSeams.js';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAGvD,OAAO,EAAE,cAAc,EAAE,MAAU,gCAAgC,CAAA;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAA;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAQ,kCAAkC,CAAA;AACrE,OAAO,EAAE,cAAc,EAAE,MAAU,gCAAgC,CAAA;AAGnE,OAAO,EAAE,aAAa,EAAE,MAAO,+BAA+B,CAAA;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAO,+BAA+B,CAAA;AAG9D,OAAO,EAAE,WAAW,EAAE,MAAa,6BAA6B,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAA;AACvE,OAAO,EAAE,SAAS,EAAE,MAAe,2BAA2B,CAAA;AAG9D,YAAY,EAAE,qBAAqB,EAAE,MAAU,gCAAgC,CAAA;AAC/E,YAAY,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAA;AACnF,YAAY,EAAE,uBAAuB,EAAE,MAAQ,kCAAkC,CAAA;AACjF,YAAY,EAAE,qBAAqB,EAAE,MAAU,gCAAgC,CAAA;AAC/E,YAAY,EAAE,oBAAoB,EAAE,MAAW,+BAA+B,CAAA;AAC9E,YAAY,EAAE,oBAAoB,EAAE,MAAW,+BAA+B,CAAA;AAC9E,YAAY,EAAE,kBAAkB,EAAE,MAAa,6BAA6B,CAAA;AAC5E,YAAY,EAAE,QAAQ,EAAE,MAAuB,2BAA2B,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ // ── Core ──────────────────────────────────────────────────────────────────────
2
+ export { BaseUnwrapper } from './core/BaseUnwrapper.js';
3
+ // ── Projection unwrappers ─────────────────────────────────────────────────────
4
+ export { CubeProjection } from './unwrappers/CubeProjection.js';
5
+ export { CylinderProjection } from './unwrappers/CylinderProjection.js';
6
+ export { SphereProjection } from './unwrappers/SphereProjection.js';
7
+ export { SmartUVProject } from './unwrappers/SmartUVProject.js';
8
+ // ── Parametric unwrappers ─────────────────────────────────────────────────────
9
+ export { ConformalLSCM } from './unwrappers/ConformalLSCM.js';
10
+ export { AngleBasedABF } from './unwrappers/AngleBasedABF.js';
11
+ // ── UV operations ─────────────────────────────────────────────────────────────
12
+ export { PackIslands } from './operations/PackIslands.js';
13
+ export { AverageIslandScale } from './operations/AverageIslandScale.js';
14
+ export { MarkSeams } from './operations/MarkSeams.js';
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAEvD,iFAAiF;AACjF,OAAO,EAAE,cAAc,EAAE,MAAU,gCAAgC,CAAA;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAA;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAQ,kCAAkC,CAAA;AACrE,OAAO,EAAE,cAAc,EAAE,MAAU,gCAAgC,CAAA;AAEnE,iFAAiF;AACjF,OAAO,EAAE,aAAa,EAAE,MAAO,+BAA+B,CAAA;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAO,+BAA+B,CAAA;AAE9D,iFAAiF;AACjF,OAAO,EAAE,WAAW,EAAE,MAAa,6BAA6B,CAAA;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAA;AACvE,OAAO,EAAE,SAAS,EAAE,MAAe,2BAA2B,CAAA"}
@@ -0,0 +1,15 @@
1
+ import { BufferGeometry } from 'three';
2
+ /**
3
+ * AverageIslandScale — Blender UV: Average Island Scale
4
+ *
5
+ * Scales UV islands so every island has the same texel density.
6
+ * Ratio = sqrt(3D area / UV area) per island.
7
+ * After this operation all islands have a uniform texel-per-unit ratio.
8
+ *
9
+ * Non-destructive: always returns a new BufferGeometry.
10
+ */
11
+ export declare class AverageIslandScale {
12
+ parameters: Record<string, number>;
13
+ apply(geometry: BufferGeometry): BufferGeometry;
14
+ }
15
+ //# sourceMappingURL=AverageIslandScale.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AverageIslandScale.d.ts","sourceRoot":"","sources":["../../src/operations/AverageIslandScale.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAmB,MAAM,OAAO,CAAA;AAEvD;;;;;;;;GAQG;AACH,qBAAa,kBAAkB;IAC7B,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAK;IAEvC,KAAK,CAAC,QAAQ,EAAE,cAAc,GAAG,cAAc;CA0GhD"}
@@ -0,0 +1,109 @@
1
+ import { BufferAttribute } from 'three';
2
+ /**
3
+ * AverageIslandScale — Blender UV: Average Island Scale
4
+ *
5
+ * Scales UV islands so every island has the same texel density.
6
+ * Ratio = sqrt(3D area / UV area) per island.
7
+ * After this operation all islands have a uniform texel-per-unit ratio.
8
+ *
9
+ * Non-destructive: always returns a new BufferGeometry.
10
+ */
11
+ export class AverageIslandScale {
12
+ constructor() {
13
+ this.parameters = {};
14
+ }
15
+ apply(geometry) {
16
+ const result = geometry.clone();
17
+ const uvAttr = result.getAttribute('uv');
18
+ if (!uvAttr)
19
+ return result;
20
+ const posAttr = result.getAttribute('position');
21
+ const count = uvAttr.count;
22
+ const numTris = result.index ? result.index.count / 3 : Math.floor(count / 3);
23
+ const getIdx = (t, v) => result.index ? result.index.array[t * 3 + v] : t * 3 + v;
24
+ // Build UV island adjacency
25
+ const adj = Array.from({ length: count }, () => new Set());
26
+ for (let t = 0; t < numTris; t++) {
27
+ const i = getIdx(t, 0), j = getIdx(t, 1), k = getIdx(t, 2);
28
+ adj[i].add(j);
29
+ adj[i].add(k);
30
+ adj[j].add(i);
31
+ adj[j].add(k);
32
+ adj[k].add(i);
33
+ adj[k].add(j);
34
+ }
35
+ const visited = new Uint8Array(count);
36
+ const islands = [];
37
+ for (let start = 0; start < count; start++) {
38
+ if (visited[start])
39
+ continue;
40
+ const island = [];
41
+ const queue = [start];
42
+ visited[start] = 1;
43
+ while (queue.length) {
44
+ const v = queue.shift();
45
+ island.push(v);
46
+ for (const n of adj[v]) {
47
+ if (!visited[n]) {
48
+ visited[n] = 1;
49
+ queue.push(n);
50
+ }
51
+ }
52
+ }
53
+ islands.push(island);
54
+ }
55
+ // Compute texel density ratio per island
56
+ const vertSet = new Set();
57
+ const densities = islands.map(verts => {
58
+ vertSet.clear();
59
+ for (const v of verts)
60
+ vertSet.add(v);
61
+ let area3D = 0, uvArea = 0;
62
+ let sumU = 0, sumV = 0;
63
+ for (let t = 0; t < numTris; t++) {
64
+ const i = getIdx(t, 0), j = getIdx(t, 1), k = getIdx(t, 2);
65
+ if (!vertSet.has(i) && !vertSet.has(j) && !vertSet.has(k))
66
+ continue;
67
+ // 3D area
68
+ const ax = posAttr.getX(i), ay = posAttr.getY(i), az = posAttr.getZ(i);
69
+ const bx = posAttr.getX(j), by = posAttr.getY(j), bz = posAttr.getZ(j);
70
+ const cx = posAttr.getX(k), cy = posAttr.getY(k), cz = posAttr.getZ(k);
71
+ const ex = bx - ax, ey = by - ay, ez = bz - az;
72
+ const fx = cx - ax, fy = cy - ay, fz = cz - az;
73
+ const crx = ey * fz - ez * fy, cry = ez * fx - ex * fz, crz = ex * fy - ey * fx;
74
+ area3D += 0.5 * Math.sqrt(crx * crx + cry * cry + crz * crz);
75
+ // UV area
76
+ const ui = uvAttr.getX(i), vi2 = uvAttr.getY(i);
77
+ const uj = uvAttr.getX(j), vj = uvAttr.getY(j);
78
+ const uk = uvAttr.getX(k), vk = uvAttr.getY(k);
79
+ uvArea += Math.abs((uj - ui) * (vk - vi2) - (uk - ui) * (vj - vi2)) * 0.5;
80
+ }
81
+ for (const v of verts) {
82
+ sumU += uvAttr.getX(v);
83
+ sumV += uvAttr.getY(v);
84
+ }
85
+ const ratio = uvArea > 1e-12 ? Math.sqrt(area3D / uvArea) : 1;
86
+ return {
87
+ verts,
88
+ ratio,
89
+ centerU: sumU / verts.length,
90
+ centerV: sumV / verts.length,
91
+ };
92
+ });
93
+ // Compute median ratio so all islands converge to the same density
94
+ const ratios = densities.map(d => d.ratio).sort((a, b) => a - b);
95
+ const medianRatio = ratios[Math.floor(ratios.length / 2)] || 1;
96
+ // Scale each island around its UV center
97
+ const newUV = new Float32Array(uvAttr.array);
98
+ for (const d of densities) {
99
+ const scale = d.ratio / medianRatio;
100
+ for (const v of d.verts) {
101
+ newUV[v * 2] = d.centerU + (uvAttr.getX(v) - d.centerU) * scale;
102
+ newUV[v * 2 + 1] = d.centerV + (uvAttr.getY(v) - d.centerV) * scale;
103
+ }
104
+ }
105
+ result.setAttribute('uv', new BufferAttribute(newUV, 2));
106
+ return result;
107
+ }
108
+ }
109
+ //# sourceMappingURL=AverageIslandScale.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AverageIslandScale.js","sourceRoot":"","sources":["../../src/operations/AverageIslandScale.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { BufferGeometry } from 'three';
2
+ export interface SeamEdge {
3
+ /** Index of first vertex of the seam edge. */
4
+ a: number;
5
+ /** Index of second vertex of the seam edge. */
6
+ b: number;
7
+ }
8
+ /**
9
+ * MarkSeams — Blender UV: Mark Seam
10
+ *
11
+ * Stores seam edges in geometry.userData.seams.
12
+ * Seams are used by ConformalLSCM and AngleBasedABF to cut the mesh
13
+ * into disc-topology patches before unwrapping.
14
+ *
15
+ * Non-destructive: returns a clone of the geometry with updated userData.
16
+ */
17
+ export declare class MarkSeams {
18
+ parameters: Record<string, number>;
19
+ /**
20
+ * Mark edges as seams on the geometry.
21
+ * @param geometry Source geometry
22
+ * @param edges Array of vertex-index pairs defining seam edges
23
+ */
24
+ apply(geometry: BufferGeometry, edges: SeamEdge[]): BufferGeometry;
25
+ /**
26
+ * Clear all seam markings from geometry.
27
+ */
28
+ clear(geometry: BufferGeometry): BufferGeometry;
29
+ /**
30
+ * Retrieve seam edges stored on a geometry (or empty array if none).
31
+ */
32
+ static getSeams(geometry: BufferGeometry): SeamEdge[];
33
+ }
34
+ //# sourceMappingURL=MarkSeams.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkSeams.d.ts","sourceRoot":"","sources":["../../src/operations/MarkSeams.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AAEtC,MAAM,WAAW,QAAQ;IACvB,8CAA8C;IAC9C,CAAC,EAAE,MAAM,CAAA;IACT,+CAA+C;IAC/C,CAAC,EAAE,MAAM,CAAA;CACV;AAED;;;;;;;;GAQG;AACH,qBAAa,SAAS;IACpB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAK;IAEvC;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,cAAc;IAMlE;;OAEG;IACH,KAAK,CAAC,QAAQ,EAAE,cAAc,GAAG,cAAc;IAQ/C;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,EAAE;CAGtD"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * MarkSeams — Blender UV: Mark Seam
3
+ *
4
+ * Stores seam edges in geometry.userData.seams.
5
+ * Seams are used by ConformalLSCM and AngleBasedABF to cut the mesh
6
+ * into disc-topology patches before unwrapping.
7
+ *
8
+ * Non-destructive: returns a clone of the geometry with updated userData.
9
+ */
10
+ export class MarkSeams {
11
+ constructor() {
12
+ this.parameters = {};
13
+ }
14
+ /**
15
+ * Mark edges as seams on the geometry.
16
+ * @param geometry Source geometry
17
+ * @param edges Array of vertex-index pairs defining seam edges
18
+ */
19
+ apply(geometry, edges) {
20
+ const result = geometry.clone();
21
+ result.userData = { ...geometry.userData, seams: edges.map(e => ({ a: e.a, b: e.b })) };
22
+ return result;
23
+ }
24
+ /**
25
+ * Clear all seam markings from geometry.
26
+ */
27
+ clear(geometry) {
28
+ const result = geometry.clone();
29
+ const ud = { ...geometry.userData };
30
+ delete ud['seams'];
31
+ result.userData = ud;
32
+ return result;
33
+ }
34
+ /**
35
+ * Retrieve seam edges stored on a geometry (or empty array if none).
36
+ */
37
+ static getSeams(geometry) {
38
+ return geometry.userData['seams'] ?? [];
39
+ }
40
+ }
41
+ //# sourceMappingURL=MarkSeams.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkSeams.js","sourceRoot":"","sources":["../../src/operations/MarkSeams.ts"],"names":[],"mappings":"AASA;;;;;;;;GAQG;AACH,MAAM,OAAO,SAAS;IAAtB;QACE,eAAU,GAA2B,EAAE,CAAA;IA8BzC,CAAC;IA5BC;;;;OAIG;IACH,KAAK,CAAC,QAAwB,EAAE,KAAiB;QAC/C,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAA;QAC/B,MAAM,CAAC,QAAQ,GAAG,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAA;QACvF,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAwB;QAC5B,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,EAAE,CAAA;QAC/B,MAAM,EAAE,GAAG,EAAE,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAA;QACnC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAA;QAClB,MAAM,CAAC,QAAQ,GAAG,EAAE,CAAA;QACpB,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,QAAwB;QACtC,OAAQ,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAA4B,IAAI,EAAE,CAAA;IACrE,CAAC;CACF"}
@@ -0,0 +1,22 @@
1
+ import { BufferGeometry } from 'three';
2
+ export interface PackIslandsOptions {
3
+ /** Margin between islands [0–0.1]. Default 0.02. Blender: Pack Islands → Margin */
4
+ margin?: number;
5
+ }
6
+ /**
7
+ * PackIslands — Blender UV: Pack Islands
8
+ *
9
+ * Re-packs all UV islands into the [0,1]² space with minimal wasted area.
10
+ * Extracts connected UV islands, normalises their size to preserve relative
11
+ * 3D area, then shelves them into the UV square.
12
+ *
13
+ * Non-destructive: always returns a new BufferGeometry.
14
+ */
15
+ export declare class PackIslands {
16
+ parameters: {
17
+ margin: number;
18
+ };
19
+ constructor(opts?: PackIslandsOptions);
20
+ apply(geometry: BufferGeometry): BufferGeometry;
21
+ }
22
+ //# sourceMappingURL=PackIslands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PackIslands.d.ts","sourceRoot":"","sources":["../../src/operations/PackIslands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAmB,MAAM,OAAO,CAAA;AAEvD,MAAM,WAAW,kBAAkB;IACjC,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;GAQG;AACH,qBAAa,WAAW;IACtB,UAAU,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;gBAElB,IAAI,GAAE,kBAAuB;IAIzC,KAAK,CAAC,QAAQ,EAAE,cAAc,GAAG,cAAc;CA0HhD"}
@@ -0,0 +1,129 @@
1
+ import { BufferAttribute } from 'three';
2
+ /**
3
+ * PackIslands — Blender UV: Pack Islands
4
+ *
5
+ * Re-packs all UV islands into the [0,1]² space with minimal wasted area.
6
+ * Extracts connected UV islands, normalises their size to preserve relative
7
+ * 3D area, then shelves them into the UV square.
8
+ *
9
+ * Non-destructive: always returns a new BufferGeometry.
10
+ */
11
+ export class PackIslands {
12
+ constructor(opts = {}) {
13
+ this.parameters = { margin: opts.margin ?? 0.02 };
14
+ }
15
+ apply(geometry) {
16
+ const result = geometry.clone();
17
+ const uvAttr = result.getAttribute('uv');
18
+ if (!uvAttr)
19
+ return result; // no UVs to pack
20
+ const posAttr = result.getAttribute('position');
21
+ const count = uvAttr.count;
22
+ const margin = this.parameters.margin;
23
+ // Step 1: find connected UV islands
24
+ // Build vertex adjacency by triangle connectivity
25
+ const numTris = result.index ? result.index.count / 3 : Math.floor(count / 3);
26
+ const getIdx = (t, v) => result.index ? result.index.array[t * 3 + v] : t * 3 + v;
27
+ const adj = Array.from({ length: count }, () => new Set());
28
+ for (let t = 0; t < numTris; t++) {
29
+ const i = getIdx(t, 0), j = getIdx(t, 1), k = getIdx(t, 2);
30
+ adj[i].add(j);
31
+ adj[i].add(k);
32
+ adj[j].add(i);
33
+ adj[j].add(k);
34
+ adj[k].add(i);
35
+ adj[k].add(j);
36
+ }
37
+ // BFS to find islands
38
+ const visited = new Uint8Array(count);
39
+ const islands = [];
40
+ for (let start = 0; start < count; start++) {
41
+ if (visited[start])
42
+ continue;
43
+ const island = [];
44
+ const queue = [start];
45
+ visited[start] = 1;
46
+ while (queue.length) {
47
+ const v = queue.shift();
48
+ island.push(v);
49
+ for (const n of adj[v]) {
50
+ if (!visited[n]) {
51
+ visited[n] = 1;
52
+ queue.push(n);
53
+ }
54
+ }
55
+ }
56
+ islands.push(island);
57
+ }
58
+ const islandInfos = islands.map(verts => {
59
+ let uvMinU = Infinity, uvMaxU = -Infinity;
60
+ let uvMinV = Infinity, uvMaxV = -Infinity;
61
+ let area3D = 0;
62
+ for (const v of verts) {
63
+ const u = uvAttr.getX(v), uv = uvAttr.getY(v);
64
+ if (u < uvMinU)
65
+ uvMinU = u;
66
+ if (u > uvMaxU)
67
+ uvMaxU = u;
68
+ if (uv < uvMinV)
69
+ uvMinV = uv;
70
+ if (uv > uvMaxV)
71
+ uvMaxV = uv;
72
+ }
73
+ // Approximate 3D area for this island by summing incident triangle areas
74
+ const vertSet = new Set(verts);
75
+ for (let t = 0; t < numTris; t++) {
76
+ const i = getIdx(t, 0), j = getIdx(t, 1), k = getIdx(t, 2);
77
+ if (!vertSet.has(i) && !vertSet.has(j) && !vertSet.has(k))
78
+ continue;
79
+ const ax = posAttr.getX(i), ay = posAttr.getY(i), az = posAttr.getZ(i);
80
+ const bx = posAttr.getX(j), by = posAttr.getY(j), bz = posAttr.getZ(j);
81
+ const cx = posAttr.getX(k), cy = posAttr.getY(k), cz = posAttr.getZ(k);
82
+ const ex = bx - ax, ey = by - ay, ez = bz - az;
83
+ const fx = cx - ax, fy = cy - ay, fz = cz - az;
84
+ const crx = ey * fz - ez * fy, cry = ez * fx - ex * fz, crz = ex * fy - ey * fx;
85
+ area3D += 0.5 * Math.sqrt(crx * crx + cry * cry + crz * crz);
86
+ }
87
+ return { verts, uvMinU, uvMaxU, uvMinV, uvMaxV, area3D };
88
+ });
89
+ // Step 3: scale each island proportional to sqrt(area3D)
90
+ const totalArea = islandInfos.reduce((s, ii) => s + ii.area3D, 0) || 1;
91
+ const rects = islandInfos.map((ii, idx) => {
92
+ const scale = Math.sqrt(ii.area3D / totalArea);
93
+ const w = (ii.uvMaxU - ii.uvMinU) * scale || 0.01;
94
+ const h = (ii.uvMaxV - ii.uvMinV) * scale || 0.01;
95
+ return { x: 0, y: 0, w, h, islandIdx: idx };
96
+ });
97
+ // Step 4: shelf pack
98
+ rects.sort((a, b) => b.h - a.h);
99
+ let curX = 0, curY = 0, rowH = 0;
100
+ for (const rect of rects) {
101
+ if (curX + rect.w + margin > 1.0) {
102
+ curX = 0;
103
+ curY += rowH + margin;
104
+ rowH = 0;
105
+ }
106
+ rect.x = curX;
107
+ rect.y = curY;
108
+ if (rect.h > rowH)
109
+ rowH = rect.h;
110
+ curX += rect.w + margin;
111
+ }
112
+ // Step 5: remap UV coordinates
113
+ const newUV = new Float32Array(count * 2);
114
+ for (let ri = 0; ri < rects.length; ri++) {
115
+ const rect = rects[ri];
116
+ const ii = islandInfos[rect.islandIdx];
117
+ const pW = ii.uvMaxU - ii.uvMinU || 1;
118
+ const pH = ii.uvMaxV - ii.uvMinV || 1;
119
+ for (const v of ii.verts) {
120
+ const oldU = uvAttr.getX(v), oldV = uvAttr.getY(v);
121
+ newUV[v * 2] = rect.x + ((oldU - ii.uvMinU) / pW) * rect.w;
122
+ newUV[v * 2 + 1] = rect.y + ((oldV - ii.uvMinV) / pH) * rect.h;
123
+ }
124
+ }
125
+ result.setAttribute('uv', new BufferAttribute(newUV, 2));
126
+ return result;
127
+ }
128
+ }
129
+ //# sourceMappingURL=PackIslands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PackIslands.js","sourceRoot":"","sources":["../../src/operations/PackIslands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { BufferGeometry } from 'three';
2
+ import { BaseUnwrapper } from '../core/BaseUnwrapper.js';
3
+ export interface AngleBasedABFOptions {
4
+ /** Maximum solver iterations. Default 400. */
5
+ maxIterations?: number;
6
+ /** Solver convergence tolerance. Default 1e-6. */
7
+ tolerance?: number;
8
+ }
9
+ /**
10
+ * AngleBasedABF — Blender UV: Unwrap (Angle Based)
11
+ *
12
+ * Angle-Based Flattening approximation using mean-value coordinates.
13
+ * Minimises angle distortion better than LSCM for meshes with obtuse triangles.
14
+ * Uses mean-value weights instead of cotangent weights — always positive,
15
+ * so it handles obtuse triangles without negative weights.
16
+ *
17
+ * Works best on meshes with a natural boundary (disc topology).
18
+ * For closed meshes, a seam is automatically inserted between the two
19
+ * farthest-apart vertices.
20
+ */
21
+ export declare class AngleBasedABF extends BaseUnwrapper {
22
+ readonly unwrapType = "AngleBasedABF";
23
+ parameters: {
24
+ maxIterations: number;
25
+ tolerance: number;
26
+ };
27
+ constructor(opts?: AngleBasedABFOptions);
28
+ apply(geometry: BufferGeometry): BufferGeometry;
29
+ }
30
+ //# sourceMappingURL=AngleBasedABF.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AngleBasedABF.d.ts","sourceRoot":"","sources":["../../src/unwrappers/AngleBasedABF.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAOxD,MAAM,WAAW,oBAAoB;IACnC,8CAA8C;IAC9C,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,aAAc,SAAQ,aAAa;IAC9C,QAAQ,CAAC,UAAU,mBAAkB;IACrC,UAAU,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;gBAE5C,IAAI,GAAE,oBAAyB;IAQ3C,KAAK,CAAC,QAAQ,EAAE,cAAc,GAAG,cAAc;CAwIhD"}