diff options
-rw-r--r-- | main.c | 41 | ||||
-rw-r--r-- | ray.c | 51 | ||||
-rw-r--r-- | ray.h | 28 | ||||
-rw-r--r-- | vector.c | 121 | ||||
-rw-r--r-- | vector.h | 36 | ||||
-rw-r--r-- | viewpoint.c | 63 | ||||
-rw-r--r-- | viewpoint.h | 28 |
7 files changed, 368 insertions, 0 deletions
@@ -0,0 +1,41 @@ +#include <stdio.h> +#include <math.h> +#include <stdlib.h> + +#include "vector.h" +#include "viewpoint.h" +#include "ray.h" + +typedef struct { + viewpoint_t view; +} space_t; + +int main() +{ + printf("Starting\n"); + + space_t s; + + vector_set(&s.view.position, 10, 20, 10); + vector_set(&s.view.target, 0, 0, 0); + s.view.width = 100; + s.view.height = 100; + + viewpoint_init(&s.view); + + ray_t r; + r.start = &s.view.position; + viewpoint_ray(&s.view, &r.direction, 66, 33); + + vector_print(&r.direction); + + plane_t pl; + pl.start = vector_set(NULL, 0, 0, 12); + vector_set(&pl.norm, 6, 2, 0); + vector_scale_inv(&pl.norm, &pl.norm, vector_len(&pl.norm)); + vector_print(&pl.norm); + + printf("Intersect distance %f\n", ray_intersect_plane(&pl, &r)); + + +} @@ -0,0 +1,51 @@ +#include <math.h> +#include "vector.h" + +#include "ray.h" + +// https://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection +// http://viclw17.github.io/2018/07/16/raytracing-ray-sphere-intersection/ +COORD_T ray_intersect_sphere(sphere_t *s, ray_t *ray) +{ + // Vector between vector start and center of circle + vector_t oc; + vector_sub(&oc, ray->start, s->center); + + // Solve quadratic function + // TODO Not sure if this step i neccesary because dir is unit + COORD_T a = vector_dot(&ray->direction, &ray->direction); + COORD_T b = 2 * vector_dot(&oc, &ray->direction); + COORD_T c = vector_dot(&oc, &oc) - s->radius * s->radius; + + COORD_T d = b * b - 4 * a * c; + + // no intersection + if (d < 0) { + return -1; + } + + // Else take the closest intersection + return (-b - sqrt(d) ) / (2.0 * a); +} + +// Requires that vectors are normalized +// https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-plane-and-ray-disk-intersection +COORD_T ray_intersect_plane(plane_t *p, ray_t *ray) +{ + // If zero ray is parralel to plane + COORD_T nr = vector_dot(&p->norm, &ray->direction); + vector_print(&ray->direction); + // + // Take care of rounding errors + if (nr < ZERO_APROX && nr > -ZERO_APROX) { + return -1; + } + + // Calculate distance + vector_t tmp; + vector_copy(&tmp, p->start); + vector_sub(&tmp, &tmp, ray->start); + + COORD_T t = vector_dot(&tmp, &p->norm) / nr; + return t; +} @@ -0,0 +1,28 @@ +#ifndef RAY_H +#define RAY_H + +#include "vector.h" + +typedef struct { + // Start is not unique so it's a pointer to save copying time + vector_t *start; + + vector_t direction; +} ray_t; + +typedef struct { + vector_t *center; + COORD_T radius; +} sphere_t; + +// TODO make this less inconsistent +typedef struct { + vector_t *start; + vector_t norm; +} plane_t; + + +COORD_T ray_intersect_sphere(sphere_t *s, ray_t *ray); +COORD_T ray_intersect_plane(plane_t *p, ray_t *ray); + +#endif diff --git a/vector.c b/vector.c new file mode 100644 index 0000000..87eba37 --- /dev/null +++ b/vector.c @@ -0,0 +1,121 @@ +#include "vector.h" + +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include <stdio.h> + +static inline vector_t *vector_exists(vector_t *v) +{ + if (v) { + return v; + } + + return (vector_t *) malloc(sizeof(vector_t)); +} + +// Overwrites stuff in p. If p is null a new vector is created +vector_t *vector_set(vector_t *p, COORD_T x, COORD_T y, COORD_T z) +{ + p = vector_exists(p); + + p->x = x; + p->y = y; + p->z = z; + + return p; +} + +// Can also be used to create a vector by leaving v NULL +vector_t *vector_copy(vector_t *dest, vector_t *src) +{ + dest = vector_exists(dest); + + // If v exist copy it over + if (src) { + memcpy(dest, src, sizeof(vector_t)); + } + + return dest; +} + +COORD_T vector_len(vector_t *v) +{ + return sqrt( v->x * v->x + v->y * v->y + v->z * v->z ); +} + +vector_t *vector_add(vector_t *dest, vector_t *a, vector_t *b) +{ + dest = vector_exists(dest); + + dest->x = a->x + b->x; + dest->y = a->y + b->y; + dest->z = a->z + b->z; + + return dest; +} + +vector_t *vector_sub(vector_t *dest, vector_t *a, vector_t *b) +{ + dest = vector_exists(dest); + + dest->x = a->x - b->x; + dest->y = a->y - b->y; + dest->z = a->z - b->z; + + return dest; +} + +vector_t *vector_mult(vector_t *dest, vector_t *a, vector_t *b) +{ + dest = vector_exists(dest); + + dest->x = a->x * b->x; + dest->y = a->y * b->y; + dest->z = a->z * b->z; + + return dest; +} + +vector_t *vector_scale(vector_t *dest, vector_t *a, COORD_T b) +{ + dest = vector_exists(dest); + + dest->x = a->x * b; + dest->y = a->y * b; + dest->z = a->z * b; + + return dest; +} + +vector_t *vector_scale_inv(vector_t *dest, vector_t *a, COORD_T b) +{ + dest = vector_exists(dest); + + dest->x = a->x / b; + dest->y = a->y / b; + dest->z = a->z / b; + + return dest; +} + +COORD_T vector_dot(vector_t *a, vector_t *b) +{ + return a->x * b->x + a->y * b->y + a->z * b->z; +} + +vector_t *vector_cross(vector_t *dest, vector_t *a, vector_t *b) +{ + dest = vector_exists(dest); + + dest->x = a->y * b->z - a->z * b->y; + dest->y = a->z * b->x - a->x * b->z; + dest->z = a->x * b->y - a->y * b->x; + + return dest; +} + +void vector_print(vector_t *v) +{ + printf("[ %f, %f, %f ]\n", v->x, v->y, v->z); +} diff --git a/vector.h b/vector.h new file mode 100644 index 0000000..5609215 --- /dev/null +++ b/vector.h @@ -0,0 +1,36 @@ +#ifndef VECTOR_H +#define VECTOR_H + +#define COORD_T float +#define ZERO_APROX 1e-6 + +typedef struct { + COORD_T x; + COORD_T y; + COORD_T z; +} vector_t; + +// Set vector to specified coordinates +// If p is NULL it is created +vector_t *vector_set(vector_t *p, COORD_T x, COORD_T y, COORD_T z); + +// Copy vector src. If dest is NULL a vector is allocated +vector_t *vector_copy(vector_t *dest, vector_t *src); + +// Calculate the length of v +COORD_T vector_len(vector_t *v); + +COORD_T vector_dot(vector_t *a, vector_t *b); + +// Basic math functions +vector_t *vector_add(vector_t *dest, vector_t *a, vector_t *b); +vector_t *vector_sub(vector_t *dest, vector_t *a, vector_t *b); +vector_t *vector_mult(vector_t *dest, vector_t *a, vector_t *b); + +vector_t *vector_cross(vector_t *dest, vector_t *a, vector_t *b); + +vector_t *vector_scale(vector_t *dest, vector_t *a, COORD_T b); +vector_t *vector_scale_inv(vector_t *dest, vector_t *a, COORD_T b); + +void vector_print(vector_t *v); +#endif diff --git a/viewpoint.c b/viewpoint.c new file mode 100644 index 0000000..d51e646 --- /dev/null +++ b/viewpoint.c @@ -0,0 +1,63 @@ +#include "viewpoint.h" + +#include <stdio.h> +#include <math.h> +#include <stdlib.h> + +static const vector_t up = {0, 1, 0}; + +void viewpoint_init(viewpoint_t *view) +{ + // Vector from E to T + vector_t t; + vector_sub(&t, &view->target, &view->position); + + // Calculate orthogonal vectors to E + vector_t b, v; + vector_cross(&b, (vector_t *)&up, &t); + + // Convert to unit-vectors + vector_scale_inv(&t, &t, vector_len(&t)); + vector_scale_inv(&b, &b, vector_len(&b)); + + vector_cross(&v, &t, &b); + + // Calculate size of viewplane + COORD_T gx = tanf( FOV / 2 ); + COORD_T gy = gx * ((COORD_T)view->height / view->width); + + // Calculate viewplane vectors + vector_scale(&view->qx, &b, ( 2 * gx ) / (view->width - 1)); + vector_scale(&view->qy, &v, ( 2 * gy ) / (view->height - 1)); + + // Viewplane starting point + vector_copy(&view->blc, &t); + // This will thrash b and v + vector_sub(&view->blc, &view->blc, vector_scale(&b, &b, gx)); + vector_sub(&view->blc, &view->blc, vector_scale(&v, &v, gy)); + + // Debug print + printf("Calculated the following viewpoint stuff\n"); + printf("qx"); vector_print(&view->qx); + printf("qy"); vector_print(&view->qy); + printf("blc"); vector_print(&view->blc); +} + +// Calculate ray for viewport w, h +// https://en.wikipedia.org/wiki/Ray_tracing_(graphics) +void viewpoint_ray(viewpoint_t *view, vector_t *r, unsigned x, unsigned y) +{ + // Calculate ray vector + vector_copy(r, &view->blc); + + vector_t t; + vector_scale(&t, &view->qx, x); + vector_add(r, r, &t); + + vector_scale(&t, &view->qy, y); + vector_add(r, r, &t); + + // Calculate unit vector + vector_scale_inv(r, r, vector_len(r)); +} + diff --git a/viewpoint.h b/viewpoint.h new file mode 100644 index 0000000..0aae5db --- /dev/null +++ b/viewpoint.h @@ -0,0 +1,28 @@ +#ifndef VIEWPOINT_H +#define VIEWPOINT_H + +#include "vector.h" + +// 90 degrees +#define FOV 3.1415/2 + +typedef struct { + // Viewpoint dimensions + unsigned int width; + unsigned int height; + + // Position and orientation + vector_t position, target; + + // Viewpoint shift vectors + // Calculated at initialisation + vector_t qx, qy; + // Left button center pixel location + vector_t blc; +} viewpoint_t; + +// Todo handle initial setup +void viewpoint_init(viewpoint_t *view); + +void viewpoint_ray(viewpoint_t *view, vector_t *r, unsigned x, unsigned y); +#endif |