learn-wgpu icon indicating copy to clipboard operation
learn-wgpu copied to clipboard

Wrong view projection matrices

Open Azkellas opened this issue 6 months ago • 4 comments

The view proj matrices in the course don't provide far clipping. Projecting a point at dist = far_plane returns 0.33.

After comparing with wgpu examples, for the same parameters, the computed matrices are indeed different, and their matrices return the correct depth. This also affects xy that are 33% smaller in learn-wgpu, resulting in a smaller fov.

#478 transposed OPENGL_TO_WGPU_MATRIX but reverting this change fixes the discrepancy between the two libraries, both for perspective and orthogonal matrices, fixing the issue.

I lack insight to know what was the issue in #478, but without more analysis, I think it's better to revert the change to be aligned with wgpu examples and get a correct depth/fov back.

On a side note, wgpu examples use glam, a "wgpu-ready" linalg crate with bytemuck integration and only has specific functions for gl matrices, wgpu being the default. I think it is a good alternative to consider to be more pure wgpu. I'm willing to look into it if you agree with my sentiment.

I'm copying the comparison code here for reference, and the archive in a zip file:

Comparison code
use cgmath::prelude::*;

#[rustfmt::skip]
const CURRENT_OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
  1.0, 0.0, 0.0, 0.0,
  0.0, 1.0, 0.0, 0.0,
  0.0, 0.0, 0.5, 0.5,
  0.0, 0.0, 0.0, 1.0,
);

#[rustfmt::skip]
const FIXED_OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4<f32> = cgmath::Matrix4::new(
  1.0, 0.0, 0.0, 0.0,
  0.0, 1.0, 0.0, 0.0,
  0.0, 0.0, 0.5, 0.0,
  0.0, 0.0, 0.5, 1.0,
);

struct CameraData {
  eye: (f32, f32, f32),
  target: (f32, f32, f32),
  up: (f32, f32, f32),
  fovy: f32,
  aspect: f32,
  znear: f32,
  zfar: f32,
}

fn build_cgmath_view_projection_matrix(camera_data: &CameraData) -> cgmath::Matrix4<f32> {
  let view = cgmath::Matrix4::look_at_rh(
      camera_data.eye.into(),
      camera_data.target.into(),
      camera_data.up.into(),
  );
  let proj = cgmath::perspective(
      cgmath::Deg(camera_data.fovy),
      camera_data.aspect,
      camera_data.znear,
      camera_data.zfar,
  );
  proj * view
}

fn build_glam_view_projection_matrix(camera_data: &CameraData) -> glam::Mat4 {
  let view = glam::Mat4::look_at_rh(
      camera_data.eye.into(),
      camera_data.target.into(),
      camera_data.up.into(),
  );
  let proj = glam::Mat4::perspective_rh(
      camera_data.fovy.to_radians(),
      camera_data.aspect,
      camera_data.znear,
      camera_data.zfar,
  );
  proj * view
}

fn main() {
  let camera_data = CameraData {
      eye: (0.0, 0.0, 0.0),
      target: (0.0, 0.0, 1.0),
      up: (0.0, 1.0, 0.0),
      fovy: 45.0,
      aspect: 1.0,
      znear: 0.1,
      zfar: 100.0,
  };

  let cgmath_view_projection_matrix = build_cgmath_view_projection_matrix(&camera_data);

  let current_cgmath = CURRENT_OPENGL_TO_WGPU_MATRIX * cgmath_view_projection_matrix;
  let fixed_cgmath = FIXED_OPENGL_TO_WGPU_MATRIX * cgmath_view_projection_matrix;
  println!("{:?}", current_cgmath);
  // [[-2.4142134, 0.0, 0.0, 0.0], [0.0, 2.4142134, 0.0, 0.0], [0.0, 0.0, 0.501001, 1.501001], [0.0, 0.0, -0.1001001, -0.1001001]]
  println!("{:?}", fixed_cgmath);
  // [[-2.4142134, 0.0, 0.0, 0.0], [0.0, 2.4142134, 0.0, 0.0], [0.0, 0.0, 1.001001, 1.0], [0.0, 0.0, -0.1001001, 0.0]]

  let glam_view_projection_matrix = build_glam_view_projection_matrix(&camera_data);
  println!("{}", glam_view_projection_matrix);
  // [[-2.4142134, 0.0, 0.0, 0.0], [0.0, 2.4142134, 0.0, 0.0], [0.0, 0.0, 1.001001, 1.0], [0.0, 0.0, -0.1001001, 0.0]]

  // target on far plane
  let target = (20.0, -10.0, camera_data.zfar);

  let current_cgmath_projected = current_cgmath.transform_point(target.into());
  let fixed_cgmath_projected = fixed_cgmath.transform_point(target.into());
  let mut glam_projected =
      glam_view_projection_matrix * glam::Vec4::new(target.0, target.1, target.2, 1.0);
  glam_projected /= glam_projected.w;

  println!("{:?}", current_cgmath_projected);
  // Point3 [-0.32189512, -0.16094756, 0.33333334]
  println!("{:?}", fixed_cgmath_projected);
  // Point3 [-0.48284265, -0.24142133, 1.0]
  println!("{:?}", glam_projected);
  // Vec4(-0.48284268, -0.24142134, 1.0, 1.0)
}

learn_wgpu_matrices.zip

Azkellas avatar Dec 11 '23 20:12 Azkellas