hgkjshegfskef

hgkjshegfskef

The Ray Tracer Challenge: chapter 7 final image is flipped (camera issues) (pp. 105-107)

@jamis

Unfortunately, my final image of chapter 7 is flipped:

All the tests from the chapter pass.

My camera and ray generation are implemented as:

camera::camera(unsigned hsize, unsigned vsize, float fov) noexcept
    : hsize{hsize}, vsize{vsize}, fov{fov}, tform{} {
    float half_view = std::tan(fov / 2.f);
    float aspect = float(hsize) / float(vsize);
    if (aspect >= 1.f) {
        half_width = half_view;
        half_height = half_view / aspect;
    } else {
        half_width = half_view * aspect;
        half_height = half_view;
    }
    pixel_size = (half_width * 2.f) / hsize;
}

tform4 view(pnt3 const& from, pnt3 const& to, vec3 const& up) noexcept {
    vec3 const forward = normalize(to - from);
    vec3 const left = normalize(cross(forward, normalize(up)));
    vec3 const true_up = normalize(cross(left, forward));
    //    vec3 const true_up = -normalize(cross(left, forward));
    tform4 orientation{left.x,     left.y,     left.z,     0, //
                       true_up.x,  true_up.y,  true_up.z,  0, //
                       -forward.x, -forward.y, -forward.z, 0};
    return orientation * tform4::translate({-from.x, -from.y, -from.z});
}

ray ray_for_pixel(camera const& cam, float px, float py) noexcept {
    // offset from edge of canvas to pixel center
    float const xoffset = (px + 0.5f) * cam.pixel_size;
    float const yoffset = (py + 0.5f) * cam.pixel_size;

    // cam looks towards -z, x is to the left
    float const world_x = cam.half_width - xoffset;
    float const world_y = cam.half_height - yoffset;
    assert(-1.f <= world_x && world_x <= 1.f);
    assert(-1.f <= world_y && world_y <= 1.f);

    tform4 const inv_cam_tform = inverse(cam.tform);
    // canvas is at z=-1
    pnt3 const pixel = inv_cam_tform * pnt3{world_x, world_y, -1};
    pnt3 const origin = inv_cam_tform * pnt3{0, 0, 0};
    vec3 const direction = normalize(pixel - origin);
    return ray{origin, direction};
}

If I negate the true_up vector, as commented out, then the image is correct:

Obviously, if I negate it, some tests fail. This is a workaround, or one bug undoing the problem caused by another bug.

If I understand correctly, forward designates Z axis, which grows into the screen (assuming left hand coordinate system, X growing right and Y growing up). Then left vector designates X, since it is the result of the left hand coordinate cross product of Z and Y. Then true_up designates X and Z cross product. Flipping the sign on true_up cross is the same as making the cross of Z and X, which would point the Y axis downwards. But this is obviously wrong.

My render() is:

canvas render(camera const& cam, world const& w) noexcept {
    canvas image{cam.hsize, cam.vsize};
    image.fill({0, 0, 0});
    for (int y = cam.vsize - 1; y >= 0; --y) {
        for (unsigned x = 0; x < cam.hsize - 1; ++x) {
            image(x, y) = color_at(w, ray_for_pixel(cam, x, y));
        }
    }
    return image;
}

My canvas’s (x,y) addressing differs from the book. In the book, the canvas’s X grows right, Y grows down, like in 2D array. Since this is difficult to reason about, my canvas’s abstraction is that X grows right, and Y grows up, same as the left hand coordinate system. But it is also implemented as 2D array (addressed as 1D array), where Y grows down, so I transform the coordinates inside the canvas implementation:

canvas::canvas(unsigned int w, unsigned int h) noexcept
    : canvas_{std::make_unique<color[]>(w * h)}, w_{w}, h_{h} {}

color& canvas::operator()(unsigned int x, unsigned int y) noexcept {
    // Internally, X grows right, but Y grows down, hence the conversion
    return canvas_[(h_ - y - 1) * w_ + x];
}

This could be the reason, but I don’t think so.

Any ideas what could be going wrong? The full code is here.

First Post!

gautierdag

gautierdag

@jamis

Curious, what was the bug with this in the end?

Where Next?

Popular Pragmatic Bookshelf topics Top

jon
Some minor things in the paper edition that says “3 2020” on the title page verso, not mentioned in the book’s errata online: p. 186 But...
New
mikecargal
Title: Hands-On Rust (Chapter 11: prefab) Just played a couple of amulet-less games. With a bit of debugging, I believe that your can_p...
New
New
patoncrispy
I’m new to Rust and am using this book to learn more as well as to feed my interest in game dev. I’ve just finished the flappy dragon exa...
New
hgkjshegfskef
The test is as follows: Scenario: Intersecting a scaled sphere with a ray Given r ← ray(point(0, 0, -5), vector(0, 0, 1)) And s ← sphere...
New
jskubick
I found an issue in Chapter 7 regarding android:backgroundTint vs app:backgroundTint. How to replicate: load chapter-7 from zipfile i...
New
Charles
In general, the book isn’t yet updated for Phoenix version 1.6. On page 18 of the book, the authors indicate that an auto generated of ro...
New
taguniversalmachine
Hi, I am getting an error I cannot figure out on my test. I have what I think is the exact code from the book, other than I changed “us...
New
mert
AWDWR 7, page 152, page 153: Hello everyone, I’m a little bit lost on the hotwire part. I didn’t fully understand it. On page 152 @rub...
New
Keton
When running the program in chapter 8, “Implementing Combat”, the printout Health before attack was never printed so I assumed something ...
New

Other popular topics Top

PragmaticBookshelf
Write Elixir tests that you can be proud of. Dive into Elixir’s test philosophy and gain mastery over the terminology and concepts that u...
New
wolf4earth
@AstonJ prompted me to open this topic after I mentioned in the lockdown thread how I started to do a lot more for my fitness. https://f...
New
Exadra37
Please tell us what is your preferred monitor setup for programming(not gaming) and why you have chosen it. Does your monitor have eye p...
New
AstonJ
Do the test and post your score :nerd_face: :keyboard: If possible, please add info such as the keyboard you’re using, the layout (Qw...
New
AstonJ
Saw this on TikTok of all places! :lol: Anyone heard of them before? Lite:
New
AstonJ
Biggest jackpot ever apparently! :upside_down_face: I don’t (usually) gamble/play the lottery, but working on a program to predict the...
New
PragmaticBookshelf
Author Spotlight Jamis Buck @jamis This month, we have the pleasure of spotlighting author Jamis Buck, who has written Mazes for Prog...
New
PragmaticBookshelf
Author Spotlight Mike Riley @mriley This month, we turn the spotlight on Mike Riley, author of Portable Python Projects. Mike’s book ...
New
New
NewsBot
Node.js v22.14.0 has been released. Link: Release 2025-02-11, Version 22.14.0 'Jod' (LTS), @aduh95 · nodejs/node · GitHub
New

Sub Categories: