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

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

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

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

Unity3D

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

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

Q&A

解決済

1回答

1234閲覧

Unityにおける3Dゲームオブジェクトの回転制御

Izayoi-san

総合スコア12

C#

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

Unity3D

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

オブジェクト

オブジェクト指向において、データとメソッドの集合をオブジェクト(Object)と呼びます。

0グッド

0クリップ

投稿2020/09/14 05:28

現在、顔の動きをWEBカメラで認識し、その動きをUnityのゲームオブジェクト上に反映させるシステムの構築を行っています。
その際に、顔の位置の移動に合わせたゲームオブジェクトの移動は成功しています。
ただし、顔の座標の回転(右を向く等)に合わせた、ゲームオブジェクトの回転において、下記のエラーが発生しています。

・顔座標を回転させたのちにゲームオブジェクトがその方向に回り続ける。試した対処方法は下記になります。

以前2Dのゲームオブジェクトを作成した際に、慣性により回転し続けるという問題が生じたため、それと同様の問題であると考えてました。
2Dの際はRigidBody2Dをアタッチして、FreezeRotationのZ軸にチェックを入れる方法で慣性を削除できた記憶があるので、
同様の手法としてRigidBodyをアタッチし、各FreezeRotationにチェックを入れてみましたが、やはり回転し続けました。

また、下記コードのように、顔の座標の回転量によるゲームオブジェクトの回転量には制限を設けているため、やはり慣性が原因ではないかと考えています。
下記コードにおいて、CurrentFaceRotationが顔座標の回転を考慮した数値、BaseFaceRotationが基準となるゲームオブジェクトのもともとの数値です。
まず顔座標が変化していること(0.1f以上かどうか)を確認し、変化量が一定以下(35)である場合にゲームオブジェクトを回転させるプログラムです。

C++

1 void Update() 2 { 3 if (Mathf.Abs(Mathf.DeltaAngle(CurrentFaceRotation.x, BaseFaceRotation.x)) > 0.1f) 4 { 5 int bairitsu = 1; 6 if ((Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.x), Mathf.Abs(BaseFaceRotation.x)) < 35) && (Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.x), Mathf.Abs(BaseFaceRotation.x)) > -35)) 7 { 8 CurrentFaceTransform.Rotate(new Vector3(CurrentFaceRotation.x * bairitsu, 0, 0)); 9 } 10 } 11 if (Mathf.Abs(Mathf.DeltaAngle(CurrentFaceRotation.y, BaseFaceRotation.y)) > 0.1f) 12 { 13 int bairitsu = 1; 14 if ((Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.y), Mathf.Abs(BaseFaceRotation.y)) < 35) && (Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.y), Mathf.Abs(BaseFaceRotation.y)) > -35)) 15 { 16 CurrentFaceTransform.Rotate(new Vector3(0, CurrentFaceRotation.y * bairitsu, 0)); 17 } 18 } 19 if (Mathf.Abs(Mathf.DeltaAngle(CurrentFaceRotation.z, BaseFaceRotation.z)) > 0.1f) 20 { 21 int bairitsu = 1; 22 if ((Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.z), Mathf.Abs(BaseFaceRotation.z)) < 35) && (Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.z), Mathf.Abs(BaseFaceRotation.z)) > -35)) 23 { 24 CurrentFaceTransform.Rotate(new Vector3(0, 0, CurrentFaceRotation.z * bairitsu)); 25 } 26 } 27 }

慣性の制御方法(できれば挙動が重くなりすぎないものがいいです)と、そもそも慣性が原因ではなく他に調べるべきことがあるなどあれば
ご指導ご鞭撻のほどよろしくお願いいたします。

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

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

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

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

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

YAmaGNZ

2020/09/14 07:06

BaseFaceRotationというのは顔が正面を向いた状態の値なのでしょうか?
Izayoi-san

2020/09/14 07:09

顔が正面を向いた初期状態の値になります。 こちらはGameObjectからStartのタイミングで下記のように取得しています。 CurrentFaceTransform = Face.transform; BaseFAceTransform = CurrentFaceTransform;
YAmaGNZ

2020/09/14 07:16

if文にてどのような値を比較しているのか確認してみてはどうでしょうか? BaseFaceRotationが正面を向いた状態でCurrentFaceRotationがカメラ画像から検出した顔の傾きだった場合、40度顔を傾けた場合、毎フレームif文の中が実行されたりしませんか? もし、オブジェクトを回転させた後にそれらの値が更新されてうまくif文が機能しているのであれば、私のコメントは忘れてください。
Izayoi-san

2020/09/15 00:03

現在の設定のままだとWEBカメラから取得した値分の初期値の誤差が発生したため、BaseFaceRotationにWEBカメラのデータの初回取得分を補正したUpdateFaceRotationを使用するようにしました。 これにより、if文で比較しているUpdateFaceRotationとCurrentFaceRotationの差分はWEBカメラで取得した顔の座標の変化だけになっていることをInspector上で確認しました。 しかし、それでも回転し続けているので、やはり慣性は原因ではないかと考えています。
YAmaGNZ

2020/09/15 01:51

すみません、基本的なことで申し訳ありませんが、 if文の中が実行され続けているために回転し続けているということでしょうか? それとも、if文の中は1度しか実行していないにも関わらず、回転し続けるということでしょうか?
Izayoi-san

2020/09/15 02:42

