如何获取Android平台下Unity游戏场景的渲染耗时
不用Unity Profiler,在Android上获取Unity精确渲染耗时的方案
嘿,刚好做过类似的需求,给你分享几个在Android平台上不用Unity Profiler就能精准获取Unity渲染耗时的方案,开销都很小,不会影响游戏性能:
方法一:利用Unity RenderPipelineManager的帧渲染回调
这个方法是最直接的Unity层面实现,不管你用Built-in、URP还是HDRP渲染管线都适用,核心是捕获渲染管线的开始/结束帧渲染事件,用高精度计时器计算时间差。
实现代码(C#)
using UnityEngine; using UnityEngine.Rendering; using System.Diagnostics; public class RenderTimeTracker : MonoBehaviour { private Stopwatch _renderTimer; private void OnEnable() { // 注册渲染管线的帧开始/结束回调 RenderPipelineManager.beginFrameRendering += OnFrameRenderStart; RenderPipelineManager.endFrameRendering += OnFrameRenderEnd; // 初始化高精度计时器 _renderTimer = new Stopwatch(); } private void OnDisable() { // 记得注销回调,避免内存泄漏 RenderPipelineManager.beginFrameRendering -= OnFrameRenderStart; RenderPipelineManager.endFrameRendering -= OnFrameRenderEnd; } private void OnFrameRenderStart(ScriptableRenderContext context, Camera[] cameras) { // 帧渲染开始时启动计时器 _renderTimer.Restart(); } private void OnFrameRenderEnd(ScriptableRenderContext context, Camera[] cameras) { // 帧渲染结束时停止计时并计算耗时 _renderTimer.Stop(); long renderTimeMs = _renderTimer.ElapsedMilliseconds; double renderTimePreciseMs = _renderTimer.Elapsed.TotalMilliseconds; // 输出到Android Logcat,或者写入本地文件 AndroidJNI.Log($"[UnityRender] 本次渲染耗时: {renderTimePreciseMs:F2}ms"); } }
说明
Stopwatch是C#提供的高精度计时器,比Time.time精准得多,几乎没有性能开销- 回调的时机完全对应Unity渲染管线的实际渲染阶段,不会包含脚本逻辑、UI更新等其他耗时
- 如果是多相机场景,这个回调会在所有相机渲染完成后触发,统计的是整个帧的总渲染耗时
方法二:Android原生层结合Unity帧回调
如果需要更贴近Android系统层面的计时,可以结合Unity的帧回调和Android原生的高精度时钟,适合需要和原生代码联动的场景。
步骤1:Unity端C#代码
using UnityEngine; public class NativeRenderTracker : MonoBehaviour { private AndroidJavaObject _nativeTracker; private void Start() { // 获取当前Unity的Activity实例 using (var unityPlayerClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { var currentActivity = unityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity"); // 初始化原生层的计时工具 _nativeTracker = new AndroidJavaObject("com.yourcompany.yourgame.RenderTimeLogger", currentActivity); } // 注册Unity的帧渲染结束回调 Application.onRenderFrame += OnRenderFrameEnd; } private void OnRenderFrameEnd() { // 通知原生层渲染结束 _nativeTracker.Call("OnRenderFrameCompleted"); } private void OnDestroy() { // 清理资源 Application.onRenderFrame -= OnRenderFrameEnd; _nativeTracker?.Dispose(); } // 可以在渲染开始时调用这个方法,比如在Camera的OnPreRender里 public void NotifyRenderStart() { _nativeTracker?.Call("OnRenderFrameStarted"); } }
步骤2:Android原生Java代码
package com.yourcompany.yourgame; import android.os.SystemClock; import android.util.Log; public class RenderTimeLogger { private long _renderStartNanos; public RenderTimeLogger(android.app.Activity activity) { // 初始化操作,比如申请存储权限(如果要写入文件) } public void OnRenderFrameStarted() { // 用系统的纳秒级时钟记录开始时间 _renderStartNanos = SystemClock.elapsedRealtimeNanos(); } public void OnRenderFrameCompleted() { long renderEndNanos = SystemClock.elapsedRealtimeNanos(); float renderTimeMs = (renderEndNanos - _renderStartNanos) / 1000000.0f; // 输出到Logcat,或者写入本地日志文件 Log.d("UnityRenderNative", "渲染耗时: " + String.format("%.2f", renderTimeMs) + "ms"); } }
说明
- Android的
SystemClock.elapsedRealtimeNanos()是系统级的高精度计时,不受系统时间调整影响 - 可以在Unity的
Camera.onPreRender回调里调用NotifyRenderStart(),确保计时起点是单个相机的渲染开始(如果有多相机,需要分别统计)
关键注意事项
- 避免在计时回调里做耗时操作:比如不要在
OnFrameRenderEnd里直接写文件,建议把耗时数据缓存到内存,每隔N帧再批量写入,减少性能影响 - 适配多相机场景:如果你的场景有多个相机(比如UI相机、主相机),用
Camera.onPreRender/Camera.onPostRender可以分别统计单个相机的渲染耗时 - 测试时关闭额外调试:比如Unity的Gizmos、Stats面板等,这些都会增加额外开销,影响计时准确性
内容的提问来源于stack exchange,提问作者MSD Paul
相关产品推荐
相关产品推荐

