This picture depicts my current immagination of the coordinate systems involved in ray tracing:
Explanation:
So the green rectangle is the [-0.5, nx-0.5] x [-0.5, ny-0.5] coordinate system and you can translate that coordinate system to the {u, v, w} coordinate system's coordinates (the world coordinate system) w/ the equations near the green rectangle.
From the origin of the world coordinate system, you can cast rays into the [l, r] x [b, t] coordinate system w/ the equation near the red rectangle ($s = e + u_{s} * u + v_{s} * v + w_{s} * w$).
The [-0.5, nx-0.5] x [-0.5, ny-0.5] matches a classic windowing systems coordinate sytem while the [l, r] x [b, t] seems to be the "ray tracer's screen"/"ray tracer's view area".
Both apparently define the view frustum depicted above. This however is counterintuitive for me since I expect the screen directly in front of the world coordinate system. So the screen I am seeing is the green rectangle, the [-0.5, nx-0.5] x [-0.5, ny-0.5]. That means everything goes backwards.
The ray tracer algorithm in my own words (and with my current understanding):
"Cause" the world space to shoot a ray so that it goes through each pixel of the window screen [-0.5, nx-0.5] x [-0.5, ny-0.5] and check for an intersection within the frustum along the way. If there is an intersection color it, if not leave it at the background color.
IOW: I am a "commander" and as I go through each pixel of [-0.5, nx-0.5] x [-0.5, ny-0.5] I cause the world space to shoot/cast a ray so that it goes through the pixel that I am currently at as well while checking for intersections within the frustum.
With my current understanding I tried to implement a ray tracer on the basis of a set_pixel() function.
My implementation attempt (w/ a skewed green sphere as a result):
void game::Engine::run()
{
int nx = window_width; // 1366
int ny = window_heigth; // 768
// Construct the "ray tracer window"/"ray tracer screen"
int left = -200;
int right = 200;
int top = 100;
int bottom = -100;
int distance = 10;
// Create the {u, v, w} coordinate system
Vec3f e{ 0, 0, float(distance) };
Vec3f u{ 1, 0, 0 };
Vec3f v{ 0, 1, 0 };
Vec3f w{ 0, 0, float(distance) };
// Create the sphere
Vec3f center{ -50, -20, 11 };
float radius = 3.0f;
// Game loop
bool running{ true };
SDL_Event event{};
while (running)
{
// Clear buffer
SDL_SetRenderDrawColor(renderer, 153, 153, 153, 255);
SDL_RenderClear(renderer);
// Draw
for (int i = 0; i <= window_width; ++i) {
for (int j = 0; j < window_heigth; ++j) {
// Calculate the scalar factors from the pixel position for each axis of the {u, v, w} coordinate system
float u_s = (left + (right - left) * (i + 0.5)) / nx;
float v_s = (bottom + (top - bottom) * (j + 0.5)) / ny;
float w_s = -distance;
// Cast a ray (in a perspective manner)
Ray3f s{ e, u * u_s + v * v_s + w * w_s};
Vec3f co = center - s.origin_vector;
// Calculate the intersection between the sphere and the ray
float a = Vec3f::dot_product(s.direction_vector, s.direction_vector);
float b = 2 * Vec3f::dot_product(co, s.direction_vector);
float c = Vec3f::dot_product(co, co) - radius * radius;
float discriminant = b * b - 4 * a * c;
Vec3f color_vec{ 0, 0, 0 }; // default background color
if (discriminant > 0)
{
// Make the hit sphere green
color_vec.x = 0;
color_vec.y = 1;
color_vec.z = 0;
}
set_pixel(renderer, i, j, 255 * color_vec.x, 255 * color_vec.y, 255 * color_vec.z, 255);
}
}
// Swap buffers
SDL_RenderPresent(renderer);
// Process event queue
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
running = false;
break;
}
}
}
}
The result:
My conclusion:
I got the coordinate system totally wrong thus the skewed result.
So the window 1366 x 768 and the ray tracer's screen 400 x 200 as well as the world coordinate system that is spanned with the standard basis in the code doesn't lead to the expected result the sphere beeing on the center of the screen and not looking skewed. Plus, the coordinate system acts weird and seems to be arbitrary.
Thus something is fundamentally wrong with my current understanding.
References:
Lecture on ray tracing
Peter Shirley's treatise on ray tracing
left + (right - left)*(i+0.5)/nx
Notice thatleft
doesn't get divided bynx
$\endgroup$a
's $\endgroup$