76 lines
1.9 KiB
C
76 lines
1.9 KiB
C
#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 = world_color_at(world, ray);
|
|
canvas_write_pixel(canvas, x, y, color);
|
|
}
|
|
}
|
|
}
|