Unity 录制视频

Unity 录制视频

概述

最近偶尔需要录制视频给策划展示模型动画效果,所以总结一下 Unity 里面录制视频的方法。

OBS 录屏法

这个方法很简单,但是确实可以快速录制视频。而且此方法适用范围广,不仅限于录制Unity的视频,还可以用在直播推流等场景。坏处是相当于直接捕获显示器上的内容(至于是整个显示器显示的内容还是显示器部分区域的内容则是看你的设置来定),没法直接录制到目标分辨率。如果策划就是想要录制分辨率是 1920x1080 视频,那么没法直接在编辑器环境中直接录制出来。需要独立一个游戏运行窗口保证窗口分辨率在 1920x1080,或者打包然后让应用运行在 1920x1080 分辨率环境下,相对比较麻烦。

内置 Recorder 录制法

这个方法复杂一点,但是还是比较简单的。Unity 要求版本是 2018.4 以上。

首先我们先从 Package Manager 中导入 Unity Recorder:

20230808145258

如果 Package Manager 中没显示 Unity Recorder,可能需要勾选 Enable Preview Packages 之类的选项(理论上不会不显示,毕竟已经出了正式版)。

导入之后就可以看到类似这样的窗口:

20230808145855

如果没有这个录制操作窗口就需要在 Window 里面打开:

20230808150005

普通录制直接手动点击打开的录制操作窗口中的“START RECORDING”按钮,或者红色的播放按钮就可以开始录制。只是录制简单的游戏画面内容的话基本够用了,如果还需要了解各个参数的作用可以参考官方文档

自动化

使用 Unity Recorder 的好处在于能够自动化,例如批量读取动画数据文件,每个文件录制并保存为单独的视频文件/图片/动图等。但是官方文档没有特别详细说明如何在脚本中调用录制等功能,只是提供了一些例子脚本。这些脚本可以在 Package Manager 中导入:

20230808152435

建议直接看 MultipleRecordingsExample.cs 脚本的内容,这个脚本里面就举了一个同时创建 3 种录制器的例子,分别将录制的内容输出为视频、图片、Unity 内置的 Anim。

下面直接看代码,内容简单易懂:

#if UNITY_EDITOR

using System.IO;
using UnityEditor;
using UnityEditor.Recorder;
using UnityEditor.Recorder.Input;

namespace UnityEngine.Recorder.Examples
{
    /// <summary>
    /// This example shows how to set up a recording session via script.
    /// To use this example, add the MultipleRecordingsExample component to a GameObject.
    ///
    /// Enter the Play Mode to start the recording.
    /// The recording automatically stops when you exit the Play Mode or when you disable the component.
    ///
    /// This script saves the recording outputs in [Project Folder]/SampleRecordings (except for the recorded animation,
    /// which is saved in Assets/SampleRecordings).
    /// </summary>
    public class MultipleRecordingsExample : MonoBehaviour
    {
        RecorderController m_RecorderController;

        void OnEnable()
        {
            var controllerSettings = ScriptableObject.CreateInstance<RecorderControllerSettings>();
            m_RecorderController = new RecorderController(controllerSettings);

            var mediaOutputFolder = Path.Combine(Application.dataPath, "..", "SampleRecordings");
            // animation output is an asset that must be created in Assets folder
            var animationOutputFolder = Path.Combine(Application.dataPath, "SampleRecordings");

            // Video
            var videoRecorder = ScriptableObject.CreateInstance<MovieRecorderSettings>();
            videoRecorder.name = "My Video Recorder";
            videoRecorder.Enabled = true;

            // 设置格式,除了 MP4 还支持 WebM、MOV
            videoRecorder.OutputFormat = MovieRecorderSettings.VideoRecorderOutputFormat.MP4;
            // 比特率,主要影响录制出来的视频质量,如果想要好点可以设置为 Medium 或者 High
            videoRecorder.VideoBitRateMode = VideoBitrateMode.Low;

            // 设置游戏分辨率
            videoRecorder.ImageInputSettings = new GameViewInputSettings
            {
                OutputWidth = 1920,
                OutputHeight = 1080
            };

            // 设置保留音频
            videoRecorder.AudioInputSettings.PreserveAudio = true;
            // 设置输出的路径、文件名
            videoRecorder.OutputFile = Path.Combine(mediaOutputFolder, "video_v") + DefaultWildcard.Take;

            // Animation
            // 这里是录制并输出 anim 格式的文件
            var animationRecorder = ScriptableObject.CreateInstance<AnimationRecorderSettings>();
            animationRecorder.name = "My Animation Recorder";
            animationRecorder.Enabled = true;

            // 这里其实是创建了一个球体来录制,如果是希望录制指定对象,那么最好还是自己传要录制
            // 的对象,例如通过 [SerializeField] 传
            var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);

