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

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

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

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

Unity3D

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

Q&A

解決済

1回答

1656閲覧

一人称視点のカメラ制御

DONKAMA

総合スコア1

C#

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

Unity3D

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

0グッド

0クリップ

投稿2020/10/02 05:10

前提・実現したいこと

一人称視点のホラーゲームを作っています。
カメラに「Lerp減衰」「FoV変動」「手振れ」の機能を、スクリプトかChinemachineどちらかで制御する方法が知りたいです。

動かすキャラはStandard AssetのFPSControllerを使っています。
(できればキャラクターはFPSControllerを使い続けたいです)

発生している問題

問題1:
「Lerp減衰」「FoV変動」「手振れ」のスクリプトをアタッチして制御しようとしたのですが、「手振れ」のみ機能せず、sceneを切り替えると画面がガクガクに揺れマウス操作が効かなくなります。

問題2:
公式アセットのCinemachineを使うと手振れなどのカメラの機能は正しく働くようになりました。しかし、ゆっくりマウスを動かせば視点方向に前進するが早く振り返ったりすると前進ボタンを押しても後退してしまいます。
CinemachineとFPSControllerについているカメラとのマウス加速度の差?に違いがあるように感じているのですが解決方法が分かりません。

※両方ともエラーメッセージは一切ありません

試したこと

・新しく作ったカメラに3つの機能のスクリプトをつけると手振れが機能するようになりました。
しかし、移動とマウス操作のスクリプトを追加すると移動はできてもマウス操作が効きませんでした。

・スクリプトのUpdate()をFixedUpdate()に変更しました。
初動に画面が揺れることはなくなったが、移動して停止すると数秒間カメラが前後にガクガク揺れるようになった。

