播放视频

Godot 通过 VideoStreamPlayer 节点支持视频的播放。

支持的播放格式

核心中仅支持 Ogg Theora 格式(请勿与 Ogg Vorbis 音频混淆)。扩展可以支持额外的格式,但是截止到 2022 年 7 月,还没有这种扩展存在。

Godot 核心无法支持 H.264 和 H.265,因为它们都被软件专利所限。AV1 不需要授权,但 CPU 解码仍然很慢,也不是所有 GPU 都已支持硬件解码。

Godot 3.x 核心中支持 WebM,但是会在 4.0 中移除支持,因为 bug 很多且难以维护。

备注

你的视频可能使用的是 .ogg 或者 .ogx 扩展名,这是带有数据的 Ogg 容器的通用扩展名。

将这些文件扩展名修改为 .ogv可能可以让视频在 Godot 中导入。不过,并不是所有 .ogg.ogx 扩展名的文件都是视频——有些可能只包含音频。

设置 VideoStreamPlayer

  1. 使用“新建 Node”对话框创建 VideoStreamPlayer 节点。

  2. 在场景树面板上选中 VideoStreamPlayer 节点,到检查器中为 Stream 属性加载 .ogv 文件。

  3. 如果你希望在场景加载时立即播放视频,请在检查器中勾选 Autoplay。否则,请保持 Autoplay 关闭,并在需要时在脚本中调用 VideoStreamPlayer 节点的 play() 开始播放。

处理大小变化及不同的纵横比

Godot 4.0 中在默认情况下,VideoStreamPlayer 会自动调整到与视频分辨率相匹配的大小。你可以让它遵循普通的 Control 大小规则,启用 VideoStreamPlayer 节点的 Expand 即可。

要调整 VideoStreamPlayer 节点的大小随窗口大小改变的方式,请通过 2D 编辑器视口顶部的布局按钮调整锚点。不过,这种设置可能不足以处理所有可能的情况,例如全屏播放视频但不造成形变(需要在边界处留白)。要进行精确的控制,你可以使用专为处理这种情况设计的 AspectRatioContainer 节点:

添加一个 AspectRatioContainer 节点。请确保它不是任何其他容器节点的子节点。选中该 AspectRatioContainer 节点,然后在 2D 编辑器的顶部将布局设置为整个矩形。将 AspectRatioContainer 节点的 Ratio(比例)设置为与你的视频的长宽比匹配的比例。你可以在检查器里直接输入数学公式。请记住要将其中的一个操作数写成浮点形式,否则会得到整数的商。

在编辑器检查器中修改 AspectRatioContainer 的 Ratio 属性

求值会得到(大约)1.777778

配置好 AspectRatioContainer 之后,请将你的 VideoStreamPlayer 节点调整为该 AspectRatioContainer 节点的子节点。请确保禁用了该 VideoPlayer 的 Expand。你的视频现在应该就会自动适应到全屏的大小,不产生变形。

参见

更多在项目中支持不同的长宽比的技巧,请参阅 多分辨率

在 3D 表面上显示视频

使用 VideoStreamPlayer 节点作为 SubViewport 节点的子节点,就可以在 3D 表面上显示任何 2D 节点。例如,可以用于显示动态的广告板,帧动画可能花费太多的内存。

可以使用以下步骤实现:

  1. 创建一个 SubViewport 节点。将其设置为与你的视频大小相匹配的像素大小。

  2. 创建一个 VideoStreamPlayer 节点作为该 SubViewport 节点的子节点,并为其指定一个视频的路径。请确保禁用了 Expand,需要时启用 Autoplay

  3. 创建一个 MeshInstance3D 节点,将其 Mesh 属性设为 PlaneMesh 或 QuadMesh。将该网格的大小调整到与视频的长宽比一致(否则看上去就会变形)。

  4. 在 GeometryInstance3D 部分的 Material Override 属性中新建一个 StandardMaterial3D 资源。

  5. 在该 StandardMaterial3D(底部)的 Resource 部分启用 Local To Scene。这是在 Albedo Texture 属性中使用 ViewportTexture 所必须的

  6. 在该 StandardMaterial3D中,将 Albedo > Texture 属性设置为新建 ViewportTexture。点击编辑这个新的资源,在 Viewport Path 属性中指定指向 SubViewport 节点的路径。

  7. 在该 StandardMaterial3D 中启用 Albedo Texture Force sRGB,防止颜色变化。

  8. 如果广告板需要自发光,请将 着色模式 设置为 无阴着色 以提高渲染性能。

