From 7359b43f9fde19b6911b3ed95c8b31ea5e6a689b Mon Sep 17 00:00:00 2001 From: Julian T Date: Thu, 26 Mar 2020 15:43:23 +0100 Subject: Started work on area light, cleaned up ray.c and clamped colors --- main.c | 33 +++++++++++++-------- pgm.c | 49 ++++++++++++++++++++---------- pgm.h | 2 ++ ray.c | 103 ++++++++++++++++++++++++++++++++++++++-------------------------- scene.c | 5 +++- scene.h | 32 ++++++++++++++------ 6 files changed, 144 insertions(+), 80 deletions(-) diff --git a/main.c b/main.c index 56d565b..4bb068c 100644 --- a/main.c +++ b/main.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "vector.h" #include "ray.h" @@ -26,7 +27,7 @@ typedef struct { unsigned percent = 0; pthread_mutex_t percentlock; -#define OBJECTS 9 +#define OBJECTS 10 #define MATERIALS 6 #define LIGHTS 1 @@ -62,16 +63,13 @@ int main() material_t *m = add_material(cont); vector_set(&m->color, 0.4, 0.4, 1); m->defuse = 1; - m->specular = 0.0; + m->specular = 0; m->shine = 80; m->reflective = 0.0; - material_t *m3 = add_material(cont); - vector_set(&m3->color, 1, 0.3, 0.1); - m3->defuse = 0.95; - m3->specular = 0.0; - m3->shine = 80; - m3->reflective = 0.05; + material_t *ml = add_material(cont); + vector_set(&ml->color, 1, 1, 1); + ml->emissive = 1; material_t *m2 = add_material(cont); vector_set(&m2->color, 1, 1, 1); @@ -111,7 +109,7 @@ int main() o->m = m; o = add_object(cont, TYPE_SPHERE); - vector_set(&o->sph.center, 1, 1, 5); + vector_set(&o->sph.center, 1, 1, 1); o->sph.radius = 1; o->m = m; @@ -144,11 +142,19 @@ int main() vector_set(&o->pl.start, 5, 0, 0); vector_set(&o->pl.norm, 1, 0, 0); o->m = mplred; + + // Used for the light ball + /* + o = add_object(cont, TYPE_SPHERE); + vector_set(&o->sph.center, 2, -2, 8); + o->sph.radius = 1; + o->m = ml; + */ - light_t *l = add_light(cont); - vector_set(&l->pos, 3, 0, 1); - color_set(&l->defuse, 1, 1, 1); - color_set(&l->specular, 0.5, 0.5, 0.5); + light_t *l = add_light(cont, TYPE_L_POINT); + vector_set(&l->point.pos, 2, 0, 5); + color_set(&l->color, 1, 1, 1); + l->radiance = 10; pgm_write_header(stdout, TESTW, TESTH); @@ -210,6 +216,7 @@ void *worker_func(void *arg) { //color_t c; seed = x * y; ray_trace(&cont->space, TESTW - x, TESTH - y, 2, c, &seed); + color_clamp(c); } if (y % PERCENTSTEP == 0) { diff --git a/pgm.c b/pgm.c index eb0c101..4280486 100644 --- a/pgm.c +++ b/pgm.c @@ -10,6 +10,33 @@ int pgm_write_header(FILE *fp, unsigned int w, unsigned int h) return fprintf(fp, "P3\n%d %d\n%d\n", w, h, COLOR_MAX); } +/* + * Diden't really look that nice. +void color_clamp(color_t *c) +{ + // Fint the max of the 3 values + COORD_T max = c->r > c->g ? c->r : c->g; + max = max > c->b ? max : c->b; + + if (max <= 1.0) { + return; + } + + // Scale everything by this + color_scale(c, c, (COORD_T) 1 / max); +} +*/ + +#define MAXOUT(v) ( if (v > 1) { v = 1; } ) + +void color_clamp(color_t *c) +{ + // Just max them out + if (c->r > 1) { c->r = 1; } + if (c->g > 1) { c->g = 1; } + if (c->b > 1) { c->b = 1; } +} + int pgm_write_pixel(FILE *fp, color_t *c) { return fprintf(fp, "%.0lf %.0lf %.0lf\n", c->r * COLOR_MAX, c->g * COLOR_MAX, c->b * COLOR_MAX); @@ -26,28 +53,18 @@ color_t *color_set(color_t *c, COORD_T r, COORD_T g, COORD_T b) color_t *color_add(color_t *dest, color_t *a, color_t *b) { - COORD_T tmp = a->r + b->r; - dest->r = tmp > 1 ? 1 : tmp; - - tmp = a->g + b->g; - dest->g = tmp > 1 ? 1 : tmp; - - tmp = a->b + b->b; - dest->b = tmp > 1 ? 1 : tmp; + dest->r = a->r + b->r; + dest->g = a->g + b->g; + dest->b = a->b + b->b; return dest; } color_t *color_scale(color_t *dest, color_t *a, COORD_T b) { - COORD_T tmp = a->r * b; - dest->r = tmp > 1 ? 1 : tmp; - - tmp = a->g * b; - dest->g = tmp > 1 ? 1 : tmp; - - tmp = a->b * b; - dest->b = tmp > 1 ? 1 : tmp; + dest->r = a->r * b; + dest->g = a->g * b; + dest->b = a->b * b; return dest; } diff --git a/pgm.h b/pgm.h index 5a6621d..91c756b 100644 --- a/pgm.h +++ b/pgm.h @@ -9,6 +9,8 @@ typedef struct { COORD_T r, g, b; } color_t; +void color_clamp(color_t *c); + color_t *color_set(color_t *c, COORD_T r, COORD_T g, COORD_T b); color_t *color_scale(color_t *dest, color_t *a, COORD_T b); color_t *color_add(color_t *dest, color_t *a, color_t *b); diff --git a/ray.c b/ray.c index eba29c0..465b154 100644 --- a/ray.c +++ b/ray.c @@ -131,11 +131,63 @@ object_t *ray_cast(space_t *s, ray_t *r, COORD_T *dist_ret, bool chk, COORD_T ch return smallest; } -static void direct_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vector_t *eye, vector_t *point) +// Light (l) the object o reflects. Given is the point of intersect, vector to the light l, vector to viewer V, and normal at point N. +static void reflected_at(object_t *o, color_t *dest, light_t *light, COORD_T dist, vector_t *point, vector_t *l, vector_t *V, vector_t *N) { + // Calculate light intensity + COORD_T i = light->radiance / ( dist * dist); + + // Calculate Deffuse part + color_t tmp; + COORD_T cl = vector_dot(l, N) * i; + if (cl > 0) { + color_scale(&tmp, &light->color, cl * o->m->defuse); + color_add(dest, &tmp, dest); + } + + // 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); + + // Add it to the light + cl = vector_dot(&R, V) * i; + if (cl > 0) { + cl = pow(cl, o->m->shine); + color_scale(&tmp, &light->color, cl * o->m->specular); + color_add(dest, &tmp, dest); + } +} + +// Calculate the contribution of light on o. V is vector to viewer and N is normal at point +static void contribution_from_pointlight(space_t *s, color_t *dest, object_t *o, light_t *light, vector_t *point, vector_t *V, vector_t *N) { + vector_t l; + + // Prepare ray ray_t r; r.start = point; - + + // Calculate distance to light + vector_sub(&l, &light->point.pos, point); + COORD_T d = vector_len(&l); + + // Normalice + vector_scale_inv(&l, &l, vector_len(&l)); + + // Find obstacles + r.direction = &l; + object_t *obs = ray_cast(s, &r, NULL, true, d); + if (obs) { + return; + } + + // Calculate the reflected light + reflected_at(o, dest, light, d, point, &l, V, N); +} + +static void direct_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vector_t *eye, vector_t *point) +{ // And vector towards viewer vector_t V; vector_sub(&V, eye, point); @@ -143,47 +195,11 @@ static void direct_light(space_t *s, color_t *dest, object_t *o, vector_t *N, ve // Normalice it vector_scale_inv(&V, &V, vector_len(&V)); - // Cast light rays + // Loop lights light_t *light = s->lights; while (light) { - vector_t l; - - // Calculate distance to light - vector_sub(&l, &light->pos, point); - COORD_T d = vector_len(&l); - - // Normalice - vector_scale_inv(&l, &l, vector_len(&l)); - - // Find obstacles - r.direction = &l; - object_t *obs = ray_cast(s, &r, NULL, true, d); - if (obs) { - light = light->next; - continue; - } - - // Calculate Deffuse part - color_t tmp; - COORD_T cl = vector_dot(&l, N); - if (cl > 0) { - color_scale(&tmp, &light->defuse, cl * o->m->defuse); - color_add(dest, &tmp, dest); - } - - // 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); - - // 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(dest, &tmp, dest); - } + // Calculate contribution depending on the light type + contribution_from_pointlight(s, dest, o, light, point, &V, N); light = light->next; } @@ -278,6 +294,11 @@ int ray_trace_recur(space_t *s, color_t *dest, ray_t *ray, unsigned hop, COORD_T vector_t N; obj_norm_at(o, &N, r.start, ray->direction); + // Check if emissive + if (o->m->emissive > ZERO_APROX) { + color_set(&c, o->m->emissive, o->m->emissive, o->m->emissive); + } + // Check if we should calculate light if (o->m->defuse + o->m->specular > ZERO_APROX) { // Add all light hitting o at r.start to c diff --git a/scene.c b/scene.c index 730d8c8..6008942 100644 --- a/scene.c +++ b/scene.c @@ -90,13 +90,15 @@ object_t *add_object(container_t *cont, unsigned type) return o; } -light_t *add_light(container_t *cont) +light_t *add_light(container_t *cont, unsigned type) { light_t *o = container_lig_space(cont); if (!o) { return NULL; } + o->type = type; + space_t *s = &cont->space; if (s) { o->next = s->lights; @@ -112,6 +114,7 @@ light_t *add_light(container_t *cont) material_t *add_material(container_t *cont) { material_t *m = container_mat_space(cont); + memset(m, 0, sizeof(material_t)); return m; } diff --git a/scene.h b/scene.h index 08ed9e9..cbaaf3a 100644 --- a/scene.h +++ b/scene.h @@ -11,6 +11,9 @@ #define TYPE_SPHERE 1 #define TYPE_PLANE 2 +#define TYPE_L_POINT 1 +#define TYPE_L_AREA 2 + #define CONTAINER_SIZE(objs, mats, ligs) (sizeof(container_t) + objs * sizeof(object_t) + ligs * sizeof(light_t)) typedef struct { @@ -23,19 +26,13 @@ typedef struct { vector_t norm; } plane_t; -typedef struct light_s{ - vector_t pos; - color_t defuse; - color_t specular; - - struct light_s *next; -} light_t; - typedef struct { vector_t color; // Light properties COORD_T defuse; + // If this object emits light. Only makes sense if combined with a area light. + COORD_T emissive; COORD_T specular; unsigned int shine; @@ -57,6 +54,23 @@ typedef struct object_s{ }; } object_t; +typedef struct light_s{ + unsigned type; + color_t color; + + COORD_T radiance; + + union { + struct { + vector_t pos; + } point; + object_t *area; + }; + struct light_s *next; +} light_t; + +light_t l; + typedef struct { viewpoint_t view; @@ -102,7 +116,7 @@ container_t *container_init(container_t *c, unsigned objs, unsigned mats, unsign space_t *container_prepare_space(container_t *c); object_t *add_object(container_t *cont, unsigned type); -light_t *add_light(container_t *cont); +light_t *add_light(container_t *cont, unsigned type); material_t *add_material(container_t *cont); void obj_norm_at(object_t *o, vector_t *dest, vector_t *point, vector_t *direction); -- cgit v1.2.3