Abstract
重心坐标在计算机图形学中十分重要,经常用做一种三角形内的插值算法。
References:
- https://zhuanlan.zhihu.com/p/58199366 此博主的叙述对我的启发很大
算法
考虑一个三角形,已知三个顶点坐标A,B,C以及一个内部点坐标P,我们假设有三个值(alpha)、(eta)、(gamma)满足:
-
(alpha + eta + gamma = 1 (1))
-
(alpha A + eta B + gamma C = P (2))
将式((2))变形:
-> (alpha A + eta B + gamma C - 1 * P = 0)
-> (alpha A + eta B + gamma C - (alpha + eta + gamma) * P = 0)
-> (alpha (A-P) + eta (B - P) + gamma (C - P) = 0)
-> (alpha vec{PA} + eta vec{PB} + gamma vec{PC} = 0)
这里我引用了开头知乎链接博主对重心坐标的形象描述,非常巧妙:
当挂在(A)、(B)、(C)上的权重分别为(alpha, eta, gamma)时,P点可正好使三角形立于一点上并保持平衡。
现在回到方程,将(alpha, eta, gamma)解出来并用代码实现。
-
(alpha + eta + gamma = 1 (1))
-
(alpha A + eta B + gamma C = P (2))
((2))解释为方程组即为:
(egin{cases} x_{p} = alpha x_{A} + eta x_{B} + gamma x_{C}\ y_{p} = alpha y_{A} + eta y_{B} + gamma y_{C} end{cases})
由((1))得:(alpha = 1 - eta - gamma),将其带入(2)方程组中:
(egin{cases} x_{p} - x_{A} = eta (x_{B} - x_{A}) + gamma (x_{C} - x_{A}) \ y_{p} - y_{A} = eta (y_{B} - y_{A}) + gamma (y_{C} - y_{A}) end{cases})
由此解出(eta)和(gamma),再由((1))直接算出(alpha)。
我手推了一下:
用代码实现便是:
static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector3f* v)
{
float xp = x, yp = y;
float xa = v[0].x(), ya = v[0].y();
float xb = v[1].x(), yb = v[1].y();
float xc = v[2].x(), yc = v[2].y();
float gamma = ((xb - xa) * (yp - ya) - (xp - xa) * (yb - ya)) /
((xb - xa) * (yc - ya) - (xc - xa) * (yb - ya));
float beta = (xp - xa - gamma * (xc - xa)) / (xb - xa);
float alpha = 1.0f - beta - gamma;
return {alpha,beta,gamma};
}