Skip to content

jd-cg/Unreal-Custom-Camera

Repository files navigation

Asymmetric Camera — UE5 非对称投影相机插件

English

适用于 Unreal Engine 5.4 / 5.5 / 5.6 的离轴投影插件,可用于 CAVE 系统、投影映射、多屏显示和头部追踪显示。

功能

  • 零开销投影覆盖 — 通过 ISceneViewExtension 直接覆盖玩家相机投影矩阵,无需 Render Target 或 SceneCapture
  • 编辑器交互可视化 — 可直观拖拽调整屏幕位置、朝向和大小,实时预览视锥
  • 精细调试开关 — 屏幕边框、视锥线、眼球、近裁切面、标签均可独立开关
  • 立体渲染 — 内置眼间距,支持左眼/右眼立体输出
  • MRQ 立体渲染 — 自定义渲染 Pass,同一帧渲染左右眼并自动合成 SBS/TB 视频或图片序列(内置 FFmpeg)
  • 蓝图支持 — 所有参数均暴露给蓝图
  • 外部数据输入 — 支持导入 Max/Maya 标定数据,可引用场景 Actor 的 Transform
  • MRQ 渲染支持 — 非对称投影支持离线渲染,可跟随 Sequencer 驱动的电影相机,完整支持运动模糊(每眼独立追踪)

快速开始

  1. 在关卡中放置 AsymmetricCameraActor
  2. 选中 Actor,在 Details 面板调整 Screen 组件的位置/旋转和 ScreenWidth / ScreenHeight
  3. 按 Play,玩家相机投影自动被覆盖
  4. (可选)设置 Tracked Actor 实现头部追踪

组件结构

AAsymmetricCameraActor
└── Root (SceneComponent)
    ├── Screen (AsymmetricScreenComponent — 投影屏幕平面)
    └── Camera (AsymmetricCameraComponent — 眼睛位置 + 投影计算)

参数说明

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 回退。

Screen 组件 (AsymmetricScreenComponent)

参数 说明
ScreenWidth 屏幕宽度,世界单位,默认 160
ScreenHeight 屏幕高度,世界单位,默认 90

屏幕平面在组件本地 YZ 平面,法线沿 +X 方向。通过组件的 Transform 控制位置和朝向。

调试开关

参数 说明
bShowDebugFrustum 主开关:编辑器调试可视化
bShowScreenOutline 屏幕边框 + 对角线 + 法线箭头(绿色)
bShowFrustumLines 眼睛到屏幕四角的连线(黄色)
bShowEyeHandle 眼球位置球体(黄色)
bShowNearPlane 近裁切面矩形(红色)
bShowLabels 角点标签和屏幕信息文字
bShowStereoFrustums 同时显示左眼(青色)和右眼(品红色)视锥,验证立体视差(需要 EyeSeparation > 0)
bShowDebugInGame 游戏运行时显示调试线

蓝图 API

AsymmetricCameraComponent — 蓝图函数

函数 说明
GetEyePosition() 获取当前生效的眼睛世界坐标(优先级:ExternalEyeActor > ExternalEyePosition > TrackedActor > 组件自身位置)
GetEffectiveScreenCorners() 获取当前生效的屏幕四角坐标(外部数据或 ScreenComponent)
SetExternalData(Eye, BL, BR, TL, TR) 一次性设置全部外部数据
CalculateOffAxisProjection() 手动计算离轴投影矩阵和视图旋转矩阵

AsymmetricScreenComponent — 蓝图函数

函数 说明
GetScreenSize() 获取屏幕尺寸,返回 FVector2D(ScreenWidth, ScreenHeight)
SetScreenSize(NewSize) 设置屏幕尺寸(世界单位)
GetScreenCornersWorld(BL, BR, TL, TR) 获取屏幕四角的世界坐标(左下、右下、左上、右上)
GetScreenCornersLocal(BL, BR, TL, TR) 获取屏幕四角在 Actor 局部空间的坐标

工作原理

