Y軸を90°以上回転させたとき、他の軸がフリップする機能を抑制したい

質問です。
アクターのある軸に沿って、ピボットのD&Dで回転させる際、ある角度を超えるとフリップしてしまいます。

現象1.X軸とZ軸に関して、絶対値180°を超えるとその軸が(-1)倍される。

現象2.Y軸に関して、絶対値90°を超えると、ほかの2軸が0°の場合、-180°になる。

この機能を抑制できませんでしょうか。

フリップしたところで同じ姿勢が保たれるので、このアクターに関しては問題はありません。

ただし今、あるアクターAの角度を、別のアクターBの角度をk倍した角度にするBPを組んでいるのですが、
この親切な機能のせいで、アクターBのY軸を90°以上回転させたとき、アクターAは不連続な回転をしてしまいます。

数値を手入力した場合は、360°すら超えることができるので、なんらかの方法で抑制できることを期待しているのですが、その方法はありませんでしょうか?

UE4の仕様であり、抑制できるか、という問題ではありません。

「ジンバルロック」という用語について調べてみてください。

現象2に関してはご指摘の通りと理解しました。ありがとうございます。

同時に、現象1に関しては現象2と別問題であることも理解できました。
現象1に関しては、ギズモ回転の絶対値に最大値が定められていることが原因かと考えます。質問文には180°で(-1)倍されると書きましたが、「絶対値が最大値を超えると、±360°される」という挙動が正しそうですね。私が本当に解決したい不具合(アクターAの不連続な回転)はこちらが原因だったと見られます。

この最大値を超えたときの挙動を変更する方法はありませんでしょうか。
(別のスレッドにするべきかもしれませんが…)

登場しているActorは2つあります。親記事に合わせてActorA、ActorBとします。

今ActorBを、Editor上で、マウスを使って、ギズモ(ピボット)をドラッグすることで回しています。
私の質問は、このドラッグの動作中においてのみX,Z軸がフリップしてしまう機能(現象1)を抑制できないか、というものです。

「回しているか、指定しているか」という確認に関して回答いたしますと、「“ActorAは”、SetActorRotationで向きを指定しています」となりますが、このActorAに関しての挙動は本旨ではありません。


本旨ではありませんが、情報を小出しにするのは良くありませんし、「仕様により変更不可」という場合を見据えた次の解決方法を考えたく、話を具体的にして続けたいと思います。

簡単のために、Leapのα=0.5、初期input回転値を(0,0,0)としています。この制御により、ActorAにActorBの半回転を与えることになります。

ActorBをマウスでX=0°→179.99°となるまでドラッグすると、図のBPによりActorAはX=0→89.995°となります。

この調子で、ドラッグをほんのわずか、0.02° 分だけ進めますと、ActorBのX=179.99°→ -179.99°となりますね。180.01°となってほしいのに!

そしてActorAは図のBP制御により、(本来89.995°→90.005°となってほしいところが、)89.995° → -89.995°となります。これは期待の結果と、文字通り180°違ってしまいます。真逆の結果です。

これを解消するため、ギズモのD&Dで(←これは必須条件です)、179.99°→ 180.01°を実現する方法はありませんでしょうか。

追記:多少面倒な制御(例えば180°前後で、直前の回転値を記憶してフリップを検出するなど)をすれば、この半回転制御に関しては解決できる気はしますが、あくまで半回転制御は、困っている問題の一例であって、根本原因としてやはりこのフリップを抑制したいです。

確認なのですが、そのActorというのは「回していますか」?それとも「向きを指定していますか」?


上記では違いが分かりづらいと思いますので、ノード名で具体的に書きますと

前者は AddWorldRotationAddLocalRotation を使っていることを想定しています。
これは変化量を与えて「回す」挙動になります。

後者は SetActorRotation 等を使っていることを想定しています。
こちらは任意の値を与えて「その方向に向ける」という挙動になります。

同じRotationに関することでも指定の仕方によって挙動が変わってきます。
可能な範囲でBlueprintの内容を開示していただくほうが、回答はしやすくなります。

前提として、UE4のRotatorの各要素の値は-180~+180です。
(内部ではFloatなので誤差があったりする関係上、実際に180になることはないようですが)

設計意図については想像ですが、

  • 符号でどちらの方向を向いているか判別できる
  • 比較のために単位を合わせる必要がある
  • 向きの比較にとって「何回転しているか」の情報は不要

あたりが挙げられます。
後ろ2つはほぼ同じ意味ではありますが。


提示されたBlueprintはTickイベントに刺さっているので、実運用を判断しかねますが、おそらくエディタ上の話と考えています

レベルエディタのビューポート内で変更した内容については、確定した値をメタデータにフィードバックする形になるので、実際に空間内で取り扱っている-180~+180の値で書き換えられます

逆にプロパティ内でメタデータを変更した場合は、Actorに反映する際に変換するので、メタデータ上で入力範囲を越えていても問題ない(内部値には影響しない)と考えます


長々と書きましたが、結論として、ビューポート内で操作をする上で要求を満たすことは不可能と考えます
どうしても要求を満たしたい場合は、UE4のルールを覆すためのエンジン改造が必要になりますが、コストに対するメリットがありませんので、考え方を見直すほうが懸命でしょう

意図と異なる場合は訂正をお願いします

提示されたBlueprintはTickイベントに刺さっているので、実運用を判断しかねますが、おそらくエディタ上の話と考えています

失礼しました、ご想像の通りです。
上図は手早く動作確認したもので、本来はconstruction scriptに刺しています。

レベルエディタのビューポート内で変更した内容については、確定した値をメタデータにフィードバックする形になるので、実際に空間内で取り扱っている-180~+180の値で書き換えられます

逆にプロパティ内でメタデータを変更した場合は、Actorに反映する際に変換するので、メタデータ上で入力範囲を越えていても問題ない(内部値には影響しない)と考えます

これは非常にわかりやすく、期待している動作は仕様上不可能であることが理解できます。エディタ上で変更できる値とプロパティの値との違いをまったく意識できていませんでした。

頭を切り替えて、うまい手("いま何回転目なのか"の検知方法)を考えたいと思います。初期角度(0)をまたいでプラスにふれたら+1回転目、マイナスにふれたら-1回転目…などを保存しておくとかでしょうか。これでうまくいけばいいのですが……

とは言え、具体的な解決方法はこれから考えることとしても、本旨の質問に対しては疑問は残っておりませんので、解決済といたします。

下手な質問にも関わらず、親切にお付き合いいただき、誠にありがとうございます。非常に勉強になりました。