I am writing a simple graphics engine using Rusts WGPU. I have a Sphere rendering at the origin of my scene like so:

let globe_radius = 100.0;
let globe_matrix = cgmath::Matrix4::identity();

// ...generate bind groups, layout, buffers, etc.

let globe_matrix_bind_group_layout = mesh_system.create_model_matrix_bind_group_layout();
let globe_mesh_component = MeshComponent {
    vertex_buffer: mesh_system.create_vertex_buffer(&globe_vertices_vec.as_slice()),
    index_buffer: mesh_system.create_index_buffer(&globe_indices_vec.as_slice()),
    num_indices: globe_indices_vec.len() as u32,
    model_matrix_bind_group_layout: globe_matrix_bind_group_layout,
    model_matrix_bind_group: globe_matrix_bind_group,
    model_matrix: globe_matrix,

and I am creating a camera that is 200 units away from the origin / center of the sphere like so:

let camera = Camera {      
    eye: (0.0, 0.0, 200.0).into(),
    target: (0.0, 0.0, 0.0).into(),      
    up: cgmath::Vector3::unit_y(),
    aspect: screen_width as f32 / screen_height as f32,
    fovy: 45.0,
    znear: 0.1,
    zfar: 100.0,

const OPENGL_TO_WGPU_MATRIX= 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,
let view_matrix = cgmath::Matrix4::look_at_rh(eye, target, up);
let proj_matrix = cgmath::perspective(cgmath::Deg(fovy), aspect, znear, zfar);
let view_proj_matrix = OPENGL_TO_WGPU_MATRIX * proj * view.into();

this results in the following scene: enter image description here

the scene you see when starting the program

Finally, I have the ray-sphere intersection happening on-click. I have hardcoded the click to click directly in the middle of the screen. This should result in my point_closest_to_origin being 0. However, I instead get 200, meaning that the closest point of my ray is the ray_origin (camera_origin) on click:

let screen_width = self.config.width as f32;
let screen_height = self.config.height as f32;
let position_x = screen_width / 2.0;
let position_y = screen_height / 2.0;
let cam_proj_matrix = self.camera_component.camera_uniform.proj_matrix;
let cam_view_matrix = self.camera_component.camera_uniform.view_matrix;

let globe_origin = cgmath::Matrix4::identity();
let ray_origin = cgmath::Vector4::new(

let mouse_pos_clip_space = cgmath::Vector4::new(
    (position_x * 2.0) / screen_width - 1.0,
    1.0 - (2.0 * position_y) / screen_height,
let mut mouse_pos_view_space =
        * mouse_pos_clip_space;

mouse_pos_view_space = mouse_pos_view_space / mouse_pos_view_space.w;

let model_matrix_inverse = globe_origin.invert().unwrap();

let mouse_pos_world_space = model_matrix_inverse * mouse_pos_view_space;

let ray_direction = (mouse_pos_world_space - ray_origin).normalize();

// This should be 0.0, but instead I am getting 200.0
let point_closest_to_origin = (globe_origin[3] - ray_origin).dot(ray_direction);

This is where I have been stuck at for the past couple of days and cannot tell where the issue is stemming from. I am beginning to think it has something to do with the OPENGL_TO_WGPU_MATRIX affecting the z-axis, but I cannot figure out how to confirm or deny that.

To make things as easy to possible to debug, here is also the output of all variables when running the program:

enter image description here

You can also view this code on github here: https://github.com/shanebenlolo/hypersphere/tree/ray-sphere-intersection

Thank you very much for any and all help you can offer.

  • \$\begingroup\$ What is purpose/goal of the code? \$\endgroup\$
    – agone
    Commented Dec 15, 2023 at 0:39
  • \$\begingroup\$ @agone the purpose is to derive the latitude and longitude of the location clicked on the globe \$\endgroup\$
    – shaneB
    Commented Dec 15, 2023 at 1:00
  • \$\begingroup\$ For that, you would need to deproject the mouse onto the surface of the sphere, not its origin. The dot product applies the spherical correction, but the bounds are wrong. \$\endgroup\$
    – agone
    Commented Dec 15, 2023 at 1:44


You must log in to answer this question.

Browse other questions tagged .