我的问题类似于How to Make a Point Orbit a Line, 3D,但那里的答案似乎没有解决我的问题.我正在寻找的是一般解决方案.
为了记录,我试图解决OpenGL ES(Java / Android)中的问题.
我有一个圆圈,其中心有一个3D点,半径和一个3D矢量,用于指定圆所在平面的法线.
我需要找到表示圆周上的点的3D点,该点在“旋转的”X轴的给定角度(根据法线向量旋转).
我已经在成员函数的point类中实现了一个实现,pointAt在有限的情况下工作.具体来说,在我目前的实现中,我假设圆位于XY平面并相应地返回一个点然后,因为我知道圆实际上位于XZ平面中,我只是在返回的点中交换Y和Z值并且它起作用.但是,这不是一般解决方案,这就是我需要的.
当我尝试在How to Make a Point Orbit a Line, 3D中给出的算法时,我得到的分数远远超出它们应该存在的位置.
那么,我怎么能计算出这样一个圆周上的一个点呢?
[编辑]
我想我的解释还不够.我的假设是圆在X-Y平面中“正常”,在Z方向上具有法向矢量(0,0,1)-1.如果需要圆周上的点,则该点由以下定义:
x = R*cos(a) + Cx
y = R*sin(a) + Cy
其中R是半径,Cx和Cy是圆心的X和Y坐标,a是从矢量到圆的中心点并与X轴平行的角度.
现在,如果圆没有沿Z轴指向的法线向量,而是一些任意(x,y,z)向量,我该如何找到相同的点?
解决方法:
您需要的是一个用于放置圆的新坐标系.作为任何常见的坐标系,我们希望基矢量彼此正交,并且每个都具有长度1.我将命名基矢量v1,v2和v3,它们按顺序对应于x,y和z.
替换z的新基矢量,即v3,由圆的法线矢量给出.如果尚未标准化,您需要在此处对其进行标准化:
[ v3x ]
v3 = [ v3y ] = normalize(circleNormal)
[ v3z ]
接下来,我们将选择v1.这可以是与v3正交的任意向量.由于我们希望它取代x轴,我们可以选择它的y分量为0:
[ v3z ]
v1 = normalize([ 0 ])
[ -v3x]
注意,该向量与v3的点积为0,这意味着这两个向量确实是正交的.如果圆的法向矢量精确地指向y方向,则矢量将是简并的.如果您的使用中存在问题,我会告诉您如何处理.
现在我们只需要最后一个向量,它可以计算为另外两个的叉积:
v2 = v3 x v1
这已经归一化,因为v1和v3被归一化,并且是正交的.
有了这个新基础,圆上的点现在可以计算为:
p = centerPoint + R * (cos(a) * v1 + sin(a) * v2)
将整个事物更接近代码形式(未经测试):
// Only needed if normal vector (nx, ny, nz) is not already normalized.
float s = 1.0f / (nx * nx + ny * ny + nz * nz);
float v3x = s * nx;
float v3y = s * ny;
float v3z = s * nz;
// Calculate v1.
s = 1.0f / (v3x * v3x + v3z * v3z);
float v1x = s * v3z;
float v1y = 0.0f;
float v1z = s * -v3x;
// Calculate v2 as cross product of v3 and v1.
// Since v1y is 0, it could be removed from the following calculations. Keeping it for consistency.
float v2x = v3y * v1z - v3z * v1y;
float v2y = v3z * v1x - v3x * v1z;
float v2z = v3x * v1y - v3y * v1x;
// For each circle point.
px = cx + r * (v1x * cos(a) + v2x * sin(a))
py = cy + r * (v1y * cos(a) + v2y * sin(a))
pz = cz + r * (v1z * cos(a) + v2z * sin(a))