草庐IT

UE4 云渲染环境搭建

tianyapai 2024-02-20 原文

基于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 

有关UE4 云渲染环境搭建的更多相关文章

  1. ruby-on-rails - 渲染另一个 Controller 的 View - 2

    我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>

  2. ruby-on-rails - Rails HTML 请求渲染 JSON - 2

    在我的Controller中,我通过以下方式在我的index方法中支持HTML和JSON:respond_todo|format|format.htmlformat.json{renderjson:@user}end在浏览器中拉起它时,它会自然地以HTML呈现。但是,当我对/user资源进行内容类型为application/json的curl调用时(因为它是索引方法),我仍然将HTML作为响应。如何获取JSON作为响应?我还需要说明什么? 最佳答案 您应该将.json附加到请求的url,提供的格式在routes.rb的路径中定义。这

  3. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  4. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  5. UE4 源码阅读:从引擎启动到Receive Begin Play - 2

    一、引擎主循环UE版本:4.27一、引擎主循环的位置:Launch.cpp:GuardedMain函数二、、GuardedMain函数执行逻辑:1、EnginePreInit:加载大多数模块int32ErrorLevel=EnginePreInit(CmdLine);PreInit模块加载顺序:模块加载过程:(1)注册模块中定义的UObject,同时为每个类构造一个类默认对象(CDO,记录类的默认状态,作为模板用于子类实例创建)(2)调用模块的StartUpModule方法2、FEngineLoop::Init()1、检查Engine的配置文件找出使用了哪一个GameEngine类(UGame

  6. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

    之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

  7. ruby-on-rails - ruby gem如何在rails环境下工作 - 2

    我试图在rails中了解rubygems是如何变得可以自动使用的,而不是在使用required的文件中gem? 最佳答案 这是通过bundler/setup完成的:http://bundler.io/v1.3/bundler_setup.html.它在您的config/boot.rb文件中是必需的。简而言之,它首先将环境变量设置为指向您的Gemfile:ENV['BUNDLE_GEMFILE']||=File.expand_path('../../Gemfile',__FILE__)然后它通过要求bundler/setup将所有ge

  8. ruby-on-rails - 我需要一个真正的 UNIX RoR 开发环境 - 2

    从一开始,我就是一个Windows高手。我从MS-DOS开始。我安装了Windows2.1以及此后的所有Windows。现在,我家里有10台不同的Windows机器在运行,从Windows7Ultimate到各种版本的WindowsServer。我还没有完成Windows8,也不想去那里。我在服务器和各种软件方面都有UNIX经验,但它并不是我的首选环境。但是,我想我正在转换。我试图假装使用Cygwin和MSYS在Windows下运行UNIX。我的目的是搭建一个开发环境。两者都让我失望了。我花了比开发更多的时间来解决一系列技术问题。这是NotAcceptable。到目前为止,我的Ruby

  9. ruby-on-rails - Rails 渲染带有驼峰命名法的 json 对象 - 2

    我在一个简单的RailsAPI中有以下Controller代码:classApi::V1::AccountsControllerehead:not_foundendendend问题在于,生成的json具有以下格式:{id:2,name:'Simpleaccount',cash_flows:[{id:1,amount:34.3,description:'simpledescription'},{id:2,amount:1.12,description:'otherdescription'}]}我需要我生成的json是camelCase('cashFlows'而不是'cash_flows'

  10. ruby-on-rails - 如果特定语言环境中缺少翻译,如何配置 i18n 以使用 en 语言环境? - 2

    如果特定语言环境中缺少翻译,如何配置i18n以使用en语言环境翻译?当前已插入翻译缺失消息。我正在使用RoR3.1。 最佳答案 找到相似的question这里是答案:#application.rb#railswillfallbacktoconfig.i18n.default_localetranslationconfig.i18n.fallbacks=true#railswillfallbacktoen,nomatterwhatissetasconfig.i18n.default_localeconfig.i18n.fallback

随机推荐