CAVE TooL ← 返回首页

CAVE TooL · 软件原理说明

本文说明 CAVE TooL 的工作原理、设计思路、完整工作流程与应用注意事项。 内容依据当前代码实现(src/ 引擎与 desktop/app/core/pipeline.py)编写。

一、软件的原理

1.1 要解决的问题

CAVE 是由 3~6 块屏幕围合而成的沉浸式显示空间,观众站在(或坐在)空间内部或开口一侧。 普通视频只有一个视点的画面:它假定观众正对一块平面屏幕。

把这个画面直接分发到多面屏体上,会出现三类几何错误:

1.2 核心原理:在播放前把每一面的像素算好

软件采用的是预畸变(pre-warp):在视频进入播放环节之前,先把每一面屏幕最终应该显示的像素逐帧计算出来并编码成视频文件。 屏体按原始几何关系播放这些预处理过的画面后,观众看到的才是连续、正确的空间影像。

实现上有一个关键选择——反查(inverse mapping)而不是正推:

对每一面屏幕上的每一个像素,反推"它应该取自源视频的哪个位置",然后采样。

而不是"把源视频的每个像素推到目标面上"(那样会在目标面留下没有被任何源像素覆盖的空洞,表现为黑点或裂缝)。

具体做法:

  1. 为目标面的每个像素建立一个 3D 点(由该面的中心、朝向、物理宽高决定);
  2. 按所选模式(透视 / 全景)把这个点映射回源视频的 (u, v) 坐标;
  3. 把整面的 (u, v) 存成一张映射表 map_x / map_y,形状为 (高, 宽);
  4. 逐帧用 cv2.remap 按映射表采样,得到该面这一帧的画面。

因为映射表只与几何参数有关、与画面内容无关,所以它只在开始处理时计算一次; 之后每帧只做一次重采样和一次编码。这是软件能做到实时逐帧处理的原因。

1.3 像素密度:分辨率从物理尺寸推导

分辨率不是让用户填的,而是由屏体物理尺寸和点间距推导:

像素密度 ppm(像素/米) = 1000 ÷ 点间距(mm)
某一面的输出分辨率 = round(该面物理宽 × ppm) × round(该面物理高 × ppm)

支持的点间距档位(src/core/pitch.py):

档位实际点间距像素密度
P1.251.25 mm800 px/m
P1.51.538 mm650 px/m
P1.861.875 mm533 px/m
P2.02.0 mm500 px/m
P2.52.5 mm400 px/m

为什么这样做:每个面的输出分辨率必须与它对应的屏体一致。前幕(7.2 m 宽)与侧幕(3.8 m 深) 在物理上就不一样宽,用同一个分辨率去渲染必然有一个面被拉伸。按物理尺寸同比例推导, 各面像素密度一致,拼在一起才不会在接缝处出现比例跳变。

输出尺寸会向上取到偶数(yuv420p 编码要求宽高为偶数),软件自动处理。

二、基本思路

2.1 用参数描述"一个 CAVE 空间"

软件把 CAVE 抽象为一个长方体空间,用六个面来描述(src/core/types.py):

面说明物理宽度取自
front 前幕观众正对的主屏空间宽度
left / right 左右侧幕两侧围合空间进深
back 后幕封闭式 CAVE 的背面空间宽度
floor 地面投地空间宽度 × 进深
ceiling 顶面吊顶投影空间宽度 × 进深

每个面记录:中心点、法向、上方向、物理宽高、输出分辨率。 观众视点(viewer)是另一个关键参数,它决定了映射的透视关系。

用户实际只需要填三个物理量——宽(前幕宽度)、高(屏体净高)、深(前后幕间距), 其余(各面中心坐标、朝向、法向)由软件自动计算。

2.2 三种素材模式,对应三套映射关系

不同来源的素材,成像方式完全不同,因此使用不同的映射算法:

① 普通视频 —— 外视点透视映射

把源视频看作一台虚拟针孔相机在设定视点拍摄到的画面,再把 CAVE 各面重新投影回这台相机的像平面。

② 180° 全景 —— 半 CAVE 环绕映射

源素材是等距柱状投影(equirectangular)的 180° 全景图。

③ 360° 全景 —— 完整 CAVE 中心映射

源素材是 360° 全景(完整等距柱状投影)。

2.3 展开布局:把多面拼成一张画布

为了让"一台播放设备输出整幅画面"的场景可用,软件按墙面在空间中的实际相邻关系, 把各面拼成一张十字展开画布:

            ┌──────────────┐
            │    顶面      │
