#pragma once #include "math.h" #include "matrices.h" #include "rays.h" #include "world.h" #include "canvas.h" struct camera { float hsize; float vsize; float field_of_view; struct mat4x4 transform; float half_width; float half_height; float pixel_size; }; struct camera camera(float hsize, float vsize, float field_of_view) { float half_view = tanf(field_of_view / 2.0f); float aspect = hsize / vsize; float half_width; float half_height; if (aspect >= 1.0f) { half_width = half_view; half_height = half_view / aspect; } else { half_width = half_view * aspect; half_height = half_view; } float pixel_size = (half_width * 2.0f) / hsize; return (struct camera){ hsize, vsize, field_of_view, mat4x4_identity(), half_width, half_height, pixel_size }; } struct ray camera_ray_for_pixel(struct camera * camera, float px, float py) { float xoffset = (px + 0.5f) * camera->pixel_size; float yoffset = (py + 0.5f) * camera->pixel_size; float world_x = camera->half_width - xoffset; float world_y = camera->half_height - yoffset; struct mat4x4 t_inverse = mat4x4_inverse(&camera->transform); struct tuple world_point = point(world_x, world_y, -1.0f); struct tuple pixel = mat4x4_mul_t(&t_inverse, &world_point); struct tuple world_origin = point(0.0f, 0.0f, 0.0f); struct tuple origin = mat4x4_mul_t(&t_inverse, &world_origin); struct tuple direction = tuple_normalize(tuple_sub(pixel, origin)); return ray(origin, direction); } void camera_render(struct camera * camera, struct world * world, struct canvas * canvas) { canvas->width = camera->hsize; canvas->height = camera->vsize; for (int y = 0; y < camera->vsize; y++) { for (int x = 0; x < camera->hsize; x++) { struct ray ray = camera_ray_for_pixel(camera, x, y); struct tuple color = color_at(world, ray); canvas_write_pixel(canvas, x, y, color); } } }