「Lerp減衰」「FoV変動」「手振れ」のスクリプト

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class CameraController3D : MonoBehaviour 6{ 7 public GameObject TargetObject; 8 public float Height = 1.5f; 9 public float Distance = 5.0f; 10 public float HeightAngle = 10.0f; 11 public float RotAngle = 0.0f; 12 public float RotAngleAttenRate = 5.0f; 13 public float AngleAttenRate = 40.0f; 14 15 public bool EnableAtten = true; 16 public float AttenRate = 3.0f; 17 18 public bool EnableNoise = true; 19 public float NoiseSpeed = 0.5f; 20 public float MoveNoiseSpeed = 1.5f; 21 public float NoiseCoeff = 1.3f; 22 public float MoveNoiseCoeff = 2.5f; 23 24 public bool EnableFieldOfViewAtten = true; 25 public float FieldOfView = 50.0f; 26 public float MoveFieldOfView = 60.0f; 27 28 public float ForwardDistance = 2.0f; 29 30 private Camera cam; 31 private Vector3 addForward; 32 private Vector3 deltaTarget; 33 private Vector3 nowPos; 34 private float nowfov; 35 36 private float nowRotAngle; 37 private float nowHeightAngle; 38 39 private Vector3 prevTargetPos; 40 41 // Use this for initialization 42 void Start() 43 { 44 cam = GetComponent<Camera>(); 45 nowfov = FieldOfView; 46 nowPos = TargetObject.transform.position; 47 } 48 49 // Update is called once per frame 50 void FixedUpdate() 51 { 52 RotAngle -= Input.GetAxis("Mouse X") * 5.0f; 53 HeightAngle += Input.GetAxis("Mouse Y") * 5.0f; 54 HeightAngle = Mathf.Clamp(HeightAngle, 0.0f, 80.0f); 55 56 var delta = TargetObject.transform.position - deltaTarget; 57 deltaTarget = TargetObject.transform.position; 58 59 // 減衰 60 if (EnableAtten) 61 { 62 var deltaPos = TargetObject.transform.position - prevTargetPos; 63 prevTargetPos = TargetObject.transform.position; 64 deltaPos *= ForwardDistance; 65 66 addForward += deltaPos * Time.deltaTime * 20.0f; 67 addForward = Vector3.Lerp(addForward, Vector3.zero, Time.deltaTime * AttenRate); 68 69 nowPos = Vector3.Lerp(nowPos, TargetObject.transform.position + Vector3.up * Height + addForward, Mathf.Clamp(Time.deltaTime * AttenRate, 0.0f, 1.0f)); 70 } 71 else nowPos = TargetObject.transform.position + Vector3.up * Height; 72 73 // 手ブレ 74 bool move = Mathf.Abs(delta.x) > 0.0f; 75 var noise = new Vector3(); 76 if (EnableNoise) 77 { 78 var ns = (move ? MoveNoiseSpeed : NoiseSpeed); 79 var nc = (move ? MoveNoiseCoeff : NoiseCoeff); 80 81 var t = Time.time * ns; 82 83 var nx = Mathf.PerlinNoise(t, t) * nc; 84 var ny = Mathf.PerlinNoise(t + 10.0f, t + 10.0f) * nc; 85 var nz = Mathf.PerlinNoise(t + 20.0f, t + 20.0f) * nc * 0.5f; 86 noise = new Vector3(nx, ny, nz); 87 } 88 89 // FoV 90 if (EnableFieldOfViewAtten) nowfov = Mathf.Lerp(nowfov, move ? MoveFieldOfView : FieldOfView, Time.deltaTime); 91 else nowfov = FieldOfView; 92 cam.fieldOfView = nowfov; 93 94 // カメラ位置 95 if (EnableAtten) nowRotAngle = Mathf.Lerp(nowRotAngle, RotAngle, Time.deltaTime * RotAngleAttenRate); 96 else nowRotAngle = RotAngle; 97 98 if (EnableAtten) nowHeightAngle = Mathf.Lerp(nowHeightAngle, HeightAngle, Time.deltaTime * RotAngleAttenRate); 99 else nowHeightAngle = HeightAngle; 100 101 var deg = Mathf.PI / 180.0f; 102 var cx = Mathf.Sin(nowRotAngle * deg) * Mathf.Cos(nowHeightAngle * deg) * Distance; 103 var cz = -Mathf.Cos(nowRotAngle * deg) * Mathf.Cos(nowHeightAngle * deg) * Distance; 104 var cy = Mathf.Sin(nowHeightAngle * deg) * Distance; 105 transform.position = nowPos + new Vector3(cx, cy, cz); 106 107 // カメラ向き 108 var rot = Quaternion.LookRotation((nowPos - transform.position).normalized) * Quaternion.Euler(noise); 109 if (EnableAtten) transform.rotation = Quaternion.Slerp(transform.rotation, rot, Time.deltaTime * AngleAttenRate); 110 else transform.rotation = rot; 111 } 112} 113

補足情報(FW/ツールのバージョンなど)

Unityバージョン:2019.4.9f1

参考にしたサイト
https://qiita.com/yoship1639/items/9bf6f8ad080b3c496b12
http://bboydaisuke.wp.xdomain.jp/2020/06/05/post-313/

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

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

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

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

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

guest

回答1

0

ベストアンサー

ご提示のスクリプトにはマウス操作でカメラの動きを制御するコードが含まれているようですが、FirstPersonController自体にもカメラ制御機能がありますので、それと干渉しないよう工夫する必要がありそうですね。
基本的なカメラ制御はFirstPersonControllerに任せることにして、そこに後から効果を加えるように改変してみました。これならどうでしょうか?

C#

1using System.Collections; 2using UnityEngine; 3using UnityStandardAssets.Characters.FirstPerson; 4 5[RequireComponent(typeof(Camera))] 6public class CameraControllerFPS : MonoBehaviour 7{ 8 [Header("Position/Rotation Attenuation")] 9 public bool EnableAtten = true; 10 public float PositionAttenRate = 3.0f; 11 public float RotationAttenRate = 40.0f; 12 public float ForwardDistance = 0.5f; 13 14 [Header("Noise")] 15 public bool EnableNoise = true; 16 public float NoiseSpeed = 0.5f; 17 public float MoveNoiseSpeed = 1.5f; 18 public float NoiseCoeff = 1.3f; 19 public float MoveNoiseCoeff = 2.5f; 20 21 [Header("FoV Attenuation")] 22 public bool EnableFieldOfViewAtten = true; 23 public float FieldOfView = 50.0f; 24 public float MoveFieldOfView = 60.0f; 25 26 private new Camera camera; 27 private Transform cameraTransform; 28 private float previousFov; 29 private Vector3 previousCameraPosition; 30 private Quaternion previousCameraRotation; 31 private Vector3 expectedCameraPosition; 32 private Quaternion expectedCameraRotation; 33 34 private Transform playerTransform; 35 private Vector3 previousPlayerPosition; 36 37 private Vector3 addForward; 38 39 private Coroutine revertCameraTransformToExpectedCoroutine; 40 41 // Use this for initialization 42 private void Start() 43 { 44 camera = GetComponent<Camera>(); 45 cameraTransform = camera.transform; 46 47 // 念のため親階層にFirstPersonControllerがあるか確認する 48 MonoBehaviour fpsController = cameraTransform.GetComponentInParent<FirstPersonController>(); 49 if (fpsController == null) 50 { 51 fpsController = cameraTransform.GetComponentInParent<RigidbodyFirstPersonController>(); 52 if (fpsController == null) 53 { 54 Debug.LogError("FirstPersonController not found."); 55 enabled = false; 56 return; 57 } 58 } 59 60 // FirstPersonControllerを持っているオブジェクトをプレイヤーオブジェクトとして扱う 61 playerTransform = fpsController.transform; 62 63 // それぞれの前フレームデータに初期値をセットする 64 previousPlayerPosition = playerTransform.position; 65 previousFov = FieldOfView; 66 previousCameraPosition = cameraTransform.position; 67 previousCameraRotation = cameraTransform.rotation; 68 69 // 各フレームのレンダリング後にカメラ位置・回転の変更を取り消すためのコルーチンを始動する 70 revertCameraTransformToExpectedCoroutine = StartCoroutine(RevertCameraTransformToExpected()); 71 } 72 73 private IEnumerator RevertCameraTransformToExpected() 74 { 75 var wait = new WaitForEndOfFrame(); 76 while (true) 77 { 78 yield return wait; 79 80 if (cameraTransform == null) 81 { 82 StopCoroutine(revertCameraTransformToExpectedCoroutine); 83 revertCameraTransformToExpectedCoroutine = null; 84 yield break; 85 } 86 87 cameraTransform.position = expectedCameraPosition; 88 cameraTransform.rotation = expectedCameraRotation; 89 } 90 } 91 92 // LateUpdate is called once per frame after Update 93 private void LateUpdate() 94 { 95 // まずFirstPersonControllerが設定したカメラの位置・回転を保存しておく 96 // 次のフレームでFirstPersonControllerが正しくカメラをコントロールできるようにするため、 97 // レンダリング後に上記のRevertCameraTransformToExpectedで位置・回転を元に戻すようにする 98 expectedCameraPosition = cameraTransform.position; 99 expectedCameraRotation = cameraTransform.rotation; 100 101 // このフレームでのプレイヤーの移動量を求めておく 102 var currentPlayerPosition = playerTransform.position; 103 var playerDeltaPosition = currentPlayerPosition - previousPlayerPosition; 104 105 // 減衰 106 var currentCameraPosition = expectedCameraPosition; 107 if (EnableAtten) 108 { 109 addForward += playerDeltaPosition * (Time.deltaTime * ForwardDistance * 20.0f); 110 addForward = Vector3.Lerp(addForward, Vector3.zero, Time.deltaTime * PositionAttenRate); 111 currentCameraPosition = Vector3.Lerp( 112 previousCameraPosition, 113 currentCameraPosition + addForward, 114 Time.deltaTime * PositionAttenRate); 115 } 116 117 // 手ブレ 118 var move = playerDeltaPosition.sqrMagnitude > 0.0f; 119 var noise = new Vector3(); 120 if (EnableNoise) 121 { 122 var ns = move ? MoveNoiseSpeed : NoiseSpeed; 123 var nc = move ? MoveNoiseCoeff : NoiseCoeff; 124 var t = Time.time * ns; 125 var nx = Mathf.PerlinNoise(t, t) * nc; 126 var ny = Mathf.PerlinNoise(t + 10.0f, t + 10.0f) * nc; 127 var nz = Mathf.PerlinNoise(t + 20.0f, t + 20.0f) * nc * 0.5f; 128 noise = new Vector3(nx, ny, nz); 129 } 130 131 // FoV 132 var currentFov = move ? MoveFieldOfView : FieldOfView; 133 if (EnableFieldOfViewAtten) 134 { 135 currentFov = Mathf.Lerp(previousFov, currentFov, Time.deltaTime); 136 } 137 138 // カメラ向き 139 var currentCameraRotation = expectedCameraRotation * Quaternion.Euler(noise); 140 if (EnableAtten) 141 { 142 currentCameraRotation = Quaternion.Slerp( 143 previousCameraRotation, 144 currentCameraRotation, 145 Time.deltaTime * RotationAttenRate); 146 } 147 148 // カメラの位置・回転・FoVに修正を加える 149 transform.position = currentCameraPosition; 150 transform.rotation = currentCameraRotation; 151 camera.fieldOfView = currentFov; 152 153 // 次のフレームに備えて現フレームのデータを保存しておく 154 previousPlayerPosition = currentPlayerPosition; 155 previousFov = currentFov; 156 previousCameraPosition = currentCameraPosition; 157 previousCameraRotation = currentCameraRotation; 158 } 159}

投稿2020/10/03 22:19

Bongo

総合スコア10807

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

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

DONKAMA

2020/10/05 05:28

元のスクリプトにカメラ操作機能が入っていたことは盲点でした。 ご指摘していただいた上にプログラムも改変していただきありがとうございました。無事カメラ制御をすることができました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問