0%

三角形插值

三角形插值(重心坐标)

点$P$在$\triangle ABC$组成的三角形内

求点$P$的插值$\alpha,\beta,\gamma$

先求出$\vec{AP}$与$\vec{BC}$的交点$A^,$

然后计算$\alpha,\beta,\gamma$

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
float* lt::InterpolationTriangle(Vector2<float> p, Vector2<float> a, Vector2<float> b, Vector2<float> c)
{
Vector2<float> a1b1 = p - a;
Vector2<float> a2b2 = c - b;
Vector2<float> a2a1 = a - b;
Vector2<float> a1a2 = b - a;
float u = (a2b2.x * a2a1.y - a2a1.x * a2b2.y) / (a1b1.x * a2b2.y - a2b2.x * a1b1.y);
Vector2<float> aintersected = a + a1b1 * u;

float arr[3];
arr[0] = (p - a).magnitude() / (aintersected - a).magnitude();
arr[1] = (aintersected - p).magnitude() / (aintersected - a).magnitude() * (aintersected - b).magnitude() / (c-b).magnitude();
arr[2] = (aintersected - p).magnitude() / (aintersected - a).magnitude() * (c - aintersected).magnitude() / (c - b).magnitude();
return arr;
}

重心法(质心)

显然,无论是线性插值还是双线性插值的都无法解决这个问题。而使用重心坐标则可以很好的解决这个问题。简单的来说,重心坐标就是子三角形与大三角形的面积比,具体的解释参看维基百科,计算过程如下:

  已知三角形的三个顶点坐标P1, P2, P3, 在三角形内的任意点P, 都存在u和v(由于三角形是一个2D图形,只有两个自由度,所以只要u和v即可),使得

    P = (1 - u - v) P1 + u P2 + v * P3

  P点在三角形内,所以(u, v)必须满足条件u ≥ 0, v ≥ 0, u + v ≤ 1。u、v体现了每个顶点对特定区域的权重贡献,(1 - u - v)则是第三个权重,只要计算出u和v,就可以计算出每个顶点对P点的贡献。现在已知P1, P2, P3和P的坐标值,求解u和v,只需要解二元一次方程即可:

    P.x = (1 - u - v) P1.x + u P2.x + v * P3.x

    P.y = (1 - u - v) P1.y + u P2.y + v * P3.y

  有了u、v值,对P1, P2, P3的颜色值进行加权平均,即可得到P点颜色值。

1
2
3
4
5
6
7
float* lt::InterpolationTriangle(Vector2<float> p, Vector2<float> a, Vector2<float> b, Vector2<float> c) {
float arr[3];
arr[1] = ((p.x - a.x)*(c.y - a.y) - (c.x - a.x) * (p.y - a.y)) / ((b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y));
arr[2] = ((p.x - a.x)*(b.y - a.y) - (b.x - a.x) * (p.y - a.y)) / ((c.x - a.x) * (b.y - a.y) - (b.x - a.x) * (c.y - a.y));
arr[0] = 1 - arr[1] - arr[2];
return arr;
}

面积法


a0 占三角形整体面积的比例代表 V2(P2对应的数值)占 V 的比例,
a1 占三角形整体面积的比例代表 V1(P1对应的数值)占 V 的比例,
而 a2 占三角形整体面积的比例则代表 V0(P0对应的数值)占 V 的比例,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public static float Cross(Vector2 v0, Vector2 v1)
{
return v0.x * v1.y - v1.x * v0.y;
}

public static float TriangleArea(Vector2 v0, Vector2 v1)
{
return 0.5f * Math.Abs(Cross(v0, v1));
}

public static float TriangleLerp(Value2f val0, Value2f val1, Value2f val2, Vector2 p)
{
var v01 = val1.Vector - val0.Vector;
var v02 = val2.Vector - val0.Vector;
var v0p = p - val0.Vector;

var a = TriangleArea(v01, v02);
Debug.Assert(a > 0, "[MathUtil]Error to do triangle Lerp, seems vertexes collinear ...");

var a0 = TriangleArea(v01, v0p);
var a1 = TriangleArea(v0p, v02);
var a2 = a - a0 - a1;

return (val2.v * a0 + val1.v * a1 + val0.v * a2) / a;
}