# Conformal Texture Mapping

In two previous articles, I’ve explored some unusual methods of texture mapping—beyond the conventional approach of linearly interpolating UV coordinates across triangles. This post is a sort of continuation-in-spirit of that work, but I’m no longer focusing specifically on quadrilaterals.

A problem that often afflicts texture mapping on smooth, curvy models (such as characters) is distortion: in some regions, the texture may appear overly squashed, stretched, or sheared on the 3D model. A related but distinct problem is that of different regions of the model having different texel density, due to varying scale in the UV mapping. I wanted to explore these issues mathematically. Are there ways to create texture mappings that have low distortion by construction?

Ultimately, I didn’t come to an altogether satisfying resolution of this question, but I encountered plenty of interesting math along the way and I want to share some of it. This post will be on the more esoteric, less immediately-applicable side—but I hope you’ll find the topic intriguing nonetheless.

## Quantifying Texture Distortion

How can we mathematically characterize “distortion” in a texture mapping? To begin with, we should make a distinction between local and global forms of distortion. Local distortion would be visible when zooming in on a small region of the model—looking at a single triangle, or a small neighborhood around a point. Conversely, global distortion might only show up when you look at the whole model and compare texture scale and orientation across widely separated points.

Some amount of global distortion is inevitable in mapping a flat, 2D texture to a non-flat, 3D object. It’s not necessarily a problem, and it can even be useful in some cases to allow varying texel density to concentrate more texels in more-important or more-detailed parts of a model. For example, human head models usually give more texel density to the face region than to the sides, top, and back of the head.

However, local distortion is usually undesirable. It changes the shapes of features in the texture, distorts the shape of filter kernels operating in texture space, and gives unequal texel density along different axes—bad news all around.

To measure local distortion, we can look at the tangent basis implied by the UVs assigned on the mesh—the same basis we typically compute as part of the setup for normal and parallax mapping.

This basis can be computed per-triangle, and consists of the two 3D vectors within the triangle’s plane that correspond to the texture’s U and V axes—known as the tangent and bitangent vectors, respectively. (The triangle normal is usually included as a third basis vector, but we won’t need that here.) If the triangle’s vertex positions are $p_1, p_2, p_3$ and the corresponding UVs are $(u_1, v_1) \ldots (u_3, v_3)$, then the tangent and bitangent vectors $T, B$ can be defined by: $$ \begin{aligned} p_2 - p_1 &= (u_2 - u_1)T + (v_2 - v_1)B \\ p_3 - p_1 &= (u_3 - u_1)T + (v_3 - v_1)B \end{aligned} $$ These equations can be cast in matrix form, and solved as follows: $$ \begin{bmatrix} T_x & B_x \\ T_y & B_y \\ T_z & B_z \end{bmatrix} = \begin{bmatrix} (p_{2x} - p_{1x}) & (p_{3x} - p_{1x}) \\ (p_{2y} - p_{1y}) & (p_{3y} - p_{1y}) \\ (p_{2z} - p_{1z}) & (p_{3z} - p_{1z}) \end{bmatrix} \begin{bmatrix} (u_2 - u_1) & (u_3 - u_1) \\ (v_2 - v_1) & (v_3 - v_1) \end{bmatrix}^{-1} $$ In the case of a general parameterized surface given by $p(u, v)$, the tangent basis at a point is defined as $T = \partial p / \partial u, B = \partial p / \partial v$.

When using a tangent basis for normal mapping, you’d probably orthonormalize it at this point. Here, we don’t want to do that—the “raw” tangent basis contains the information we want to extract about texture distortion.

There are a couple of different ways a texture can be distorted locally. One is for it to be non-uniformly scaled; another is for it to be sheared:

Both of these effects can be measured by looking at the tangent basis. Nonuniform scaling can be measured by comparing the lengths of $T$ and $B$, and shear can be measured by the angle between them; an unsheared texture mapping should have $T$ and $B$ perpendicular.

A convenient metric for both forms of distortion is the eccentricity of the ellipse created by transforming a unit circle from tangent space to model space. If the mapping is undistorted, it will map the unit circle to another circle; if there’s any nonuniform scaling or shear present, the circle will get elongated into an ellipse (though not necessarily an axis-aligned one):

