I am trying to write a raytracer in Rust that is able to load a .gltf file and render it. To do this I model a scene in Blende, export it to gltf (y up) and use my renderer to render the scene.

The Issue I am currently having is that the rotations in Blender and the exported gltf file do not seem to match up. If I for example set a rotation of (0,0.5,0.5,0|XYZW) in Blender, it gets exported as (0,1,0,0|XYZW). If I however render this Image using my code, yet another rotation seems to be used (an image is produced corresponding to a rotation of (0.5,0,0,0.5|XYZW) in Blender). easy_gltf yields the following transform matrix (world -> camera):

camera.transform = Matrix4 
[-1.0, 0.0, 0.0, 2.0
0.0, 1.0, 0.0, 10.0
0.0, 0.0, -1.0, -2
0.0, 0.0, 0.0, 1.0]

The camera is located at (2,2,10) in Blender, so at least the translational component appears to be working.

To load the gltf file, I use easy_gltf in Rust. The following code is used to generate the ray directions:

//ray origin in world space
let origin_world_space = camera.position();
// the distance from the camera origin to the view plane
let z: f32 = height as f32 / (2.0 * fovy.mul(0.5).tan());

//obtain the inverse transformation Matrix
let inverse_transform = camera.transform.invert().unwrap_or_else(||
    panic!("Non invertible transform Matrix. giving up.")

//TODO: take ray multiplier per pixel into account here
let mut rays: Vec<Ray> = Vec::with_capacity(height * width);

//generate all rays for this pixel and add them to the rays vector
//TODO: use blue noise here to generate multiple rays per pixel

fn generate_single_primary_ray(image_width: usize,
                               image_height: usize,
                               inverse_transform: &Matrix4<f32>,
                               focal_length: f32,
                               u: usize,
                               v: usize,
                               ray_origin: Vector3<f32>) -> Ray {
    //calculate the ray direction and translate it to world space
    let direction_view_space: Vector4<f32> =
        Vector4::new(u as f32 - (image_width as f32 / 2.0),
                     v as f32 - (image_height as f32 / 2.0),
    //TODO: Rotation is fucked
    //x rotation has sign wrong, y and z are flipped
    let direction_world_space = inverse_transform * direction_view_space.normalize();

    Ray { source: ray_origin, direction: direction_world_space.truncate().normalize() }

As you may see from the code above, to calculate the ray direction I first calculate the distance from the camera origin to the projection plane, take the inverse of the World-to-Camera-Matrix and then map the Camera space coordinates to world space directions using the inverse transform matrix (which I get from the eays_gltf API -> no influence on that).

Now I tried debugging this for hours but I cannot seem to pin down the issue. Is the export process wrong? Is easy gltf constructing the Matrix wrongly or do I have an issue in my code?

The code, .blend file and .gltf file are available here: https://git.cdaut.de/CDaut/raytrace-rs

  • $\begingroup$ I don't know about easy_gltf, but I'll offer some hints that I do know: 1. Blender "up" is +Z but glTF "up" is +Y, so on export there will be a 90-deg clockwise rotation about X to change from one system to the other. Also 2. Be careful that Blender's UI specifies WXYZ but in glTF the quaternion is XYZW, so be careful comparing the two. And 3. of course [0, 0.5, 0.5, 0] is not a normalized quaternion; the middle numbers would need to be 0.707107 or such instead of 0.5. $\endgroup$
    – emackey
    Dec 4, 2023 at 21:37
  • $\begingroup$ Also if you could isolate a specific .blend and corresponding .gltf instead of a link to a full repo, that might help narrow down the question. $\endgroup$
    – emackey
    Dec 4, 2023 at 21:37


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.