空间已知三点的位置 p1(x1,y1,z1),p2(x2,y2,z2),p3(x3,y3,z3), 令它们逆时针在空间摆放. 这样就可以得到平面的两个向量 p1p2(x2-x1,y2-y1,z2-z1),p1p3(x3-x1,y3-y1,z3-z1), 而平面法线总是和这两个向量垂直. 也就是说, p1p2 与 p1p3 的向量积就是平面的法向量 n.
复习一下向量积, 已知向量
a=(a1,a2,a3) b=(b1,b2,b3)
其向量积可表示为:
a*b=(a2b3-a3b2,a3b1-a1b3,a1b2-a2b1)
将其套入到 p1p2 和 p1p3 即可.
具体实现代码如下:
- #include<iostream>
- using namespace std;
- // 三维 double 矢量
- struct Vec3d
- {
- double x, y, z;
- Vec3d()
- {
- x = 0.0;
- y = 0.0;
- z = 0.0;
- }
- Vec3d(double dx, double dy, double dz)
- {
- x = dx;
- y = dy;
- z = dz;
- }
- void Set(double dx, double dy, double dz)
- {
- x = dx;
- y = dy;
- z = dz;
- }
- };
- // 计算三点成面的法向量
- void Cal_Normal_3D(const Vec3d& v1, const Vec3d& v2, const Vec3d& v3, Vec3d &vn)
- {
- //v1(n1,n2,n3);
- // 平面方程: na * (x - n1) + nb * (y - n2) + nc * (z - n3) = 0 ;
- double na = (v2.y - v1.y)*(v3.z - v1.z) - (v2.z - v1.z)*(v3.y - v1.y);
- double nb = (v2.z - v1.z)*(v3.x - v1.x) - (v2.x - v1.x)*(v3.z - v1.z);
- double nc = (v2.x - v1.x)*(v3.y - v1.y) - (v2.y - v1.y)*(v3.x - v1.x);
- // 平面法向量
- vn.Set(na, nb, nc);
- }
- int main()
- {
- Vec3d v1(1.0, 5.2, 3.7);
- Vec3d v2(2.8, 3.9, 4.5);
- Vec3d v3(7.6, 8.4, 6.2);
- Vec3d vn;
- Cal_Normal_3D(v1, v2, v3, vn);
- cout <<"法向量为:"<< vn.x << '\t' << vn.y << '\t' << vn.z << '\n';
- return 0;
- }
对于一个空间的平面而言, 其法向量可以是两个方向, 可以向上也可以向下. 所以在 OpenGL 中默认规定的也是右手法则, 右手除拇指之外的四指根据点的逆时针握住, 大拇指的方向即为法线方向. 其逆时针的一面为正面, 可以接受到光照; 顺时针为反面, 无法接受光照.
来源: http://www.bubuko.com/infodetail-3030944.html