更多关于设置的信息,请参阅 使用 Viewport3D GUI 演示

循环视频

要循环视频,可以启用 Loop 属性。这样视频在抵达末尾时就会无缝重启。

请注意,将项目设置 视频延迟补偿 设置为非零的值可能会导致视频循环不再无缝,因为音频和视频的同步发生在每个循环开始时,会导致偶尔丢失帧。将项目设置中的 视频延迟补偿 设置为 0 以避免丢帧问题。

视频解码条件及推荐分辨率

由于 GPU 在解码 Theora 视频时没有硬件加速,所以视频解码是在 CPU 上执行的。现代的桌面 CPU 可以以 1440p @ 60 FPS 或更高的速度解码 Ogg Theora 格式的视频,但低端移动 CPU 处理高分辨率视频可能会比较吃力。

为了确保视频在各种硬件上都能够顺利解码:

  • 为桌面平台开发游戏时,建议最多编码为 1080p(最好是 30 FPS)。大多数人还在使用 1080p 或者更低分辨率的显示器,所以编码为更高分辨率的视频可能不值那些增大的文件大小和 CPU 需求。

  • 为移动和 Web 平台开发游戏时,建议最多编码为 720p(最好是 30 FPS 或更低)。移动设备上 720p 和 1080p 的视频通常很难看出区别。

播放限制

Godot 中目前的视频播放实现有一些限制:

  • 不支持将视频跳跃到特定的时间点。

  • 不支持修改播放速度。VideoStreamPlayer 也不会遵循 Engine.time_scale

  • 不支持从 URL 播放视频流。

推荐 Theora 编码设置

建议是(在大多数情况下)避免依赖内置的 Ogg Theora 导出器。你可能想要优先使用外部程序编码视频的原因有 2 个:

  • Blender 等程序可以渲染 Ogg Theora。然而,默认的质量预设就如今的标准而言通常是非常低的。你可能可以在软件里提高质量选项,但输出的质量可能仍然不理想(提升了文件大小)。这通常意味着那个软件只支持按照固定比特率(CBR)去进行编码,不支持可变比特率(VBR)。大多数场合应该都优先使用 VBR 编码,因为在相同的文件大小下能够提供更好的质量。

  • 有些其他的程序根本无法渲染 Ogg Theora。

在这种情况下,你可以将视频使用高质量格式渲染作为中介(例如高比特率 H.264 视频),然后再重新编码成 Ogg Theora。理想情况下,你应该使用无损或者未压缩格式作为中介格式,最大化输出 Ogg Theora 视频的质量,不过这样做会需要大量的磁盘空间。

HandBrake(GUI)和 FFmpeg(CLI)都是这方面非常流行的开源工具。FFmpeg 的学习曲线相对陡峭,但功能也更强大。

Here are example FFmpeg commands to convert an MP4 video to Ogg Theora. Since FFmpeg supports a lot of input formats, you should be able to use the commands below with almost any input video format (AVI, MOV, WebM, …).

备注

请确保你的 FFmpeg 副本是启用 libtheora 和 libvorbis 编译的。检查方法是不带任何参数执行 ffmpeg,然后查看命令输出中的 configuration: 一行。

平衡质量与文件大小

视频质量等级(-q:v)必须在 110 之间。将质量设为 6 是在质量和文件大小之间的一个不错的妥协。如果要编码较高的分辨率(例如 1440p 或者 4K),你可能想要把 -q:v 降为 5,把文件大小控制在合理的范围内。因为 1440p 和 4K 视频的像素密度更高,相较于低分辨率的视频,较低的质量预设看上去的效果是一样甚至更好的。

** 音频质量**等级(-q:a)必须在 -110 之间。将质量设为 6 是在质量和文件大小之间的一个不错的妥协。与视频质量不同,提升音频质量并不会显著增加输出文件的大小。因此,如果你想要尽可能清晰的音频,可以将其设为 9,达到感知上无损的音频。在你的输入文件使用的已经是有损音频压缩时,这个设置尤其有用。更高质量的音频确实会增加解码器的 CPU 使用率,因此在系统负载较高的情况下可能会导致音频丢失。Ogg Vorbis 音频质量预设及其对应的可变比特率表见这个页面

FFmpeg:转换时保持原始视频分辨率

以下命令会在保持原始分辨率的前提下对视频进行转换。视频和音频的比特率会被设为可变,在最大化质量的同时在不需要高比特率视频/音频的时候节省空间(例如静态场景)。

  1. ffmpeg -i input.mp4 -q:v 6 -q:a 6 output.ogv

