aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2020-02-19 22:35:48 +0100
committerJulian T <julian@jtle.dk>2020-02-19 22:35:48 +0100
commit63a84080f9f0e3d719d5470e370584a5eff18a47 (patch)
tree58264ab5ee632218ab898f70a8a0170b29e595bf
Viewpoint system and share/ray intersection working
-rw-r--r--main.c41
-rw-r--r--ray.c51
-rw-r--r--ray.h28
-rw-r--r--vector.c121
-rw-r--r--vector.h36
-rw-r--r--viewpoint.c63
-rw-r--r--viewpoint.h28
7 files changed, 368 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..0f64c57
--- /dev/null
+++ b/main.c
@@ -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));
+
+
+}
diff --git a/ray.c b/ray.c
new file mode 100644
index 0000000..d2b15cc
--- /dev/null
+++ b/ray.c
@@ -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;
+}
diff --git a/ray.h b/ray.h
new file mode 100644
index 0000000..999923a
--- /dev/null
+++ b/ray.h
@@ -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