How can we compute the eccentricity from the tangent basis? The major and minor radii of the ellipse are the singular values of the tangent-to-model transform (i.e. the $[T, B]$ matrix). I’ll skip the detailed derivation, but I found that the major and minor radii $a, b$ can be expressed in terms of $T$ and $B$ as follows: $$ \begin{aligned} a^2 &= \tfrac{1}{2} \left[ (T^2 + B^2) + \sqrt{(T^2 - B^2)^2 + 4(T \cdot B)^2} \right] \\ b^2 &= \tfrac{1}{2} \left[ (T^2 + B^2) - \sqrt{(T^2 - B^2)^2 + 4(T \cdot B)^2} \right] \end{aligned} $$ The eccentricity of the ellipse can then be computed as: $$ \epsilon = \sqrt{1 - \frac{b^2}{a^2}} $$ This value equals 0 when the ellipse is a circle, and grows toward 1 as it becomes more elongated.

## Conformal Maps

If a texture mapping—either on a triangle mesh or a general parameterized surface—has no
local distortion anywhere, i.e. its eccentricity equals 0 at every point, then it belongs to
a class known as **conformal maps**.

Conformal maps are a rich seam of mathematics, with a lot of connections to deep parts of geometry, analysis, and mathematical physics. In two dimensions, they’re particularly powerful and flexible (their usefulness falls off in higher dimensions).

Moreover, conformal maps are oddly aesthetically pleasing. 😄 There’s often a rather soothing quality of smoothness to them, owing to their lack of local distortion.

The key geometric property of these maps is that they preserve angles. To be precise:
if two lines or curves intersect at a certain angle, then their images under a conformal
map will intersect with the same angle. However, *distances* aren’t preserved in general: a
conformal map may scale things up and down, with different scale factors at different points. As
a result, shapes and sizes of things may be distorted in a global sense.

Another way to express the same idea is that a conformal map can be approximated to first order near any point as a similarity transformation—a linear transformation with no shear or nonuniform scaling, only rotation and uniform scaling.

We can also relax the definition of a conformal map by allowing the eccentricity to be bounded by a
constant, $0 \leq \epsilon \leq \epsilon_{\text{max}}$, rather than requiring it to be exactly zero
everywhere. This is called a **quasiconformal map**.

## Möbius Transformations

To get some initial intuition for what conformal maps are like, it’s useful to narrow our focus to a
specific type of conformal map that’s easy to analyze and play with. For this, we’ll look at
**Möbius transformations**, which are
just about the simplest conformal maps that are interesting enough to be worth studying. (They’re
named after August Ferdinand Möbius,
the same fellow better-known for the Möbius strip; he also invented homogeneous coordinates.)

In 2D, the most straightforward way to define these maps is with complex numbers. A 2D Möbius transformation has the form: $$ f(z) = \frac{az + b}{cz + d}, \qquad z \in \mathbb{C} $$ where $a, b, c, d \in \mathbb{C}$ are some constants, which should satisfy $ad - bc \neq 0$ (or the transform will be degenerate).

Here’s a Shadertoy that applies a Möbius transformation to a coordinate grid, animating the parameters over time. While watching this, pay attention to the grid intersections. Though the straight lines become curved, and the overall shapes may distort quite a bit, wherever two grid lines meet each other they always remain perpendicular! That’s the conformal property at work.

A few interesting facts about Möbius transformations, in no particular order:

- They form a mathematical group. The composition of two Möbius transformations is another Möbius, and the inverse of a Möbius is another Möbius!
- Although it has four complex parameters (eight components total), a Möbius has only
*six*degrees of freedom. That’s because an overall complex factor multiplied into all the parameters has no effect. In other words, parameters $(a, b, c, d)$ and $(ua, ub, uc, ud)$ specify the same transformation, for any $u \neq 0 \in \mathbb{C}$. - Möbius transformations generally map lines to circles, and circles to other circles. (And, occasionally, circles to lines.)
- Möbius transformations can be defined in higher dimensions as well, and they behave analogously, with (hyper)planes mapping to (hyper)spheres.
- In 3D and higher, Möbius transformations are the
*only*conformal maps that exist. In 2D, they’re just a small subset of a much richer collection of conformal maps.

The six degrees of freedom of a 2D Möbius are just enough that we can construct a transformation to map any three chosen points to three others. This makes it tempting to think that we could use them for texture mapping, by applying a Möbius to each triangle of a 3D model.

Unfortunately, the mapping will not in general be continuous from one triangle to the next: the
shared edge will be mapped to different circles by each triangle’s Möbius, and there are no more
degrees of freedom available to try to fix it.
There have been some papers, like this one,
trying to patch together piecewise Möbius transformations with least-squares optimization, to produce
*approximate* conformal maps.

There’s a good deal more that could be said about Möbius transformations. However, let’s move on for now and look at a broader set of conformal maps.

## Holomorphic Functions