基于 Robert Kooima 的 广义透视投影 (Generalized Perspective Projection) 算法:

  1. BeginPlay 时,UAsymmetricCameraComponent 注册 FAsymmetricViewExtensionFWorldSceneViewExtension
  2. 每帧 UE5 调用扩展的 SetupViewProjectionMatrix() — 适用于游戏运行时
  3. 扩展计算离轴投影矩阵(UE5 reversed-Z 格式)和屏幕对齐的视图旋转矩阵
  4. 两者写入 FSceneViewProjectionData,直接覆盖玩家相机 — 无 RT、无 SceneCapture、无额外渲染 Pass
  5. MRQ 离线渲染时,扩展在 SetupView() 中覆盖投影(MRQ 不调用 SetupViewProjectionMatrix);此路径使用 InView.ViewLocation 作为眼睛位置,以正确尊重 MoviePipelineAsymmetricStereoPass 已应用的左右眼偏移

运动模糊: 每眼独立维护上一帧的眼睛位置和视图旋转,避免立体渲染时两眼互相污染运动向量缓冲区。

MRQ 渲染工作流

  1. 在关卡中放置 AsymmetricCameraActor,配置屏幕参数
  2. 放置 CineCameraActor,用 Sequencer 制作动画
  3. 在 AsymmetricCamera 组件上勾选 Follow Target Camera,将 Target Camera 指向 CineCameraActor
  4. 确保 Enable MRQ Support 已开启(默认开启)
  5. 使用 Movie Render Queue 渲染 — 输出使用非对称投影,动画由 CineCameraActor 驱动

注意:

  • 运动模糊已完整支持 — 插件对每只眼独立追踪前帧相机变换,确保速度缓冲区计算正确。
  • MRQ 的高分辨率 tiling 渲染与非对称投影不兼容,建议将 tiling 设为 1×1。

MRQ 运动模糊设置

运动模糊需要三方面配合。

1. MRQ Anti-Aliasing 设置

在 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 避免重叠模糊

1b. MRQ Console Variables 设置

在 MRQ Job 的设置列表中添加 Console Variables 设置项,添加以下变量:

控制台变量 说明
r.MotionBlurQuality 4 运动模糊渲染质量,0 = 关闭,4 = 最高质量。MRQ 离线渲染某些配置下会将此值重置为 0,必须显式设置

如果不添加此变量,运动模糊可能在 MRQ 渲染中完全不出现,即使 Post Process Volume 和时间采样都已正确配置。

2. Post Process Volume 运动模糊

由于 AsymmetricCamera 通过 ISceneViewExtension 覆盖相机投影,后处理设置应通过场景中的 Post Process Volume 来配置(对任何相机视图可靠生效),而非 CineCameraActor 上的后处理。

设置步骤:

  1. 在场景中放置 Post Process Volume(菜单 Place Actors → Volumes → Post Process Volume)
  2. Details 面板 → 勾选 Infinite Extent (Unbound)(覆盖整个场景)
  3. 展开 Rendering FeaturesMotion Blur
  4. 勾选每个参数左侧的复选框,然后填入数值(不勾选 = 不覆盖,填的数值不生效)
参数 默认值 推荐值 说明
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 即使有时间采样也不会产生运动模糊。

3. 插件侧(无需额外配置)

插件在 SetupView() 中自动为每帧写入 InView.PreviousViewTransform,提供正确的前帧相机变换供速度缓冲区计算。无需额外的插件参数配置。

注意: 序列的第一帧没有运动模糊(无前帧数据可用),这是 MRQ 离线渲染的固有限制。

MRQ 立体渲染

插件提供 Asymmetric Stereo Pass,可在 MRQ 中渲染立体视频(Side-by-Side 或 Top-Bottom)。

设置步骤

  1. 在 MRQ Job 的 Render Pass 中,移除默认的 "Deferred Rendering",添加 Asymmetric Stereo Pass
  2. 配置参数(见下表)
  3. 输出设置的文件名模板中包含 {camera_name}(自动填充 LeftEye / RightEye)
  4. 渲染完成后,插件根据 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.jpegstereo_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 文件。

FFmpeg

FFmpegPath 中填写 FFmpeg 可执行文件的绝对路径(如 D:/tools/ffmpeg/bin/ffmpeg.exe),或点击 ... 按钮浏览选择。留空时将使用系统 PATH 中的 ffmpeg(需自行安装并加入 PATH)。

提示: FFmpeg 可从 ffmpeg.orggyan.dev 下载 Windows 预编译版本。

Git LFS

本项目使用 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"

开发环境(VSCode IntelliSense)

本项目配置了 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

About

UE5 非对称视锥投影插件,适用于 CAVE 系统、投影映射和多屏显示 | UE5 off-axis / asymmetric frustum projection plugin for CAVE systems, projection mapping, and multi-display setups

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors