Chapter 4: Parametrization¶
import igl
import scipy as sp
import numpy as np
from meshplot import plot, subplot, interact
import os
root_folder = os.getcwd()
In computer graphics, we denote as surface parametrization a map from the surface to \(\mathbf{R}^2\). It is usually encoded by a new set of 2D coordinates for each vertex of the mesh (and possibly also by a new set of faces in one to one correspondence with the faces of the original surface). Note that this definition is the inverse of the classical differential geometry definition.
A parametrization has many applications, ranging from texture mapping to surface remeshing. Many algorithms have been proposed, and they can be broadly divided in four families:
-
Single patch, fixed boundary: these algorithm can parametrize a disk-like part of the surface given fixed 2D positions for its boundary. These algorithms are efficient and simple, but they usually produce high-distortion maps due to the fixed boundary.
-
Single patch, free boundary: these algorithms let the boundary deform freely, greatly reducing the map distortion. Care should be taken to prevent the border to self-intersect.
-
Global parametrization: these algorithms work on meshes with arbitrary genus. They initially cut the mesh in multiple patches that can be separately parametrized. The generated maps are discontinuous on the cuts (often referred as seams).
-
Global seamless parametrization: these are global parametrization algorithm that hides the seams, making the parametrization “continuous”, under specific assumptions that we will discuss later.
Harmonic parametrization¶
Harmonic parametrization (Eck, 2005) is a single patch, fixed boundary parametrization algorithm that computes the 2D coordinates of the flattened mesh as two harmonic functions.
The algorithm is divided in 3 steps:
- Detection of the boundary vertices
- Map the boundary vertices to a circle
- Compute two harmonic functions (one for u and one for the v coordinate). The harmonic functions use the fixed vertices on the circle as boundary constraints.
The algorithm is coded with libigl in the following example. bnd
contains the indices of the boundary vertices, bnd_uv their position on the UV plane, and “1” denotes that we want to compute an harmonic function (2 will be for biharmonic, 3 for triharmonic, etc.). Note that each of the three
functions is designed to be reusable in other parametrization algorithms.
The UV coordinates are then used to apply a procedural checkerboard texture to the mesh.
v, f = igl.read_triangle_mesh(os.path.join(root_folder, "data", "camelhead.off"))
## Find the open boundary
bnd = igl.boundary_loop(f)
## Map the boundary to a circle, preserving edge proportions
bnd_uv = igl.map_vertices_to_circle(v, bnd)
## Harmonic parametrization for the internal vertices
uv = igl.harmonic(v, f, bnd, bnd_uv, 1)
v_p = np.hstack([uv, np.zeros((uv.shape[0],1))])
p = subplot(v, f, uv=uv, shading={"wireframe": False, "flat": False}, s=[1, 2, 0])
subplot(v_p, f, uv=uv, shading={"wireframe": True, "flat": False}, s=[1, 2, 1], data=p)
# @interact(mode=['3D','2D'])
# def switch(mode):
# if mode == "3D":
# plot(v, f, uv=uv, shading={"wireframe": False, "flat": False}, plot=p)
# if mode == "2D":
# plot(v_p, f, uv=uv, shading={"wireframe": True, "flat": False}, plot=p)