下記のようにテストプログラムを組んだ場合、pを入力することでif文の実行を強制的に終了した場合、回転が止まりました。 また、pを入力する前はデバッグログにtestが表示され続けていたため、if文の中が実行され続けていたため回転し続けていることがわかりました。 if (Input.GetKey("p")) { isTest = false; } if (isTest) {       Debug.Log("test");   回転制御プログラム }
YAmaGNZ

2020/09/15 03:16

if (Mathf.Abs(Mathf.DeltaAngle(CurrentFaceRotation.x, BaseFaceRotation.x)) > 0.1f) { int bairitsu = 1; if ((Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.x), Mathf.Abs(BaseFaceRotation.x)) < 35) && (Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.x), Mathf.Abs(BaseFaceRotation.x)) > -35)) { CurrentFaceTransform.Rotate(new Vector3(CurrentFaceRotation.x * bairitsu, 0, 0));       Debug.Log("test");   } } としないとRoteteが実行され続けているか判断できなさそうですが、 if文の中のRotateが実行され続けているということですよね? 以下のようなことなのではないのですか? BaseFaceRotation = 顔を正面に向けている時の状態 CurrentFaceRotation = カメラに映っている映像を調べ、「正面を基準とした顔の傾き」を検知した値 正面を0として、顔を40度傾けた状態でカメラに映っているとします。 1回目のUpdate:BaseFaceRotationとCurrentFaceRotationを比較し、40となるのでCurrentFaceTransform.Rotateで現在から40度回転する カメラ画像から顔の傾きを算出:CurrentFaceRotationを更新し、傾きが40度 2回目のUpdate:BaseFaceRotationとCurrentFaceRotationを比較し、40度となるのでCurrentFaceTransform.Rotateで現在から40度回転する と顔を傾けている間は常にCurrentFaceRotationは40度となるので回り続ける状態になっているのではないでしょうか? CurrentFaceRotationが「前回算出した傾きからの傾き」なのであれば、こうはならないのでしょう。 実際にCurrentFaceRotationがどのような変化をしているのか確認はされましたか?
Izayoi-san

2020/09/15 03:31

すみません。追記が抜けておりました。 ご指摘の正面を向いている場合を0、最初の顔の角度を40とした場合~~に関しては 下記のように初期状態に補正をかけております。 これによりCurrentFaceRotationは常にWebカメラが検出している値をBaseFaceRotationに加算した値になっていることを確認しています。 if (!isFirst) { //Debug.Log("test " + d_horizontal_pos); //Debug.Log("test " + d_vertical_pos); //Debug.Log("test " + d_yow); //Debug.Log("test " + d_pitch); //Debug.Log("test " + d_roll); //ゲームオブジェクトの初期値に、顔座標の初期値分の補正をかける UpdateFacePos.x = BaseFacePos.x + (float)d_horizontal_pos; UpdateFacePos.y = BaseFacePos.y + (float)d_vertical_pos; UpdateFaceRotation.x = BaseFaceRotation.x + (float)d_pitch; UpdateFaceRotation.y = BaseFaceRotation.y + (float)d_yow; UpdateFaceRotation.z = BaseFaceRotation.z + (float)d_roll; isFirst = true; } if ((Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.x), Mathf.Abs(UpdateFaceRotation.x)) < 35) && (Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.x), Mathf.Abs(UpdateFaceRotation.x)) > -35)) { CurrentFaceTransform.Rotate(new Vector3(CurrentFaceRotation.x * bairitsu, 0, 0)); }
YAmaGNZ

2020/09/15 03:50 編集

顔を傾けてカメラに映った場合は1フレームのみUpdateFaceRotationとCurrentFaceRotationの差が40となり、次のフレームには0になるということであっていますか?
Izayoi-san

2020/09/15 04:06

1フレーム目が開始した時点ではUpdateFaceRotationとCurrentFaceRotationの差が40となりますが、 補正をしたのちにif文による比較がスタートします。 そのため、比較のタイミングではUpdateFaceRotationとCurrentFaceRotationの差は1フレーム目であっても0になっています。
YAmaGNZ

2020/09/15 04:22

UpdateFaceRotationというのは実行された最初に計算され、以降変更がかからないというのは合っていますか? また、CurrentFaceRotationは顔を傾けてカメラに映っている間はずっと40となるというので合っていますか?
Izayoi-san

2020/09/15 04:30

UpdateFAxeRotationは最初の計算移行数値が変動しません。 CurrentFaceRotationはUpdateの各フレームごとにカメラの情報を取得するため、常に40というわけではありません(顔を動かすと40が35になったり変動します。)
YAmaGNZ

2020/09/15 04:40

顔を40に固定した場合にはCurrentFaceRotationは40の値を取り続けるという事であっているのですよね? そうなると、顔を40に固定してカメラに映った場合、毎フレームUpdateFaceRotationとCurrentFaceRotationの差は40となり、Rotateが実行されて回転し続けることになります。 というのを延々言っているつもりです。 もしかしてRotateは指定の角度に向くといった動作だと勘違いされているのでしょうか? Rotateは引数に渡した角度が加算されるという動きのはずです。
Izayoi-san

2020/09/15 05:03

初期値の補正を加味した下記の条件分岐により回転し続けるのは止まりました。 if ((Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.x), Mathf.Abs(UpdateFaceRotation.x)) < 35) && (Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.x){}
guest

回答1

0

自己解決

初期値の補正を加味した下記の条件分岐により回転し続けるのは止まりました。

if ((Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.x), Mathf.Abs(UpdateFaceRotation.x)) < 35) && (Mathf.DeltaAngle(Mathf.Abs(CurrentFaceRotation.x){}

投稿2020/09/15 05:03

Izayoi-san

総合スコア12

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問