我正在编写星际争霸2自定义地图,并在3D中获得了一些数学方法.目前我正在尝试创建和旋转任意轴周围的点,由x,y和z给出(xyz向量被标准化).
我一直在尝试和浏览互联网上的很多东西,但我不知道它是如何正常工作的.我当前的脚本(你可能不知道语言,但它没什么特别的)是几个小时打破所有内容的结果(无法正常工作):
point CP;
fixed AXY;
point D;
point DnoZ;
point DXY_Z;
fixed AZ;
fixed LXY;
missile[Missile].Angle = (missile[Missile].Angle + missile[Missile].Acceleration) % 360.0;
missile[Missile].Acceleration += missile[Missile].AirResistance;
if (missile[Missile].Parent > -1) {
D = missile[missile[Missile].Parent].Direction;
DnoZ = Point(PointGetX(D),0.0);
DXY_Z = Normalize(Point(SquareRoot(PointDot(DnoZ,DnoZ)),PointGetHeight(D)));
AZ = MaxF(ACos(PointGetX(DXY_Z)),ASin(PointGetY(DXY_Z)))+missile[Missile].Angle;
DnoZ = Normalize(DnoZ);
AXY = MaxF(ACos(PointGetX(DnoZ)),ASin(PointGetY(DnoZ)));
CP = Point(Cos(AXY+90),Sin(AXY+90));
LXY = SquareRoot(PointDot(CP,CP));
if (LXY > 0) {
CP = PointMult(CP,Cos(AZ)/LXY);
PointSetHeight(CP,Sin(AZ));
} else {
CP = Point3(0.0,0.0,1.0);
}
} else {
CP = Point(Cos(missile[Missile].Angle),Sin(missile[Missile].Angle));
}
missile[Missile].Direction = Normalize(CP);
missile[Missile].Position = PointAdd(missile[Missile].Position,PointMult(missile[Missile].Direction,missile[Missile].Distance));
Run Code Online (Sandbox Code Playgroud)
我只是无法理解数学.如果你能用简单的术语解释它是最好的解决方案,那么剪切的代码也会很好(但不太有帮助,因为我计划将来做更多的3D东西).
Gra*_*ity 23
http://en.wikipedia.org/wiki/Rotation_matrix.从轴和角度看旋转矩阵部分.为方便起见,这是您需要的矩阵.它有点毛茸茸.theta是角度,ux,uy和uz是归一化轴向量的x,y和z分量

