如何分解Unity相机投影矩阵以获取相机内参矩阵?
从Unity相机矩阵中提取内参矩阵
首先明确:Unity里的投影矩阵(Camera.projectionMatrix)本身就包含内参的核心信息;如果你拿到的是包含旋转平移的视图投影矩阵(即投影矩阵乘视图矩阵),得先分离出纯投影部分再提取内参。
一、透视相机:从纯投影矩阵提取内参
Unity的透视投影矩阵是列优先存储的,结构如下(基于右手坐标系):
[ 2n/(r-l) 0 (r+l)/(r-l) 0 ] [ 0 2n/(t-b) (t+b)/(t-b) 0 ] [ 0 0 -(f+n)/(f-n) -2fn/(f-n) ] [ 0 0 -1 0 ]
其中n是近裁剪面距离,f是远裁剪面距离,l/r/t/b分别对应裁剪面的左/右/上/下边界。
提取步骤:
- 获取投影矩阵:
Matrix4x4 projMatrix = Camera.main.projectionMatrix; - 从矩阵中提取关键元素:
float proj00 = projMatrix[0, 0]; // 对应2n/(r-l)float proj11 = projMatrix[1, 1]; // 对应2n/(t-b)float proj02 = projMatrix[0, 2]; // 对应(r+l)/(r-l)float proj12 = projMatrix[1, 2]; // 对应(t+b)/(t-b)
- 结合图像分辨率计算内参:
假设相机渲染的图像分辨率为width(宽)、height(高),内参矩阵的参数为:float fx = proj00 * width / 2f;float fy = proj11 * height / 2f;float cx = (proj02 + 1f) * width / 2f;float cy = (proj12 + 1f) * height / 2f;
(如果项目启用了Y轴翻转,比如VR或特定渲染管线,cy需要调整为height - cy)
- 构建3x3内参矩阵
K:[ fx 0 cx ] [ 0 fy cy ] [ 0 0 1 ]
二、处理包含外参的视图投影矩阵
如果你拿到的是视图投影矩阵(即projMatrix * Camera.main.worldToCameraMatrix,包含旋转平移的外参),需要先分离出纯投影矩阵:
- 获取视图矩阵(外参):
Matrix4x4 viewMatrix = Camera.main.worldToCameraMatrix; - 从视图投影矩阵反推纯投影矩阵:
Matrix4x4 pureProjMatrix = viewProjMatrix * viewMatrix.inverse; - 之后按照第一步的方法从
pureProjMatrix提取内参即可。
三、正交相机的内参提取(可选)
正交相机的投影矩阵结构不同,但提取逻辑类似:
- 提取投影矩阵元素:
float proj00 = projMatrix[0, 0]; // 对应2/(r-l)float proj11 = projMatrix[1, 1]; // 对应2/(t-b)float proj02 = projMatrix[0, 2]; // 对应(r+l)/(r-l)float proj12 = projMatrix[1, 2]; // 对应(t+b)/(t-b)
- 计算内参:
float fx = proj00 * width / 2f;float fy = proj11 * height / 2f;float cx = (proj02 + 1f) * width / 2f;float cy = (proj12 + 1f) * height / 2f;
关键注意点
- Unity矩阵是列优先存储,所以访问元素是
matrix[列索引, 行索引],和数学上的行优先矩阵索引顺序相反,别搞混。 - 透视相机下,
fx/fy应该等于相机的aspect(宽高比),可以用这个验证结果是否正确。
内容的提问来源于stack exchange,提问作者HusCet
相关产品推荐
相关产品推荐