┌──────┬────┴──────┬───────┴──────┬──────┐
│ 左幕 │   前幕    │    右幕      │ 后幕 │
└──────┴───────────┴──────────────┴──────┘
            │    地面      │
            └──────────────┘

2.4 输出形式:三种交付方式

输出形式产物适用场景
标准展开一张十字展开画布视频播放端支持多屏分割输出,或需要做融合处理
每面单独每个面一个视频文件每一面由独立播放器驱动(最常见)
两者都要同时输出上述两种一次导出拿全,便于交付与备份

三、工作流程

3.1 用户操作流程

① 选择素材          ② 设置屏体            ③ 生成预览            ④ 导出
导入本地视频    →   填宽/高/深、点间距  →  展开图 + 空间预览  →  选输出形式与编码
选素材模式与折幕面   视点可自动算也可手调    确认几何关系正确      得到可部署的视频

3.2 软件内部流程

以一次导出为例,实际发生的事情是:

第一步 · 探测 读取源视频的宽高、帧率、总帧数(VideoDecoder.probe)。 若是普通视频,还会读第一帧并检测有效画面区域,用于剔除黑边。

第二步 · 构建空间 按"素材模式 + 折幕类型 + 所选面"构造 CAVE 空间; 解析视点(用户填了就用,没填按素材模式与尺寸自动计算)。

第三步 · 计算每面分辨率与像素密度 ppm = 1000 ÷ 点间距 × 能力系数,各面分辨率 = 物理尺寸 × ppm,再按用户选择的缩放比例(100/75/50/25%)缩放。 随后用前幕的实际分辨率反推像素密度,保证展开画布的像素密度与面板一致。

第四步 · 构建映射引擎 按素材模式选择引擎,并一次性生成各面的映射表:

素材模式引擎映射方式
普通视频FovFoldEngine针孔相机投影
180° 全景PanoFoldEngine(180)经纬度(半幅)
360° 全景PanoFoldEngine(360)经纬度(整幅)

第五步 · 逐帧映射 对每一帧:解码 → 按映射表对每个面做一次重采样 → 写入对应的编码器。 展开画布由各面结果按布局拼合而成。

第六步 · 编码与并行

第七步 · 交付 输出目录中生成:展开视频(*_unfolded)、各面视频(cave_front / cave_left / …)、以及可选的打包文件。 "两者都要"模式下会有两套展开命名(含 _both_)以便区分。

3.3 预览环节做了什么

预览不是截图,而是用第一帧真实跑一遍完整映射,得到三样东西:

  1. 标准展开图:确认各面裁切与拼版位置;
  2. 各面图:逐面检查是否拉伸、是否取到预期内容;
  3. CAVE 空间预览:把各面贴回三维空间做轴测渲染,并在桌面端以可旋转的 3D 视图呈现,用于确认折角关系。

预览时同样会应用像素密度与授权状态,因此它反映的是最终产物的真实比例。


四、应用说明

4.1 屏体参数怎么填

参数含义填写要点
宽前幕的净显示宽度不是房间宽度;按实际点亮的屏体尺寸量
高屏体净高地面到屏体顶边(或吊顶屏下沿)
深前幕到后幕的间距侧幕的实际宽度由它决定
点间距现场屏体规格按屏体真实规格选;选大了分辨率不足,选小了文件体积暴涨
视点 Y / Z观众眼睛的相对位置留空即自动计算;只有观众站位明显偏离中心时才需要手调

4.2 三种模式怎么选

素材推荐模式说明
常规拍摄视频、动画、演示片普通视频外视点透视,适合"把画面放进折幕"
半球拍摄、投影仪片源180° 全景半 CAVE 环绕,前幕在 − 深度处
全景相机素材360° 全景视点在中心,观众环视即为拍摄现场方向

4.3 分辨率与体积的实际感受

以 7.2 m × 3.4 m × 3.8 m、P1.86、四折幕(前/左/右/地)为例:

面物理尺寸输出分辨率
前幕7.2 × 3.4 m3840 × 1814
左幕 / 右幕3.8 × 3.4 m2028 × 1814
地面7.2 × 3.8 m3840 × 2028
十字展开画布14.8 × 7.2 m约 7894 × 3840

展开画布接近 8K 级别,单帧就有约 3000 万像素。因此:

4.4 参数选择的经验值

硬件编码器数量有限(消费级显卡通常 3~5 路),并行数过高反而会排队或失败;

4.5 已知限制

4.6 数据与隐私

转换全程在本机完成,源视频不上传任何服务器。 软件的联网行为仅限:设备账号建立、授权校验(含离线宽限)、版本更新检查。