| name | mesh-parameterization |
| description | Create UV mappings and parameterize mesh surfaces to 2D domains. Use for texture mapping, surface flattening, and geometry processing. Supports conformal, harmonic, and LSCM parameterization methods. |
Mesh Parameterization
Map 3D mesh surfaces to 2D parameter domains.
Using libigl (Python bindings)
import igl
import numpy as np
# Load mesh
v, f = igl.read_triangle_mesh("model.obj")
# Find boundary
b = igl.boundary_loop(f)
# Map boundary to circle
bc = igl.map_vertices_to_circle(v, b)
# Harmonic parameterization
uv = igl.harmonic(v, f, b, bc, 1)
# LSCM (Least Squares Conformal Maps)
# Fix two boundary points
b_fixed = np.array([b[0], b[len(b)//2]])
bc_fixed = np.array([[0, 0], [1, 0]])
_, uv = igl.lscm(v, f, b_fixed, bc_fixed)
Using PyMeshLab
import pymeshlab
ms = pymeshlab.MeshSet()
ms.load_new_mesh("model.obj")
# Trivial per-triangle parameterization
ms.compute_texcoord_by_function_per_vertex(
u="x",
v="y"
)
# LSCM parameterization
ms.compute_texcoord_parametrization_flat_plane_per_vertex()
# Atlas parameterization
ms.compute_texcoord_parametrization_and_texture_from_registered_rasters()
ms.save_current_mesh("parameterized.obj")
Using Trimesh
import trimesh
mesh = trimesh.load("model.obj")
# Simple planar projection
vertices_2d = mesh.vertices[:, :2] # Project to XY
# Normalize to [0, 1]
uv = vertices_2d - vertices_2d.min(axis=0)
uv = uv / uv.max()
# Apply UV coordinates
mesh.visual = trimesh.visual.TextureVisuals(uv=uv)
Conformal Parameterization
Preserves angles:
import igl
import numpy as np
v, f = igl.read_triangle_mesh("model.obj")
b = igl.boundary_loop(f)
bc = igl.map_vertices_to_circle(v, b)
# Conformal (minimizes angle distortion)
uv = igl.harmonic(v, f, b, bc, 1)
ABF (Angle-Based Flattening)
import pymeshlab
ms = pymeshlab.MeshSet()
ms.load_new_mesh("model.obj")
# ABF++ parameterization
ms.compute_texcoord_parametrization_abf_plus_plus()
ms.save_current_mesh("abf_parameterized.obj")
Quality Metrics
import numpy as np
def compute_distortion(v, f, uv):
"""Compute stretch distortion per face."""
distortions = []
for face in f:
# 3D triangle
p0, p1, p2 = v[face]
e1_3d = p1 - p0
e2_3d = p2 - p0
area_3d = np.linalg.norm(np.cross(e1_3d, e2_3d)) / 2
# 2D triangle
q0, q1, q2 = uv[face]
e1_2d = q1 - q0
e2_2d = q2 - q0
area_2d = abs(np.cross(e1_2d, e2_2d)) / 2
# Stretch
if area_2d > 0:
distortions.append(area_3d / area_2d)
else:
distortions.append(float('inf'))
return np.array(distortions)
Seamless Parameterization
For closed surfaces without boundary:
import igl
v, f = igl.read_triangle_mesh("closed_mesh.obj")
# Create cut to open surface
# ... (requires cutting along seams)
# Then parameterize the opened mesh