背景概要
一直以来,有关云游戏的讨论层出不穷,各个巨头公司也有过很多尝试,像Google的Stadia、微软的Project xCloud、亚马逊的Luna云游戏等。云游戏的核心思想是游戏客户端上云,利用云端的计算能力渲染画面再传输到终端设备上,减轻终端设备压力,实现跨设备平台、轻量级的游戏场景。
各大游戏引擎也在最近几年推出图形渲染流的相关项目,意向解决游戏画面传输问题,比如 Unreal Engine 的 Pixel Streaming,再比如 Unity3d 的 Render Streaming。这类项目的核心都是通过WebRTC(Web Real-Time Communication)实现媒体流的传输。本文旨在借助UnityRenderStreaming 容器化Unity应用,实现画面在云端渲染、然后实时传输至浏览器这样的云游戏场景。
在实践之前,我们先讨论为何要将Unity应用容器化。我们都知道在游戏场景下,图形计算资源的使用时间和玩家游戏时间是同步的,这意味着在理想情况下图形计算应在玩家游戏时提供,离开游戏时回收。容器轻量化的特点使得调度部署都更加灵活,可以满足上述需求,最大程度上增加资源的利用率。
接下来我们来在ACK上进行一个Unity远程渲染的Demo演示
实践演示
1. 使用Unity Editor开发Unity Render Streaming应用
Unity Editor Version: 2021.3.2f1c1 / Mac M1 silicon
新建Project,在Window选项卡中选中Package Manager
单击右上角 + 号按钮选择: Add package from git URL
输入com.unity.renderstreaming@3.1.0-exp.2,搜索该package,点击Add
跳出弹窗,是否使用新的输入方案,单击Yes,项目重启
重启后可以看到Unity Render Streaming包已经导入
我们直接使用官方Samples,1.19MB的Example 点击Import,Assets表已更新
由于是Demo演示,我们不做任何修改,直接Build,选择Target Platform 为 linux,Scenes仅选择WebBrowserInput,单击Build
将其命名为mac-linux,得到以下文件
除了编译Unity应用以外,我们需要制作对应的Webserver实现浏览器对其的传输访问。这里由于是官方Sample,所以直接下载对应的webserver即可。如图所示,点击Download web app
至此,一个能够进行Remote Render Streaming的应用就开发完成。我们得到了一个Unity的可执行文件,以及一个webserver服务应用。有关RenderStreaming更多的实现方式可以参考: https://docs.unity3d.com/Packages/com.unity.renderstreaming@3.1/manual/index.html
2. 容器化Unity应用
在这一步,我们需要容器化unity和其对应的webserver
webserver的容器化和大多web型应用类似,Dockfile如下:
FROM ubuntu:20.04
WORKDIR /run
COPY webserver ./
CMD webserver -w
unity的容器化可以参考文章《ACK上图形应用(GUI Application)容器化最佳实践》,需要注意的是基础镜像的选择,和unity Render Streaming相关依赖包的安装。基础镜像从https://hub.docker.com/r/unityci/editor选择对应的版本,当前例子我选择的是 ubuntu-2021.3.2f1-mac-mono-1.0.1 。为了使例子正常运行,需要额外安装依赖包:vulkan-util 、libc++1 、 libc++abi1
得到两个镜像后,我们将其部署至ACK集群上。实践环境如下:
-
ACK托管集群,版本为 1.22.3-aliyun.1
-
节点池操作系统为 Alibaba Cloud Linux 2.1903
-
实例规格为 ecs.gn6v-c8g1.2xlarge
-
Docker Engine 版本:为 19.3.15
我们将两个容器放在一个pod中,共享网络命名空间,unity demo会与websever 就127.0.0.1:80进行websocket连接,而webserver暴露对应端口,等待浏览器访问,建立该端连接。该pod的yaml如下:
apiVersion: v1
kind: Pod
metadata:
name: unity-demo
namespace: default
spec:
# 由于linux版本的webserver示例在使用web socket时只暴露了127.0.0.1地址,所以在这里pod使用宿主网络,通过EIP访问宿主的方式让浏览器建立ws连接。
hostNetwork: true
nodeName: xxx
containers:
- image: xxx:xx
name: unity
command: ["/run/mac-linux/mac-linux.x86_64"]
securityContext:
privileged: true
- image: xxx:xx
name: webserver
ports:
- containerPort: 80
protocol: TCP
restartPolicy: Always
3. 访问服务,并查看效果
在浏览器端直接访问宿主EIP:80,界面如下:
选择VideoPlayer Sample的模式,来看看效果如何:
通过多次访问发现实时显示效果跟网络环境有很大关系,在网络通畅的情况下基本上没有卡顿的情况出现。