質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

1363閲覧

VR環境でアバターに物を掴んで移動(回転)させたい

kazuz

総合スコア20

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

1クリップ

投稿2019/03/08 03:44

先日質問させていただいた内容https://teratail.com/questions/178292
スクリプトを全て張りなおし再投稿させて頂きました。

VR環境で ものを掴んで移動させる事を行いたいのですが
現実で物を掴んで移動させたときに物体に加わる「回転」がうまく再現でず煮詰まっています。

基準のオブジェクト obj 
掴む対象のオブジェクト hitObj 途中で_grabObject に代わる

// ◆◆◆個々の部分がわからない↓↓ _grabOffsetR * _grabOffsetR と同じ?? var eee = _grabOffsetR * Quaternion.Inverse(obj.transform.rotation); _grabObject.transform.rotation =Quaternion.Inverse(eee);

上記のもので それらしい物はできたのですが、掴んだ瞬間に
基準のobjと同じ方向に向きなおしてしまいます、それ以降は自分に同じ面を向けながら移動させる事は出来るのですが・・・

ルービックキューブの青い面を手前に手で掴んで振り回しても自分からは常に青い面を向いている状態(伝わってくれ!)
槍で突き刺した魚をグルグル回すような?感じ

かなり分りづらい説明で申し訳ないのですが、ご教授お願いします。

C#

1//ネットから拾ってきた物を改造してるので使われていない変数などがあります。 2using System.Collections; 3using System.Collections.Generic; 4using UnityEngine; 5 6public class LaserPointer2 : MonoBehaviour { 7 public Transform obj; 8 9 [SerializeField] 10 private Transform _rightPointer = null; 11 [SerializeField] 12 private Transform _leftPointer = null; 13 14 // オブジェクトを掴む 15 private GameObject hitObj = null; 16 private GameObject hitObj2 = null; 17 private GameObject _grabObject = null; 18 private Vector3 _grabOffset; 19 private Quaternion _grabOffsetR; 20 private Quaternion _grabOffset2; 21 private float _grabDistance = 0; 22 private Vector3 _gravPrevFramePos; 23 24 // 現在アクティブな左右のどちらかのコントロールを得る 使ってないはず・・・ 25 private Transform GetController() { 26 var controller = OVRInput.GetActiveController(); 27 return (controller == OVRInput.Controller.RTrackedRemote ? _rightPointer : _leftPointer); 28 } 29 30 // Update is called once per frame 31 void Update () { 32 var controller = GetController(); 33 34 // コントローラーから前に伸ばしたRayを作成 35 var pointerRay = new Ray(obj.position, obj.transform.forward); 36 Debug.DrawRay(pointerRay.origin, pointerRay.direction * 1, Color.green, 1, false); 37 38 // Rayがヒットした位置を取得 39 RaycastHit hitInfo; 40 if (Physics.Raycast(pointerRay, out hitInfo, 1)) { 41 // ヒットしたオブジェクトを取得 42 hitObj = hitInfo.collider.gameObject; 43 44 45 // トリガーボタンを押した時 46 if (OVRInput.GetDown(OVRInput.RawButton.RHandTrigger)) { 47 if (hitObj.name != "Plane") { // 地面は掴めない 48 _grabObject = hitObj; 49 _grabDistance = hitInfo.distance; 50 _grabOffset = hitObj.transform.position - hitInfo.point; // ヒットした場所からオブジェクト中心までの距離 51 _gravPrevFramePos = hitObj.transform.position; 52 _grabOffsetR = obj.transform.rotation; 53 } 54 } 55 } 56 57 58 // 掴んだオブジェクトを移動 59 if (_grabObject != null) { 60 61 // 移動 62 _gravPrevFramePos = _grabObject.transform.position; 63 _grabObject.transform.position = pointerRay.GetPoint(_grabDistance) + _grabOffset; 64 _grabObject.GetComponent<Rigidbody>().velocity = Vector3.zero; 65 66 // ◆◆◆個々の部分がわからない↓↓ _grabOffsetR * _grabOffsetR と同じ?? 67 var eee = _grabOffsetR * Quaternion.Inverse(obj.transform.rotation); 68 _grabObject.transform.rotation =Quaternion.Inverse(eee); 69 70 } 71 72 // 掴んだオブジェクトを離す 73 if (OVRInput.GetUp(OVRInput.RawButton.RHandTrigger)) { 74 // トリガーボタンを離した時 75 Vector3 force = _grabObject.transform.position - _gravPrevFramePos; 76 _grabObject.GetComponent<Rigidbody>().velocity = force * 30f; 77 _grabObject = null; 78 hitObj2 = null; 79 } 80 81 } 82} 83 84

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Oculusを持っていないのでうまくいくか不確かですが、下記のようにしてみました。

