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

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

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

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

Q&A

解決済

1回答

2097閲覧

Unity : カメラが壁を映さないようにする方法

dragonshot

総合スコア4

Unity

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

0グッド

1クリップ

投稿2020/05/18 17:05

前提・実現したいこと

建物の中のカメラの動きについて、被写体を追いかけるカメラが壁を映してしまいます。
カメラと被写体の間に壁が存在する時は、壁を映さないまたはカメラを近づけるという機能を実装したいです。
前者はRaycastを使用して壁を判定し、非表示にする方法で実現しましたがカメラを動かす度に壁が映ったり消えたりを繰り返すので実用的ではなく困っています。
色々な実装方法があるかとは思いますがカメラが壁を映さないようにする方法についてアドバイスをいただけたらと思います。

試したこと

https://qiita.com/sakura-crowd/items/3608b2fd6df8a953240a
こちらを参考に作成しました。

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

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

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

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

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

guest

回答1

0

ベストアンサー

被写体からカメラに向かって衝突判定を行い、最初に衝突した位置にカメラを移動するというのはどうでしょうか。

C#

1using UnityEngine; 2 3[RequireComponent(typeof(Camera))] 4public class CameraController : MonoBehaviour 5{ 6 [SerializeField] private Transform targetTransform; 7 [SerializeField] private float angularSpeed = 30.0f; 8 [SerializeField] private string horizontalAxis = "Horizontal"; 9 private Transform cameraTransform; 10 private float distance; 11 private float angle; 12 private Vector3 initialDirection; 13 14 [Header("Obstacle Avoidance")] 15 [SerializeField] private bool avoidObstacles = true; 16 [SerializeField] private LayerMask obstacleLayers = 1; 17 [SerializeField] private float cameraRadius = 0.5f; 18 [SerializeField] private float smoothTime = 0.125f; 19 private float actualDistance; 20 private float distanceVelocity; 21 22 private void Start() 23 { 24 this.cameraTransform = this.transform; 25 this.cameraTransform.LookAt(this.targetTransform); 26 this.distance = Vector3.Distance(this.cameraTransform.position, this.targetTransform.position); 27 this.actualDistance = this.distance; 28 this.initialDirection = (this.cameraTransform.position - this.targetTransform.position).normalized; 29 } 30 31 private void LateUpdate() 32 { 33 // まず障害物は考慮せずにカメラを移動・回転させる 34 var deltaAngle = Input.GetAxis(this.horizontalAxis) * this.angularSpeed * Time.deltaTime; 35 this.angle -= deltaAngle; 36 var direction = Quaternion.Euler(0.0f, this.angle, 0.0f) * this.initialDirection; 37 this.cameraTransform.position = this.targetTransform.position + (direction * this.distance); 38 this.cameraTransform.LookAt(this.targetTransform); 39 40 // 障害物回避を行わないならばここで処理終了 41 if (!this.avoidObstacles) 42 { 43 return; 44 } 45 46 // ターゲットからカメラに向かってヒットテストを行い、 47 // ヒットしていればそれを目標距離に、さもなくば 48 // 本来の距離を目標距離とする 49 var targetDistance = Physics.SphereCast( 50 this.targetTransform.position, 51 this.cameraRadius, 52 direction, 53 out var hitInfo, 54 this.distance, 55 this.obstacleLayers) 56 ? hitInfo.distance 57 : this.distance; 58 59 // 目標距離へなめらかに移動させるためスムージングを行い... 60 this.actualDistance = Mathf.SmoothDamp( 61 this.actualDistance, 62 targetDistance, 63 ref this.distanceVelocity, 64 this.smoothTime); 65 66 // 最終的なカメラ距離に合わせてカメラの位置を再調整する 67 this.cameraTransform.position = this.targetTransform.position + (direction * this.actualDistance); 68 } 69}

図

たぶんCinemachineColliderとかも似たような感じでやっているんじゃないでしょうかね?

投稿2020/05/18 20:34

Bongo

総合スコア10811

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

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

dragonshot

2020/05/19 12:08

回答者様のコードを参考に作成したところ、気になる点がありコメントしました。 勉強不足で大変申し訳ないのですがターゲットからカメラに向かってヒットテストを行う際、Raycastではなく、Spherecastを使用しているのは何か意図があるのでしょうか?
Bongo

2020/05/19 12:22

Raycastでもかまわないと思います。Raycastも試してみて、挙動がしっくりくる方を選ぶといいでしょう。 私がSphereCastを選んだのは、私の感覚ですとカメラの衝突判定に若干の大きさ(回答に例示したスクリプトの場合、デフォルトの半径は0.5)を持たせた方が好ましいかな...と思っただけで、さほど重要な点ではありません。 一緒に載せました実行時の図を観察いただきますと、視界が柱で隠れるギリギリではなく、若干の余裕を持って少しだけ早めにカメラが接近しているのを見て取れますでしょうか?
dragonshot

2020/05/19 13:12

コメント返信ありがとうございます。 実行時の図の確認をしましたところ、確かに少し早めにカメラが接近しております。 引き続いてRaycastとの差異も確認したいと思います。 本筋から逸れるコメントで申し訳ないのですが、カメラとターゲットの間に壁が存在しオブジェクトに接近する際、現状ですとターゲットの高さに水平にカメラが移動するという状態なのですが、このカメラの位置を変更することは可能でしょうか? 回答者様のコードに加え上下のカメラ移動を想定した場合、下から見上げるような構図を取ると床もオブジェクト(壁)として判定されてしまい、カメラが移動しターゲットの足元を映し続ける状態になりました。 〇をターゲット、©をカメラと仮定した場合、 ______________〇_____ 床       ↗     © 上記のような下から見上げる構図の時、以下のような状態になってしまいます。 ______________©〇_____ 床             移動後のカメラの位置を変更することで解決できそうかなと思い試行錯誤しているのですが苦戦しております。 お手数をおかけし申し訳ありませんが、アドバイスをいただきたく思います。
Bongo

2020/05/19 14:30

なるほど、床は障害物と見なさない方がいいということでしょうか(床に関しては通常通り床の下へカメラが移動する)? それでしたら、キャラクターからターゲットの方への衝突判定をとる際の対象レイヤー(私の例示したスクリプトで言うところのobstacleLayers)を調整することで対応できないでしょうか。 たとえば私のスクリプトではobstacleLayersのデフォルト値は「Defaultレイヤーのみ」ということになっていますが、これはつまりDefaultレイヤー以外は障害物として検出されないということですから、床オブジェクトのレイヤーをDefault以外の何かに変えてしまえばいいかと思います。 それとも、床はやはり障害物に含めた上で、なるべくカメラを本来の距離まで引いてキャラクターに近づかないようにしたい...つまり ___©__________〇_____ 床 のような構図にしたいということでしょうか? こちらの方針ですと現状のスクリプトでは対応できないはずですので、さらに手を加える必要がありますね...
dragonshot

2020/05/20 15:20

返信が遅くなってしまい申し訳ありません。 試行錯誤の末、空のオブジェクトに床と壁を一塊に設定していたレイヤー名を分割してレイヤーを再設定するという形で解決することができました。 RaycastとSpherecastの違いについても学ぶことができ、とても勉強になりました。 コメントでの迅速な対応と丁寧な回答、及び解説ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問