@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.
- package/dist/core/BaseUnwrapper.d.ts +24 -0
- package/dist/core/BaseUnwrapper.d.ts.map +1 -0
- package/dist/core/BaseUnwrapper.js +16 -0
- package/dist/core/BaseUnwrapper.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/operations/AverageIslandScale.d.ts +15 -0
- package/dist/operations/AverageIslandScale.d.ts.map +1 -0
- package/dist/operations/AverageIslandScale.js +109 -0
- package/dist/operations/AverageIslandScale.js.map +1 -0
- package/dist/operations/MarkSeams.d.ts +34 -0
- package/dist/operations/MarkSeams.d.ts.map +1 -0
- package/dist/operations/MarkSeams.js +41 -0
- package/dist/operations/MarkSeams.js.map +1 -0
- package/dist/operations/PackIslands.d.ts +22 -0
- package/dist/operations/PackIslands.d.ts.map +1 -0
- package/dist/operations/PackIslands.js +129 -0
- package/dist/operations/PackIslands.js.map +1 -0
- package/dist/unwrappers/AngleBasedABF.d.ts +30 -0
- package/dist/unwrappers/AngleBasedABF.d.ts.map +1 -0
- package/dist/unwrappers/AngleBasedABF.js +162 -0
- package/dist/unwrappers/AngleBasedABF.js.map +1 -0
- package/dist/unwrappers/ConformalLSCM.d.ts +29 -0
- package/dist/unwrappers/ConformalLSCM.d.ts.map +1 -0
- package/dist/unwrappers/ConformalLSCM.js +165 -0
- package/dist/unwrappers/ConformalLSCM.js.map +1 -0
- package/dist/unwrappers/CubeProjection.d.ts +22 -0
- package/dist/unwrappers/CubeProjection.d.ts.map +1 -0
- package/dist/unwrappers/CubeProjection.js +57 -0
- package/dist/unwrappers/CubeProjection.js.map +1 -0
- package/dist/unwrappers/CylinderProjection.d.ts +25 -0
- package/dist/unwrappers/CylinderProjection.d.ts.map +1 -0
- package/dist/unwrappers/CylinderProjection.js +50 -0
- package/dist/unwrappers/CylinderProjection.js.map +1 -0
- package/dist/unwrappers/SmartUVProject.d.ts +30 -0
- package/dist/unwrappers/SmartUVProject.d.ts.map +1 -0
- package/dist/unwrappers/SmartUVProject.js +212 -0
- package/dist/unwrappers/SmartUVProject.js.map +1 -0
- package/dist/unwrappers/SphereProjection.d.ts +24 -0
- package/dist/unwrappers/SphereProjection.d.ts.map +1 -0
- package/dist/unwrappers/SphereProjection.js +40 -0
- package/dist/unwrappers/SphereProjection.js.map +1 -0
- package/dist/utils/linearSolver.d.ts +19 -0
- package/dist/utils/linearSolver.d.ts.map +1 -0
- package/dist/utils/linearSolver.js +73 -0
- package/dist/utils/linearSolver.js.map +1 -0
- package/dist/utils/meshGraph.d.ts +71 -0
- package/dist/utils/meshGraph.d.ts.map +1 -0
- package/dist/utils/meshGraph.js +315 -0
- package/dist/utils/meshGraph.js.map +1 -0
- 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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|