FFmpeg:调整视频大小并转换

以下命令会在保持现有长宽比的前提下将视频调整到 720 像素高(720p)。如果原始文件分辨率是大于 720p 的,就能够显著降低文件大小:

  1. ffmpeg -i input.mp4 -vf "scale=-1:720" -q:v 6 -q:a 6 output.ogv

色键视频

色键(Chroma Key)也就是常说的“绿幕”“蓝幕”效果,能够移除图像或视频中的特定颜色,替换为其他背景。这种效果在视频制作领域广泛使用,可以将不同的元素无缝合成到一起。

../../_images/chroma_key_video.webp

我们将通过在 GDScript 中编写自定义着色器,并使用 VideoStreamPlayer 节点来显示视频内容来实现色键效果。

场景设置

确保场景包含用于播放视频的 VideoStreamPlayer 节点,和用于保存用于控制色键效果的 UI 元素的 Control 节点。

../../_images/chroma_key_scene.webp

编写自定义着色器

要实现色键效果,请按照下列步骤操作:

  1. 选择场景中的 VideoStreamPlayer 节点。转到该节点属性栏,在 CanvasItem > Material 下,创建一个名为“ChromaKeyShader.gdshader”的新着色器。

  2. 在“ChromaKeyShader.gdshader”文件中,编写自定义着色器代码,如下所示:

  1. shader_type canvas_item;
  2. # Uniform variables for chroma key effect
  3. uniform vec3 chroma_key_color : source_color = vec3(0.0, 1.0, 0.0);
  4. uniform float pickup_range : hint_range(0.0, 1.0) = 0.1;
  5. uniform float fade_amount : hint_range(0.0, 1.0) = 0.1;
  6. void fragment() {
  7. # Get the color from the texture at the given UV coordinates
  8. vec4 color = texture(TEXTURE, UV);
  9. # Calculate the distance between the current color and the chroma key color
  10. float distance = length(color.rgb - chroma_key_color);
  11. # If the distance is within the pickup range, discard the pixel
  12. # the lesser the distance more likely the colors are
  13. if (distance <= pickup_range) {
  14. discard;
  15. }
  16. # Calculate the fade factor based on the pickup range and fade amount
  17. float fade_factor = smoothstep(pickup_range, pickup_range + fade_amount, distance);
  18. # Set the output color with the original RGB values and the calculated fade factor
  19. COLOR = vec4(color.rgb, fade_factor);
  20. }

着色器使用距离计算来识别接近色键颜色的像素并将其丢弃,从而有效地删除所选颜色。距离色键颜色稍远的像素将根据 fade_factor 进行淡入淡出,从而使它们与周围的颜色平滑地混合。此过程会创建所需的色键效果,使其看起来像是背景已被其他图像或视频替换。

上面的代码是色键着色器的简单演示,用户可以根据自己的具体要求进行自定义。

UI 控件

为了允许用户实时操纵色键效果,我们在 Control 节点中创建了滑动条。 Control 节点的脚本包含以下功能:

  1. extends Control
  2. func _on_color_picker_button_color_changed(color):
  3. # Update the "chroma_key_color" shader parameter of the VideoStreamPlayer's material
  4. $VideoStreamPlayer.material.set("shader_parameter/chroma_key_color", color)
  5. func _on_h_slider_value_changed(value):
  6. # Update the "pickup_range" shader parameter of the VideoStreamPlayer's material
  7. $VideoStreamPlayer.material.set("shader_parameter/pickup_range", value)
  8. func _on_h_slider_2_value_changed(value):
  9. # Update the "fade_amount" shader parameter of the VideoStreamPlayer's material
  10. $VideoStreamPlayer.material.set("shader_parameter/fade_amount", value)
  11. func _on_video_stream_player_finished():
  12. # Restart the video playback when it's finished
  13. $VideoStreamPlayer.play()

还要确保滑动条的范围合适,此处我们的设置是:

../../_images/slider_range.webp

信号处理

将适当的信号从 UI 元素连接到你创建的 Control 节点的脚本上,来控制色键效果。这些信号处理函数会更新着色器的 uniform 变量,响应用户输入。

保存并运行场景来查看色键效果的实际表现!通过 godot 提供的 UI 控件,现在你可以实时调整色键颜色、拾取范围(pickup range)和淡入度量(fade amount),从而为你的视频内容实现所需的色键功能。