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

brianokken
Many tasks_proj/tests directories exist in chapters 2, 3, 5 that have tests that use the custom markers smoke and get, which are not decl...
New
lirux
Hi Jamis, I think there’s an issue with a test on chapter 6. I own the ebook, version P1.0 Feb. 2019. This test doesn’t pass for me: ...
New
AleksandrKudashkin
On the page xv there is an instruction to run bin/setup from the main folder. I downloaded the source code today (12/03/21) and can’t see...
New
jeremyhuiskamp
Title: Web Development with Clojure, Third Edition, vB17.0 (p9) The create table guestbook syntax suggested doesn’t seem to be accepted ...
New
brunogirin
When I run the coverage example to report on missing lines, I get: pytest --cov=cards --report=term-missing ch7 ERROR: usage: pytest [op...
New
AufHe
I’m a newbie to Rails 7 and have hit an issue with the bin/Dev script mentioned on pages 112-113. Iteration A1 - Seeing the list of prod...
New
taguniversalmachine
It seems the second code snippet is missing the code to set the current_user: current_user: Accounts.get_user_by_session_token(session["...
New
jwandekoken
Book: Programming Phoenix LiveView, page 142 (157/378), file lib/pento_web/live/product_live/form_component.ex, in the function below: d...
New
tkhobbes
After some hassle, I was able to finally run bin/setup, now I have started the rails server but I get this error message right when I vis...
New
ggerico
I got this error when executing the plot files on macOS Ventura 13.0.1 with Python 3.10.8 and matplotlib 3.6.1: programming_ML/code/03_...
New

Other popular topics Top

siddhant3030
I’m thinking of buying a monitor that I can rotate to use as a vertical monitor? Also, I want to know if someone is using it for program...
New
brentjanderson
Bought the Moonlander mechanical keyboard. Cherry Brown MX switches. Arms and wrists have been hurting enough that it’s time I did someth...
New
PragmaticBookshelf
From finance to artificial intelligence, genetic algorithms are a powerful tool with a wide array of applications. But you don't need an ...
New
AstonJ
There’s a whole world of custom keycaps out there that I didn’t know existed! Check out all of our Keycaps threads here: https://forum....
New
New
PragmaticBookshelf
Rails 7 completely redefines what it means to produce fantastic user experiences and provides a way to achieve all the benefits of single...
New
PragmaticBookshelf
Build efficient applications that exploit the unique benefits of a pure functional language, learning from an engineer who uses Haskell t...
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 Rebecca Skinner @RebeccaSkinner Welcome to our latest author spotlight, where we sit down with Rebecca Skinner, auth...
New
New

Sub Categories: