ue 切换像素流分辨率

发布时间 2023-12-06 11:33:57作者: makalo

参考文档

https://docs.unrealengine.com/4.27/zh-CN/SharingAndReleasing/PixelStreaming/PixelStreamingIntro/

https://docs.unrealengine.com/5.0/zh-CN/unreal-engine-pixel-streaming-reference/

准备工作

信令服务 和 前端

可以先把信令服务起起来,如

image-20231206093226748

至于前端的话,参考:

https://www.cnblogs.com/makalochen/p/17803468.html

这里不做赘述

前端示例

<!DOCTYPE html>
<html>

<head>
	<!-- 该文件处理浏览器和虚幻引擎应用间的通信,接受并显示来自服务器的媒体流。在非必要的情况下,请勿修改此JavaScript文件 -->
	<script type="text/javascript" src="../scripts/webRtcPlayer.js"></script>
	<!-- 此文件将设置处理键盘、鼠标和触摸事件的事件监听器 -->
	<script type="text/javascript" src="../scripts/app.js"></script>


	<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">
	<title>myUI</title>
</head>

<body onload="load()">
	<div>
		<button onclick="ueSend('1', '1', '')">晴天</button>
		<button onclick="ueSend('1', '2', '')">雨天</button>
		<button onclick="ueSend('1', '3', '')">雪天</button>
		<button onclick="ueSend('1', '4', '')">雾天</button>
		<button onclick="ueSend2()">设置时间</button> <input type="text" id='setTime'>
		<button onclick="ueSend3('3', '-2', '')">切换到 -2 楼 </button>
		<button onclick="ueSend3('3', '-1', '')">切换到 -1 楼 </button>
		<button onclick="ueSend3('3', '1', '')">切换到 1 楼 </button>
		<button onclick="ueSend3('3', '2', '')">切换到 2 楼 </button>
		<button onclick="ueSend3('3', '3', '')">切换到 3 楼 </button>
		<button onclick="ueSend3('3', '4', '')">切换到 4 楼 </button>
		<button onclick="ueSend3('3', '5', '')">切换到 5 楼 </button>
		<button onclick="ueSend3('3', '6', '')">关闭楼层掀盖 </button>

		<button id="480P" type="button" class="btn btn-secondary" onclick="setRes(854, 480)">
			<span>480P</span>
		</button>
		<button id="720p" type="button" class="btn btn-secondary" onclick="setRes(1280, 720)">
			<span>720p</span>
		</button>
		<button id="1080p" type="button" class="btn btn-secondary" onclick="setRes(1920, 1080)">
			<span>1080p</span>
		</button>
		<button id="720p" type="button" class="btn btn-secondary" onclick="setRes(2560,1440)">
			<span>2K</span>
		</button>
		<button id="4k" type="button" class="btn btn-secondary" onclick="setRes(3840, 2160)">
			<span>4k</span>
		</button>
	</div>
	<div id="playerUI">
		<div id="player"></div>
		<div id="overlay" class="overlay text-light bg-dark">
		<!-- <div id="overlay" class="overlay text-light bg-dark" hidden="hidden"> -->
			<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>
						<!-- <input type="checkbox" id="enlarge-display-to-fill-window-tgl" class="tgl tgl-flat"> -->
						<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>
				<br>

				<!-- 编码设置 -->
				<section id="encoderSettings">
					<div class="settings-text">Encoder Settings</div>
					<div id="encoderParamsContainer" class="collapse">
						<div class="form-group">
							<label for="encoder-rate-control" class="settings-text">Rate Control</label>
							<select id="encoder-rate-control">
								<option value="CBR" selected>CBR</option>
								<option value="VBR">VBR</option>
								<option value="ConstQP">ConstQP</option>
							</select>
							<label for="encoder-target-bitrate-text">Target Bitrate (kbps)</label>
							<input type="number" class="form-control" id="encoder-target-bitrate-text" value="0" min="0"
								max="100000" />
							<label for="encoder-max-bitrate-text">Max Bitrate (kbps)</label>
							<input type="number" class="form-control" id="encoder-max-bitrate-text" value="0" min="0"
								max="100000" />
							<label for="encoder-min-qp-text">Min QP</label>
							<input type="number" class="form-control" id="encoder-min-qp-text" value="0" min="0"
								max="999" />
							<label for="encoder-max-qp-text">Max QP</label>
							<input type="number" class="form-control" id="encoder-max-qp-text" value="0" min="0"
								max="999" />
							<label for="encoder-multipass" class="settings-text">Multipass</label>
							<select id="encoder-multipass">
								<option value="DISABLED" selected>DISABLED</option>
								<option value="QUARTER">QUARTER</option>
								<option value="FULL">FULL</option>
							</select>
							<div class="settings-text">Filler Data</div>
							<label class="tgl-switch">
								<input type="checkbox" id="encoder-filler-data-tgl" class="tgl tgl-flat">
								<div class="tgl-slider"></div>
							</label>
						</div>
						<input id="encoder-params-submit" class="btn btn-primary btn-lg mt-3" type="button"
							value="Apply">
					</div>
					<br>
				</section>

				<!-- webRTC 设置 -->
				<section id="webRTCSettings">
					<div class="settings-text">WebRTC Settings</div>
					<div id="webrtcParamsContainer" class="collapse">
						<div class="form-group">
							<label for="webrtc-degradation-pref">Degradation Pref</label>
							<select id="webrtc-degradation-pref">
								<option value="BALANCED">BALANCED</option>
								<option value="MAINTAIN_FRAMERATE">MAINTAIN_FRAMERATE</option>
								<option value="MAINTAIN_RESOLUTION">MAINTAIN_RESOLUTION</option>
							</select>
							<label for="webrtc-max-fps-text">Max FPS</label>
							<input type="number" class="form-control" id="webrtc-max-fps-text" value="1" min="1"
								max="999" />
							<label for="webrtc-min-bitrate-text">Min Bitrate (kbps)</label>
							<input type="number" class="form-control" id="webrtc-min-bitrate-text" value="0" min="0"
								max="100000" />
							<label for="webrtc-max-bitrate-text">Max Bitrate (kbps)</label>
							<input type="number" class="form-control" id="webrtc-max-bitrate-text" value="0" min="0"
								max="100000" />
							<label for="webrtc-low-qp-text">Low QP Threshold</label>
							<input type="number" class="form-control" id="webrtc-low-qp-text" value="0" min="0"
								max="999" />
							<label for="webrtc-high-qp-text">High QP Threshold</label>
							<input type="number" class="form-control" id="webrtc-high-qp-text" value="0" min="0"
								max="999" />
						</div>
						<input id="webrtc-params-submit" class="btn btn-primary btn-lg mt-3" type="button"
							value="Apply">
					</div>
				</section>
				<br>

				<!-- 显示FPS -->
				<div id="showFPS">
					<div class="settings-text">Show FPS</div>
					<label class="btn-overlay">
						<input type="button" id="show-fps-button" class="overlay-button btn-flat" value="Toggle">
					</label>
				</div>
				<div id="matchViewportResolution">
					<div class="settings-text">Match Viewport Resolution</div>
					<label class="tgl-switch">
						<input type="checkbox" id="match-viewport-res-tgl" class="tgl tgl-flat">
						<div class="tgl-slider"></div>
					</label>
				</div>

				<div id="statsPanel">
					<div class="settings-text">Show Stats</div>
					<label class="tgl-switch">
						<!-- <input type="checkbox" id="show-stats-tgl" class="tgl tgl-flat" checked> -->
						<input type="checkbox" id="show-stats-tgl" class="tgl tgl-flat">
						<div class="tgl-slider"></div>
					</label>
					<div id="statsContainer" class="statsContainer">
						<div id="stats" class="stats"></div>
					</div>
					<br>
				</div>

				<div id="latencyTest">
					<div class="settings-text">Latency Stats</div>
					<label class="btn-overlay">
						<input type="button" id="test-latency-button" class="overlay-button btn-flat"
							value="Test Latency">
					</label>
					<div id="latencyStatsContainer" class="statsContainer">
						<div id=LatencyStats class="stats">No stats yet...</div>
					</div>
				</div>
			</div>
		</div>
	</div>
