适用于 Unreal Engine 5.4 / 5.5 / 5.6 的离轴投影插件,可用于 CAVE 系统、投影映射、多屏显示和头部追踪显示。
- 零开销投影覆盖 — 通过
ISceneViewExtension直接覆盖玩家相机投影矩阵,无需 Render Target 或 SceneCapture - 编辑器交互可视化 — 可直观拖拽调整屏幕位置、朝向和大小,实时预览视锥
- 精细调试开关 — 屏幕边框、视锥线、眼球、近裁切面、标签均可独立开关
- 立体渲染 — 内置眼间距,支持左眼/右眼立体输出
- MRQ 立体渲染 — 自定义渲染 Pass,同一帧渲染左右眼并自动合成 SBS/TB 视频或图片序列(内置 FFmpeg)
- 蓝图支持 — 所有参数均暴露给蓝图
- 外部数据输入 — 支持导入 Max/Maya 标定数据,可引用场景 Actor 的 Transform
- MRQ 渲染支持 — 非对称投影支持离线渲染,可跟随 Sequencer 驱动的电影相机,完整支持运动模糊(每眼独立追踪)
- 在关卡中放置
AsymmetricCameraActor - 选中 Actor,在 Details 面板调整 Screen 组件的位置/旋转和
ScreenWidth/ScreenHeight - 按 Play,玩家相机投影自动被覆盖
- (可选)设置
Tracked Actor实现头部追踪
AAsymmetricCameraActor
└── Root (SceneComponent)
├── Screen (AsymmetricScreenComponent — 投影屏幕平面)
└── Camera (AsymmetricCameraComponent — 眼睛位置 + 投影计算)
| 参数 | 说明 |
|---|---|
bUseAsymmetricProjection |
启用/禁用离轴投影 |
NearClip |
近裁切面距离,默认 20 |
FarClip |
远裁切面距离,0 表示无限远 |
EyeSeparation |
立体渲染眼间距,0 为单目 |
EyeOffset |
左眼 -1 / 中心 0 / 右眼 1 |
StereoLayout |
立体布局模式:Mono / Side by Side / Top Bottom |
bMatchViewportAspectRatio |
自动匹配屏幕宽高比,防止画面拉伸 |
bEnableMRQSupport |
MRQ 离线渲染时也应用非对称投影 |
TrackedActor |
追踪目标 Actor,用作眼睛位置 |
bFollowTargetCamera |
每帧同步 Owner Actor 的 Transform 到目标相机 |
TargetCamera |
要跟随的目标相机 Actor(通常是 CineCameraActor) |
ScreenComponent |
引用的屏幕组件(自动查找同 Actor 上的组件) |
启用 bUseExternalData 后可绕过 Screen 组件,通过世界坐标或 Actor 引用定义投影屏幕(如 Max/Maya 标定数据)。
| 参数 | 说明 |
|---|---|
bUseExternalData |
使用外部数据代替 ScreenComponent |
ExternalEyeActor |
外部眼睛位置 Actor 引用(优先于 ExternalEyePosition) |
ExternalEyePosition |
外部眼睛位置(世界坐标) |
ExternalScreenBLActor |
外部屏幕左下角 Actor 引用 |
ExternalScreenBL |
外部屏幕左下角(世界坐标) |
ExternalScreenBRActor |
外部屏幕右下角 Actor 引用 |
ExternalScreenBR |
外部屏幕右下角(世界坐标) |
ExternalScreenTLActor |
外部屏幕左上角 Actor 引用 |
ExternalScreenTL |
外部屏幕左上角(世界坐标) |
ExternalScreenTRActor |
外部屏幕右上角 Actor 引用 |
ExternalScreenTR |
外部屏幕右上角(世界坐标) |
优先级:Actor 引用 > FVector 坐标 > TrackedActor/ScreenComponent 回退。
| 参数 | 说明 |
|---|---|
ScreenWidth |
屏幕宽度,世界单位,默认 160 |
ScreenHeight |
屏幕高度,世界单位,默认 90 |
屏幕平面在组件本地 YZ 平面,法线沿 +X 方向。通过组件的 Transform 控制位置和朝向。
| 参数 | 说明 |
|---|---|
bShowDebugFrustum |
主开关:编辑器调试可视化 |
bShowScreenOutline |
屏幕边框 + 对角线 + 法线箭头(绿色) |
bShowFrustumLines |
眼睛到屏幕四角的连线(黄色) |
bShowEyeHandle |
眼球位置球体(黄色) |
bShowNearPlane |
近裁切面矩形(红色) |
bShowLabels |
角点标签和屏幕信息文字 |
bShowStereoFrustums |
同时显示左眼(青色)和右眼(品红色)视锥,验证立体视差(需要 EyeSeparation > 0) |
bShowDebugInGame |
游戏运行时显示调试线 |
| 函数 | 说明 |
|---|---|
GetEyePosition() |
获取当前生效的眼睛世界坐标(优先级:ExternalEyeActor > ExternalEyePosition > TrackedActor > 组件自身位置) |
GetEffectiveScreenCorners() |
获取当前生效的屏幕四角坐标(外部数据或 ScreenComponent) |
SetExternalData(Eye, BL, BR, TL, TR) |
一次性设置全部外部数据 |
CalculateOffAxisProjection() |
手动计算离轴投影矩阵和视图旋转矩阵 |
| 函数 | 说明 |
|---|---|
GetScreenSize() |
获取屏幕尺寸,返回 FVector2D(ScreenWidth, ScreenHeight) |
SetScreenSize(NewSize) |
设置屏幕尺寸(世界单位) |
GetScreenCornersWorld(BL, BR, TL, TR) |
获取屏幕四角的世界坐标(左下、右下、左上、右上) |
GetScreenCornersLocal(BL, BR, TL, TR) |
获取屏幕四角在 Actor 局部空间的坐标 |
基于 Robert Kooima 的 广义透视投影 (Generalized Perspective Projection) 算法:
BeginPlay时,UAsymmetricCameraComponent注册FAsymmetricViewExtension(FWorldSceneViewExtension)- 每帧 UE5 调用扩展的
SetupViewProjectionMatrix()— 适用于游戏运行时 - 扩展计算离轴投影矩阵(UE5 reversed-Z 格式)和屏幕对齐的视图旋转矩阵
- 两者写入
FSceneViewProjectionData,直接覆盖玩家相机 — 无 RT、无 SceneCapture、无额外渲染 Pass - MRQ 离线渲染时,扩展在
SetupView()中覆盖投影(MRQ 不调用SetupViewProjectionMatrix);此路径使用InView.ViewLocation作为眼睛位置,以正确尊重MoviePipelineAsymmetricStereoPass已应用的左右眼偏移
运动模糊: 每眼独立维护上一帧的眼睛位置和视图旋转,避免立体渲染时两眼互相污染运动向量缓冲区。
- 在关卡中放置
AsymmetricCameraActor,配置屏幕参数 - 放置
CineCameraActor,用 Sequencer 制作动画 - 在 AsymmetricCamera 组件上勾选 Follow Target Camera,将 Target Camera 指向 CineCameraActor
- 确保 Enable MRQ Support 已开启(默认开启)
- 使用 Movie Render Queue 渲染 — 输出使用非对称投影,动画由 CineCameraActor 驱动
注意:
- 运动模糊已完整支持 — 插件对每只眼独立追踪前帧相机变换,确保速度缓冲区计算正确。
- MRQ 的高分辨率 tiling 渲染与非对称投影不兼容,建议将 tiling 设为 1×1。
运动模糊需要三方面配合。
在 MRQ Job 的设置列表中添加 Anti-Aliasing 设置项:
| 参数 | 默认值 | 推荐值 | 说明 |
|---|---|---|---|
Temporal Sample Count |
1 | 8 ~ 32 | 时间采样数,必须 > 1 才会产生运动模糊,越高越平滑 |
Spatial Sample Count |
1 | 1 | 空间采样,通常保持默认 |
Override Anti Aliasing |
不勾选 | 勾选 | 强制覆盖渲染器 AA 设置 |
Anti Aliasing Method |
— | None |
MRQ 自行做时间累积,禁用引擎内置 AA 避免重叠模糊 |
在 MRQ Job 的设置列表中添加 Console Variables 设置项,添加以下变量:
| 控制台变量 | 值 | 说明 |
|---|---|---|
r.MotionBlurQuality |
4 |
运动模糊渲染质量,0 = 关闭,4 = 最高质量。MRQ 离线渲染某些配置下会将此值重置为 0,必须显式设置 |
如果不添加此变量,运动模糊可能在 MRQ 渲染中完全不出现,即使 Post Process Volume 和时间采样都已正确配置。
由于 AsymmetricCamera 通过 ISceneViewExtension 覆盖相机投影,后处理设置应通过场景中的 Post Process Volume 来配置(对任何相机视图可靠生效),而非 CineCameraActor 上的后处理。
设置步骤:
- 在场景中放置 Post Process Volume(菜单 Place Actors → Volumes → Post Process Volume)
- Details 面板 → 勾选 Infinite Extent (Unbound)(覆盖整个场景)
- 展开 Rendering Features → Motion Blur
- 勾选每个参数左侧的复选框,然后填入数值(不勾选 = 不覆盖,填的数值不生效)
| 参数 | 默认值 | 推荐值 | 说明 |
|---|---|---|---|
| Motion Blur → Amount ✅ | 0.5 | 0.5 | 模糊强度,0 = 关闭,必须 > 0 |
| Motion Blur → Max ✅ | 5.0 | 5.0 | 最大模糊距离(屏幕百分比) |
| Motion Blur → Target FPS ✅ | 0 | 0 | 0 = 跟随输出帧率自动计算快门时间 |
如果 Amount 复选框未勾选或值为 0,MRQ 即使有时间采样也不会产生运动模糊。
插件在 SetupView() 中自动为每帧写入 InView.PreviousViewTransform,提供正确的前帧相机变换供速度缓冲区计算。无需额外的插件参数配置。
注意: 序列的第一帧没有运动模糊(无前帧数据可用),这是 MRQ 离线渲染的固有限制。
插件提供 Asymmetric Stereo Pass,可在 MRQ 中渲染立体视频(Side-by-Side 或 Top-Bottom)。
- 在 MRQ Job 的 Render Pass 中,移除默认的 "Deferred Rendering",添加 Asymmetric Stereo Pass
- 配置参数(见下表)
- 输出设置的文件名模板中包含
{camera_name}(自动填充 LeftEye / RightEye) - 渲染完成后,插件根据
CompositeMode设置自动合成 SBS/TB 图片序列或视频(默认为Image Sequence)
Pass 参数:
| 参数 | 说明 |
|---|---|
StereoLayout |
Side by Side(左右)或 Top / Bottom(上下) |
EyeSeparation |
眼间距,单位厘米,默认 6.4 |
bSwapEyes |
交换左右眼 |
CompositeMode |
合成模式:Disabled(保留分离序列)/ Image Sequence(每帧合并图片,默认)/ Video(合并视频) |
FFmpegPath |
FFmpeg 可执行文件路径。点击 ... 浏览选择,或直接输入绝对路径(如 D:/tools/ffmpeg/bin/ffmpeg.exe)。留空则使用系统 PATH 中的 ffmpeg |
VideoCodec |
视频编码器:H.264 / H.265(仅 Video 模式有效) |
CompositeQuality |
CRF 质量值(0=无损,18=推荐,51=最差,仅 Video 模式有效) |
OutputFormat |
输出格式:MP4 / MOV / MKV / AVI(H.265 强制使用 MKV,仅 Video 模式有效) |
bDeleteSourceAfterComposite |
合成成功后自动删除左右眼源图片序列(默认开启) |
bDebugSaveConcatFiles |
调试模式:保留 concat 列表文件和 FFmpeg 日志(_concat_*.txt / _ffmpeg_log_*.txt),默认关闭,合成失败时可开启排查 |
立体 3D 元数据(
Video模式):
- H.264 输出在码流中嵌入 Frame Packing Arrangement SEI(type 3=SBS / type 4=TB),VLC、PotPlayer 等播放器可自动识别。
- H.265 输出强制使用 MKV 容器,通过
stereo_mode容器元数据标记立体格式(x265 不支持 frame-packing CLI 参数)。
输出文件名包含布局模式和 Shot 名称,Shot 名称取自 Sequencer 中的 Shot Section 名称(如 shot0000):
| 模式 | 输出文件名示例 |
|---|---|
Image Sequence |
stereo_SBS_shot0000_%05d.jpeg、stereo_TB_shot0001_%05d.png |
Video (SBS) |
stereo_SBS_shot0000.mp4 |
Video (TB) |
stereo_TB_shot0000.mkv(H.265) |
多个 Shot 会各自生成独立的合成文件,按顺序串行处理。
合成使用 FFmpeg 的 concat demuxer,通过临时文件列表明确指定每帧的文件路径,而非依赖帧号模式(%04d)。这意味着:
- 帧号起始值无关 — Handle Frames、中段 Shot、任意起始帧号均可正确处理
- 文件名格式无关 — 不要求文件名使用特定分隔符或零填充位数
- 不连续帧安全 — 部分帧重渲染、跳帧场景不会导致合成失败
- 多 Shot 全覆盖 — 每个 Shot 独立合成,不再只处理最后一个 Shot
- 精确帧率 — 使用
Numerator/Denominator分数形式(如24000/1001表示 23.976 fps)
唯一的要求:输出文件名模板中必须包含 {camera_name},以便区分 LeftEye 和 RightEye 文件。
在 FFmpegPath 中填写 FFmpeg 可执行文件的绝对路径(如 D:/tools/ffmpeg/bin/ffmpeg.exe),或点击 ... 按钮浏览选择。留空时将使用系统 PATH 中的 ffmpeg(需自行安装并加入 PATH)。
提示: FFmpeg 可从 ffmpeg.org 或 gyan.dev 下载 Windows 预编译版本。
本项目使用 Git LFS 管理大文件(如内置的 ffmpeg.exe)。克隆前请确保已安装 Git LFS:
git lfs install
git clone <repo-url>如果已克隆但未拉取 LFS 文件:
git lfs pull# 快速编译(自动检测 UE5 路径,支持 5.4 / 5.5 / 5.6)
QuickBuild.bat
# 如果 QuickBuild 无法找到引擎,可用文本编辑器打开脚本,
# 手动填写你的引擎路径:
# set "UE5_PATH=C:\Your\Path\To\UE_5.X"
# 也可直接在编辑器中编译(Ctrl+Alt+F11)
start "" "MyCustomCam.uproject"本项目配置了 clangd 以提供准确的 C++ 代码补全和跳转。
前提: 安装 VSCode clangd 扩展,并禁用 Microsoft C/C++ 扩展(两者冲突)。
生成编译数据库(首次或修改 Build.cs 后执行):
GenerateCompileCommands.bat脚本会调用 UBT 生成 compile_commands.json 并复制到项目根目录。完成后在 VSCode 中执行 clangd: Restart language server 使配置生效。
compile_commands.json已加入.gitignore,不会提交到仓库,每台开发机需单独生成。
Apache License 2.0