You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何逆视口投影矩阵中两个元素始终为0?

视口-投影-视图逆矩阵中e41、e42恒为0的原因与优化安全性解析

问题背景

我在编写光线追踪器时,需要通过视口-投影-视图矩阵的逆矩阵将屏幕像素坐标转换为世界空间坐标。过程中发现,无论如何移动、缩放、环绕或旋转相机,逆矩阵的最后一行前两个元素(e41、e42)始终为0。虽然利用这个特性可以提前计算w除法来优化transform方法,但不确定这个假设的成立条件,同时也疑惑为何透视矩阵的逆矩阵看起来近似仿射。

相关代码与矩阵示例

Matrix类核心实现(OpenGL列向量布局)

public final class Matrix4 {
    public double e11, e12, e13, e14;
    public double e21, e22, e23, e24;
    public double e31, e32, e33, e34;
    public double e41, e42, e43, e44;
    
    public void transform(Vec3 v) {
        double x = v.x, y = v.y, z = v.z;
        double w = (x * e41) + (y * e42) + (z * e43) + (e44);
        double norm = 1 / w;
        v.x = ((x * e11) + (y * e12) + (z * e13) + (e14)) * norm;
        v.y = ((x * e21) + (y * e22) + (z * e23) + (e24)) * norm;
        v.z = ((x * e31) + (y * e32) + (z * e33) + (e34)) * norm;
    }
    
    public void perspectiveFovLH(double fovy, double aspect, double znear, double zfar) {
        double yscale = 1 / tan(fovy * 0.5);
        double xscale = yscale / aspect;
        double Q = zfar / (zfar - znear);
        
        e11 = xscale;
        e22 = yscale;
        e33 = Q;
        e34 = Q * -znear;
        e43 = 1;
    }
}

移动相机后的视口-投影-视图矩阵

[ -331.62051997,  -616.31014741, -927.45531750,  354532.72229686
   158.60434983, -1091.70516425,  427.49500301,  420008.37868979
     0.75468455,    -0.51045982,   -0.41337968,     766.88486375
     0.75430721,    -0.51020459,   -0.41317299,     771.50142132 ]

对应的逆矩阵

[ -0.00058203, -0.00019009,  113.94949731, -112.89669211
  -0.00033747, -0.00072765,  -84.29481494,   84.34162134
  -0.00064586,  0.00055151,  -61.14292715,   60.77360931
  -0.00000000, -0.00000000,   -0.19990000,    0.20000000 ]

核心解析

1. 逆矩阵e41、e42恒为0的原因

视口-投影-视图矩阵是三个矩阵的乘积:M = 视口矩阵 * 投影矩阵 * 视图矩阵,逐个分析各矩阵的结构特性:

  • 视图矩阵:本质是相机的逆变换,仅包含旋转和平移,属于仿射矩阵,最后一行固定为[0, 0, 0, 1]。
  • 投影矩阵:你实现的左手系透视矩阵,最后一行是[0, 0, 1, 0](仅e43为1,其余最后一行元素默认0),仅在z方向引入透视缩放。
  • 视口矩阵:负责将NDC坐标转屏幕像素,仅包含缩放和平移,也是仿射矩阵,最后一行固定为[0, 0, 0, 1]。

当计算这三个矩阵的乘积M时,M的最后一行由投影矩阵的最后一行与视图矩阵相乘后,再与视口矩阵相乘得到。而投影矩阵的最后一行前两个元素为0,结合仿射矩阵的特性,最终M的逆矩阵在计算时,最后一行的前两个元素必然被抵消为0——因为逆矩阵的最后一行需要满足与M的前两列点积为0,而M的前两列来自仿射变换的旋转缩放部分,与投影矩阵的透视方向(z轴)正交。

2. 近似仿射的逆矩阵

你观察到逆矩阵近乎仿射(最后一行前两个元素为0),原因在于:

  • 投影矩阵的逆矩阵最后一行前两个元素本身就是0(推导后可知,你的透视矩阵逆矩阵最后一行是[0, 0, 1/(zfar-znear), zfar/(zfar-znear)])。
  • 视图和视口矩阵的逆矩阵都是仿射矩阵(最后一行[0,0,0,1])。

两者相乘后,逆矩阵的最后一行仅保留投影逆矩阵的z方向相关元素,前两个元素保持为0,因此看起来近似仿射(严格来说不是,因为仿射矩阵最后一行必须是[0,0,0,1],而这里最后一行第三、四个元素非零,用于处理z方向的透视逆变换)。

3. 优化的安全性

你基于e41、e42为0的优化是完全安全的,只要满足以下条件:

  • 始终使用仅在z方向引入透视的投影矩阵(比如当前的左手系透视矩阵,最后一行前两个元素为0)。
  • 视图矩阵仅包含旋转、平移等仿射变换,不引入透视。
  • 视口矩阵仅包含缩放、平移等仿射变换,不引入透视。

只要不修改上述矩阵的类型(比如不要添加x/y方向的透视,或非仿射的视口/视图变换),这个特性就不会失效。


内容的提问来源于stack exchange,提问作者Boann

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 06:57:03