Help us understand the problem. What is going on with this article?

【Unity(C#)】HMD装着時にFPSを確認する

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の表示をオフにした瞬間です)

chain_2.gif

コード(修正版)

キャンバスをワールドにしてカメラを一つに
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


  1. 参考リンク 

  2. Unityのバージョンは2018.4.1f1 

  3. 参考リンク 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした