目的:网格法向量的计算
最近发现一个非常有意思的东西,网上的资料较少,所以记下来供大家查阅,
就是在网格化三维polygon 3d的时候,对于polygon 3d的法向量和网格化为三角形的时候。生成obj文件的时候三角面片的方向只和三角形的顶点顺序有关。如果三角面片上进行顶点的normal设置,可能毫无效果。在meshlab中只和顶点的顺序有关。polygon 3d的法向量和三角面片的法向量一致。
三角面片的法向量:
测试它是左手坐标系还是右手坐标系生成的法向量?从顶点的顺序(也是半面结构)来看它是左手坐标系生成的法向量。
为了测试我们要了解向量叉乘的几何意义,如果左乘的话,它是右手坐标系下做的(可以这样规定)。它的几何意义如下:
可以看出来,在
a
×
b
a × b
a×b 是左乘的角度可以看出来,右手坐标系,从
a
a
a到
b
b
b的方向。
对于三角形的面片的方向,可能不一样。它规定了一个顺序。如果
p
0
,
p
1
,
p
2
p0, p1, p2
p0,p1,p2三个顶点的顺序,然后我们需要计算它是哪个方向为主。需要看一下方向。在测试的途中,
v 0.0 0.0 0.0
v 0.0 1.0 0.0
v 1.0 0.0 0.0
f 3 2 1
从这个可以看到,
p
0
=
(
1
,
0
,
0
)
;
p
1
=
(
0
,
1
,
0
)
;
p
3
=
(
0
,
0
,
0
)
p0=(1,0,0); p1=(0,1,0); p3=(0,0,0)
p0=(1,0,0);p1=(0,1,0);p3=(0,0,0),它的顺序,
可以得到normal =(0,0,1),
如果从顶点的顺序来看的话。
它是典型的左手坐标系。如果用数学中的向量来算的话,可能需要改变一下思路,需要计算两个向量的叉乘。会得到
a
=
(
p
1
−
p
0
)
;
b
=
(
p
2
−
p
0
)
a=(p1 - p0); b = (p2-p0)
a=(p1−p0);b=(p2−p0),然后叉乘
a
×
b
a × b
a×b可以得到。就是那种从它其实和逻辑是自洽的,因为我们如果用
(
p
1
−
p
0
)
×
(
p
2
−
p
1
)
(p1-p0)×(p2-p1)
(p1−p0)×(p2−p1)这个不是三角形的夹角,而是180-夹角,。所以叉乘可能需要变化一下,对夹角的计算。代码如下:
Eigen::Vector3f GetNormalFrom3Points(Eigen::Vector3f& a, Eigen::Vector3f& b, Eigen::Vector3f& c)
{
Eigen::Vector3f e1 = b - a;
Eigen::Vector3f e2 = c - a;
Eigen::Vector3f e1_(e1.x, e1.y, e1.z), e2_(e2.x, e2.y, e2.z);
Eigen::Vector3f normal = e1.cross(e2);
if (normal.norm() < 0.0001) { //如果太小了,可以返回(0,0,0)
#ifdef LIULINGFEI
printf("result = %f, %f, %f\n", 0, 0, 0);
#endif
return Eigen::Vector3f(0, 0, 0);
}
else {
Eigen::Vector3f temp = normal.normalized();
#ifdef LIULINGFEI
printf("result = %f, %f, %f\n", temp(0), temp(1), temp(2));
#endif
return normal.normalized();
}
}
网上可能对于三角面片的法向量有一些资料,但是对于polygon 面片的法向量可能需要一些,可能不一样。它需要对每一个顶点计算法向量(邻近的顶点构成三角形,然后计算这个三角形的法向量然后计算这个顶点的反向量),然后区平均值。但是也可以计算polygon的法向量了。代码如下:
Eigen::Vector3f GetPolygonNormalFrom3Points(std::vector<Eigen::Vector3f>& poly_pnts)
{
Eigen::Vector3f sum(0,0,0);
for(int i = 0; i < poly_pnts.size(); ++i)
{
Eigen::Vector3f pre_pnt = poly_pnts[(i-1)%poly_pnts.size()];
Eigen::Vector3f pnt = poly_pnts[(i)%poly_pnts.size()];
Eigen::Vector3f next_pnt = poly_pnts[(i+1)%poly_pnts.size()];
Eigen::Vector3f tmp_normal = GetNormalFrom3Points(pre_pnt, pnt, next_pnt);
//对于其中的tmp_normal 不一样,可能不同的权重,但是我都归一化了,得到相应的法向量。
sum += tmp_normal;
}
if(poly_pnts.empty())
{
return sum;
}
else
{
return sum.normal();
}
}
感悟:测试这个polygon的法向量得到。