UE4 云渲染环境搭建

该文详细介绍了如何利用UE4的云渲染功能将实时渲染图像帧通过视频流传输到浏览器。开发过程包括前端、基于NodeJS的信令服务和UE4服务端的设置,涉及命令转发与接收。通过UE4的强大渲染能力,提供优质的网页端三维体验。此外,文章还展示了前端与UE4服务端的命令交互实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于ue4的云渲染目的在与将ue4实时渲染图像帧通过视频流的方式一帧一帧的传到浏览器端,主要是因为基于web的三维渲染效果不佳,通过ue4的强大渲染能力与各种功能的支持能力使得网页端也可以实时看到好的效果。

这个过程服务之间使用的是反向代理的机制,过程大概分为三个应用:

前端------(控制命令与视频流)node信令服务--------ue4视频流服务。

知识准备工作:

1、前端:web端需要通过html+js的方式显示视频与后端交互,需要熟悉前端的一些知识;

2、信令服务:基于nodejs开发的服务,接受前端发送过来的命令,并将命令转发到ue4服务端,同时接受ue4服务端发送过来的视频流与其他信息转发给前端;

3、ue4服务端:接收信令服务的控制命令信息,根据命令调用相应的功能进行渲染,将渲染结果发送给信令服务。

开发过程:

1、建立ue4工程(本人使用的是4.26版本)名称是"Test",开启"Pixel Streaming"插件。

2、打包工程,打包之后会在生成的目录中包含"node的信令服务",例如:打包目录"D:\WindowsNoEditor",

3、信令服务

信令服务的目录是 "D:\WindowsNoEditor\Engine\Source\Programs\PixelStreaming\WebServers",在"WebServers\SignallingWebServer"文件夹下,包含一些用于启动node的批处理文件。例如run.bat文件

:: Copyright Epic Games, Inc. All Rights Reserved.
@echo off

pushd %~dp0

call setup.bat   ::调用另一个批处理文件(用于安装依赖的npm包)

title Cirrus     ::窗口标题

::Run node server
::If running with frontend web server and accessing outside of localhost pass in --publicIp=<ip_of_machine>
node cirrus %*   ::启动js脚本服务

popd
pause

其中cirrus.js文件会读取"config.json"中的配置信息启动node服务,这些配置信息比较重要的是一些ip地址和端口,"config.json"如下:

{
	"UseFrontend": false,
	"UseMatchmaker": false,
	"UseHTTPS": false,          //是否使用https
	"UseAuthentication": false, //认证信息
	"LogToFile": true,
	"HomepageFile": "Player.htm", //访问的主页
	"AdditionalRoutes": {},
	"EnableWebserver": true,
	"httpPort": 82,             //前端网页的访问地址
	"streamerPort": 8888        //ue4流服务的注册地址
}

由于"run.bat"目录比较深,可以使用快捷方式或者重新定义bat的方式启动,例如:

::信令服务启动
@echo off

call "WebServers/SignallingWebServer/run.bat"

启动信令服务之后会出现下面的窗口

 绿色的部分显示了ue4流服务链接的端口8888,web端链接的端口80,在网页中输入"localhost:80"就可以打开页面,

 3、ue4渲染服务

ue4服务的目录是 "D:\WindowsNoEditor\Test.exe",单纯启动这个程序不会链接到信令服务,需要配置一些参数,例如创建快捷方式,通过在快捷方式的属性中输入一些配置命令,由于"Test.exe"目录比较深,可以使用快捷方式或者重新定义bat的方式启动,例如:

@echo off

start WindowsNoEditor/PixStreamServer.exe -ResX=1920 -ResY=1080 -PixelStreamingIP=localhost -PixelStreamingPort=8888 -log -RenderOffScreen

::参数解析
::ResX、ResY设置窗口的分辨率
::PixelStreamingIP 信令服务的ip
::PixelStreamingPort 信令服务的端口
::log 日志
::RenderOffScreen 是否显示ue4服务窗口

开启"ue4服务"后,点击网页会显示如下界面表明已经开启

 同时"信令服务"界面会显示链接信息

4、命令转发

前端需要编写调用的命令, 调用命令的传递方式是以json格式传输的,所以前端需要调用相应的接口将json数据传输出去就可以了。

打开前面信令服务文件夹下的"config.json",可以看到"HomepageFile": "Player.htm", 访问的主页,主页的代码如下:

<!-- Copyright Epic Games, Inc. All Rights Reserved. -->
<!DOCTYPE HTML>
<html>
<head>
	<link rel="shortcut icon" href="/images/favicon.ico" type="image/x-icon">
	<link rel="icon" type="image/png" sizes="96x96" href="/images/favicon-96x96.png">
	<link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32.png">
	<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png">
	<link type="text/css" rel="stylesheet" href="player.css">
    <script type="text/javascript" src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
    <script type="text/javascript" src="scripts/webRtcPlayer.js"></script>
    <script type="text/javascript" src="scripts/app.js"></script>
