课程链接:
GAMES301曲面参数化
曲面参数化说白了就是研究建模展uv贴图、研究如何把一个曲面展开到平面上的,在建模软件和游戏引擎里面应用很广。
对本次作业中主要要解的线性方程组的理解
原理:对于没有隧道并且有且只有一条边界线的流型网格体,将其边界顶点有序地落在一个凸多边形上,并且保证内部的顶点是其邻居的凸线性组合,那么得到的(u,v)坐标参数化是双射的。
也就是说以这种方式展uv,得到的uv图结果不存在自交、重叠。
对于参数化后的每一个非边界顶点
P
i
P_i
Pi,要保证其为为邻居顶点
P
i
,
j
P_{i,j}
Pi,j的凸线性组合,则有:
W
i
,
0
P
i
,
0
+
W
i
,
1
P
i
,
1
+
W
i
,
2
P
i
,
2
+
…
=
(
∑
W
i
,
j
)
P
i
W_{i,0}P_{i,0}+W_{i,1}P_{i,1}+W_{i,2}P_{i,2}+\ldots=(\sum W_{i,j})P_{i}
Wi,0Pi,0+Wi,1Pi,1+Wi,2Pi,2+…=(∑Wi,j)Pi(
W
i
,
j
>
0
W_{i,j}>0
Wi,j>0)
移项得到:
W
i
,
0
P
i
,
0
+
W
i
,
1
P
i
,
1
+
W
i
,
2
P
i
,
2
+
…
−
(
∑
W
i
,
j
)
P
i
+
…
=
0
W_{i,0}P_{i,0}+W_{i,1}P_{i,1}+W_{i,2}P_{i,2}+\ldots-(\sum W_{i,j})P_{i}+\ldots=0
Wi,0Pi,0+Wi,1Pi,1+Wi,2Pi,2+…−(∑Wi,j)Pi+…=0
写成矩阵形式:
[
W
i
,
0
W
i
,
1
W
i
,
2
⋯
−
(
∑
W
i
,
j
)
⋯
]
[
P
i
,
0
P
i
,
1
P
i
,
2
⋮
P
i
⋮
]
=
0
\begin{bmatrix}W_{i,0}&W_{i,1}&W_{i,2}&{\cdots} &-(\sum W_{i,j})&{\cdots}\end{bmatrix} \begin{bmatrix}P_{i,0}\\ P_{i,1}\\ P_{i,2}\\ {\vdots}\\ P_{i}\\ {\vdots}\\ \end{bmatrix}=0
[Wi,0Wi,1Wi,2⋯−(∑Wi,j)⋯]⎣
⎡Pi,0Pi,1Pi,2⋮Pi⋮⎦
⎤=0
将所有顶点都表示出来,就可以能得到
(其中u0 Bound v0 Bound等等,代表的是边界顶点固定到平面后的坐标)
可简写为方程
A
X
=
B
AX=B
AX=B
在我的代码中我把等号左边的稀疏矩阵命名为A,等号右边的矩阵为B,中间的那个矩阵命名为X,其中代表u轴坐标的一列被我命名为Xu,代表v轴坐标的一列被我命名为Xv,并分别使用Eigen数学库中求解稀疏矩阵的方法求解Xu和Xv
而什么样的权重,能使该线性方程组解出的uv图相比原网格体形变更小,更合理,就是后面权重计算的任务
权重计算
对于均匀权重的计算,不必过度赘述。直接来到Floater权重的计算
Floater权重的核心思想是:
对于每个非边界顶点
P
i
P_i
Pi,新建一个以
P
i
P
i
,
0
⃗
\vec{P_iP_{i,0}}
PiPi,0(
P
i
,
0
P_{i,0}
Pi,0可以为
P
i
P_{i}
Pi的任意邻居顶点)方向为x轴的平面直角坐标系,并把它放到该坐标系的原点,然后把它的某一个邻居顶点将点的1-邻域保角度比例、保长度地映射到该平面区域。求得在此坐标系下
P
i
P_i
Pi点相对于其邻居顶点的重心权重并填入矩阵A,这样解出的uv图就能尽量吻合原本的形状
即
∣
∣
P
i
,
j
−
P
i
∣
∣
=
∣
∣
X
i
,
j
−
X
i
∣
∣
||P_{i,j}-P_{i}||=||X_{i,j}-X_{i}||
∣∣Pi,j−Pi∣∣=∣∣Xi,j−Xi∣∣
和
a
n
g
(
P
i
,
k
−
1
,
P
i
,
P
i
,
k
)
=
2
π
a
n
g
(
X
i
,
k
−
1
,
X
i
,
X
i
,
k
)
/
θ
i
ang(P_{i,k-1},P_i,P_{i,k})=2\pi ang(X_{i,k-1},Xi,X_{i,k})/\theta_i
ang(Pi,k−1,Pi,Pi,k)=2πang(Xi,k−1,Xi,Xi,k)/θi
( X i X_i Xi和 X i , j X_{i,j} Xi,j分别表示原网格体上的中心顶点和其邻居顶点, P i P_i Pi和 P i , j P_{i,j} Pi,j分别表示“拍平”后的中心顶点和其邻居顶点,其中 θ i \theta_i θi为中心顶点 X i X_i Xi与其邻居顶点 X i , k X_{i,k} Xi,k组成的夹角的总和)
求解
P
i
P_i
Pi点相对于其邻居顶点的重心权重的方法:
首先,对于每条
P
i
P
i
,
l
P_iP_{i,l}
PiPi,l直线,(
P
i
P
i
,
l
P_iP_{i,l}
PiPi,l代指所有
P
i
P_i
Pi点与其邻居点的连线)都要寻找相邻的两个邻居顶点
P
i
,
k
−
1
P_{i,k-1}
Pi,k−1和
P
i
,
k
P_{i,k}
Pi,k,使得线段
P
i
,
k
−
1
P
i
,
k
P_{i,k-1}P_{i,k}
Pi,k−1Pi,k与直线
P
i
P
i
,
l
P_iP_{i,l}
PiPi,l相交,组成三角形
△
P
i
,
l
P
i
,
k
−
1
P
i
,
k
\triangle P_{i,l}P_{i,k-1}P_{i,k}
△Pi,lPi,k−1Pi,k,并在此三角形中求得其中心顶点
P
i
P_i
Pi的重心权重{a,b,c},分别对应{
P
i
,
l
,
P
i
,
k
−
1
,
P
i
,
k
P_{i,l},P_{i,k-1},P_{i,k}
Pi,l,Pi,k−1,Pi,k}这三个顶点。
注意,我们可以使用叉乘的方法来判断
P
i
,
k
−
1
P_{i,k-1}
Pi,k−1和
P
i
,
k
P_{i,k}
Pi,k是否在直线
P
i
P
i
,
l
P_iP_{i,l}
PiPi,l两侧;也可以直接计算重心权重,如果重心权重a,b,c的值都在(0,1)区间,那么也可以说明
P
i
P_i
Pi在三角形
△
P
i
,
l
P
i
,
k
−
1
P
i
,
k
\triangle P_{i,l}P_{i,k-1}P_{i,k}
△Pi,lPi,k−1Pi,k内部。
假设我们遍历到了某个中心顶点
P
i
P_i
Pi,它有4个邻居顶点,分别是
P
i
,
0
,
P
i
,
1
,
P
i
,
2
,
P
i
,
3
P_{i,0},P_{i,1},P_{i,2},P_{i,3}
Pi,0,Pi,1,Pi,2,Pi,3,那么我们就创建一个4*4的矩阵Mu(读做希腊字母μ),把遍历
P
i
P
i
,
l
P_iP_{i,l}
PiPi,l直线时,得到的权重{a,b,c},分别填到Mu的第l列的第j行,第k-1行和第k行。然后按行求和得到个列向量Sum_mu
矩阵A中,权重 W i , j W_{i,j} Wi,j的计算代码如下(*vertex为当前遍历到的中心顶点 neibors为其邻居顶点)
Eigen::VectorXd Sum_mu = Mu.rowwise().sum();//综合邻居权重
size_t size = neibors.size();
double sum_weight = 0;
for (size_t n = 0; n< size; n++)
{
double sum_mu = Sum_mu[n];
double Wij = sum_mu / n_neibors;
sum_weight += Wij;
Eigen::Triplet<double> t((*vertex)->index(), (*neibors.at(n))->index(), Wij);
triplet_list.push_back(t);
}
Eigen::Triplet<double> t((*vertex)->index(), (*vertex)->index(), -sum_weight);
triplet_list.push_back(t);
作业中遇到的坑
①提前setPositon,把网格体的边界顶点固定了,没有用原始网格体数据,导致后面计算角度时出错,debug了很久才找到原因
②判定三角形时候出错,导致计算出来的A矩阵存在not a number的问题
作业效果图
均匀权重
猫头模型离散网格均匀权重参数化效果图(如果发现是反的,就拖拽旋转一下它)
半球模型均匀权重离散网格参数化效果图
Floater权重
猫头模型离散网格Floater权重参数化效果图(如果发现是反的,就拖拽旋转一下它)
半球模型离散网格Floater权重参数化效果图