From this point forward, we’ll restrict ourselves to the 2D case. Given that Möbius transformations aren’t quite as flexible as we might like, how can we construct other types of conformal maps?

It’s no accident that we used complex numbers to define the Möbius transformation in the previous section. Complex numbers, in fact, are intimately linked to conformal maps in 2D.

Why is this? If you recall, I mentioned earlier that one way to define a conformal map is that it can be approximated to first order near any point as a similarity transformation. Well, multiplication by a (nonzero) complex number implements a 2D similarity transformation: if $z = re^{i\theta}$, then multiplication by $z$ will scale by $r$ and rotate by $\theta$.

As you may have guessed, “approximated to first order near a point” is a long-winded way of talking
about derivatives. So, what we’re saying is that for a function on $\mathbb{C}$ to be a conformal
map, its derivative at any point should act as a complex number. In other words, it should be
*complex differentiable*. Functions that satisfy this requirement are called
**holomorphic functions**.

I should note that being complex-differentiable is different—and much more restrictive—than just being
differentiable as a vector function on $\mathbb{R}^2$. In other words, it’s not enough for the
$x$ and $y$ components of a mapping to *individually* be differentiable. As seen before, the
derivative at each point must take the form of a similarity transform; formally, the $x$ and $y$
components must satisfy the Cauchy–Riemann equations,
which state that the mapping’s tangent and bitangent vectors must be orthogonal, and
of equal length, at each point. Only when these conditions are satisfied can you interpret the mapping
as a differentiable complex function of a complex variable.

Fortunately, the basic differentiation rules we learn in school for real-valued functions do carry over to complex functions! In particular, all the basic arithmetic operations on complex numbers are differentiable. So, to make a holomorphic function, all we have to do is write down an algebraic formula—pretty much whatever we like—for a complex function $f(z)$. These functions will always produce conformal maps, by construction.

We can also use exp, log, and trig functions, as well as many other special functions; they can be
can be extended into the complex domain and are holomorphic too. However, there are a few operations
we *can’t* use: the complex conjugate, magnitude, argument, or real or imaginary parts of a complex
number. Those *aren’t* holomorphic, it turns out. As long as we follow these rules, any function we
build will be holomorphic and therefore conformal.

So, okay! We know a lot about how to build functions to accomplish specific things. In fact, we can try taking functions we’ve already got experience with, and just extending them to the complex domain. For instance, take a 1D cubic Bézier curve with control points $c_0, c_1, c_2, c_3$: $$ B(t) = (1-t)^3 c_0 + 3(1-t)^2 t c_1 + 3(1-t) t^2 c_2 + t^3 c_3 $$ We’ll use the same formula, but make everything complex numbers—both the control points and the input variable. $$ B(z) = (1-z)^3 c_0 + 3(1-z)^2 z c_1 + 3(1-z) z^2 c_2 + z^3 c_3 $$ Let’s see what it looks like! Here I’ve set it up to produce the identity map with a little bit of animated (complex) wiggle in the tangents at the endpoints, 0 and 1.

Huh. Well, it’s doing…*something*. The mapping does seem to be conformal, for the most part—right
angles are staying right angles. But why are we seeing the unit square getting duplicated and kinda
merging with itself into curvy 8-sided and 12-sided figures? Why do the grid lines seem to break
and reconnect all the time? This is interesting to look at, but doesn’t seem too useful for texture
mapping. What’s going on?

## Invertibility And Critical Points

The problem comes down to *invertibility*. When we get this “multiple copies” phenomenon, what we’re
seeing is the complex function mapping multiple regions of its domain (the Shadertoy’s screen space)
to the same region of its range (the coordinate grid being visualized). In other words, the function
isn’t one-to-one—and therefore it fails to be invertible.

Stepping back to real-valued functions for a moment may help clarify. Here’s the graph of the real function $f(x) = x^2$:

It’s a parabola, of course. It’s also one of the simplest examples of a non-invertible function.
Why? Because inputs $x$ and $-x$ both map to the same value, $x^2$. If you squint at it a bit, you
can see the graph as being made up of two distorted copies of the *positive half* of the real line.

The complex extension of this function $f(z) = z^2$, works the same way—but a bit more
dramatically, it gives us two distorted copies of *the entire complex plane*, squished together!

Now, a funny thing happens when we look at higher powers. When we restrict ourselves to the real numbers only, $x^3$ is invertible, $x^4$ is not, $x^5$ is, and so on: odd powers are invertible, while even ones aren’t. Even powers all map $x$ and $-x$ to the same value, while odd powers maintain the distinction.