</body>
<script>
	// 发送到ue
	function api_send(type, action, param, callback) {
		let data = { type, action, param };
		console.log('data ----------->', data);
		// 发送
		emitUIInteraction(data);
		// 注册ue response 监听函数
		addResponseEventListener("handle_responses", callback);
	}
	// 发送ue消息-天气切换
	function ueSend(type, action, param) {
		console.log(`type : ${type}, action : ${action}, param : ${param}`);
		api_send(type, action, param, (info) => {
			console.log(info);
		});
	}
	// 发送ue消息-设置时间
	function ueSend2() {
		const setTime = document.getElementById('setTime').value;
		console.log(`setTime ---------------->, ${setTime}`);
		api_send('2', '', setTime, (info) => {
			console.log(info);
		});
	}
	// 发送ue消息-切换楼层
	function ueSend3(type, action, param) {
		console.log(`type : ${type}, action : ${action}, param : ${param}`);
		api_send(type, action, param, (info) => {
			console.log(info);
		});
	}

	// 重置分辨率
	function setRes(width, height) {
		const param = 'r.' + 'setRes ' + width + 'x' + height + 'w'
		console.log('setRes ->>>>>>>>', param);
		api_send('4', '', param, (info) => {
			console.log(info);
		});
	}
</script>

</html>