            // 指定录制对象是前面创建的球体,并且包括其子物体
            animationRecorder.AnimationInputSettings = new AnimationInputSettings
            {
                gameObject = sphere,
                Recursive = true,
            };

            // 添加录制的内容,这里是录制 Transform 组件的内容
            animationRecorder.AnimationInputSettings.AddComponentToRecord(typeof(Transform));
            animationRecorder.OutputFile = Path.Combine(animationOutputFolder, "anim_") + DefaultWildcard.GeneratePattern("GameObject") + "_v" + DefaultWildcard.Take;

            // Image Sequence
            // 这里创建录制照片用的 Recorder
            var imageRecorder = ScriptableObject.CreateInstance<ImageRecorderSettings>();
            imageRecorder.name = "My Image Recorder";
            imageRecorder.Enabled = true;

            // 输出 PNG 模式
            imageRecorder.OutputFormat = ImageRecorderSettings.ImageRecorderOutputFormat.PNG;
            // 录制 Alpha 通道,我理解是如果需要录制透明背景的话这个设置时必须为 true
            imageRecorder.CaptureAlpha = true;

            // 这里是设置输出的路径、文件名
            // DefaultWildcard.Take 相当于第几个 session
            // DefaultWildcard.Frame 当前 frame id,通常是四位数显示,前面用0补齐,例如0001
            imageRecorder.OutputFile = Path.Combine(mediaOutputFolder, "_png", "image_v") + DefaultWildcard.Take + "." + DefaultWildcard.Frame;

            imageRecorder.imageInputSettings = new CameraInputSettings
            {
                Source = ImageSource.MainCamera,
                OutputWidth = 1920,
                OutputHeight = 1080,
                CaptureUI = true
            };

            // Setup Recording
            // 传入前面创建的设置
            controllerSettings.AddRecorderSettings(videoRecorder);
            controllerSettings.AddRecorderSettings(animationRecorder);
            controllerSettings.AddRecorderSettings(imageRecorder);

            // 变成受代码、手动操作控制,另外的模式分别是 SingleFrame、
            // FrameInterval、TimeInterval,和面板里面的参数是对应的
            // 根据自己需要来选即可
            controllerSettings.SetRecordModeToManual();
            // 录制时候游戏运行的目标帧率
            controllerSettings.FrameRate = 60.0f;

            // 这个可以忽略,如果设置为 true 那么会打出更详细的 log
            RecorderOptions.VerboseMode = false;
            // 准备录制需要的内部数据,具体做啥可以先不理解
            // 只需要记得在开始录制之前先执行这个指令
            // 其实就是读取 Setting 中传入的一堆 RecorderSetting
            // 根据 Setting 创建对应的 Recorder Session
            m_RecorderController.PrepareRecording();
            // 开始录制
            m_RecorderController.StartRecording();
        }

        void OnDisable()
        {
            // 停止录制
            m_RecorderController.StopRecording();
        }
    }
}

#endif

脚本头部的注释已经写得很清楚了,只需要将这个脚本放到场景中的某个物体上就可以开始执行脚本内容进行录制。其他部分的代码我都加上了注释,我们自己写自动化脚本的时候对照着这个脚本抄就好。

总结

简单总结了一下 Unity Recorder 的使用方法,解析了官方例子 MultipleRecordingsExample.cs,平时如果遇到需要制作脚本录制视频的场合就可以对着官方例子写自己需要的录制逻辑。

参考

  1. 官方 Unity Recorder 文档
posted @ 2023-08-08 16:04  夜溅樱  阅读(649)  评论(0编辑  收藏  举报