我正在尝试在 3d 空间中渲染四边形,但是当我应用投影矩阵时,当我希望它仍然位于屏幕中心时,会出现垂直偏移。我觉得我已经消除了所有其他变量(没有其他矩阵,1/1 屏幕比例等),所以投影矩阵本身一定有问题。下图中唯一的区别是我乘以投影矩阵还是单位矩阵。
渲染引擎的坐标系是X向右,Y向前,Z向上。在两个示例中,通过将投影矩阵与翻转轴的矩阵相乘,将其转换为 Vulkan 坐标系。
所以我的问题是,我在投影矩阵计算中哪里出错了?
同样重要的是,矩阵是行主矩阵,NDC 为 (-1, -1, -1) 到 (1, 1, 1)。
编辑: 更多测试确实表明 Z 轴上发生了不需要的偏移。我做了一个简单的投影矩阵,
Matrix4x4f::perspective_near_plane(-1.0, 1.0, 1.0, -1.0, 1.0, 100.0)
并将近平面和远平面的角点坐标乘以投影。这应该简单地给出 NDC 的角点,但返回的是:
[-1, 1, 1, 1] -> [-1, -0.9999999, 2, 1] -> [-1, -0.9999999, 2, 1]
[1, 1, 1, 1] -> [1, -0.9999999, 2, 1] -> [1, -0.9999999, 2, 1]
[1, 1, -1, 1] -> [1, -0.9999999, 0, 1] -> [1, -0.9999999, 0, 1]
[-1, 1, -1, 1] -> [-1, -0.9999999, 0, 1] -> [-1, -0.9999999, 0, 1]
[-100, 100, 100, 1] -> [-100, 100, 101, 100] -> [-1, 1, 1.01, 1]
[100, 100, 100, 1] -> [100, 100, 101, 100] -> [1, 1, 1.01, 1]
[100, 100, -100, 1] -> [100, 100, -99, 100] -> [1, 1, -0.99, 1]
[-100, 100, -100, 1] -> [-100, 100, -99, 100] -> [-1, 1, -0.99, 1]
impl<T> Matrix4x4<T> {
pub fn perspective_near_plane(left: T, top: T, right: T, bottom: T, near: T, far: T) -> Self
where T: Real {
let m11 = ((T::one() + T::one()) * near) / (right - left);
let m12 = T::zero();
let m13 = T::zero();
let m14 = T::zero();
let m21 = -(right + left) / (right - left);
let m22 = (far + near) / (far - near);
let m23 = -(top + bottom) / (top - bottom);
let m24 = T::one();
let m31 = T::zero();
let m32 = T::zero();
let m33 = ((T::one() + T::one()) * near) / (top - bottom);
let m34 = T::zero();
let m41 = T::zero();
let m42 = (-(T::one() + T::one()) * far * near) / (far - near);
let m43 = T::one();
let m44 = T::zero();
Self::new(
m11, m12, m13, m14,
m21, m22, m23, m24,
m31, m32, m33, m34,
m41, m42, m43, m44)
}
pub fn perspective_horizontal_fov(horizontal_fov: T, aspect_ratio: T, near: T, far: T) -> Self
where T: Real {
let right = (horizontal_fov / (T::one() + T::one())).tan() * near;
let left = -right;
let top = right / aspect_ratio;
let bottom = -top;
Self::perspective_near_plane(left, top, right, bottom, near, far)
}
}
let projection = Matrix4x4f::perspective_horizontal_fov(
60.0 / 180.0 * std::f32::consts::PI,
window_size.x as f32 / window_size.y as f32,
0.1,
1000.0);
Matrix4x4f::new(
1.0, 0.0, 0.0, 0.0,
0.0, 0.0, 1.0, 0.0,
0.0, -1.0, 0.0, 0.0,
0.0, 0.0, 0.0, 1.0
)
static const float3 positions[6] = {
float3(-0.5, 1, -0.5),
float3(0.5, 1, 0.5),
float3(-0.5, 1, 0.5),
float3(-0.5, 1, -0.5),
float3(0.5, 1, -0.5),
float3(0.5, 1, 0.5),
};
我找到罪魁祸首了!我将 m24 和 m43 的值都设置为 1。但正如您在this示例中所看到的,矩阵中只有一个元素应该具有非零常数值。
由于 m43 是这两个元素中唯一影响 Z 轴的元素,因此必须将其设置为零。该值被添加到 Z 位置,导致垂直偏移。