</head>

<body onload="load()">
	<div>
    <!-- 这四行代码是我自行添加的,用于测试命令-->
	<button onclick="ButtonTest1()" style="width:100px;height: 50px;">测试1</button>
	<button onclick="ButtonTest2()" style="width:100px;height: 50px;">测试2</button>
	<button onclick="ButtonTest3()" style="width:100px;height: 50px;">测试3</button>
	<button onclick="ButtonTest4()" style="width:100px;height: 50px;">测试4</button>
    

	<div id="playerUI">
		<div id="player"></div>
		<div id="overlay" class="overlay">
			<div>
				<div id="qualityStatus" class="greyStatus">&#9679</div>
				<div id="overlayButton">+</div>
			</div>
			<div id="overlaySettings">
				<div id="KickOthers">
					<div class="settings-text">Kick all other players</div>
					<label class="btn-overlay">
						<input type="button" id="kick-other-players-button" class="overlay-button btn-flat" value="Kick">
					</label>
				</div>
                <div id="FillWindow">
                    <div class="settings-text">Enlarge Display to Fill Window</div>
                    <label class="tgl-switch">
                        <input type="checkbox" id="enlarge-display-to-fill-window-tgl" class="tgl tgl-flat" checked>
                        <div class="tgl-slider"></div>
                    </label>
                </div>
                <div id="QualityControlOwnership">
                    <div class="settings-text">Quality control ownership</div>
                    <label class="tgl-switch">
                        <input type="checkbox" id="quality-control-ownership-tgl" class="tgl tgl-flat">
                        <div class="tgl-slider"></div>
                    </label>
                </div>
				<div id="statsSetting"> 
					<div class="settings-text">Show Stats</div>
					<label class="tgl-switch">
						<input type="checkbox" id="show-stats-tgl" class="tgl tgl-flat" checked>
						<div class="tgl-slider"></div>
					</label>
					<div id="statsContainer">
						<div id="stats"></div>
					</div>
				</div>
			</div>
		</div>
	</div>
	</div>
</body>
</html>

可以看到脚本中引用了

    <script type="text/javascript" src="scripts/webRtcPlayer.js"></script>
    <script type="text/javascript" src="scripts/app.js"></script>

这两行,其中"webRtcPlayer.js"用来播放,而"app.js"中有很多传输命令的接口。

app.js文件中的部分代码如下
 

。。。。。。

function sendInputData(data) {
	if (webRtcPlayerObj) {
		resetAfkWarningTimer();
		webRtcPlayerObj.send(data);
	}
}


// A generic message has a type and a descriptor.
function emitDescriptor(messageType, descriptor) {
	// Convert the dscriptor object into a JSON string.
	let descriptorAsString = JSON.stringify(descriptor);

	// Add the UTF-16 JSON string to the array byte buffer, going two bytes at
	// a time.
	let data = new DataView(new ArrayBuffer(1 + 2 + 2 * descriptorAsString.length));
	let byteIdx = 0;
	data.setUint8(byteIdx, messageType);
	byteIdx++;
	data.setUint16(byteIdx, descriptorAsString.length, true);
	byteIdx += 2;
	for (i = 0; i < descriptorAsString.length; i++) {
		data.setUint16(byteIdx, descriptorAsString.charCodeAt(i), true);
		byteIdx += 2;
	}
	sendInputData(data.buffer);
}

// A UI interation will occur when the user presses a button powered by
// JavaScript as opposed to pressing a button which is part of the pixel
// streamed UI from the UE4 client.
function emitUIInteraction(descriptor) {
	emitDescriptor(MessageType.UIInteraction, descriptor);
}

。。。。。。

// 下面是我自定义按钮的处理函数
function ButtonTest1(){
	let data = {
		"type":"test1",
		"number":1.0,
		"bool":true,
		"string":"xiaoming",
		"subObject":{
			"name":"xiaoming",
			"age":15
		}
	};
	emitUIInteraction(data);
}

可以看到emitUIInteraction是app.js封装的接口,有助于我们传输json数据。

5、ue4命令接收命令

ue4中接收信令服务转发过来的命令使用的是"PixelStreamerInput"插件,一般情况下我们自己创建ue4项目时会创建自己的gamepaly结构,其中gamemode是组织其他功能的一个类,所以通常将"PixelStreamerInput"插件挂到gamemode下面,在蓝图下添加如下节点:

 "PixelStreamerInput"插件内置了接收前端数据、解析json、发送数据的接口。

备注:为了调试方便,可以在ue4的编辑器设置中添加启动参数,这样就不用每次发布出来用exe启动项目了;

over 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值