UE4の勉強記録

UE4の勉強の記録です。個人用です。

「Unreal Engine4.xを使用してRPGを作成する」のChapter 3 を勉強する。Part 4

<前文>

f:id:kazuhironagai77:20190505210929p:plain

今週はゴールデンウィークなので、ちょっとだけ寄り道して数学の勉強をします。

<本文>

今週はちょっと教科書から離れて数学の勉強をします。そうです。前回のオイラー角からオイラー行列への変換についてです。前回は以下に示す、

f:id:kazuhironagai77:20190505210959p:plain

FRotationTranslationMatrixクラスの行列がquaternion の回転行列だと思い込んで、ほとんど関係する資料を発見する事が出来ない中で、唯一見つかったこのビデオ(Object, coordinate space, rotation linear transformations ProgrammingTIL #167 3d math 11 tutorial)と想像と仮説で不明な部分を補う事でどうにかこの行列の導き方を割り出しました。

その後、この行列はオイラーの回転行列と呼ばれている事が判明しオイラーの回転行列から調べるともっと沢山の資料が見つかりました。例えばこのチャンネルです。

ただし、このビデオの導き出したオイラーの回転行列は、

f:id:kazuhironagai77:20190505211136p:plain

であり、答えが微妙に違います。

実は前回、しっかり計算しているようで、途中の計算を端折ってしまった箇所が何か所かあります。ので本当にその結果で正しいのと突っ込まれるとちょっと自信がない部分もあります。

例えば、軸の回転は時計回りを正として計算しましたが、その後の調査では反時計回りが正みたいです。

最後の

f:id:kazuhironagai77:20190505211206p:plain

から

f:id:kazuhironagai77:20190505211238p:plain

の計算の部分も大体しかしませんでした。

さらに、

f:id:kazuhironagai77:20190505211321p:plain

を行列で表した時に、無条件に

f:id:kazuhironagai77:20190505211353p:plain

としていましたがこの行列の転置行列が正しいのかもしれないとも密かに思っていたのですが確認しませんでした。

最後のGetUnitAxies(EAxis::X)がx軸の方向を表すと言う事についても、そういう風にサイトに書かれていたからで、自分で理由が分かったわけではありません。のでもうちょっとだけこの計算にこだわって見たいと思います。

<目的>

今回は、まずオイラー回転行列を数学的に厳密に導いて見ようと思います。まずこのチャンネルの通りに解いてみます。そしてその後上記の疑問を解いてみようと思います。

<手順>

手順と結果をここでまとめようと思ったのですが、このチャンネル、逐一解き方を説明されているので想像で補うところが全くありません。のでここで私が行った手順を説明してもそのチャンネルの解説と全く同じ事の繰り返しになるので、ここは省略します。

正し、述べた方が良い事を以下にまとめました。

  • 座標軸は右手系の場合で計算している。ただし、Z軸の正を下向きに取っている。
  • 回転方向は反時計回り。
  • 回転の順番は、Yaw、Pitch、Roll。
  • Yawの角度は、ψ。Pitchの角度はθ、Rollの角度はφで表す。
  • Yaw(Z軸)、Pitch(Y軸)、Roll(X軸)の回転とする。
  • ここで飛行機を例にして説明しているが、Pitchによって飛行機の先端が上下すると説明されているので、飛行機のYaw、Pitch、Rollと一致するためには飛行機はX軸に前後に沿って、その翼はY軸に沿っていると考えられる。これが一般的なのかは不明。

<結果>

途中何回が間違えて、全部の計算をやり直す事2回。結局2時間かかりましたが全て自分で計算し直しました。特に最後の3x3の行列の計算は大変でした。昔から2x2以上の行列の計算をすると必ず計算間違いを犯していたのですが、今回は2か所ほどケアレスミスをしてしまい、それを直してやっと答えが合いました。その結果答えは、

f:id:kazuhironagai77:20190505211507p:plain

と全く同じに成りました。

<考察>

ここまでの勉強でほぼ完ぺきにオイラー角からオイラーの回転行列を導けるようになったので、前回の良く分からなかった疑問をもう一度考察します。

まず、もう解けた疑問ですが、このチャンネルの計算結果は合っています。

f:id:kazuhironagai77:20190505211507p:plain

前回、参考にしたサイト(Conversion between quaternions and Euler angles)の計算結果(以下に示す)

f:id:kazuhironagai77:20190505211535p:plain

と違っているのは、前回参考にしたサイトは全て座標軸が左手系でこのチャンネルの座標軸は右手系だったからでした。

FRotationTranslationMatrixクラスの行列

f:id:kazuhironagai77:20190505211611p:plain

ですが、M[0][0]、M[0][1]、M[0][2]、M[0][3]が行なのか列を表しているのか、不明だったのですが、まず一般的に行列はなかの一つ一つの要素を、

f:id:kazuhironagai77:20190505211657p:plain

By Lakeworks - Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=3412522より。

と表します。更にC++チュートリアルでも、

f:id:kazuhironagai77:20190505211819p:plain

Multidimensional Arrays in C / C++ from Geeks for Geeks より

と表してますので、

f:id:kazuhironagai77:20190505211901p:plain

がFRotationTranslationMatrixクラスの行列を正しく表した行列となります。

前回は勝手に想像で、以下に示す行列

f:id:kazuhironagai77:20190505212033p:plain

が正しいと仮定していましたが、これは間違っていました。

しかし何故前回計算結果が同じになったのでしょうか?前回の計算をもう一度入念に見直したのですが、間違いは見つからなかったです。

うーん。思い出しました。前回は時計回りを正として計算したからでした。反時計回りを正とすれば、ちょうど転置行列になりFRotationTranslationMatrixクラスの行列を正しく表した行列とほぼ同じ(z軸の回転方向が逆にしないと計算が合わない問題は解決しないのでほぼ)となります。

と言うか、この辺になると慣習として反時計回りを正とするとあるサイトで言っているにも関わらず別なサイトで平気で時計回りを正として計算してたりしますね。また最後の行列の計算もz軸を最初に動かし、次にy軸最後にx軸と、このチャンネルでは説明していますが、Conversion between quaternions and Euler anglesでは逆に計算しています。慣習も全然周知されていないみたいです。最も大切な事は一貫性がある事で、その計算の途中で決まりを変えなければ結果は正しいはずですし。

となるとUnreal Engine 4のz軸の回転だけ逆にするのも、別にそれ自体が問題になる訳ではなくそれが一貫性を保っていればいいと考えられます。

UE4エディターで確認してみると、確かにZ軸を中心として45°正に回転させた場合、時計回りに回転しています。

f:id:kazuhironagai77:20190505212143p:plain

そしてX軸を中心として45°正に回転させた場合とY軸を中心として45°正に回転させた場合は、

f:id:kazuhironagai77:20190505212217p:plain

反時計周りに回転しています。

GetUnitAxies(EAxis::X)についてですが、前回調べた通り、

f:id:kazuhironagai77:20190505212249p:plain

を返します。これがx軸の回転後の方向を行列で表している事は今までの計算で明らかですが、何でこれが正面になるのでしょうか?

これは、慣習で飛行機はX軸に前後に沿って、その翼はY軸に沿っていると定義していたからと思われます。

このチャンネルでも座標は右手系ですが、飛行機を例に出してPitchの動きを解説していますが、その説明通りの動きを飛行機がするためには飛行機はX軸に前後に沿ってその翼はY軸に沿っている必要があります。

つまりは、x軸が正面であるのは慣習と言う事で深い理由はないと思われます。

f:id:kazuhironagai77:20190505212449p:plain

Third Person Characterを上から見ると、確かにX軸(赤い矢印)が正面に成っています。

<おまけ>

Blender からUE4に3Dモデルをインポートする時、今では優れてたアドオンがあるので全く自分で考える必要はなくなりましたがそのアドオンを導入するまではかなり苦痛を伴う作業でした。今回はその辺のプログラミングを将来勉強した時に理解出来る下地を作るための勉強でもありました。が想像していた以上にグダグダになってしまいました。量子化学のために数学を沢山勉強したおかげでOpenGLを勉強した時はこの辺の行列の計算は無双したのでしたが、その後、全く数学を勉強しないで幾年経ったら修練した数学の基礎が自分の中から消滅してしまってました。悲しいです。

今回のRPGの作成にはこの部分はブラックボックスとして単にGetUnitAxies(EAxis::X)とすればPlayerPawnの正面が判明すると覚えておけば多分問題ないので、今週の勉強はまあ必要ないと言えばないのでしょうがたまにはこういう勉強してもいいでしょう。