Barycentric Coordinates
Barycentric coordinates are a way to describe a point in reference to the vertices of a triangle. They have a few interesting properties and uses within game development so let's check them out. At the end of this article I hope you can completely understand what barycentric coordinates are, how to calculate them and, what kinds of values you can derive using barycentric coordinates.
Most of the examples in this article are interactive. Try clicking and dragging on the vertices of the triangles to get a feel for what is going on behind the math!
How to calculate Barycentric Coordinates
In order to calculate barycentric coordinates you need 3 vertices [v1, v2, v3]
of the Vector type
// Slide 1
const v1: Vector2 = (100, 420);
const v2: Vector2 = (100, 75);
const v3: Vector2 = (420, 420);
We connect these 3 vertices with 3 edge vectors [e1, e2, e3]
It is important to remember that winding
order matters here as it determines the orientation of the triangle in space.
// Slide 2
const v1: Vector2 = (100, 420);
const v2: Vector2 = (100, 75);
const v3: Vector2 = (420, 420);
const e1: Vector2 = v2 - v1;
const e2: Vector2 = v3 - v2;
const e3: Vector2 = v1 - v3;
These vertices and edge vectors create a triangle T
// Slide 3
const v1: Vector2 = (100, 420);
const v2: Vector2 = (100, 75);
const v3: Vector2 = (420, 420);
const e1: Vector2 = v2 - v1;
const e2: Vector2 = v3 - v2;
const e3: Vector2 = v1 - v3;
To find the barycentric coordinates, we need a Vector point p
, for which we want to get the barycentric coordinates.
// Slide 4
const v1: Vector2 = (100, 420);
const v2: Vector2 = (100, 75);
const v3: Vector2 = (420, 420);
const e1: Vector2 = v2 - v1;
const e2: Vector2 = v3 - v2;
const e3: Vector2 = v1 - v3;
const p: Vector2 = (200, 300);
If we imagine the point p
is somewhere in the triangle and draw lines from the point p
to each
vertex v1, v2, v3
we can now see how the triangle has been split into 3 sub-triangles T1, T2, T3
within the main triangle T
.
// Slide 5
const v1: Vector2 = (100, 420);
const v2: Vector2 = (100, 75);
const v3: Vector2 = (420, 420);
const e1: Vector2 = v2 - v1;
const e2: Vector2 = v3 - v2;
const e3: Vector2 = v1 - v3;
const p: Vector2 = (200, 300);
const d1: Vector2 = p - v1;
const d2: Vector2 = p - v2;
const d3: Vector2 = p - v3;
We have colored each sub-triangle a different color.
As we move this point around within the triangle observe how the area of each triangle shrinks and grows depending on
where the point p
is located. Notice as well if we move the point p
to the very same positions as any of the
vertices v1, v2, v3
how it is possible for a triangle to have 0 area. This observation of the areas of
each triangle is an important one to keep in mind.
// Slide 6
const v1: Vector2 = (100.0, 420);
const v2: Vector2 = (100, 75);
const v3: Vector2 = (420, 420);
const e1: Vector2 = v2 - v1;
const e2: Vector2 = v3 - v2;
const e3: Vector2 = v1 - v3;
const p: Vector2 = (200.0, 300.0);
const d1: Vector2 = p - v1;
const d2: Vector2 = p - v2;
const d3: Vector2 = p - v3;
If we were to calculate the area of the main triangle T
and then each sub-triangle T1, T2, T3
and
divide each T1, T2, T3
value by the main triangle T
area this would give us a value in the [0-1]
range.
This value represents the ratio of that sub-triangles area to the area of the main triangle.
These are what your barycentric coordinates represent. This is the major gotcha!
// Slide 7
const areaT = dot(cross(e1, e2), n) / 2; // 12000.0
const areaT1 = dot(cross(d1, d2), n) / 2; // 7200.0
const areaT2 = dot(cross(e2, e1), n) / 2; // 2812.5
const areaT3 = dot(cross(e3, e2), n) / 2; // 1987.5
const u = areaT1 / areaT; // 0.6
const v = areaT2 / areaT; // 0.2
const w = areaT3 / areaT; // 0.2
// Adds up to 1.0
const barycentric: Vector3 = (u, v, w);
Barycentric coordinates are expressed as a vector3 (u, v, w)
, each component being the ratio of a sub-triangle's area to T
’s area.
Once you have the barycentric coordinates there are some fun properties you can take advantage of.
- All the components added together should = 1
u + v + w === 1
Means the pointp
lies within the triangleT
.- If these values are over 1 then it means that the point
p
is not within the triangleT
. - If the point
p
is on any of the vertices of the triangleT
exact position it will look like(1, 0, 0)
or(0, 1, 0)
or(0, 0, 1)
We can find the nearest point on the triangle T
even if the point p
is not on the same plane as the triangle T
.
We can do this by multiplying each component of the vector p
by its corresponding barycentric
coordinates:
x = u
y = v
`- z = w`
That looks like:
p′= u∗v1 + v∗v2 + w∗v3
In code that looks like:
vector pPrime = u*v1 + v*v2 + w*v3;
Let's see some real work examples of the barycentric coordinates!
Try to match each triangle to the barycentric coordinates they represent.