ue 切换像素流分辨率
参考文档
https://docs.unrealengine.com/4.27/zh-CN/SharingAndReleasing/PixelStreaming/PixelStreamingIntro/
https://docs.unrealengine.com/5.0/zh-CN/unreal-engine-pixel-streaming-reference/
准备工作
信令服务 和 前端
可以先把信令服务起起来,如
至于前端的话,参考:
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">●</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>
创建基础项目
这里我们随便创建了建筑可视化项目
ue 的像素流插件
必须先启用像素流插件
设置独立进程启动参数
设置 编辑器偏好设置 -> 关卡编辑器 ->播放 -> 额外启动参数
-AudioMixer -PixelStreamingIP=localhost -PixelStreamingPort=8888 -forceres -ResX=3840 -ResY=2160
上面的意思是 像素流送 强制 以4K 运行
切换分辨率实现
其实切换分辨率 主要是ue 控制台使用
r.setRes 1920x1080w
命令实现,上面例子 表示切换到 1080P,所以接下来就是要接收h5 传过来的消息,并且执行
json结构
假设前端传过来的,消息结构如下
{
"type":"4", // 4 - 表示分辨率切换
"param": "r.setRes 1920x1080w" // 分辨率命令 和 参数
}
ue 基础蓝图功能
新建游戏基础模式
GameBaseModel
游戏模式重载
添加像素流组件
双击打开的游戏模式
添加像素流输入事件
添加基本的蓝图功能
下面的蓝图功能很简单就是:
接收前端传过来的数据,并且 加上 ue response:+ 前端传过来的数据 返回
我们先测试链路通不通
运行测试
可以看到 已经有ue 的返回了
ue 切换分辨率
在上面我们已经实现了,像素流的接收和返回,保证链路没问题,接下来我们就按照json 结构执行切换分辨率的命令
蓝图如下
运行测试
可以看到480P 画质 有点糊
再看 4K画质
应该能看出明显的区别
需要注意的地方
启动参数
关于虚幻引擎启动参数,也就是快捷方式启动参数
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
则可以修改,接收的分辨率,两个可以配合使用,缺一不可