However, when extended to the complex plane, $z^n$ *always* fails to be invertible unless $n = 1$!
In fact, graphing $z^n$ gives you $n$ copies of the plane, squished together into wedges around the
origin. All of the copies are conformal mappings—but their scale becomes increasingly extreme as
you approach the origin, and the function is not strictly conformal *at* the origin.

An example for the $n = 3$ case, which you can verify by working out the calculations if you like: $$ \begin{aligned} 1^3 &= 1 \\ (-\tfrac{1}{2} + \tfrac{\sqrt{3}}{2} i)^3 &= 1 \\ (-\tfrac{1}{2} - \tfrac{\sqrt{3}}{2} i)^3 &= 1 \\ \end{aligned} $$ Three distinct complex numbers, when cubed, all give the same result of 1.

In general, a holomorphic function will fail to be invertible wherever it has a *critical point*—a
point where its derivative equals zero. In the vicinity of such a place, the function will locally
behave like $z^n$: it will have $n$ copies of the surrounding region of the complex plane, squished
together into wedges around the critical point. Here, $n$ is one plus the order (aka multiplicity)
of the zero in the derivative.

This is what was going on in the Bézier example from the previous section. Since it was a cubic polynomial, its derivative is quadratic, and quadratic polynomials have two zeros. So the cubic Bézier curve has two critical points, which move around the plane as the curve’s parameters change. When the critical points get too close to the region of interest (the unit square, say), we can see two or even three copies of that region mushed together.

## Compulsory Criticality

If we want to build holomorphic functions that are guaranteed to be invertible, we need to avoid critical points, i.e. zeros of the derivative. Unfortunately, this turns out to be more challenging than you might expect.

It’s easy to make a real polynomial that doesn’t have any zeros, such as $f(x) = x^2 + 1$. Correspondingly, it’s easy to make a real polynomial that’s everywhere invertible, by taking the integral of one that doesn’t have any zeros: $\int (x^2 + 1) \, dx = \tfrac{1}{3}x^3 + x$, for example.

However, a crucial difference between the real and complex domains comes into play here: while zeros are optional
for real polynomials, they are *mandatory* for complex ones. A complex polynomial of degree $n \geq 1$
always has *exactly* $n$ zeros (counted with multiplicity). For example, the zeros of $z^2 + 1$ are
at $z = \pm i$. Thus, a complex polynomial of degree $n \geq 2$ always has at least one critical
point, and possibly up to $n - 1$ of them.

In other words, it’s impossible for complex polynomials of degree 2 or higher to be globally invertible.

Polynomials aren’t the only functions out there, though. What about rational functions? They
obey a similar dictum: if a rational function is degree $p$ over degree $q$, then there are
potentially $p + q - 1$ critical points (remember the quotient rule)—not to mention anywhere from
1 to $q$ poles, where the denominator goes to zero and the rational function blasts off to infinity.
Incidentally, poles behave similarly to critical points in some ways: they come in different orders,
and a pole of order $n$ will have $n$ copies of the complex plane around it. So poles are *another*
way to break invertibility.

This leads to the somewhat depressing conclusion that the *only* polynomial or rational complex
functions that are everywhere invertible are those that have degree at-most-1 over degree at-most-1.
In other words: Möbius transformations.

## Conclusion

So, polynomial and rational functions aren’t good enough—we’d need to dig deeper if we’re to find a class of invertible holomorphic functions more powerful than Möbius. One possibility might be to define $f(z) = \int e^{g(z)} \, dz$, where $g(z)$ is some holomorphic function without poles. Then $f(z)$ will have neither poles nor critical points, since its derivative is $e^{g(z)}$. (The complex exponential function, like the real version, is everywhere nonzero.)

Now, if we step back for a moment, we don’t necessarily need *global* invertibility. If we’re mainly
interested in some bounded region—such as the unit square, for texture mapping—then it may well
be sufficient for our purposes to maintain *local* invertibility there. This could be done by
keeping critical points and poles far enough from the region of interest that they don’t weird things
out too much. That still seems like a challenging juggling act to perform, though—and moreover,
the more degrees of freedom we have in our function, the more critical points or poles we probably
have to worry about.

In the course of reading up on this subject, I also found another paper that takes a quite different approach—based on Cauchy’s integral formula—to constructing conformal maps. I might write about that in another post sometime—there’s a lot more to this rabbit hole of math, and it’s interesting stuff, but ultimately it doesn’t seem very practical.

For more reading on the theory of holomorphic functions, see Terry Tao’s complex analysis course notes. (Be warned, it’s a graduate-level course and the notes are pretty dense and formal.)