目次
はじめに
個人の備忘録としてまとめています。誤った情報がある場合があります。
コメントにてご指摘のほどお願いいたします。
今回は入門向けにUEで回転するギミックを作ってみます。
詳しめに解説しているので、アンリアルエンジン初めての方もぜひ読んでみてください!
環境
UE5.4.2
サードパーソンテンプレート
解説
ジンバルロックって何?
ジンバルロックとは
3軸の全てに自由な運動がある場合は、機体の回転によって3つのジンバルリングのうち2つの軸が同一平面上にそろってしまうジンバルロック(英語版)という現象
(ウィキペディアより引用)
チョットナニイッテルカワカラナイので、エディタで体験してみよう。
任意のスタティックメッシュコンポーネントに対して
Yに90を入れます。
この状態でXのみ回転、Zのみ回転をすると、、
なんと、、X,Y軸で同じ回転挙動をしてしまいます。
実は普段目にするピッチ、ヨー、ロールでの回転設定はオイラー角といい、UEではFRotatorで定義されています。
これは下の画像のように入れ子構造になっており上位の回転の影響を受けます。
そのため、特定の条件下で本来自由である2つの軸が1つにロックされてしまう現象がジンバルロックです。
より詳しい記事
これを回避するにはオイラー角(FRotator)計算からクォータニオン(FQuat)に変換して計算する必要があります。
クォータニオンは数学的に回転を扱いやすい形ですが、オイラー角と異なり、人間が直感的に理解しづらいという欠点があります。そのため多くのゲームエンジンではオイラー角で表示しているケースが多いです。
クォータニオンってなんや!という方はこちらが参考になります。
いざ実装
➀ブループリントの作成
コンテンツウィンドウで右クリック->ブループリントクラスの作成を行います。
アクタを選択しましょう。
名前をB_RowlingPropとしました。
②回転する見た目の追加
B_RowlingPropをダブルクリックして開きます。
コンポーネントの追加からスタティックメッシュコンポーネントを3つ追加します。
名前を選択状態でF2を押してリネームして画像のように追加しました。
・SM_Pillar(柱)
・SM_Blade(回転する羽)
・SM_Base(土台)
スタティックメッシュのプロパティから形状をそれぞれ選択します。
トランスフォームのパラメーターを変更して自由に位置を調整してみましょう。
組み合わせて風車?のような見た目を作ってみました。
配置が終わったらコンパイルを行います。
コンテンツブラウザからB_RowlingPropをドラッグアンドドロップでマップに配置します。
実行してみてサイズ感などを確認しましょう。
確認が終わったらシミュレーションを停止して終了しましょう。
③回転する実装の追加
ビューポートからイベントグラフにタブを切り替えます。
回転されたいパーツ(今回はSM_Blade)をドラッグアンドドロップします。
右側のピンからクリックしてのばし、ノードGetRelativeRotationを選びます。
同じように右側のピンからクリックしてのばし、ノードSetRelativeRotationを選びます。
WorldRotationと RelativeRotation
UEにはWorldRotationとRelativeRotationがあります。
その名の通りそのコンポーネントがワールド座標による位置か、そのコンポーネントの親から見た相対位置かの違いです。
例えば、SM_BladeのGetWorldRotationを考えた場合、空間における位置を取得するため、このアクタ自身が斜めなどに回転している場合その影響を受けます。
しかし、GetRelativeRotationを利用した場合、一定です。
GetRelativeRotationノードからCombineRotatorsを検索します。
CombineRotatorsのAにGetRelativeRotationの出力をつなぎます。
SetRelativeRotationにCombineRotatorsの出力をつなぎます。
CombineRotatorsの入力BからMakeRotatorノードを配置します。
ビューポートに戻り回転させたい要素を確認しましょう。
コンポーネント(SM_Blade)をクリックしマニュピレーターが出た状態でEを押すと回転モードになります。
今回はY方向に回したいことが分かりました。
この情報をもとに、CombineRotatorsのBの要素を計算します。
イベントグラフに戻り、MakeRotatorの回転させたい要素(今回はY)からMultiplyノード(掛け算)を配置します。
可変フレームレートに対応するため、GetWorldDeltaSecondsというノードを配置します。これはEventTickのDeltaSecondsと同じ値が出力されます。
このノードはフレーム間の時間差を返すのでこれに移動量をかけることでフレームレートの影響を考慮した移動ができます。
移動量を変数化します。もう一方のピンから状況に合わせた表示に✅をいれ一番上にあるPromote to variableを押して変数化します。
変数にFloat型の変数が追加されます。
BladeSpeedという名前に変更し、右の眼のアイコンをクリックします。
BladeSpeedを選択すると詳細タブからデフォルト値を設定できます。
今回は100を登録しました。
これでノードは完成です。
コンパイルと保存を行いましょう。
④実行と確認
マップに戻りゲームを開始してみましょう。
回転していたら完成です!!
アウトライナーから配置したB_RowlingPropを選択します。
詳細を確認すると、直前の項目で追加したBlade Speed が編集可能になっています。
数を大きくしたり小さくしたりして速度が変わるのを確認しましょう。
F8もしくはコントローラーのアイコンを押すとゲームを実行しながら、プレイヤー操作からエディタ操作に切り替えられます。
これでプロパティを操作することで、ゲームを実行しながら値を変更することができます。※ここで変更した値は終了時にすべて戻ってしまうので注意!
オマケUEC++の内部実装をのぞいてみよう
今回利用したCombineRotatorsノードですが、エンジンの提供している機能です。
C++の開ける環境であれば、ノードをダブルクリックすることで内部実装を見ることができます。
▼UE独自のマクロUFUNCTIONで定義されたstatic関数 meta指定子でノードの名前や説明文、検索に引っ掛かるワードなど様々な情報が見れる。
/** Combine 2 rotations to give you the resulting rotation of first applying A, then B. */
UFUNCTION(BlueprintPure, meta=(DisplayName = "Combine Rotators", ScriptMethod = "Combine", Keywords="rotate rotation add"), Category="Math|Rotator")
static ENGINE_API FRotator ComposeRotators(FRotator A, FRotator B);
KismetMathLibrary.cppに実装が書いてあり、FRotatorをFQuatに変換したものをかけたものをFRotatiorに変換して返している内容が記述されています。
FRotator UKismetMathLibrary::ComposeRotators(FRotator A, FRotator B)
{
FQuat AQuat = FQuat(A);
FQuat BQuat = FQuat(B);
return FRotator(BQuat*AQuat);
}
つまり、これと同じことをブループリントで書けば、、
同じ挙動を再現できます。
このようにノードの中身を知ることでどのような計算ロジックで動作しているかを深く知ることができるのがアンリアルエンジンの良いところですし、自作のブループリントノードを作ることもできます。
難易度は高いですが、過去に自作C++ノードの作り方を解説しているので流し見してみてもよいかもしれません。
最後に
UE4やUE5向けの記事を書いています。
入門向けのシリーズの記事をいくつか投稿しているので、他の記事も覗いていただけると嬉しいです。
皆様の応援が投稿のモチベーションになりますので
コメントやTwitterのフォローなどしていただけるとありがたいです。
それではよきゲーム開発を。