关于旋转的一些有用的事情:
- 排列成行的任何三个正交向量都定义了到新基的变换(到该基的旋转)。
- 任何旋转的转置都是它的逆。
- 因此,排列为列的任何三个正交向量定义了从某个基础到“世界”参考系的旋转。
因此,问题是找到任何三个正交向量的集合并将它们排列为
| x1 x2 x3 0 |
| y1 y2 y3 0 |
| z1 z2 z3 0 |
| 0 0 0 1 |
这正是您所描述的方法试图做的,如果它不起作用,那么您的实现就有问题。
显然,我们可以使用法线作为 (x1,y1,z1),但问题是系统对其余两个向量有无限多个解(尽管知道其中一个向量可以得到另一个向量,即叉积)。下面的代码应该给出一个垂直于 (x1,y1,z1) 的稳定向量:
float normal[3] = { ... };
int imin = 0;
for(int i=0; i<3; ++i)
if(std::abs(normal[i]) < std::abs(normal[imin]))
imin = i;
float v2[3] = {0,0,0};
float dt = normal[imin];
v2[imin] = 1;
for(int i=0;i<3;i++)
v2[i] -= dt*normal[i];
这基本上使用 Gram-Schmidt 正交化,其维度已经与法线向量最正交。然后可以通过叉积得到 v3normal
and v2
.
您可能需要小心设置旋转,它与原点有关,因此您需要在旋转后应用平移,并且它适用于列向量而不是行向量。如果您使用 OpenGL,请注意 OpenGL 按列主要顺序(而不是 C 的行主要顺序)获取数组,因此您可能需要转置。
恐怕我还没有测试过上面的内容,我只是从我不久前编写的一些代码中获取了它并根据你的问题进行了调整!希望我没有忘记任何细节。
编辑:我确实忘记了一些事情:)
上面的矩阵假设你的多边形法线沿着x轴,我有一个偷偷怀疑它不会,你需要做的就是将“法线”向量放在旋转矩阵的正确列中,并且其他两列中的 v2/v3。因此,如果多边形的法线沿 z 轴,则法线位于第三列,v2/v3 位于前两列。
抱歉,如果这引起任何混乱。