Initializing 3D Canvas...

Harmonic & Conformal UV

3 min read•1 page

Tutte's Invariant:

1. Convex Boundary Condition: Outer mesh boundary pinned along a convex polygon (e.g. circle). 2. Harmonic Mean Value: Every internal UV coordinate equals the average of its 1-ring neighbors. 3. Zero Triangle Inversion: Determinant of every triangle's Jacobian remains strictly positive.
python
1import numpy as np
2
3def tutte_barycentric_mapping(boundary_indices, boundary_uvs, adjacency_list):
4 """
5 Tutte's Spring Embedding Theorem (1963).
6 Maps 3D mesh boundary to a convex 2D polygon (e.g. circle or square).
7 Interior vertices satisfy harmonic equilibrium:
8 u_i = (1 / d_i) * sum_{j in N(i)} u_j.
9 Guarantees a strictly bijective, flip-free, 1-to-1 planar embedding.
10 """
11 n = len(adjacency_list)
12 A = np.zeros((n, n))
13 bx = np.zeros(n)
14 by = np.zeros(n)
15
16 for i in range(n):
17 if i in boundary_indices:
18 A[i, i] = 1.0
19 idx = boundary_indices.index(i)
20 bx[i] = boundary_uvs[idx][0]
21 by[i] = boundary_uvs[idx][1]
22 else:
23 deg = len(adjacency_list[i])
24 A[i, i] = 1.0
25 for j in adjacency_list[i]:
26 A[i, j] = -1.0 / deg
27
28 u = np.linalg.solve(A, bx)
29 v = np.linalg.solve(A, by)
30 return list(zip(u, v))

Tutte's Barycentric Mapping (Harmonic Spring Embedding): Unwrapping a double-curved 3D mesh onto flat 2D UV texture space easily causes triangles to overlap or invert. In 1963, W. T. Tutte proved a foundational mathematical theorem: if the boundary of a 3-connected planar graph is mapped to the vertices of a strictly convex 2D polygon, and every internal vertex is placed at the weighted centroid of its neighbors (spring equilibrium), the resulting 2D parameterization is guaranteed to be 100% bijective and flip-free.

0=3D Hemispherical Mesh, 1=2D Tutte UV
1.00
5 min read•2 pages

LSCM Conformal Invariant:

1. Cauchy-Riemann Energy: Minimizes gradient mismatch ∇ u - J ∇ v = 0 where J is 90° rotation. 2. Free Boundary Relaxation: Boundary is free to assume its natural shape with only two pinned vertices. 3. Zero Angular Shearing: Texture grid squares remain strictly orthogonal and undistorted.
python
1import numpy as np
2
3def solve_lscm_uv(triangles, vertices, uv_coords):
4 """
5 Evaluates Least Squares Conformal Maps (LSCM, Levy et al. 2002) energy across a 3D mesh:
6 E_LSCM = sum_T 0.5 * Area(T) * || grad(u) - J * grad(v) ||^2
7 where J = [[0, -1], [1, 0]] rotates the 2D gradient by 90 degrees (Cauchy-Riemann check).
8 """
9 J = np.array([[0.0, -1.0], [1.0, 0.0]])
10 total_conformal_energy = 0.0
11
12 for i0, i1, i2 in triangles:
13 p0, p1, p2 = [np.asarray(vertices[k], dtype=float) for k in (i0, i1, i2)]
14 uv0, uv1, uv2 = [np.asarray(uv_coords[k], dtype=float) for k in (i0, i1, i2)]
15
16 # Local orthonormal 2D basis (e1, e2) in the 3D triangle plane
17 e1 = p1 - p0
18 x1 = np.linalg.norm(e1)
19 e1 /= x1
20 n = np.cross(e1, p2 - p0)
21 area = 0.5 * np.linalg.norm(n)
22 e2 = np.cross(n / np.linalg.norm(n), e1)
23 x2, y2 = np.dot(p2 - p0, e1), np.dot(p2 - p0, e2)
24
25 # Barycentric gradient vectors in local (x, y) triangle frame
26 grad_B = np.array([[y2 - 0.0, 0.0 - y2, 0.0],
27 [0.0 - x2, x2 - x1, x1]]) / (2.0 * area)
28 grad_u = grad_B @ np.array([uv0[0], uv1[0], uv2[0]])
29 grad_v = grad_B @ np.array([uv0[1], uv1[1], uv2[1]])
30 total_conformal_energy += 0.5 * area * float(np.sum((grad_u - J @ grad_v) ** 2))
31 return total_conformal_energy

Least Squares Conformal Maps (LSCM): While Tutte mapping forces boundaries into an arbitrary rigid polygon (distorting texture angles), LSCM (Lévy et al. 2002) minimizes the deviation from the Cauchy-Riemann equations. Conformal maps preserve local angles: microscopic circles on the 3D surface map to perfect 2D circles in texture space without elliptical shearing, making it the industry standard for UV texture unwrapping.

Pinned Vertex Distance
2.40

Related Concepts