VRエンジニア vs FPS
VRのFPS調整って大変ですよね。特にStandaloneデバイスしんどいですよね。
ライティング調節して、頑張って作ったエフェクト泣く泣く消して、
オブジェクトの数もゴリゴリ削って、Shader最適化して、ポストエフェクト切って、
「よっしゃこれでFPSいいかんじでしょ!」って確認したら50とかだったら泣いちゃいます。
「PCVRをスタンドアロンにコンバートしてよ!一回作って素材あるから楽勝でしょ!」
なんて言われた日には男泣きです。
FPS確認
エディタ上のStatsで確認できるんですが、
Standaloneデバイスおよび、実行形式で書きだした場合の確認はHMD越しにしかFPSを確認することはできません。
なので、スクリプト貼り付けたら勝手に画面にFPSが出現するってのを作りました。
何番煎じなんだよお前、パクリ乙って感じだと思いますが、
せっかく作ったんで書かせてください。
2019/08/14 追記
下記のコードだとカメラを余分に1つ増やしたことによる余計なレンダリング処理(?)か何かで
FPSを調べるためのスクリプトでFPSが低下するという漫談みたいな状態になっていました。
コード(FPSが低下してしまうバージョン)
using UnityEngine;
using UnityEngine.UI;
public class FpsDisplay : MonoBehaviour
{
int frameCount;
float prevTime;
float fps;
Text fpsText;
void Reset()
{
this.gameObject.name = "FPS";
}
void Start()
{
//カメラ自動生成
GameObject camera_G = new GameObject("OnlyUIRenderingCamera");
Camera faceCamera = camera_G.AddComponent<Camera>();
faceCamera.clearFlags = CameraClearFlags.Depth;
faceCamera.cullingMask = (1 << LayerMask.NameToLayer("UI"));
camera_G.transform.parent = this.gameObject.transform;
//キャンバス生成&設定
GameObject canvas_G = new GameObject("FaceCanvas");
Canvas faceCanvas = canvas_G.AddComponent<Canvas>();
canvas_G.AddComponent<CanvasRenderer>();
faceCanvas.planeDistance = 1;
faceCanvas.renderMode = RenderMode.ScreenSpaceCamera;
faceCanvas.worldCamera = faceCamera;
canvas_G.transform.parent = camera_G.transform;
//テキスト生成&設定
GameObject text_G = new GameObject("FpsText");
fpsText = text_G.AddComponent<Text>();
fpsText.font = Resources.GetBuiltinResource(typeof(Font), "Arial.ttf") as Font;
fpsText.fontSize = 34;
text_G.transform.parent = canvas_G.transform;
//テキストのポジションを調整
RectTransform textRect = text_G.GetComponent<RectTransform>();
textRect.sizeDelta = new Vector2(1000, 1000);
textRect.localPosition = new Vector3(400, -300, 0);
textRect.localScale = new Vector3(1, 1, 1);
//Layerを変更
canvas_G.layer = LayerMask.NameToLayer("UI");
text_G.layer = LayerMask.NameToLayer("UI");
}
void Update()
{
frameCount++;
float timer = Time.realtimeSinceStartup - prevTime;
if (timer >= 0.5f)
{
fps = frameCount / timer;
fpsText.text = ((int)fps).ToString() + "FPS";
frameCount = 0;
prevTime = Time.realtimeSinceStartup;
}
}
}
実際にprofilerをチェックすると一目瞭然です。(ガクッとレンダリングの負荷が低下した瞬間が、FPSの表示をオフにした瞬間です)
コード(修正版)
using UnityEngine;
using UnityEngine.UI;
public class FpsDisplay : MonoBehaviour
{
int frameCount;
float prevTime;
float fps;
Text fpsText;
void Reset()
{
this.gameObject.name = "FPS";
}
void Start()
{
//キャンバス生成&設定
GameObject canvas_G = new GameObject("FaceCanvas");
Canvas faceCanvas = canvas_G.AddComponent<Canvas>();
canvas_G.AddComponent<CanvasRenderer>();
//レンダリングをfaceCameraに
faceCanvas.renderMode = RenderMode.WorldSpace;
//このゲームオブジェクトの親、ポジションを設定
this.gameObject.transform.parent = Camera.main.transform;
this.gameObject.transform.localPosition = Vector3.zero;
this.gameObject.transform.localRotation = Quaternion.identity;
//キャンバスの親、ポジションを設定
canvas_G.transform.parent = this.gameObject.transform;
canvas_G.transform.localPosition = new Vector3(0,0,0.3f);
canvas_G.transform.localScale = new Vector3(0.01f, 0.01f, 0);
canvas_G.transform.localRotation = Quaternion.identity;
//テキスト生成&設定
GameObject text_G = new GameObject("FpsText");
fpsText = text_G.AddComponent<Text>();
fpsText.font = Resources.GetBuiltinResource(typeof(Font), "Arial.ttf") as Font;
fpsText.fontSize = 34;
fpsText.alignment = TextAnchor.MiddleCenter;
text_G.transform.parent = canvas_G.transform;
//テキストのポジションを調整
RectTransform textRect = text_G.GetComponent<RectTransform>();
textRect.sizeDelta = new Vector2(1000, 1000);
textRect.anchoredPosition = new Vector3(0, 0, 0);
textRect.localScale = new Vector3(0.1f,0.1f,1);
textRect.localRotation = Quaternion.identity;
}
void Update()
{
frameCount++;
float time = Time.realtimeSinceStartup - prevTime;
if (time >= 0.5f)
{
fps = frameCount / time;
fpsText.text = ((int)fps).ToString()+"FPS";
frameCount = 0;
prevTime = Time.realtimeSinceStartup;
}
}
}
canvas_G.transform.localPosition = new Vector3(0,0,0.3f);
の箇所で
カメラの30cm前方にワールドキャンバスを設置しています。
最前面には表示されませんが、負荷は大幅に軽減されているはずです。
使い方
空のゲームオブジェクトを生成してそれにアタッチするだけです。
オンオフはそのゲームオブジェクトのActiveを切り替えるだけです。
下記箇所でアタッチするだけでリネームされるようになってます。
void Reset()
{
this.gameObject.name = "FPS";
}
FPSの計算自体はよくある1秒間記録ではなく0.5秒間記録して精度上げましょう1っていう計算方法のやつです。
また、ここにあるやり方で、実装しているので最前面に描画されます。
ちょっと時間かかったところ
fpsText.font = Resources.GetBuiltinResource(typeof(Font), "Arial.ttf") as Font;
の部分です。
何度やってもテキストをScriptから生成した場合はFontが設定されていない状態2になってしまいました。(私だけ?)
なのでフォントを引っ張ってきてます。
テキストが表示されないだけでエラーは出なかったので見つけるのに時間がかかりました。
自分でインポートしたフォントを利用する場合は、
インポートしたフォントをResources直下にぶち込んで
Font font = Resources.Load<Font>("Resourcesより下階層のパス名);
といった感じで取得できるそうです。3