2026/7/4 1:23:43

UE像素流送实战:从原理到双向通信的完整部署指南

UE像素流送实战:从原理到双向通信的完整部署指南 如果你正在开发一个需要将 Unreal EngineUE制作的 3D 应用或游戏部署到 Web 端让用户无需下载几十个 G 的客户端打开浏览器就能体验那么“像素流送”技术就是你绕不开的解决方案。但很多开发者初次接触时会误以为这只是简单的“视频推流”上手后才发现从 UE 程序打包、信令服务器搭建、前端 SDK 集成到实现鼠标键盘交互、数据双向通信每一步都可能遇到意想不到的坑。这篇文章要解决的正是这个核心痛点如何将 UE 程序稳定、高效地“像素流送”到网页并在此基础上实现前端与 UE 应用之间真正的双向通信而不仅仅是单向的视频观看。很多人卡在第一步服务器跑起来了却看不到画面或者看到了画面却无法操作又或者能操作了但不知道怎么把网页上的数据比如一个按钮点击、一个表单输入实时传回 UE 逻辑里。本文将从一个完整的、可落地的项目视角出发带你一步步拆解 UE 像素流送的完整链路。你会看到核心原理像素流送到底在底层做了什么为什么它比传统 WebGL 方案更适合重型 UE 应用。环境搭建从 UE 项目设置、信令服务器Signalling Server部署到前端页面的基础集成。双向通信这是重点我们将深入讲解如何通过前端 JavaScript SDK 向 UE 发送自定义事件以及如何在 UE 蓝图中接收并处理这些事件实现业务逻辑的联动。避坑指南汇总了网络配置、编码参数、常见错误等高频问题帮你节省大量排查时间。无论你是前端工程师需要对接 UE 能力还是 UE 开发者希望拓展 Web 交付渠道这篇文章都将提供一份清晰的“施工图”。1. 像素流送不是推流而是远程交互式渲染在深入代码之前我们必须先厘清一个关键概念UE 的像素流送Pixel Streaming到底是什么它不是简单的 OBS 推流或 RTMP 直播。后者是单向的视频流广播延迟高且观众无法交互。而像素流送是一套低延迟、双向交互的远程渲染方案。其核心流程可以类比为“云电脑”服务端UE 应用在你的服务器或高性能机器上运行着完整的、带图形界面的 UE 应用程序。它正常渲染每一帧画面。编码与传输UE 内置的像素流插件会实时捕获渲染出的每一帧图像通过高效的视频编码器如 H.264/AVC 或 H.265/HEVC将其压缩成视频流。信令服务器Signalling Server这是一个关键的中间层通常由 Node.js 实现。它不传输视频流本身而是负责管理“会话”Session。当用户打开网页时信令服务器协调前端播放器与后端 UE 应用实例之间的连接交换双方的网络地址IP/端口等信息相当于一个“媒人”。前端播放器Web 客户端用户在浏览器中打开一个网页其中嵌入了 Pixel Streaming SDK 提供的 JavaScript 播放器。这个播放器通过 WebRTC 协议从 UE 服务端直接接收编码后的视频流并在 HTML5 的video元素或 Canvas 上解码、播放。双向通信同时前端的鼠标、键盘、触摸、甚至自定义的 UI 事件会通过同一个 WebRTC 数据通道Data Channel发送回 UE 服务端。UE 应用接收到这些输入后就像在本地操作一样进行处理从而实现真正的交互。为什么选择像素流送而不是将 UE 项目打包成 WebGL对于中小型或风格化的 3D 内容WebGL 是优秀的选择。但对于使用了大量高级渲染特性如 Lumen 全局光照、Nanite 虚拟几何体、复杂物理模拟或庞大资源包的 AAA 级 UE 项目WebGL 在性能、兼容性和功能完整性上目前还无法胜任。像素流送将计算和渲染压力完全放在了服务端用户端只需要一个能播放视频的现代浏览器即可极大地降低了终端设备的门槛。2. 环境准备明确你的技术栈与工具版本开始动手前请确保你的环境符合以下要求。版本不一致是大多数问题的根源。2.1 Unreal Engine 端UE 版本本文基于UE 5.2编写但核心流程适用于 4.27 及以上的大部分版本。请确保你的项目在该版本下能正常打包。插件启用在 UE 编辑器中打开“编辑” - “插件”搜索并启用Pixel Streaming插件。通常还需要启用相关的WebRTC插件它们通常是像素流插件的依赖项。项目设置你的 UE 项目本身应该是一个可独立运行的应用程序如第一人称或第三人称模板项目即可。操作系统服务端推荐 Windows 10/11 或 Linux。Windows 对 DirectX 的支持更原生。注意UE 编辑器本身无法直接作为像素流服务器必须打包Package出独立程序。2.2 信令服务器与前端Node.js信令服务器需要 Node.js 环境。推荐安装LTS 版本如 18.x, 20.x。信令服务器代码UE 引擎自带了一套信令服务器示例。路径通常为[YourUEInstallation]/Engine/Source/Programs/PixelStreaming/WebServers。我们将使用这里的SignallingWebServer。前端依赖前端页面需要引入 UE 提供的 Pixel Streaming 库。这些库文件也包含在上述信令服务器目录中无需额外 npm 安装。现代浏览器客户端需要 Chrome、Edge、Firefox 等支持 WebRTC 和现代视频编码的浏览器。2.3 网络环境关键要求运行 UE 应用的服务端、运行信令服务器的机器、以及访问网页的客户端三者必须在同一个局域网内或者具有公网 IP 并能互相访问。这是 WebRTC 点对点连接建立的基础。在本地开发时通常就是同一台电脑。3. 第一步从 UE 项目打包开始我们的目标是生成一个可以接收网络命令、输出视频流的 UE 可执行文件。3.1 启用像素流插件并打包在 UE 编辑器中打开你的项目。点击菜单栏的编辑-插件。在插件搜索框中输入Pixel Streaming勾选启用它并重启编辑器。点击平台-Windows-打包项目选择输出目录例如D:\MyUEGame\Package。等待打包完成这会生成一个Windows文件夹里面包含YourGame.exe等文件。3.2 配置启动参数关键步骤直接运行YourGame.exe是不会开启像素流功能的。我们需要通过命令行参数来启动它。创建一个批处理文件.bat或直接使用命令行REM 文件路径D:\MyUEGame\Package\Windows\run_with_pixelstreaming.bat echo off cd /d %~dp0 start YourGame.exe -AudioMixer -PixelStreamingIP127.0.0.1 -PixelStreamingPort8888 -RenderOffScreen -ForceRes -ResX1280 -ResY720参数解释-PixelStreamingIP127.0.0.1指定信令服务器的 IP 地址。本地测试就用 127.0.0.1。-PixelStreamingPort8888指定信令服务器的端口需与后续信令服务器配置一致。-RenderOffScreen让 UE 应用在无头模式没有可见窗口下渲染。这对于服务器部署很重要。开发调试时可以先不加此参数以便看到UE窗口。-ForceRes -ResX1280 -ResY720强制指定渲染分辨率。流送的分辨率由此决定并非前端页面大小。运行这个批处理文件你应该能看到 UE 应用启动如果没加-RenderOffScreen会看到一个窗口。此时它正在等待信令服务器的连接。4. 第二步启动信令服务器信令服务器是连接 UE 应用和前端的桥梁。我们使用 UE 自带的示例。定位服务器文件找到[YourUEInstallation]/Engine/Source/Programs/PixelStreaming/WebServers/SignallingWebServer目录。安装依赖在该目录下打开命令行运行npm install这将会安装express,ws(WebSocket) 等必要的 Node.js 模块。配置服务器查看目录下的config.json或cirrus.js(不同版本可能不同)。我们需要关注监听端口。通常默认配置是监听 80 或 8080 端口。为了不与常用端口冲突我们修改为 8888与 UE 启动参数一致。找到配置文件例如cirrus.js中类似listenPort: 80的地方改为listenPort: 8888。或者可以通过命令行参数启动时指定端口。启动服务器在SignallingWebServer目录下运行node cirrus.js如果看到类似Signalling server listening on 0.0.0.0:8888的日志说明信令服务器已成功启动。此时你的系统里应该运行着两个程序UE 应用在 127.0.0.1 的某个随机端口上等待连接。信令服务器在 127.0.0.1:8888 上运行等待前端和 UE 应用来“登记”。5. 第三步创建前端页面并建立基础连接信令服务器目录下通常有一个public文件夹里面包含了前端示例如player.html。我们可以基于它修改或者自己创建一个。5.1 基础 HTML 结构创建一个简单的index.html文件放在信令服务器的public目录下或者任何你能通过http://localhost:8888/访问到的地方。!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 titleUE Pixel Streaming Demo/title style #videoContainer { width: 1280px; height: 720px; border: 2px solid #333; position: relative; } #streamingVideo { width: 100%; height: 100%; object-fit: contain; /* 保持比例适应容器 */ } #controls { margin-top: 20px; } button { padding: 10px 20px; margin: 5px; font-size: 16px; } /style /head body h1UE 像素流交互演示/h1 p状态: span idstatus正在初始化.../span/p !-- 视频流将显示在这个容器里 -- div idvideoContainer video idstreamingVideo autoplay playsinline/video /div !-- 控制按钮区域 -- div idcontrols button idbtnJump让角色跳跃/button button idbtnChangeColor切换场景颜色/button input typetext idcustomMessage placeholder输入消息发送到UE button idbtnSendMessage发送自定义消息/button /div !-- 引入 UE Pixel Streaming SDK -- script src/libs/UE.js/script !-- 引入我们自己的逻辑脚本 -- script srcapp.js/script /body /html5.2 核心 JavaScript 逻辑 (app.js)这是实现连接和通信的核心。我们创建一个app.js文件。// 文件app.js let streamer null; let config null; document.addEventListener(DOMContentLoaded, function() { // 1. 初始化 Pixel Streaming 配置 config { initialSettings: { AutoPlayVideo: true, AutoConnect: true, // 页面加载后自动连接 StartVideoMuted: false, WaitForStreamer: true, }, // 信令服务器地址 signallingServerUrl: ws://${window.location.hostname}:8888, // 自定义函数来处理来自 UE 的消息 onCustomMessage: handleMessageFromUE, }; // 2. 创建 PixelStreaming 实例 // videoElementParent 是视频容器元素的 ID streamer new UE.PixelStreaming(config); streamer.addEventListener(playStream, () { updateStatus(已连接正在播放流); }); streamer.addEventListener(disconnect, () { updateStatus(连接断开); }); streamer.addEventListener(error, (e) { updateStatus(错误: e.detail); console.error(Pixel Streaming Error:, e.detail); }); // 3. 为按钮绑定事件发送指令到 UE document.getElementById(btnJump).addEventListener(click, () { // 发送一个名为 Jump 的指令不带参数 streamer.emitUIInteraction({ Command: Jump }); console.log(Sent Jump command); }); document.getElementById(btnChangeColor).addEventListener(click, () { // 发送一个名为 ChangeColor 的指令带一个颜色参数 let randomColor #${Math.floor(Math.random()*16777215).toString(16)}; streamer.emitUIInteraction({ Command: ChangeColor, Color: randomColor }); console.log(Sent ChangeColor command:, randomColor); }); document.getElementById(btnSendMessage).addEventListener(click, () { let message document.getElementById(customMessage).value; if(message) { // 发送一个自定义结构的数据 streamer.emitUIInteraction({ Command: CustomEvent, UserMessage: message, Timestamp: Date.now() }); console.log(Sent custom message:, message); document.getElementById(customMessage).value ; } }); // 4. 尝试自动连接 connectToStreamer(); }); function connectToStreamer() { updateStatus(正在连接到信令服务器...); // videoElementId 是页面中 video 元素的 ID streamer.connectToSignallingServer(config.signallingServerUrl, streamingVideo); } function updateStatus(msg) { document.getElementById(status).textContent msg; console.log(Status:, msg); } // 5. 处理从 UE 发来的消息双向通信的另一半 function handleMessageFromUE(message) { console.log(Message from UE:, message); // 这里可以根据 message 的内容更新网页UI // 例如如果 UE 发来 { type: scoreUpdate, value: 100 } // 我们可以更新网页上的分数显示 if(message.type scoreUpdate) { // 假设页面上有个 span idscore0/span // document.getElementById(score).textContent message.value; updateStatus(UE 通知: 分数更新为 ${message.value}); } }关键点解析UE.PixelStreaming这是 SDK 暴露的核心类管理整个连接生命周期。emitUIInteraction这是前端向 UE 发送数据的主要方法。你可以传递任何可序列化为 JSON 的对象。onCustomMessage这是一个回调函数配置项用于接收从 UE 主动发往前端的消息是实现“双向”通信的关键。connectToSignallingServer该方法会通过 WebSocket 连接到我们启动的信令服务器ws://localhost:8888并开始协商 WebRTC 连接。6. 第四步在 UE 蓝图中接收并处理前端事件前端发送了数据UE 端必须能接收并做出反应。这需要在 UE 项目中编写蓝图或 C 逻辑。6.1 创建蓝图接收器在 UE 编辑器的内容浏览器中右键 -蓝图类- 选择Actor命名为BP_PixelStreamingController。打开这个蓝图首先添加一个Pixel Streaming组件。在组件面板点击“添加组件”搜索Pixel找到Pixel Streaming并添加。在事件图表Event Graph中我们需要监听来自前端的 UI 交互事件。6.2 编写蓝图逻辑以下是关键节点的设置事件 BeginPlay当游戏开始时获取 Pixel Streaming 组件的引用并绑定自定义事件。绑定事件使用On Pixel Streaming UI Interaction节点。这个节点会在前端调用emitUIInteraction时被触发。解析 JSON该事件会传递一个String类型的参数即前端发送的 JSON 字符串。我们需要使用Parse JSON节点将其转换为蓝图可以操作的结构JsonObject。判断与执行从JsonObject中读取Command等字段根据不同的命令执行不同的游戏逻辑。由于无法直接展示蓝图节点图这里用伪代码描述其逻辑你可以在蓝图中找到对应的节点Event BeginPlay - Get a reference to the PixelStreaming component (self) - Bind Event to OnPixelStreamingUIInteraction (Custom Event) Custom Event OnPixelStreamingUIInteraction (String Message) - Parse JSON from the Message string, output a JsonObject - Get String Field from JsonObject, Field Name Command - Switch on (Command String): Case Jump: // 找到你控制的角色调用其跳跃函数 // 例如Get Player Character - Character Movement - Jump Case ChangeColor: // 从 JsonObject 获取 Color 字段 // 将颜色字符串转换为 LinearColor // 应用到某个场景物体或后处理体积上 Case CustomEvent: // 从 JsonObject 获取 UserMessage 字段 // 在屏幕上显示或进行其他逻辑处理 // 同时可以调用“发送消息到前端”的函数6.3 将蓝图放入场景将创建好的BP_PixelStreamingController拖放到你的游戏场景中。确保它在游戏开始时被实例化。6.4 从 UE 发送消息到前端实现完整双向前端可以定义onCustomMessage回调UE 端也需要能主动发送消息。在蓝图中你可以这样做在需要发送消息的地方例如角色得分时、游戏状态改变时获取Pixel Streaming组件。调用组件上的Send Player Message或Emit UI Response节点不同版本名称可能略有不同。该节点需要一个String参数你可以构建一个 JSON 字符串例如{type: scoreUpdate, value: 100}。这样前端app.js中的handleMessageFromUE函数就会收到这个消息并处理。7. 运行与验证看到画面实现交互现在让我们启动整个系统并验证。启动顺序很重要启动信令服务器在SignallingWebServer目录下运行node cirrus.js。确保它监听在 8888 端口。启动 UE 应用运行之前创建的批处理文件run_with_pixelstreaming.bat。观察日志看它是否在尝试连接127.0.0.1:8888。打开前端页面在浏览器中访问http://localhost:8888/index.html如果你的信令服务器正确配置了静态文件服务index.html在public目录下。预期结果浏览器页面状态显示“正在连接...”然后变为“已连接正在播放流”。网页中的video元素会显示出 UE 应用程序实时渲染的画面延迟通常在几十到几百毫秒取决于网络和编码设置。点击网页上的“让角色跳跃”按钮UE 应用中的角色应执行跳跃动作。点击“切换场景颜色”UE 场景的后处理或某个物体的颜色应发生变化。在输入框输入文字并点击发送UE 端应能收到并打印或显示该消息。可选在 UE 端触发一个发送消息的蓝图如角色碰到某个触发器前端页面的状态或某个元素应能更新。如果以上步骤都成功恭喜你你已经搭建了一个完整的、具备双向通信能力的 UE 像素流送系统8. 常见问题与排查思路避坑指南在实际部署中你几乎一定会遇到下面这些问题。这里提供一个快速排查清单。问题现象可能原因排查方式解决方案前端页面一直显示“正在初始化”或“连接中”1. 信令服务器未启动或端口错误。2. UE 应用未启动或启动参数错误。3. 前端 JS 中信令服务器地址配置错误。1. 检查node cirrus.js是否运行端口是否被占用。2. 检查 UE 应用命令行窗口是否有错误确认-PixelStreamingIP和-Port参数正确。3. 浏览器 F12 打开开发者工具 - “网络”(Network) 标签查看 WebSocket (ws://) 连接是否成功建立。1. 更换信令服务器端口确保防火墙开放。2. 核对 UE 启动参数本地测试确保 IP 为127.0.0.1。3. 修改app.js中的signallingServerUrl确保是ws://[服务器IP]:[端口]。能看到画面但无法操作鼠标键盘无响应1. 前端播放器未获取输入焦点。2. WebRTC 数据通道建立失败。3. UE 端 Pixel Streaming 组件未正确添加或绑定。1. 点击一下视频区域看页面焦点是否在视频元素上。2. 浏览器控制台查看是否有 WebRTC 相关错误。3. 在 UE 编辑器中检查BP_PixelStreamingController是否存在于场景OnPixelStreamingUIInteraction事件是否被绑定。1. 确保视频元素可点击或在前端代码中手动触发焦点。2. 检查网络环境WebRTC 需要 UDP 端口可达公司内网防火墙可能阻止。3. 重新打包 UE 项目并部署。前端发送消息UE 端无反应1. 前端发送的数据格式不是有效的 JSON 字符串。2. UE 蓝图解析 JSON 失败。3. 命令字符串不匹配大小写敏感。1. 在浏览器控制台打印streamer.emitUIInteraction发送的对象。2. 在 UE 蓝图的OnPixelStreamingUIInteraction事件后添加Print String节点看是否触发。3. 仔细核对蓝图Switch on String节点的 Case 值与前端发送的Command字段是否完全一致。1. 使用JSON.stringify()确保发送的是字符串。2. 在蓝图中先不解析直接打印收到的原始字符串确认数据已送达。3. 统一前后端的命令字命名规范。延迟很高或画面卡顿1. 网络带宽不足或抖动。2. 编码参数码率、分辨率设置过高。3. 服务器性能不足GPU 编码压力大。1. 检查服务器和客户端的网络状况。2. 调整 UE 启动参数降低-ResX和-ResY。3. 在 UE 的Pixel Streaming插件设置中调整编码器码率Bitrate。1. 尽可能使用有线网络保证服务器上行带宽。2. 从 720P 开始测试逐步调高。3. 在DefaultEngine.ini中配置[PixelStreaming]段的EncoderRateControl和TargetBitrate。跨公网无法连接WebRTC 需要复杂的 NAT 穿透和 ICE 协商在复杂网络环境下可能失败。使用浏览器 WebRTC 内部日志chrome://webrtc-internals分析连接状态。1. 使用TURN 服务器进行中继转发这是解决对称型 NAT 等复杂网络问题的标准方案。可以部署 Coturn 等开源 TURN 服务器并在信令服务器和前端配置中指定其地址和凭证。9. 最佳实践与进阶建议当你跑通基础流程后以下建议可以帮助你将项目推向生产环境。9.1 安全性与访问控制信令服务器加固示例服务器仅为演示。生产环境需要添加身份验证如 Token、防止 DDoS、设置 HTTPS/WSS。UE 应用沙盒确保流送的 UE 应用运行在受限环境中避免用户通过前端指令执行危险系统调用。输入验证在 UE 蓝图中严格校验前端传入的所有参数防止注入攻击。9.2 性能与伸缩自适应码率UE 像素流支持根据网络状况动态调整码率。确保在插件设置中启用相关选项。多实例与负载均衡一个信令服务器可以协调多个 UE 应用实例。你需要一个匹配器Matchmaker服务根据用户请求分配空闲的 UE 实例。UE 提供了相关示例代码。GPU 与编码使用支持 NVENC (NVIDIA) 或 AMF (AMD) 硬编码的 GPU能极大降低 CPU 负载支持更多并发流。9.3 前端体验优化自定义 UISDK 允许你完全自定义播放器 UI。隐藏默认控件用 HTML/CSS/JS 构建与你的网页风格一致的交互界面。触摸与手势移动端适配需要处理触摸事件并将其转换为鼠标/键盘事件或自定义指令发送给 UE。连接状态管理完善前端重连逻辑、断线提示、加载动画提升用户体验。9.4 配置管理不要将 IP、端口等配置硬编码在代码或批处理文件中。使用配置文件如.ini文件或环境变量来管理不同环境开发、测试、生产的配置。在DefaultEngine.ini中配置像素流参数比命令行参数更便于管理。; 文件路径YourProject/Config/DefaultEngine.ini [/Script/PixelStreaming] StreamerPort8888 StreamerIP127.0.0.1 EncoderRateControlCBR TargetBitrate5000000 ; 5 Mbps9.5 监控与日志为信令服务器添加详细的访问日志和错误日志。监控 UE 应用进程的资源占用GPU 内存、编码帧率。在前端收集播放器的关键指标如延迟、卡顿率、分辨率并上报到你的监控系统。从打通基础连接到考虑生产级部署UE 像素流送提供了一个强大而灵活的框架。它本质上将 UE 应用变成了一个可通过网络 API 调用的“渲染微服务”。无论是用于产品云端演示、沉浸式 Web 展厅、还是复杂的仿真培训系统掌握其核心原理和这套双向通信机制都能让你在 Web 3D 交互领域拥有独特的解决方案。建议你将本文中的示例代码作为起点根据实际项目需求深入探索官方文档中关于高级配置、自定义信令、WebRTC 调优等部分逐步构建起稳定可靠的流送服务。