変更点としまして、まず_grabObjectの位置は、単純に掴んだときのobjとの相対位置を覚えておいてそれを維持させることにしました。_grabObjectを回転させない場合は、確かに当初のような「objからレイ衝突点までの距離」と「レイ衝突点に対する_grabObjectの相対位置」を個別に覚えておいた方が、まさに衝突点を掴んでいるような動きになりそうでいいと思ったのですが、_grabObjectが回転する場合は位置がずれてしまい効果的でないような気がしたためです。
そして、回転も同じくobjに対する_grabObjectの相対回転を覚えておくようにしました。

動作確認をしておらず、何か見落としていたりご質問者さんの意図と食い違う点があるかもしれません。動きにおかしなところがありましたらご指摘いただけるとありがたいです。

C#

1// 簡略化のため、使っていなさそうな部分は削除してしまいました 2// 必要な部分まで削除してしまっていたらすみません 3 4using System.Collections; 5using System.Collections.Generic; 6using UnityEngine; 7 8public class LaserPointer2 : MonoBehaviour { 9 public Transform obj; 10 11 // オブジェクトを掴む 12 private GameObject hitObj = null; 13 private GameObject hitObj2 = null; 14 private GameObject _grabObject = null; 15 private Vector3 _grabPrevFramePos; 16 17 // _grabObjectを掴んだときの、objに対する相対位置・相対回転を保持するためのフィールド 18 private Vector3 _grabRelativePosition; 19 private Quaternion _grabRelativeRotation; 20 21 // Update is called once per frame 22 void Update() { 23 // コントローラーから前に伸ばしたRayを作成 24 var pointerRay = new Ray(obj.position, obj.transform.forward); 25 Debug.DrawRay(pointerRay.origin, pointerRay.direction * 1, Color.green, 1, false); 26 27 // Rayがヒットした位置を取得 28 RaycastHit hitInfo; 29 if (Physics.Raycast(pointerRay, out hitInfo, 1)) { 30 // ヒットしたオブジェクトを取得 31 hitObj = hitInfo.collider.gameObject; 32 33 // トリガーボタンを押した時 34 if (OVRInput.GetDown(OVRInput.RawButton.RHandTrigger)) { 35 if (hitObj.name != "Plane") { // 地面は掴めない 36 _grabObject = hitObj; 37 _grabPrevFramePos = hitObj.transform.position; 38 39 // objの座標系を基準とした_grabObjectの位置を保存しておく 40 _grabRelativePosition = obj.InverseTransformPoint(_grabPrevFramePos); 41 42 // 同じく、objの姿勢を基準とした_grabObjectの位置を保存しておく 43 _grabRelativeRotation = Quaternion.Inverse(obj.rotation) * _grabObject.transform.rotation; 44 } 45 } 46 } 47 48 // 掴んだオブジェクトを移動・回転 49 if (_grabObject != null) { 50 _grabPrevFramePos = _grabObject.transform.position; 51 _grabObject.GetComponent<Rigidbody>().velocity = Vector3.zero; 52 53 // 覚えておいた相対位置を、現在のobjを基準にワールド座標に変換して_grabObjectの位置とする 54 _grabObject.transform.position = obj.TransformPoint(_grabRelativePosition); 55 56 // 同様に回転も復元する 57 _grabObject.transform.rotation = obj.rotation * _grabRelativeRotation; 58 } 59 60 // 掴んだオブジェクトを離す 61 if (OVRInput.GetUp(OVRInput.RawButton.RHandTrigger)) { 62 // トリガーボタンを離した時 63 Vector3 force = _grabObject.transform.position - _grabPrevFramePos; 64 _grabObject.GetComponent<Rigidbody>().velocity = force * 30f; 65 _grabObject = null; 66 hitObj2 = null; 67 } 68 } 69}

投稿2019/03/08 09:12

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kazuz

2019/03/08 18:44

求めていた挙動になりました!ありがとうございます。 もう一点だけ参考までにお聞かせ頂ければと思うのですが 両手でオブジェクトを掴んでスマホなどの拡大、縮小のようにオブジェクトサイズを変更できるようにするには、両手で掴んでいるなどの判定はオブジェクト側に組み込むのと、先ほど頂いたスクリプトに組み込むのでは何方が良いでしょうか? 現在は「hitObj.name != "Plane"」で地面だけ掴まないようにいているので、後々オブジェクトに属性的なものを付与して つかめる物、掴めない物を区別しようと思ってます。
Bongo

2019/03/08 20:36

うーん、どちらがいいかは決めがたいですが、あえて選ぶならこちらの移動用スクリプトの方でしょうかね...? 片手で掴んでいるか両手で掴んでいるかで動作を切り替えることになるでしょうから、それら「オブジェクトを掴んで操作する」系の機能はこちら側に集中させた方が管理しやすいような気がします。 とはいえ、回答にも申し上げたようにOculusを持っていない者の意見ですので、いい案が思いついたり、スマートな製作例を見つけましたらそちらを採用して構わないと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問