My goal is to calculate a ray that points to the scene, for checking mouse clicks and stuff. I'm not using conventional perspective projection / camera, instead I'm just using an oblique projection (like a skewed orthographic proj) matrix for my scene with no camera (no view matrix). All the methods I found online are kinda specific for perspective projection and cameras, and use camera position directly as ray origin, then calculate ray direction from mouse position and proj/view matrices. However in my case (thinking about the projection in real world context) my ray origin should be calculated from mouse position, and ray direction should be the same for all rays and be able to directly calculated from the projection matrix, but I just don't know how..
This is my oblique projection matrix if that's relevant:
fn oblique_projection(cam) -> Mat4 {
let w = cam.screen_width;
let h = cam.screen_height;
let near = cam.near;
let far = cam.far;
// normal orthographic projection matrix:
let (left, right, bottom, top) = (-w / 2.0, w / 2.0, -h / 2.0, h / 2.0);
let tx = -(right + left) / (right - left);
let ty = -(top + bottom) / (top - bottom);
let tz = -(far + near) / (far - near);
let m1 = mat4![
2.0 / (right - left), 0.0, 0.0, 0.0,
0.0, 2.0 / (top - bottom), 0.0, 0.0,
0.0, 0.0, -2.0 / (far - near), 0.0,
tx, ty, tz, 1.0,
];
// apply a skew matrix on top of the orthographic matrix to get an oblique projection matrix
let a = -self.z_scale * f32::cos(self.angle);
let b = -self.z_scale * f32::sin(self.angle);
let m2 = mat4![
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
a, b, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
];
return m1 * m2;
}
(basically a skewed orthographic projection, result in something like an isometric view)
EDIT:
I found a solution that's very specific for my setup (my oblique projection)
let a = -cam.z_scale * cos(cam.angle);
let b = -cam.z_scale * sin(cam.angle);
let skewed = mat4[
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
a, b, 1.0, 0.0,
0.0, 0.0, 0.0, 1.0,
]; // the only the skew part from the projection matrix construction above
let ray_dir = (skewed * vec3!(0, 0, -1)).normalized(); // apply the skew to a unit forward vector
let mouse_pos_clip_space = screen_to_clip(mouse_pos);
let clip_coord = vec4(mouse_pos_clip_space, -1, 1);
let ray_orig = projection_matrix.inverse() * clip_coord; // unproject the oblique projection matrix calculated in the previous code block
return Ray {
origin: ray_orig,
dir: ray_dir,
};
So the idea is to first figure out how to construct a ray for an ordinary orthographic projection, then apply the skew
This makes me think there isn't a general algorithm fn get_ray(proj: Mat4, view: Mat4) -> (ray_origin: Vec3, ray_dir: Vec3)
cuz the way I construct the ray is vastly different than the way for a traditional perspective projection + camera scene.