両手に持ったそれぞれのオブジェクト同士が衝突するようにしたい。
なんとなくこうすればいいんじゃないか?というイメージはあるが
UE4でどう実現するのがベストなのかわからないので
先人たちの知恵に頼ることにする。
同じような問題、すでに誰かが解決してくれているだろう。
ググる。
・・・
んー、検索方法が悪いのか、そのものズバリの答えが見つからない。
手に持ったオブジェクトと、StaticModel とを衝突させるためには Physics Handle を使う
という例はいくつかでてくるが、今やりたいこととは微妙に違う気もする。
とりあえず自己流でやってみるか・・・。
方針としては
- 本当はこの位置にありたいという希望を表す、物理・衝突なしのオブジェクトA(=Ghost)と
- 物理挙動に従った物理・衝突ありのオブジェクトBの2つを用意して、
- Bを物理挙動に従いながらAにできる限り近づけようとする処理を作成
- Bの位置を表示オブジェクトの位置として採用する。
という感じでいいんじゃないかと。
作ってみる。
まずはダミーのオブジェクトを作って、実験。
---
んー。
ひとまず SetWorldTranslate を使って移動させてみたが、いまいち挙動がよろしくない。
どうも回転が入ると、角度はそのままで単に押し出されているだけのようなので、支点が動いてしまっている。
何かしら物理の拘束を入れられるといいんだろうか。
・・・そうか。
ここで先ほど出てきた Physics Handle というもの使えばいいのではないだろうか?
調査。
- Physics Handle
https://docs.unrealengine.com/en-US/BlueprintAPI/Physics/Components/PhysicsHandle/index.html
どうやら、移動させたい先の位置と回転を指定して、物理オブジェクトを動かすための機能のようだ。
いけそうな予感。
試してみる。
いいんじゃないか??
ゲームに組み込んでみよう。
---
オブジェクトが押し返されたら、当然手のモデルもそれに合わせて押し返されなければならない。
あれ?そういえば手の座標を決めているところはどこだろう。
BPには見当たらないような?。
・・・
あぁ、そうか。
MotionControllerというコンポーネントが
C++内部でコントローラーのトラッキング情報を取得していて、
HandMesh はその子にアタッチされているから追従している、という仕組みか。
ということは、HandMeshの親子関係を切って
物を持っている時には物理オブジェクトの位置から逆算して得られる位置に
HandMeshを表示してやればいいのでは。
具体的な処理手順は・・・
- PickableObject側
- 掴まれた時に Physics Handle を生成、GrabComponentAtLocationWithRotation を呼ぶ
- 毎フレーム MotionController の位置に SetTargetLocationAndRotation
- 離された時に Release と Physics Handleの破棄
- HandMesh側
- 物を掴んでいる時には、掴んでいる物から HandMesh の位置をもらう。
これでいいはず。
---
出来た。
よさそう?!
いろいろ試してみる。
・・・
うーん。
どうやらSphereやCubeは問題ないけれど、棒のように長いものを持つと
なんだかゆらゆらと遅延したような動きになってしまう。
なんで?
なんとなく、重心が安定しない形状だとそんな挙動になっている様子。
重心から離れた位置に力を加えて、物理オブジェクトを制御しているのだからそりゃそうなるか。。
PhysicsHandleComponentのDampingやStiffnessパラメータを変えれば
ある程度は改善するけれども、完璧ではない。
これをパラメータの調整で抑えるのは不毛な気がする。
なにかいい手はないだろうか?
---
情報を整理。
- ほかのオブジェクト等に衝突していない時は、物理を無視して手に完全にアタッチさせた挙動が理想的。
- 衝突している時には、多少動きに遅延があったり、不自然なプルプルが発生しても許容できる。
やはりハイブリッドを実現するべきか。
・・・
いろいろ試行錯誤をした結果、こんな制御に落ち着いた。
- PhysicsHandleは常に動かす。パラメータはこんな。
- Interpolate は OFF
- AngularStiffnessは大きな値に(100000.0f)
- Soft Angular Constraint は ON
- Soft Linear Constraint は OFF
- OnHitイベントを検出して、何にも衝突していないときには SetWorldLocation でオブジェクトの位置を上書き。
- 切り替わりの際はタイマーを用意して両者のTransformをLerpしてブレンドする。
結果
動画
第0043回 / 両手に持ったオブジェクト同士の衝突 #UE4 #VR #GameDev https://t.co/c7U4id8k6u pic.twitter.com/wFXojfbDjF
— ue4-master (@ue4master80) October 25, 2019
まだ微調整は必要そうだけれど、
とりあえずやりたいことは出来たー!