一、什么是质心坐标?
在几何结构中,质心坐标是指图形中的点相对各顶点的位置。
以图1的线段 AB 为例,点 P 位于线段 AB 之间,
图1 线段AB和点P
此时计算点 P 的公式为 。
同理,在三角形 ABC 中,三角形内点 P 的计算公式为:——公式一。
公式一的最终表示形式为:
那么如何计算参数 m 和 n 呢?
下面给出推导过程:
根据公式一可得:
我们将 记作向量 ,将 记作向量 , 将 记作向量 ,则公式为:
然后分别乘以 v0 和 v1 得到如下两个公式:
继续化解方程式得:
令:
继续化简方程式得:
根据莱布尼茨公式可得:
其中d =
注意:到此整个系数的计算已经完成,质心的应用场景为:
- 判断一个点是否在三角形内。即根据计算处理的系数是否可以到相等的x,y坐标。
- 根据三角形的三个顶点得到三角形内任何一点P
- 可以把系数当作权重,即三个点的任何属性,例如颜色、深度等信息,也可以使用这里的m、n、(1-m-n)得出对应的加权后的值。例如3D人脸的渲染跟深度计算就是根据这个原理得出的。
C++实现代码:
//vPos1, vPos2,vPos3 分别代表三角形的三个顶点
//vP代表三角形内的一个点、
//fI代表 vPos1的系数
//fJ代表 vPos2的系数
//fK 代表 vPos3的系数
bool GetBarycentricCoord(vec2 vPos1, vec2 vPos2, vec2 vPos3, vec2 vP, float& fI, float& fJ, float& fK)
{
// Compute vectors
vec2 v0 = vPos2 - vPos1;
vec2 v1 = vPos3 - vPos1;
vec2 v2 = vP - vPos1;
// Compute dot products
float fDot00 = Dot(v0, v0);
float fDot01 = Dot(v0, v1);
float fDot02 = Dot(v0, v2);
float fDot11 = Dot(v1, v1);
float fDot12 = Dot(v1, v2);
// Compute barycentric coordinates
float fInvDenom = 1 / (fDot00 * fDot11 - fDot01 * fDot01);
float fTempU = (fDot11 * fDot02 - fDot01 * fDot12) * fInvDenom;
float fTempV = (fDot00 * fDot12 - fDot01 * fDot02) * fInvDenom;
// Check if point is in triangle or edge
bool bIsInTri = (fTempU >= 0) && (fTempV >= 0) && (fTempU + fTempV <= 1);
if (bIsInTri)
{
fJ = fTempU;
fK = fTempV;
fI = 1 - fJ - fK;
}
return bIsInTri;
}
python实现代码:
## 获得重心权重的函数
def get_point_weight(point, tri_points):
''' Get the weights of the position
Args:
point: (2,). [u, v] or [x, y]
tri_points: (3 vertices, 2 coords). three vertices(2d points) of a triangle.
Returns:
w0: weight of v0
w1: weight of v1
w2: weight of v3
'''
tp = np.array(tri_points)
# vectors
v0 = tp[2,:] - tp[0,:]
v1 = tp[1,:] - tp[0,:]
v2 = np.array(point) - tp[0,:]
# dot products
dot00 = np.dot(v0.T, v0) # distance of p2 and p0
dot01 = np.dot(v0.T, v1) #
dot02 = np.dot(v0.T, v2)
dot11 = np.dot(v1.T, v1)
dot12 = np.dot(v1.T, v2)
# barycentric coordinates
if dot00*dot11 - dot01*dot01 == 0:
inverDeno = 0
else:
inverDeno = 1/(dot00*dot11 - dot01*dot01)
u = (dot11*dot02 - dot01*dot12)*inverDeno
v = (dot00*dot12 - dot01*dot02)*inverDeno
w0 = 1 - u - v
w1 = v
w2 = u
return w0, w1, w2
使用到的人脸3d重构参考工程:
https://github.com/cleardusk/3DDFA
渲染工程:
https://github.com/cleardusk/SimRender/blob/master/lib/CMakeLists.txt