创建基础项目

这里我们随便创建了建筑可视化项目

image-20231206094511270

ue 的像素流插件

必须先启用像素流插件

image-20231206093643217

设置独立进程启动参数

设置 编辑器偏好设置 -> 关卡编辑器 ->播放 -> 额外启动参数

-AudioMixer -PixelStreamingIP=localhost -PixelStreamingPort=8888 -forceres -ResX=3840 -ResY=2160

image-20231206093955221

上面的意思是 像素流送 强制 以4K 运行

切换分辨率实现

其实切换分辨率 主要是ue 控制台使用

r.setRes 1920x1080w

命令实现,上面例子 表示切换到 1080P,所以接下来就是要接收h5 传过来的消息,并且执行

json结构

假设前端传过来的,消息结构如下

{
  "type":"4",    // 4 - 表示分辨率切换
  "param": "r.setRes 1920x1080w"    // 分辨率命令 和 参数
}

ue 基础蓝图功能

新建游戏基础模式

image-20231206104423763

image-20231206104452887

GameBaseModel

image-20231206104513796

游戏模式重载

image-20231206110358218

添加像素流组件

双击打开的游戏模式

image-20231206104731828

image-20231206104750629

添加像素流输入事件

image-20231206104837751

image-20231206104849456

添加基本的蓝图功能

下面的蓝图功能很简单就是:

接收前端传过来的数据,并且 加上 ue response:+ 前端传过来的数据 返回

image-20231206105110945

我们先测试链路通不通

运行测试

image-20231206105318687

image-20231206110526443

可以看到 已经有ue 的返回了

ue 切换分辨率

在上面我们已经实现了,像素流的接收和返回,保证链路没问题,接下来我们就按照json 结构执行切换分辨率的命令

蓝图如下

image-20231206111220016

运行测试

可以看到480P 画质 有点糊

image-20231206112308918

再看 4K画质

image-20231206112511090

应该能看出明显的区别

需要注意的地方

启动参数

关于虚幻引擎启动参数,也就是快捷方式启动参数

4.27 版本官网这块没有,但是5.0有,也可以用

参考:

https://docs.unrealengine.com/5.0/zh-CN/unreal-engine-pixel-streaming-reference/

-forceres -ResX=3840 -ResY=2160

需要加上这个,如果不加,使用

r.setRes

是改变不了分辨率的,只会改变独立进程的窗口大小,在我理解 ,可能像素流插件默认有一个推送分辨率,只会启动的时候设置,但是如果启动参数加上

-forceres -ResX=3840 -ResY=2160

这个参数,就会以4K 分辨率推流

r.setRes

则可以修改,接收的分辨率,两个可以配合使用,缺一不可