instructions
We have already said what the barycentric coordinates of a triangle mean:
- Represents the weight of each vertex, that is, the amount affected by each vertex;
- The three vertices are regarded as the x, y and z axes of the local coordinate system, and the barycentric coordinates are the coordinates in the local coordinate system.
In this article, we have another explanation:
- Each component of the barycentric coordinate represents the area ratio of the smaller triangle that is formed by dividing the triangle at that point.
The geometric
For example, the center of massBarycentric coordinatesfor(a third, a third, 1/3)
The center of gravity divides the original triangle into three smaller triangles, each accounting for one third of the total area. In this way, it is easy to understand why the barycentric coordinates of the points in the triangle add up to 1. Because the area of the three smaller triangles added together is obviously the same as the area of the larger triangle.What happens when the point is outside the triangle? Then the area would be negative, so at least one of the barycenter coordinates would be negative, but the sum would still be 1.
So why is the sum of the barycenter coordinates equal to one? It’s essentially saying that the point and the sides of the triangle form a new little triangle, and the sum of the areas is the same as the area of the original triangle, which is essentially saying that the point is coplanar with the original triangle. And if you only have three dimensions, you have a coplanar problem. If the point is not coplanar with the triangle, then the sum of the barycenter coordinates, which is the area ratio, is not equal to 1.
In general, when a point is coplanar with a triangle, the barycentric coordinates have a clearer geometric meaning. So in three dimensions, to find the barycenter coordinates of any point on a triangle, you have to make sure that it’s coplanar. And then you take the cross product and you figure out the area of each of these little triangles, and you divide by the total area and you get the barycentric coordinates of that point.
Of course, there is another method, which is to take advantage of the constant area ratio after projection, projection into two dimensions (i.e. discarding a coordinate in x, y and Z), and then use the plane geometric formula to deal with the barycentric coordinate problem. As for which coordinate component to discard, we can judge by the normal line of the triangle. For example, the dot product of the normal line and the X-axis will give the largest result, that is, the closest parallel. Then we can discard the X-axis coordinates and project them onto the Yz plane.
On the surface, this method has one less dimension and less computation. But in fact, it has more branch processing, and can not give full play to the efficiency of SIMD instructions, the actual effect is not good. In three dimensions, it’s better to just use the cross product to find the area.
code
/// The barycentric coordinates of the point on the triangle
static func computeBarycenricCoordinate(of point:simd_float3, in triangle:Triangle) -> simd_float3? {
let e1 = triangle.point3 - triangle.point2
let e2 = triangle.point1 - triangle.point3
let e3 = triangle.point2 - triangle.point1
let d1 = point - triangle.point1
let d2 = point - triangle.point2
let d3 = point - triangle.point3
let n = cross(e1, e2)
if !n.isPerpendicular(to: d1) {
// The point is not coplanar with the triangle
return nil
}
let an = dot(cross(e1, e2), n)
if an < Float.leastNormalMagnitude {
// Degenerate triangle: a triangle whose area is zero
return nil
}
let b1 = dot(cross(e1, d3), n) / an
let b2 = dot(cross(e2, d1), n) / an
let b3 = dot(cross(e3, d2), n) / an
return simd_float3(b1, b2, b3)
}
/// The barycentric coordinates of the point on the triangle
static func computeBarycenricCoordinate2(of point:simd_float3, in triangle:Triangle) -> simd_float3? {
let d1 = triangle.point2 - triangle.point1
let d2 = triangle.point3 - triangle.point2
let n = cross(d1, d2)
let t = point - triangle.point1
if !n.isPerpendicular(to: t) {
// The point is not coplanar with the triangle
return nil
}
var u1,u2,u3,u4:Float
var v1,v2,v3,v4:Float
if (fabsf(n.x) > = fabsf(n.y)) && (fabsf(n.x) > = fabsf(n.z)) {
// Discard x and project onto the yz plane
u1 = triangle.point1.y - triangle.point3.y
u2 = triangle.point2.y - triangle.point3.y
u3 = point.y - triangle.point1.y
u4 = point.y - triangle.point3.y
v1 = triangle.point1.z - triangle.point3.z
v2 = triangle.point2.z - triangle.point3.z
v3 = point.z - triangle.point1.z
v4 = point.z - triangle.point3.z
} else if fabsf(n.y) > = fabsf(n.z){
// Discard y and project into the Xz plane
u1 = triangle.point1.z - triangle.point3.z
u2 = triangle.point2.z - triangle.point3.z
u3 = point.z - triangle.point1.z
u4 = point.z - triangle.point3.z
v1 = triangle.point1.x - triangle.point3.x
v2 = triangle.point2.x - triangle.point3.x
v3 = point.x - triangle.point1.x
v4 = point.x - triangle.point3.x
} else {
u1 = triangle.point1.x - triangle.point3.x
u2 = triangle.point2.x - triangle.point3.x
u3 = point.x - triangle.point1.x
u4 = point.x - triangle.point3.x
v1 = triangle.point1.y - triangle.point3.y
v2 = triangle.point2.y - triangle.point3.y
v3 = point.y - triangle.point1.y
v4 = point.y - triangle.point3.y
}
let denom = v1 * u2 - v2 * u1
if abs(denom) < Float.leastNormalMagnitude {
// Degenerate triangle: a triangle whose area is zero
return nil
}
// Calculate the barycenter coordinates
let oneOverDenom = 1.0 / denom
let b0 = (v4*u2 - v2*u4) * oneOverDenom
let b1 = (v1*u3 - v3*u1) * oneOverDenom
let b2 = 1 - b0 - b1
return simd_float3(b0, b1, b2)
}
Copy the code