纹理映射

重心坐标

重心坐标定义

对于一个三角形的三点坐标A,B,C,平面内的一点(x,y)可以写成三点的线性组合式

$$(x,y)=\alpha A + \beta B + \gamma C = \alpha + \beta + \gamma = 1$$

此时三个顶点的权重($\alpha , \beta , \gamma$)为(x,y)的重心坐标

注意:如果三个坐标值都为非负,则这个重心位于三角形内部

三角形的几何角度下求解

将点与三个顶点相连,三个三角形的面积分别为$A_A,A_B,A_C$对应的重心坐标的计算式,

$$\alpha = \frac{A_A}{A_A+A_B+A_C}$$

$$\beta = \frac{A_B}{A_A+A_B+A_C}$$

$$\gamma = \frac{A_C}{A_A+A_B+A_C}$$

在已知四点坐标的情况下则可通过行列式的几何意义求解(任意两个二维向量组合成矩阵的行列式的绝对值为这两条向量所围成平行四边形的面积)

设任意一点为P(x,y)则

$$A_B = \lvert AP,AC \rvert $$ $$A_C = \lvert AB,AP \rvert $$ $$A_A = \lvert BC,BP \rvert $$

可得出 $$\gamma = \frac{(y_a - y_b) + (x_b - x_a)y + x_a y_b - x_b y_a }{(y_a - y_b)x_c + (x_b - x_a)y_c + x_a y_b - x_b y_a}$$

$$\beta = \frac{(y_a - y_c)x + (x_c - x_a)y + x_a y_c - x_c y_a}{(y_a - y_c)x_b + (x_c - x_a)y_b + x_a y_c - x_c y_a}$$

$$\alpha = 1 - \beta - \gamma$$

三角形的坐标系角度下求解

对于重心坐标系存在另一种等价视角:

以A点为原点,AB,AC分别为新的坐标系的单位向量构建坐标系,如图

给定的任意点P的坐标可表示为$P(\beta , \gamma)$ ,可推出P点坐标满足以下关系

$$p = a + \beta(b - a) + \gamma(c - a)$$

化简后得

$$p = (1 - \beta - \gamma )a + \beta b + \gamma c $$

表现为一个线性方程组如下

$$ \begin{bmatrix} x_b - x_a & x_c - x_a \\ y_b - y_a & y_c - y_a \end{bmatrix} \begin{bmatrix} \beta \\ \gamma \end{bmatrix}= \begin{bmatrix} x_p - x_a \\ y_p - y_a \end{bmatrix} $$

重心坐标的用处

对顶点处的值进行线性插值,如下图

$$V = \alpha V_A + \beta V_B + \gamma V_C$$

$V_A,V_B,V_C$ 可以对应为:

  1. 位置
  2. 纹理坐标
  3. 颜色
  4. 法线
  5. 深度
  6. 材质属性
插值部分代码实现
 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
26
27
28
29
30
31
32
33
34
35
//三维向量插值
static Eigen::Vector3f interpolate(float alpha, float beta, float gamma, const Eigen::Vector3f& vert1, const Eigen::Vector3f& vert2, const Eigen::Vector3f& vert3, float weight)
{
    return (alpha * vert1 + beta * vert2 + gamma * vert3) / weight;
}

// 二维向量插值
static Eigen::Vector2f interpolate(float alpha, float beta, float gamma, const Eigen::Vector2f& vert1, const Eigen::Vector2f& vert2, const Eigen::Vector2f& vert3, float weight)
{
    auto u = (alpha * vert1[0] + beta * vert2[0] + gamma * vert3[0]);
    auto v = (alpha * vert1[1] + beta * vert2[1] + gamma * vert3[1]);

    u /= weight;
    v /= weight;

    return Eigen::Vector2f(u, v);
}
//计算重心
static std::tuple<float, float, float> computeBarycentric2D(float x, float y, const Vector4f* v){
    float c1 = (x*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*y + v[1].x()*v[2].y() - v[2].x()*v[1].y()) / (v[0].x()*(v[1].y() - v[2].y()) + (v[2].x() - v[1].x())*v[0].y() + v[1].x()*v[2].y() - v[2].x()*v[1].y());
    float c2 = (x*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*y + v[2].x()*v[0].y() - v[0].x()*v[2].y()) / (v[1].x()*(v[2].y() - v[0].y()) + (v[0].x() - v[2].x())*v[1].y() + v[2].x()*v[0].y() - v[0].x()*v[2].y());
    float c3 = (x*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*y + v[0].x()*v[1].y() - v[1].x()*v[0].y()) / (v[2].x()*(v[0].y() - v[1].y()) + (v[1].x() - v[0].x())*v[2].y() + v[0].x()*v[1].y() - v[1].x()*v[0].y());
    return {c1,c2,c3};
}

//光栅化时,判断深度之后进行插值计算得出对应的数值

// auto interpolated_color(颜色)
auto interpolated_color=interpolate(alpha,beta,gamma,t.color[0],t.color[1],t.color[2],1);
// auto interpolated_normal(法线)
auto interpolated_normal = interpolate(alpha,beta,gamma,t.normal[0],t.normal[1],t.normal[2],1).normalized();
// auto interpolated_texcoords(纹理坐标)
auto interpolated_texcoords = interpolate(alpha,beta,gamma,t.tex_coords[0],t.tex_coords[1],t.tex_coords[2],1);
// auto interpolated_shadingcoords(着色坐标)
auto interpolated_shadingcoords = interpolate(alpha,beta,gamma,view_pos[0],view_pos[1],view_pos[2],1);
updatedupdated2022-07-112022-07-11