You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Unity中为第一人称角色相机实现15fps帧率截图

解决Unity第一人称相机每1/15秒截图的问题

首先先排查最容易忽略的细节:检查Unity Inspector面板中你的SS脚本的fps参数是否设置为15。如果这个值被误设为1,就会导致每秒只截一张图,这很可能是你当前遇到的核心问题。

如果fps参数已经正确设置,那问题出在Update中用Time.deltaTime累加的方式容易受帧率波动影响,导致时间间隔不准确。下面提供两种更可靠的解决方案:

方案一:修复Update逻辑,优化时间累加

调整当前的代码逻辑,避免冗余判断,同时优化时间累加方式减少误差:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SS : MonoBehaviour {
    public int resWidth = 640;
    public int resHeight = 480;
    public int fps = 15;
    private float timeSinceLastShot = 0f;
    private float captureInterval => 1f / fps; // 计算每帧间隔

    public static string ScreenShotName(int width, int height) {
        return string.Format("{0}/screenshots/screen_{1}x{2}_{3}.png", 
            Application.dataPath, width, height, 
            System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss-fff")); // 增加毫秒,避免文件名重复覆盖
    }

    void Update(){
        timeSinceLastShot += Time.deltaTime;
        
        // 用while循环确保帧率过低时不会漏帧
        while (timeSinceLastShot >= captureInterval) {
            TakeHiResShot();
            timeSinceLastShot -= captureInterval; // 减去间隔而非重置为0,避免长期误差累积
        }
    }

    private void TakeHiResShot() {
        RenderTexture rt = new RenderTexture(resWidth, resHeight, 24);
        Camera cam = GetComponent<Camera>();
        cam.targetTexture = rt;
        Texture2D screenShot = new Texture2D(resWidth, resHeight, TextureFormat.RGB24, false);
        
        cam.Render();
        RenderTexture.active = rt;
        screenShot.ReadPixels(new Rect(0, 0, resWidth, resHeight), 0, 0);
        
        // 清理资源,避免内存泄漏
        cam.targetTexture = null;
        RenderTexture.active = null;
        Destroy(rt);
        
        // 保存截图
        byte[] bytes = screenShot.EncodeToPNG();
        string filename = ScreenShotName(resWidth, resHeight);
        System.IO.File.WriteAllBytes(filename, bytes);
        Debug.Log($"Took screenshot to: {filename}");
        
        Destroy(screenShot); // 释放Texture2D资源
    }
}

优化点说明:

  • 用while循环代替if,确保帧率过低导致累计时间超过多个间隔时,能一次性补全截图,避免漏帧
  • 采用timeSinceLastShot -= captureInterval代替重置为0,减少长期运行的时间误差
  • 截图文件名增加毫秒标识(fff),避免短时间内截图导致文件名重复被覆盖
  • 增加Destroy(screenShot)释放Texture2D资源,防止内存泄漏

方案二:使用协程实现更稳定的定时截图

协程可以更精准地控制时间间隔,不受帧率波动影响,是更推荐的方式:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SS : MonoBehaviour {
    public int resWidth = 640;
    public int resHeight = 480;
    public int fps = 15;
    private float captureInterval => 1f / fps;

    private void Start() {
        // 启动截图协程
        StartCoroutine(CaptureScreenshotsCoroutine());
    }

    public static string ScreenShotName(int width, int height) {
        return string.Format("{0}/screenshots/screen_{1}x{2}_{3}.png", 
            Application.dataPath, width, height, 
            System.DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss-fff"));
    }

    private IEnumerator CaptureScreenshotsCoroutine() {
        while (true) {
            TakeHiResShot();
            // 使用WaitForSecondsRealtime,不受游戏时间缩放(暂停、慢动作)影响
            yield return new WaitForSecondsRealtime(captureInterval);
        }
    }

    private void TakeHiResShot() {
        RenderTexture rt = new RenderTexture(resWidth, resHeight, 24);
        Camera cam = GetComponent<Camera>();
        cam.targetTexture = rt;
        Texture2D screenShot = new Texture2D(resWidth, resHeight, TextureFormat.RGB24, false);
        
        cam.Render();
        RenderTexture.active = rt;
        screenShot.ReadPixels(new Rect(0, 0, resWidth, resHeight), 0, 0);
        
        cam.targetTexture = null;
        RenderTexture.active = null;
        Destroy(rt);
        
        byte[] bytes = screenShot.EncodeToPNG();
        string filename = ScreenShotName(resWidth, resHeight);
        System.IO.File.WriteAllBytes(filename, bytes);
        Debug.Log($"Took screenshot to: {filename}");
        
        Destroy(screenShot);
    }
}

协程方案的优势:

  • WaitForSecondsRealtime不受游戏时间缩放影响,间隔更精准
  • 逻辑更清晰,不需要在Update中累加时间,降低代码复杂度
  • 稳定的定时执行,适合需要固定帧率截图的场景

额外注意事项:

  • 确保Application.dataPath下的screenshots文件夹存在,否则会报错。可以在脚本启动时自动创建:
    private void Awake() {
        string screenshotPath = $"{Application.dataPath}/screenshots";
        if (!System.IO.Directory.Exists(screenshotPath)) {
            System.IO.Directory.CreateDirectory(screenshotPath);
        }
    }
    
  • 如果截图分辨率很高,频繁截图会占用大量磁盘空间和内存,建议根据需求调整分辨率或限制截图时长

内容的提问来源于stack exchange,提问作者Aditya Vartak

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:27:07