给定曲面法线,找到3D平面的旋转

Ada*_*dam 17 math 3d

所以我有一个由3个矢量描述的3D平面:

P:位于平面
N 上的点:平面的表面法线

我有一个非常大的扁平方形多边形,我想渲染它来代表这个平面.我可以很容易地将多边形转换为给定的点,但是我需要找到适当的旋转来使表面法线实际上是表面法线.

我尝试了一个其他提到的方法,其中:

1)将任何非平行向量(V)取正常值(N),取十字积(W1)
2)取(W1)和(N)的叉积(W2),即矢量(V) ')位于飞机上

然后我生成一个基于(V')放置在平面上的旋转矩阵,这样我的多边形就会与(V')对齐.虽然有效,但很明显这种方法整体上工作不正常.多边形与表面法线不完全垂直.

关于如何产生正确旋转的任何想法?

Ada*_*wen 14

关于旋转的一些有用的东西:

  • 排列为行的任何三个正交向量将变换定义为新基础(旋转到该基础中).
  • 任何旋转的转置都是相反的.
  • 因此,排列为列的任何三个正交向量都定义了从某些基础到您的"世界"参考系的旋转.

因此,问题是找到任意一组三个正交向量并将它们排列为

| x1 x2 x3  0 |
| y1 y2 y3  0 |
| z1 z2 z3  0 |
|  0  0  0  1 |
Run Code Online (Sandbox Code Playgroud)

这正是您所描述的方法尝试执行的操作,如果它不起作用,那么您的实现就会出现问题.

我们显然可以使用你的法线作为(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];
Run Code Online (Sandbox Code Playgroud)

这基本上使用Gram-Schmidt正交化,其具有已经与法向量最正交的维度.V3然后可以通过取的横产物获得normalv2.

您可能需要注意设置旋转,它是关于原点的,因此您需要在旋转后应用平移,而不是行向量而不是行向量.如果您正在使用OpenGL监视,则OpenGL以列主要顺序(而不是C的行主顺序)获取数组,因此您可能需要转置.

我担心我没有测试过上面的内容,我只是从我刚才写的一些代码中抓取它并将其改编成你的问题!希望我没有忘记任何细节.

编辑:我确实忘记了一些东西:)

上面的矩阵假设你的多边形的法线是沿着x轴,我有一个潜行的怀疑它不会,你需要做的就是将"正常"向量放在旋转矩阵的正确列中,并且其他两列中的v2/v3.因此,如果多边形的法线沿z轴,则法线进入第3列,v2/v3进入前两列.

对不起,如果这导致任何混乱.

  • 由于一个随机的原因,我发现自己重新审视这个答案,当我选择最正交的维度时,我应该使用法向量组件的绝对值 - 我在答案中对此进行了更正. (2认同)