From b0079eaa628a1f2fd99014cd12e6baac17f4d17a Mon Sep 17 00:00:00 2001 From: Julian T Date: Sun, 23 Feb 2020 18:30:21 +0100 Subject: Added phong light model and fixed sphere intersect --- main.c | 25 ++++++++++++++++---- pgm.c | 22 ++++++++++++----- ray.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++------------- scene.c | 7 ++++-- scene.h | 11 +++++++-- vector.h | 4 ++-- 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; -- cgit v1.2.3