//tips
//カメラ視線を動かす操作をカスタマイズする
カメラの視線を動かすだけでなく、視線を動かす速度も操作条件に加えてみる。
まずは角度変化の速度が基準としている速度より速いかどうかを判定するスクリプトを記載する。
float deltaAngle = previousCameraAngle - angle;
float rate = deltaAngle / Time.deltaTime;
return (rate >= sweepRate);
の部分で記載され、 private float sweepRate = 100.0f;は自分で好きな値に設定できる。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HeadGesture : MonoBehaviour
{
public bool isFacingDown = false;
public bool isMovingDown = false;
private float sweepRate = 100.0f;
private float previousCameraAngle;
void Start()
{
previousCameraAngle = CameraAngleFromGround();
}
void Update()
{
isFacingDown = DetectFacingDown();
isMovingDown = DetectMovingDown();
}
private bool DetectFacingDown()
{
return (CameraAngleFromGround() < 60.0f);
}
private bool DetectMovingDown()
{
float angle = CameraAngleFromGround();
float deltaAngle = previousCameraAngle - angle;
float rate = deltaAngle / Time.deltaTime;
previousCameraAngle = angle;
return (rate >= sweepRate);
}
private float CameraAngleFromGround()
{
return Vector3.Angle(Vector3.down, Camera.main.transform.rotation * Vector3.forward);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class FlippinDashboard : MonoBehaviour
{
private HeadGesture gesture;
//private GameObject dashboard;
[SerializeField] GameObject dashboard;
private bool isOpen = true;
//private Vector3 startRotation;
private float timer = 0.0f;
private float timerReset = 2.0f;
void Start()
{
gesture = GetComponent<HeadGesture>();
//dashboard = GameObject.Find("Dashboard");
Debug.Log(dashboard);
//startRotation = dashboard.transform.eulerAngles;
CloseDashboard();
}
void Update()
{
if (gesture.isFacingDown)
{
OpenDashboard();
}
else if(!gesture.isFacingDown)
{
timer -= Time.deltaTime;
if (timer <= 0.0f)
{
CloseDashboard();
}
}
else
{
timer = timerReset;
}
}
private void CloseDashboard()
{
if (isOpen)
{
//dashboard.transform.eulerAngles = new Vector3(180.0f, startRotation.y, startRotation.z);
dashboard.SetActive(false);
isOpen = false;
}
}
private void OpenDashboard()
{
if (!isOpen)
{
//dashboard.transform.eulerAngles = startRotation;
dashboard.SetActive(true);
isOpen = true;
Debug.Log("open");
}
}
}
//描画について理解を深める
爆発後に残像が残るバグが出ることがあるので、もう少し描画についての理解を深めて対策を立てられるようにしていく。
基本的に描画はGPU : Graphcs Prosessing Unitとという部品が処理を担当することになるが、OpenGL(Open Graphics Library)を通して、GPUに命令を出していく。
プログラムからOpenGLの命令を通して、GPUにデータや処理内容を伝えていくことになるので、CPUとGPUを繋ぐ窓口がOpenGLと考えることもできる。
フレーム処理がはじまるとCPUは「シーンに配置された全オブジェクトを対象として、そのオブジェクトを描画するべきかどうか」の判定を行う。
判定の結果、画面外に存在するなどで描画する必要がないオブジェクトを取り除き、描画しなければいけないオブジェクト1つ1つに対して「このオブジェクトを描画して」という命令(ドローコール)を蓄積していく。
このドローコールを用意するのに必要な「対象オブジェクトの頂点情報や描画設定を入れたデータ群」のことを”バッチ”と呼び、このバッチを作成する処理のことを”バッチング”と呼ぶ。
すべてのオブジェクトに対して描画チェックとドローコールの蓄積が完了すると、CPUは蓄積されたドローコールを順番にGPUに送信。
「①この環境(マテリアルの変更など)で→②このオブジェクトを描画」もしくは 「このオブジェクトを描画」という命令がCPUからGPUに送信される。
GPUはセットパスコールを受け取ると描画環境を再設定し、ドローコールを受け取ると内包されたバッチを元にオブジェクトを描画。
GPUは渡されたドローコールに内包されたバッチから頂点情報を頂点シェーダーの規則と環境に合わせて最終的な値に変換。
頂点の値が定まったところで、画面内1ピクセル毎に塗る色が決定される。
ドローコールがすべて処理されると、全ピクセルの色が決定することになり、1フレームの画面レンダリングが完了する。
これに関連してゲームシーンのstatusに表示される指標として、画面に描画されるオブジェクトの頂点数の合計Vertsやこの頂点によって構成された三角ポリゴン数の合計Trisなどがある。
オブジェクトを配置する前に、バッチングやセットパスコールが発生するのは、デフォルトで設定されているSkyboxが理由で、これはゲームシーンを内包する大きな球体のオブジェクトの内側にテクスチャを貼り付けることで、360度全方向にわたって背景を表示する仕組みであるため、描画対象として認識され、描画命令が出されている。
Window -> Analysis -> FrameDebuggerで、さらに詳しく、ドローコールを送信された順に確認することができる。
下記が大変参考になった。
https://learn.unity.com/tutorial/fixing-performance-problems#5c7f8528edbc2a002053b595
//一人称の視線で操作する
VR酔は注意しなくてはいけないが、一人称視線での操作は魅力の一つなので機能の実装方法は理解しておく。
カメラを子に持つMeMyselefEyeにスクリプトを追加する。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HeadLookWalk : MonoBehaviour
{
public float velocity = 0.7f;
void Update()
{
Vector3 moveDirection = Camera.main.transform.forward;
moveDirection *= velocity * Time.deltaTime;
transform.position += moveDirection;
}
}
カメラがどちらの方向を向いているのかをCamera.main.transform.forward;で確認し、その方向に移動する。
カメラから飛ぶレイの接触地点に向かっていることがわかる。
下記のようにy座標を固定することもできる。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HeadLookWalk : MonoBehaviour
{
public float velocity = 0.7f;
void Update()
{
Vector3 moveDirection = Camera.main.transform.forward;
moveDirection *= velocity * Time.deltaTime;
moveDirection.y = 0.0f;
transform.position += moveDirection;
}
}
次にMeMyeselfEyeにphysicsのCharacter Controllerをアタッチし、スクリプトを修正。オブジェクトを投下せず、重力にも反応するようにスクリプトを変更する。
CharacterController.SimpleMove()関数は重力とTime.deltaTimeを処理するので移動方向のベクトルを与えれば良い。
移動の開始も操作で行うことにする。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class HeadLookWalk : MonoBehaviour
{
public float velocity = 0.7f;
public bool isWalking = false;
private CharacterController controller;
private Clicker clicker = new Clicker();
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
// Vector3 moveDirection = Camera.main.transform.forward;
//moveDirection *= velocity * Time.deltaTime;
//moveDirection.y = 0.0f;
if (clicker.clicked())
{
isWalking = !isWalking;
}
if (isWalking)
{
controller.SimpleMove(Camera.main.transform.forward * velocity);
}
}
}
キーを押すことで前方への移動のオンオフを切り替える。