私はStarcraft 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));
ただ数学のことは気にしない。最善の解決策となる簡単な言葉でそれを説明できれば、コードを省略してもよいでしょう(ただし、将来的には3Dの作業をさらに行う予定なので、あまり役に立ちません)。
http://en.wikipedia.org/wiki/Rotation_matrix 。セクションの下を見てください 軸と角度からの回転行列 。あなたの便宜のために、ここにあなたが必要とするマトリックスがあります。少し毛むくじゃらです。 thetaは角度、ux、uy、uzはnormalized軸ベクトルのx、y、zコンポーネントです
行列やベクトルがわからない場合は、ポストバックしてください。
そのような回転を行うための有用な方法は、それらを quaternions で行うことです。実際には、私はそれらが使いやすく、 ジンバルロック を回避するという追加のボーナスがあることを発見しました。
ここ は、それらが任意の軸を中心とした回転にどのように、そしてなぜ使用されるかを説明する素晴らしいウォークスルーです(ユーザーの質問に対する応答です)。少しレベルが高く、アイデアを初めて使う人には良いので、そこから始めることをお勧めします。
リンクの腐食を回避するための更新
リンクされたサイトからのテキスト:
間違いなくすでに結論しているように、原点を通過する軸と、単位球上の3次元の点_(a,b,c)
_を中心とした回転は線形変換であるため、行列の乗算で表すことができます。この行列を決定するための非常に洗練された方法を示しますが、式の簡潔さを理解するには、いくつかの注意点から始めるのが賢明です。
3次元の回転は、特にベクトルの長さを維持し、(2つのベクトルを回転させた場合)ベクトル間の角度も保存するため、特別な線形変換です。このような変換は「直交」と呼ばれ、直交行列で表されます。
_M M' = I
_
ここでは、便宜的に転置を 'で示しています。つまり、直交行列の転置はその逆になります。
変換を定義するために必要なデータを検討してください。回転軸の表記_ai + bj + ck
_はすでに単位ベクトルであると想定してあります。他の唯一のデータムは回転角度です。これは、より自然な特性がないため、r(回転?)で表し、ラジアンで与えられると仮定します。
現在、回転は、直交変換の間でも実際には少し特殊であり、実際には、「向きを維持する」という特性のために、特殊直交変換(または行列)とも呼ばれます。それらを反射と比較します。これは長さと角度を維持するものであり、方向(または希望する場合は「利き手」)を維持する幾何学的特性が、行列の行列式に対応する数値を持っていることがわかります。回転の行列には行列式1があり、反射の行列には行列式-1があります。 2つのローテーションの積(または組成)もローテーションであることがわかります。これは、積の行列式が行列式の積(または、回転の場合は1)であるという事実と一致します。
これで、目的のマトリックスを構築するために従うことができるステップバイステップのアプローチを説明することができます(プロセス全体をショートカットして回答にジャンプする前に!)。最初に、単位ベクトルを回転させるステップを考えます。
_u = ai + bj + ck
_
そのため、「標準」の単位ベクトルの1つ、おそらくk(正のz軸)と一致します。これで、z軸を中心に回転する方法がわかりました。これは、x、y座標のみで通常の2x2変換を行うだけの問題です。
_ cos(r) sin(r) 0
M = -sin(r) cos(r) 0
0 0 1
_
最後に、uをkにした最初の回転を「元に戻す」必要があります。これは、その変換の逆が(行列を転置して)表すので簡単です。つまり、行列Rがuからkをとる回転を表す場合、R 'はkからuを取り、次のような変換の構成を書き出すことができます。
_R' M R
_
この行列の積にuを掛けると、uが再び返されることが簡単に確認できます。
_R' M R u = R' M k = R' k = u
_
したがって、これは実際にuで定義された軸を中心とした回転です。
この式の1つの利点は、Mの角度rへの依存性を、QとQ 'の「軸」ベクトルuへの依存性から明確に分離することです。ただし、計算を詳細に実行する必要がある場合は、明らかに行列の乗算をたくさん行うことになります。
だから、ショートカットに。すべてのダストが落ち着くと、回転間の乗算は単位四元数の乗算と同型であることがわかります。クォータニオンは、これまでに見たことがない場合に備えて、一種の複素数の4次元一般化です。彼らは1843年にウィリアムハミルトンによって「発明」されました。
[ウィリアムローワンハミルトン卿] 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²)
_
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
_
そして、最初の2行はドット積がゼロでなければなりません:
_ [ (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
_
また、一般にdet(Q) = 1
を示すことができるため、Qは実際には回転です。
しかし、Qの回転はどの軸の周りですか?そして、どの角度から?まあ、与えられた角度rと単位ベクトル:
_u = ai + bj + ck
_
以前と同様に、対応する四元数は次のとおりです。
_q = cos(r/2) + sin(r/2) * u
= cos(r/2) + sin(r/2) ai + sin(r/2) bj + sin(r/2) ck
_
したがって:
_q0 = cos(r/2), q1 = sin(r/2) a, q2 = sin(r/2) b, q3 = sin(r/2) c,
_
qによる乗算でuを「修正」するという目的のプロパティを取得できます。
_Q u = u
_
曲がりくねった代数をたどるのではなく、簡単な例を見てみましょう。
_u = 0i + 0.6j + 0.8k
_を単位ベクトル、r = piを回転角度とします。
次に、四元数は次のとおりです。
_q = cos(pi/2) + sin(pi/2) * u
= 0 + 0i + 0.6j + 0.8k
_
そして回転行列:
_ -1 0 0
Q = 0 -0.28 0.96
0 0.96 0.28
_
この具体的なケースでは、Q Q '= 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
_
すなわち。単位ベクトルuは、Qによって「固定」されるため、回転軸を定義します。
最後に、Qがuに垂直な正のx軸の方向にある単位ベクトルにどのように作用するかを考慮することにより、回転角度がpi(または180度)であることを示します。
_i + 0j + 0k, or as a vector, [ 1, 0, 0 ]'
_
次に_Q [ 1, 0, 0 ]' = [-1, 0, 0 ]'
_は、[1、0、0] 'をuを中心とした角度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
_
これらの値から回転行列を作成します。
_ (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²)
_
次に、Qによる乗算により、必要な回転が行われます。特に、
_Q u = u
_
3D回転を実行するには、回転点を原点にオフセットし、各軸を中心に順次回転させ、各軸回転間の結果を保存して、次の回転操作で使用するだけです。アルゴリズムは次のようになります。
ポイントを原点にオフセットします。
Point of Rotation = (X1, Y1, Z1)
Point Location = (X1+A, Y1+B, Z1+C)
(Point Location - Point of Rotation) = (A, B, C).
Z軸を中心に回転を実行します。
A' = A*cos ZAngle - B*sin ZAngle
B' = A*sin ZAngle + B*cos ZAngle
C' = C.
次に、Y軸を中心に回転を実行します。
C'' = C'*cos YAngle - A'*sin YAngle
A'' = C'*sin YAngle + A'*cos YAngle
B'' = B'
X軸を中心に最後の回転を実行します。
B''' = B''*cos XAngle - C''*sin XAngle
C''' = B''*sin XAngle + C''*cos XAngle
A''' = A''
最後に、これらの値を元の回転ポイントに追加します。
Rotated Point = (X1+A''', Y1+B''', Z1+C''');
これは link が非常に役立つことがわかりました。 X、Y、Z軸を中心に個別の回転を実行する方法を定義します。
数学的には、次のように一連の操作を定義できます。
ここでは、x、y、zのいずれの軸を中心に回転するために使用できるものを示します。 Rx、Ry、Rzはそれぞれエースx、y、zを中心とした回転を表します。
これをプログラムするための非常にきちんとした方法は、特に(Matlabのように)行列で操作できる場合は Rodrigues 'Rotation Formula です。
この式は回転行列を作成します 単位ベクトルで定義された軸の周り 角度 非常に単純な方程式を使用:
どこ - は単位行列であり、 は、単位ベクトルの成分によって与えられる行列 :
ベクトル は単位ベクトル、つまり は1でなければなりません。
ユークリッド軸については、式がWikipediaにあり、Aakash Anujによってここで公開されているものと正確に一致していることを確認できます。
私はそれを発見して以来、回転にのみこの式を使用します。それが誰にも役立つことを願っています。