aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c33
-rw-r--r--pgm.c49
-rw-r--r--pgm.h2
-rw-r--r--ray.c103
-rw-r--r--scene.c5
-rw-r--r--scene.h32
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 <math.h>
#include <stdlib.h>
#include <pthread.h>
+#include <string.h>
#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);