如果您不了解矩阵和向量,请回复,我会帮助您.
use*_*577 11
进行这种旋转的有用方法是使用四元数来完成它们.在实践中,我发现它们更容易使用并且具有避免万向节锁定的额外好处.
这是一个很好的演练,解释了它们如何以及为什么用于围绕任意轴的旋转(这是对用户问题的响应).这是一个更高的水平,对于这个想法的新手会很好,所以我建议从那里开始.
更新以避免链接腐蚀
来自链接网站的文字:
毫无疑问,您已经得出结论,围绕穿过原点的轴和(a,b,c)三维单位球上的点的旋转是线性变换,因此可以通过矩阵乘法来表示.我们将给出一种非常光滑的方法来确定这个矩阵,但是为了理解公式的紧凑性,从一些评论开始是明智的.
三维旋转是相当特殊的线性变换,不仅仅是因为它们保留了矢量的长度,并且(当两个矢量旋转时)矢量之间的角度.这种变换称为"正交",它们由正交矩阵表示:
M M' = I
Run Code Online (Sandbox Code Playgroud)
我们通过'方便地表示转置.换句话说,正交矩阵的转置是其反转.
考虑定义转换所需的数据.你已经给出了旋转轴的符号ai + bj + ck,方便地假设它是一个单位向量.唯一的另一个数据是旋转角度,由于缺乏更自然的特征,我将用r表示(旋转?),我们将假设以弧度给出.
现在即使在正交变换中旋转实际上也有点特殊,并且事实上它们也被称为特殊正交变换(或矩阵),因为它们具有"定向保持"的特性.将它们与反射相比较,反射也是长度和角度保持,你会发现保持方向的几何特征(或者如果你愿意的话,"手性")在矩阵的行列式中具有数字对应物.旋转矩阵具有行列式1,而反射矩阵具有行列式-1.事实证明,两次旋转的产品(或组合物)再次是旋转,这与产品的决定因素是决定因素的产物(或在旋转的情况下为1)的事实一致.
现在我们可以描述一个逐步的方法,人们可以按照这个方法构建所需的矩阵(在我们快速整个过程之前跳转到Answer!).首先考虑我们旋转单位向量的步骤:
u = ai + bj + ck
Run Code Online (Sandbox Code Playgroud)
这使得它与"标准"单位矢量之一一致,可能是k(正位z轴).现在我们知道如何围绕z轴旋转; 这是在x,y坐标上进行通常的2x2变换的问题:
cos(r) sin(r) 0
M = -sin(r) cos(r) 0
0 0 1
Run Code Online (Sandbox Code Playgroud)
最后,我们需要"撤消"将你带到k的初始旋转,这很容易,因为该变换的逆是(我们记得)由矩阵转置表示.换句话说,如果矩阵R表示将u转换为k的旋转,则R'将k取为u,我们可以写出这样的转换组合:
R' M R
Run Code Online (Sandbox Code Playgroud)
很容易证实,当乘以u时,这个矩阵乘积再次给你回复:
R' M R u = R' M k = R' k = u
Run Code Online (Sandbox Code Playgroud)
因此,这确实围绕由u定义的轴旋转.
这种表达的一个优点是它干净地分离出M对角度r的依赖性与Q和Q'对"轴"向量u的依赖关系.但是如果我们必须进行详细的计算,我们显然会有很多矩阵乘法.
所以,到了捷径.事实证明,当所有尘埃落定时,旋转之间的乘法与单位四元数的乘法同构.四元数,如果你以前没见过它们,是一种复数的四维推广.它们是威廉·汉密尔顿于1843年"发明的":
[Sir William Rowan Hamilton] http://www-gap.dcs.st-and.ac.uk/~history/Mathematicians/Hamilton.html
今天的3D图形程序员非常欠债.
q = q0 + q1*i + q2*j + q3*k然后每个单位四元数定义一个旋转矩阵:
(q0² + q1² - q2² - q3²) 2(q1q2 - q0q3) 2(q1q3 + q0q2)
Q = 2(q2q1 + q0q3) (q0² - q1² + q2² - q3²) 2(q2q3 - q0q1)
2(q3q1 - q0q2) 2(q3q2 + q0q1) (q0² - q1² - q2² + q3²)
Run Code Online (Sandbox Code Playgroud)
验证Q是正交矩阵,即.这Q Q' = I实际上意味着Q行形成了一个标准正交基础.因此,例如,第一行的长度应为1:
(q0² + q1² - q2² - q3²)² + 4(q1q2 - q0q3)² + 4(q1q3 + q0q2)²
= (q0² + q1² - q2² - q3²)² + 4(q1q2)² + 4(q0q3)² + 4(q1q3)² + 4(q0q2)²
= (q0² + q1² + q2² + q3²)²
= 1
Run Code Online (Sandbox Code Playgroud)
并且前两行应该有点积为零:
[ (q0² + q1² - q2² - q3²), 2(q1q2 - q0q3), 2(q1q3 + q0q2) ]
* [ 2(q2q1 + q0q3), (q0² - q1² + q2² - q3²), 2(q2q3 - q0q1) ]
= 2(q0² + q1² - q2² - q3²)(q2q1 + q0q3)
+ 2(q1q2 - q0q3)(q0² - q1² + q2² - q3²)
+ 4(q1q3 + q0q2)(q2q3 - q0q1)
= 4(q0²q1q2 + q1²q0q3 - q2²q0q3 - q3²q2q1)
+ 4(q3²q1q2 - q1²q0q3 + q2²q0q3 - q0²q2q1)
= 0
Run Code Online (Sandbox Code Playgroud)
它也可以一般地显示det(Q) = 1,因此Q实际上是旋转.
但围绕Q轴旋转的是什么?从什么角度来看?那么,给定角度r和单位矢量:
u = ai + bj + ck
Run Code Online (Sandbox Code Playgroud)
和以前一样,相应的四元数是:
q = cos(r/2) + sin(r/2) * u
= cos(r/2) + sin(r/2) ai + sin(r/2) bj + sin(r/2) ck
Run Code Online (Sandbox Code Playgroud)
因此:
q0 = cos(r/2), q1 = sin(r/2) a, q2 = sin(r/2) b, q3 = sin(r/2) c,
Run Code Online (Sandbox Code Playgroud)
我们能够得到所需的属性乘以Q"修复"你:
Q u = u
Run Code Online (Sandbox Code Playgroud)
让我们做一个简单的例子,而不是通过冗长的代数.
让u = 0i + 0.6j + 0.8k是我们的单位矢量,且r = PI是我们的旋转角度.
那么四元数是:
q = cos(pi/2) + sin(pi/2) * u
= 0 + 0i + 0.6j + 0.8k
Run Code Online (Sandbox Code Playgroud)
和旋转矩阵:
-1 0 0
Q = 0 -0.28 0.96
0 0.96 0.28
Run Code Online (Sandbox Code Playgroud)
在这个具体案例中,很容易验证QQ'= I和det(Q)= 1.
我们还计算:
Q u = [ 0, -0.28*0.6 + 0.96*0.8, 0.96*0.6 + 0.28*0.8 ]'
= [ 0, 0.6, 0.8 ]'
= u
Run Code Online (Sandbox Code Playgroud)
即.单位矢量u定义旋转轴,因为它由Q"固定".
最后,我们通过考虑Q在正x轴方向上作用于单位矢量的方式来说明旋转角是pi(或180度),x轴垂直于u:
i + 0j + 0k, or as a vector, [ 1, 0, 0 ]'
Run Code Online (Sandbox Code Playgroud)
然后Q [ 1, 0, 0 ]' = [-1, 0, 0 ]'是关于u的[1,0,0]'到角度pi的旋转.
作为四元数旋转表示和一些其他表示方法(以及它们的优点)的参考,请参阅此处的详细信息:
[代表3D旋转] http://gandalf-library.sourceforge.net/tutorial/report/node125.html
给定角度r以弧度和单位向量u = ai + bj + ck或[a,b,c]',定义:
q0 = cos(r/2), q1 = sin(r/2) a, q2 = sin(r/2) b, q3 = sin(r/2) c
Run Code Online (Sandbox Code Playgroud)
并从这些值构造旋转矩阵:
(q0² + q1² - q2² - q3²) 2(q1q2 - q0q3) 2(q1q3 + q0q2)
Q = 2(q2q1 + q0q3) (q0² - q1² + q2² - q3²) 2(q2q3 - q0q1)
2(q3q1 - q0q2) 2(q3q2 + q0q1) (q0² - q1² - q2² + q3²)
Run Code Online (Sandbox Code Playgroud)
乘以Q然后实现所需的旋转,特别是:
Q u = u
Run Code Online (Sandbox Code Playgroud)
要执行3D旋转,您只需将旋转点偏移到原点并围绕每个轴顺序旋转,将结果存储在每个轴旋转之间,以便与下一个旋转操作一起使用.算法如下所示:
将点偏移到原点.
Point of Rotation = (X1, Y1, Z1)
Point Location = (X1+A, Y1+B, Z1+C)
(Point Location - Point of Rotation) = (A, B, C).
Run Code Online (Sandbox Code Playgroud)
围绕Z轴执行旋转.
A' = A*cos ZAngle - B*sin ZAngle
B' = A*sin ZAngle + B*cos ZAngle
C' = C.
Run Code Online (Sandbox Code Playgroud)
接下来,围绕Y轴执行旋转.
C'' = C'*cos YAngle - A'*sin YAngle
A'' = C'*sin YAngle + A'*cos YAngle
B'' = B'
Run Code Online (Sandbox Code Playgroud)
现在执行关于X轴的最后一次旋转.
B''' = B''*cos XAngle - C''*sin XAngle
C''' = B''*sin XAngle + C''*cos XAngle
A''' = A''
Run Code Online (Sandbox Code Playgroud)
最后,将这些值添加回原始旋转点.
Rotated Point = (X1+A''', Y1+B''', Z1+C''');
Run Code Online (Sandbox Code Playgroud)
我发现这个链接非常有用.它定义了如何围绕X,Y和Z轴执行单独旋转.
在数学上,您可以像这样定义一组操作:

对此进行编程的一种非常巧妙的方法是罗德里格斯旋转公式,特别是如果您能够使用矩阵(例如在 Matlab 中)进行操作。
\n\n该公式创建旋转矩阵
绕由单位向量定义的轴
以一个角度
使用一个非常简单的方程:
您可以检查一下,对于欧几里德轴,该公式与维基百科上找到并由 Aakash Anuj 在此发布的公式完全相同。
\n\n自从我发现这个公式以来,我只使用它来进行旋转。希望它对任何人都有帮助。
\n