我正在编写一个光线追踪器,我需要将光线从屏幕转换到世界上。我使用 View -投影-视口(viewport)矩阵的逆来从屏幕像素坐标返回到世界空间坐标。
我偶然注意到,无论我如何移动、缩放、绕轨道运行或旋转相机,逆矩阵的两个元素始终为 0。我对投影矩阵的理解不够深入,不知道为什么。
这是我的 Matrix 类中希望相关的部分:
// OpenGL-style column-vectors layout.
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;
}
}
这是移动相机一段时间后的 View -投影-视口(viewport)矩阵:
[ -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 ]
当我移动相机时,大多数元素都会不断变化。逆函数右下角的两个元素似乎与 znear 和 zfar 参数直接相关。左下角的两个元素看起来总是0。
这个事实在变换方法中很有用。如果 e41 和 e42 为 0,并且当将光线的近点和远点转换到屏幕上时,输入 z 始终为 0 或 1,则可以提前计算 w 除法,而不是按像素计算。这是有效的,并且是一个有用的加速。
但是,我担心这个假设以后会破坏某些东西。所以我想知道,这两个元素都为0意味着什么,这个假设什么时候成立?
编辑:我found out仿射 4x4 矩阵具有最后四个元素 (0 0 0 1)。我的逆矩阵几乎匹配。但是,使透视矩阵的逆矩阵仿射或几乎仿射的魔力是什么?
最佳答案
对于给定的perspectiveFovLH
矩阵P和任何齐次/仿射变换矩阵M,逆R≔ (PM)−1总是有Rwx=R wy=0。
证明
要看到这一点,对于某些输入v,令t为Mv,并令s为>Pt=PMv,这样v=Rs。 请注意,每个 M 都有 Mwx=Mwy=M wz=0 且Mww=1,这样tw=vw。 然后从P的稀疏性观察sw=tz并且
sz=Qtz − Qz0tw
=Qsw − Qz0vw
解最后一个方程得出
vw=(Qsw − sz)/(Qz0)
这个公式显然只依赖于sz和sw,证明了假设 Rwx=Rwy=0。
基本原理
我们可以用一种非公式化的方式来理解这一点:3×4 矩阵足以在屏幕上进行透视,因为您只需要 2 个输出坐标和一个用于划分它们的齐次坐标。使用完整的 4×4 矩阵会引入冗余,因为结果的 z 和 w 坐标仅源自输入的 z 坐标(以及初始 w 的已知常数 1)。无论投影之前应用的世界变换如何,变换后的 z 和原始 w 中仍然有这两个方程,这足以为他们解决。
关于java - 为什么我的逆投影矩阵的两个元素始终为 0?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76398774/