aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c25
-rw-r--r--pgm.c22
-rw-r--r--ray.c82
-rw-r--r--scene.c7
-rw-r--r--scene.h11
-rw-r--r--vector.h4
6 files changed, 119 insertions, 32 deletions
diff --git a/main.c b/main.c
index 0f0103a..d7232e0 100644
--- a/main.c
+++ b/main.c
@@ -11,6 +11,7 @@
#define TESTH 1000
color_t back = {0, 0, 0};
+int print = 0;
int main()
{
@@ -18,11 +19,21 @@ int main()
space_t s;
s.objects = NULL;
s.lights = NULL;
+ color_set(&s.ambient, 30, 30, 30);
material_t m;
vector_set(&m.color, 0, 1, 0);
+ m.defuse = 1;
+ m.specular = 0.7;
+ m.shine = 20;
- vector_set(&s.view.position, 0, 15, 10);
+ material_t mpl;
+ vector_set(&mpl.color, 0, 0.396, 0.7019);
+ mpl.defuse = 1;
+ mpl.specular = 0.3;
+ mpl.shine = 20;
+
+ vector_set(&s.view.position, 0, 15, 8);
vector_set(&s.view.target, 0, 0, 0);
s.view.width = TESTW;
s.view.height = TESTH;
@@ -30,14 +41,19 @@ int main()
viewpoint_init(&s.view);
// Setup plane
- add_sphere(&s, vector_set(NULL, 0, 0, 5), 5, &m);
+ add_sphere(&s, vector_set(NULL, 3, 0, 5), 5, &m);
+ add_sphere(&s, vector_set(NULL, -6, -3, 7), 3, &m);
//add_sphere(&s, vector_set(NULL, 10, 0, 5), 5);
- add_plane(&s, vector_set(NULL, 0, 0, 2), vector_set(NULL, 0, 0, 1));
- add_light(&s, vector_set(NULL, 10, 0, 20), color_set(NULL, 255, 255, 255));
+ add_plane(&s, vector_set(NULL, 0, 0, 2), vector_set(NULL, 0, 0, 1), &mpl);
+ add_light(&s, vector_set(NULL, 10, 0, 20), color_set(NULL, 150, 150, 150), color_set(NULL, 150, 150, 150));
pgm_write_header(stdout, TESTW, TESTH);
for (int y = TESTH; y; y--) {
for (int x = TESTW; x; x--) {
+ if (0 && y <= 500) {
+ printf("Lets go");
+ print = 1;
+ }
color_t *c = ray_trace(&s, x, y);
if (c) {
@@ -46,6 +62,7 @@ int main()
pgm_write_pixel(stdout, &back);
}
free(c);
+ print = 0;
}
}
diff --git a/pgm.c b/pgm.c
index 90791de..efc50f7 100644
--- a/pgm.c
+++ b/pgm.c
@@ -32,9 +32,14 @@ color_t *color_add(color_t *dest, color_t *a, color_t *b)
dest = (color_t *) malloc(sizeof(dest));
}
- dest->r = a->r + b->r;
- dest->g = a->g + b->g;
- dest->b = a->b + b->b;
+ unsigned int tmp = a->r + b->r;
+ dest->r = tmp > 255 ? 255 : tmp;
+
+ tmp = a->g + b->g;
+ dest->g = tmp > 255 ? 255 : tmp;
+
+ tmp = a->b + b->b;
+ dest->b = tmp > 255 ? 255 : tmp;
return dest;
}
@@ -45,9 +50,14 @@ color_t *color_scale(color_t *dest, color_t *a, float b)
dest = (color_t *) malloc(sizeof(dest));
}
- dest->r = a->r * b;
- dest->g = a->g * b;
- dest->b = a->b * b;
+ unsigned int tmp = a->r * b;
+ dest->r = tmp > 255 ? 255 : tmp;
+
+ tmp = a->g * b;
+ dest->g = tmp > 255 ? 255 : tmp;
+
+ tmp = a->b * b;
+ dest->b = tmp > 255 ? 255 : tmp;
return dest;
}
diff --git a/ray.c b/ray.c
index 0e82546..d5b6a89 100644
--- a/ray.c
+++ b/ray.c
@@ -4,6 +4,8 @@
#include "ray.h"
+extern int print;
+
// https://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection
// http://viclw17.github.io/2018/07/16/raytracing-ray-sphere-intersection/
// https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection
@@ -26,6 +28,9 @@ COORD_T ray_intersect_sphere(sphere_t *s, ray_t *ray, bool skip_dist)
return -1;
}
if (skip_dist) {
+ if (print) {
+ printf("sph dist: skip\n");
+ }
return 1;
}
@@ -34,11 +39,11 @@ COORD_T ray_intersect_sphere(sphere_t *s, ray_t *ray, bool skip_dist)
-0.5 * (b + sqrt(d)) :
-0.5 * (b - sqrt(d));
- COORD_T x0 = q / a;
- COORD_T x1 = c / q;
+ COORD_T x1 = q / a;
+ COORD_T x0 = c / q;
// Take the correct result. If one is zero take the other.
- if (x0 <= 0) {
+ if (x0 <= ZERO_APROX) {
if (x1 <= 0) {
return -1;
}
@@ -47,9 +52,12 @@ COORD_T ray_intersect_sphere(sphere_t *s, ray_t *ray, bool skip_dist)
}
// If point is on sphere it will be zero close to zero
- if (x0 < 1e-3) {
+ if (x0 < ZERO_APROX) {
return -1;
}
+ if (print) {
+ printf("sph dist: %f\n", x0);
+ }
return x0;
}
@@ -60,12 +68,18 @@ COORD_T ray_intersect_plane(plane_t *p, ray_t *ray, bool skip_dist)
{
// If zero ray is parralel to plane
COORD_T nr = vector_dot(p->norm, ray->direction);
- //
+
// Take care of rounding errors
if (nr < ZERO_APROX && nr > -ZERO_APROX) {
+ if (print) {
+ printf("Ohh no");
+ }
return -1;
}
if (skip_dist) {
+ if (print) {
+ printf("pdist: skip\n");
+ }
return 1;
}
@@ -75,6 +89,9 @@ COORD_T ray_intersect_plane(plane_t *p, ray_t *ray, bool skip_dist)
vector_sub(&tmp, &tmp, ray->start);
COORD_T t = vector_dot(&tmp, p->norm) / nr;
+ if (print) {
+ printf("pdist: %f\n", t);
+ }
return t;
}
@@ -102,7 +119,10 @@ object_t *ray_cast(space_t *s, ray_t *r, COORD_T *dist_ret, bool chk, COORD_T ch
while (o) {
COORD_T d = ray_intersect(o, r, false);
- if (d > 0) {
+ if (print)
+ printf("Distance: %f\n", d);
+
+ if (d > ZERO_APROX) {
if (chk && chk_dist > d) {
if (dist_ret) {
*dist_ret = d;
@@ -143,16 +163,23 @@ color_t *ray_trace(space_t *s, unsigned int x, unsigned int y)
return NULL;
}
- // Calculate new ray point
r.start = vector_scale(NULL, r.direction, dist);
vector_add(r.start, r.start, &s->view.position);
// Calculate normal vector
vector_t n;
obj_norm_at(o, &n, r.start);
+
+ // And vector towards viewer
+ //printf("point: "); vector_print(r.start);
+ vector_t V;
+ vector_sub(&V, &s->view.position, r.start);
+ // Normalice it
+ vector_scale_inv(&V, &V, vector_len(&V));
+ //printf("V: "); vector_print(&V);
// Hit color
- color_t *c = color_set(NULL, 0, 0, 0);
+ color_t *c = color_set(NULL, s->ambient.r, s->ambient.g, s->ambient.b);
// Cast light rays
light_t *light = s->lights;
@@ -162,26 +189,49 @@ color_t *ray_trace(space_t *s, unsigned int x, unsigned int y)
vector_sub(&l, light->pos, r.start);
COORD_T d = vector_len(&l);
+ vector_scale_inv(&l, &l, vector_len(&l));
+
// Find obstacles
+ if (print) printf("Starting\n");
r.direction = &l;
object_t *obs = ray_cast(s, &r, NULL, true, d);
if (obs) {
+ if (print)
+ printf("Light ray hit\n");
+
light = light->next;
continue;
}
+ if (print)
+ printf("Light ray went through\n");
- // Calculate unit
- vector_scale_inv(&l, &l, vector_len(&l));
+ // Calculate Deffuse part
color_t tmp;
- color_scale(&tmp, light->defuse, vector_dot(&l, &n));
- color_add(c, &tmp, c);
-
+ COORD_T cl = vector_dot(&l, &n);
+ if (cl > 0) {
+ color_scale(&tmp, light->defuse, cl * o->m->defuse);
+ color_add(c, &tmp, c);
+ }
+
+ // calculate specular part. TODO implement blinn-phong
+ // Calculate R_m
+ vector_t R;
+ vector_scale(&R, &n, 2 * vector_dot(&l, &n));
+ vector_sub(&R, &R, &l);
+ //printf("R: ");vector_print(&R);
+
+ // Add it to the light
+ cl = 1 * vector_dot(&R, &V);
+ if (cl > 0) {
+ cl = pow(cl, o->m->shine);
+ color_scale(&tmp, light->specular, cl * o->m->specular);
+ color_add(c, &tmp, c);
+ }
+
light = light->next;
}
- if (o->m) {
- color_scale_vector(c, c, &o->m->color);
- }
+ color_scale_vector(c, c, &o->m->color);
return c;
}
diff --git a/scene.c b/scene.c
index 99ae0e8..5a41041 100644
--- a/scene.c
+++ b/scene.c
@@ -27,11 +27,13 @@ object_t *add_sphere(space_t *s, vector_t *c, COORD_T r, material_t *m)
return o;
}
-object_t *add_plane(space_t *s, vector_t *start, vector_t *dir)
+object_t *add_plane(space_t *s, vector_t *start, vector_t *dir, material_t *m)
{
object_t *o = (object_t *) malloc(sizeof(object_t));
o->type = TYPE_PLANE;
+ o->m = m;
+
o->pl.start = start;
o->pl.norm = dir;
@@ -40,12 +42,13 @@ object_t *add_plane(space_t *s, vector_t *start, vector_t *dir)
return o;
}
-light_t *add_light(space_t *s, vector_t *pos, color_t *defuse)
+light_t *add_light(space_t *s, vector_t *pos, color_t *defuse, color_t *specular)
{
light_t *o = (light_t *) malloc(sizeof(light_t));
o->pos = pos;
o->defuse = defuse;
+ o->specular = specular;
if (s) {
o->next = s->lights;
diff --git a/scene.h b/scene.h
index 7efb5cd..489aece 100644
--- a/scene.h
+++ b/scene.h
@@ -24,12 +24,17 @@ typedef struct {
typedef struct light_s{
vector_t *pos;
color_t *defuse;
+ color_t *specular;
struct light_s *next;
} light_t;
typedef struct {
vector_t color;
+
+ COORD_T defuse;
+ COORD_T specular;
+ unsigned int shine;
} material_t;
// General object structure
@@ -50,11 +55,13 @@ typedef struct {
viewpoint_t view;
object_t *objects;
light_t *lights;
+
+ color_t ambient;
} space_t;
object_t *add_sphere(space_t *s, vector_t *c, COORD_T r, material_t *m);
-object_t *add_plane(space_t *s, vector_t *start, vector_t *dir);
-light_t *add_light(space_t *s, vector_t *pos, color_t *defuse);
+object_t *add_plane(space_t *s, vector_t *start, vector_t *dir, material_t *m);
+light_t *add_light(space_t *s, vector_t *pos, color_t *defuse, color_t *specular);
void obj_norm_at(object_t *o, vector_t *dest, vector_t *point);
diff --git a/vector.h b/vector.h
index 2fcb648..e794f05 100644
--- a/vector.h
+++ b/vector.h
@@ -1,8 +1,8 @@
#ifndef VECTOR_H
#define VECTOR_H
-#define COORD_T float
-#define ZERO_APROX 1e-5
+#define COORD_T double
+#define ZERO_APROX 1e-6
typedef struct {
COORD_T x;