aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian T <julian@jtle.dk>2020-07-25 00:09:53 +0200
committerJulian T <julian@jtle.dk>2020-07-25 00:09:53 +0200
commitdbba33fcd07c9e81e3ca9bc4f5e8185d364fb792 (patch)
tree7e3b570853a18c7f7670c870f8bc6a09bb287a4f
parentef684a7d2ad2934af872cb19a413c95d1005c4b6 (diff)
Further experimentation with pathtracingpath_tracing
Probably starting over in cpp
-rw-r--r--main.c49
-rw-r--r--pgm.c7
-rw-r--r--pgm.h1
-rw-r--r--ray.c273
-rw-r--r--ray.h2
-rw-r--r--scene.h14
6 files changed, 63 insertions, 283 deletions
diff --git a/main.c b/main.c
index ccf546b..6b45a59 100644
--- a/main.c
+++ b/main.c
@@ -9,12 +9,12 @@
#include "scene.h"
#include "pgm.h"
-#define TESTW 1000
-#define TESTH 1000
+#define TESTW 500
+#define TESTH 500
#define PERCENTSTEP (TESTH / 100)
-#define WORKERS 1
+#define WORKERS 4
void *worker_func(void *arg);
@@ -34,31 +34,9 @@ pthread_mutex_t percentlock;
char container[ CONTAINER_SIZE(OBJECTS, MATERIALS, LIGHTS) ];
container_t *cont = (container_t *) container;
-settings_t gfx_high = {
- .arealight_samples = 64,
- .envlight_samples = 64,
- .antialias_samples = 2,
- .globallight_samples = 32,
- .gl_opt_depth = 1,
- .depth = 2,
-};
-
settings_t gfx_low = {
- .arealight_samples = 4,
- .envlight_samples = 16,
- .antialias_samples = 100,
- .globallight_samples = 16,
- .gl_opt_depth = 1,
- .depth = 16,
-};
-
-settings_t gfx_very = {
- .arealight_samples = 8,
- .envlight_samples = 8,
- .antialias_samples = 2,
- .globallight_samples = 2,
- .gl_opt_depth = 0,
- .depth = 1,
+ .samples = 10,
+ .depth = 15,
};
// Implement random
@@ -98,7 +76,7 @@ int main()
material_t *ml = add_material(cont);
vector_set(&ml->color, 1, 1, 1);
- ml->emissive = 1;
+ ml->emissive = 8;
material_t *m2 = add_material(cont);
vector_set(&m2->color, 1, 1, 1);
@@ -172,17 +150,18 @@ int main()
vector_set(&o->pl.norm, 1, 0, 0);
o->m = mplred;
- // Used for the light ball
+ // light ball
o = add_object(cont, TYPE_SPHERE);
vector_set(&o->sph.center, 0, 7, 0);
o->sph.radius = 0.5;
o->m = ml;
- light_t *l = add_light(cont, TYPE_L_AREA);
- //vector_set(&l->point.pos, 0, 5, 0);
- l->area = o;
+ /*
+ light_t *l = add_light(cont, TYPE_L_POINT);
+ vector_set(&l->point.pos, 0, 7, 0);
color_set(&l->color, 1, 1, 1);
- l->radiance = 0.1;
+ l->radiance = 5;
+ */
pgm_write_header(stdout, TESTW, TESTH);
@@ -243,14 +222,14 @@ void *worker_func(void *arg) {
color_t *c = &office->image[ y * TESTW + x ];
//color_t c;
seed = x * y;
- ray_trace(&cont->space, TESTW - x, TESTH - y, c, &seed);
+ path_trace(&cont->space, TESTW - x, TESTH - y, c, &seed);
color_clamp(c);
}
if (y % PERCENTSTEP == 0) {
// Unlock the thingy
pthread_mutex_lock(&percentlock);
- fprintf(stderr, "%d%\n", percent++);
+ fprintf(stderr, "%d%%\n", percent++);
pthread_mutex_unlock(&percentlock);
}
}
diff --git a/pgm.c b/pgm.c
index 4280486..910a148 100644
--- a/pgm.c
+++ b/pgm.c
@@ -2,6 +2,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <math.h>
#define COLOR_MAX 255
@@ -39,9 +40,15 @@ void color_clamp(color_t *c)
int pgm_write_pixel(FILE *fp, color_t *c)
{
+ //color_gamma_correct(c);
return fprintf(fp, "%.0lf %.0lf %.0lf\n", c->r * COLOR_MAX, c->g * COLOR_MAX, c->b * COLOR_MAX);
}
+void color_gamma_correct(color_t *c) {
+ c->r = sqrt(c->r);
+ c->g = sqrt(c->g);
+ c->b = sqrt(c->b);
+}
color_t *color_set(color_t *c, COORD_T r, COORD_T g, COORD_T b)
{
c->r = r;
diff --git a/pgm.h b/pgm.h
index 91c756b..af336db 100644
--- a/pgm.h
+++ b/pgm.h
@@ -11,6 +11,7 @@ typedef struct {
void color_clamp(color_t *c);
+void color_gamma_correct(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 29ec1cf..caca5fa 100644
--- a/ray.c
+++ b/ray.c
@@ -9,6 +9,8 @@
#define PI 3.14159265359
+int path_trace_recur(space_t *s, color_t *dest, ray_t *ray, unsigned hop, COORD_T scale, void *seed);
+
int ray_trace_recur(space_t *s, color_t *dest, ray_t *ray, unsigned hop, COORD_T scale, void *seed);
// https://en.wikipedia.org/wiki/Line%E2%80%93sphere_intersection
@@ -189,103 +191,10 @@ static void contribution_from_pointlight(space_t *s, color_t *dest, object_t *o,
reflected_at(o, dest, &light->color, i, point, &l, V, N);
}
-// Many of these can maybe be put in a context struct
-static void contribution_from_arealight(space_t *s, color_t *dest, object_t *o, light_t *light, vector_t *point, vector_t *V, vector_t *N, void *seed)
-{
- // This only works with spheres
- assert(light->area->type == TYPE_SPHERE);
-
- // Color to collect temporary results in
- color_t c;
- color_set(&c, 0, 0, 0);
-
- ray_t ray;
- ray.start = point;
-
- // Calculate vector from light to point
- vector_t l;
- vector_sub(&l, point, &light->area->sph.center);
- vector_norm(&l);
-
- // Initialize the transformation stuff
- csystem_t cs;
- csystem_init(&cs, &l);
-
- // Do the same monte carlo as with environment but the starting point is the center of the circle.
- // And the result is a point on the circle
- for (int i = 0; i < s->gfx->arealight_samples; i++) {
- // Do the monte carlo random distribution thing from the article
- COORD_T r1 = ray_rand(seed);
-
- // Random direction on halv sphere pointing towards point
- vector_t randpoint;
- csystem_hemisphere_random(&cs, r1, ray_rand(seed), &randpoint);
- csystem_calc_real(&cs, &randpoint, &randpoint);
-
- // Shift it up to center of circle
- vector_add(&randpoint, &randpoint, &light->area->sph.center);
-
- // Cast a ray towards it, reuse randpoint as direction
- vector_sub(&randpoint, &randpoint, point);
- COORD_T dist = vector_len(&randpoint);
-
- vector_t dir;
- vector_scale_inv(&dir, &randpoint, dist);
-
- ray.direction = &dir;
-
- object_t *obs = ray_cast(s, &ray, NULL, true, dist - ZERO_APROX);
- if (obs) {
- // We hit something skip it.
- continue;
- }
-
- // Add the light contribution
- COORD_T i = light->radiance / ( dist * dist);
- reflected_at(o, &c, &light->color, i, point, &randpoint, V, N);
-
- }
-
- // Device by pdf
- color_scale(&c, &c, ((COORD_T) 1 / s->gfx->arealight_samples) * (2 * PI));
-
- color_add(dest, dest, &c);
-
-}
-
-static void direct_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vector_t *eye, vector_t *point, void *seed)
-{
- // And vector towards viewer
- vector_t V;
- vector_sub(&V, eye, point);
-
- // Normalice it
- vector_norm(&V);
-
- // Loop lights
- light_t *light = s->lights;
- while (light) {
- // Calculate contribution depending on the light type
- switch (light->type) {
- case TYPE_L_POINT:
- contribution_from_pointlight(s, dest, o, light, point, &V, N);
- break;
- case TYPE_L_AREA:
- contribution_from_arealight(s, dest, o, light, point, &V, N, seed);
- break;
- }
-
- light = light->next;
- }
-}
-
// Calculates the global illumination. Pretty slow
// https://www.scratchapixel.com/lessons/3d-basic-rendering/global-illumination-path-tracing/global-illumination-path-tracing-practical-implementation
static void env_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vector_t *point, void *seed)
{
- if (s->gfx->envlight_samples == 0) {
- return;
- }
csystem_t cs;
csystem_init(&cs, N);
@@ -297,7 +206,7 @@ static void env_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vecto
color_t acc;
color_set(&acc, 0, 0, 0);
- for (unsigned i = 0; i < s->gfx->envlight_samples; i++) {
+ for (unsigned i = 0; i < 0; i++) {
COORD_T r1 = ray_rand(seed);
// Calculate the random direction vector
@@ -323,7 +232,7 @@ static void env_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vecto
}
// Devide by number of samples and pdf
- color_scale(&acc, &acc, ((COORD_T) 1/ s->gfx->envlight_samples) * (2 * PI));
+ color_scale(&acc, &acc, ((COORD_T) 1/ 0) * (2 * PI));
// Add to dest
color_add(dest, dest, &acc);
@@ -331,11 +240,8 @@ static void env_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vecto
}
// https://www.scratchapixel.com/lessons/3d-basic-rendering/global-illumination-path-tracing/global-illumination-path-tracing-practical-implementation
-static void global_light(space_t *s, color_t *dest, object_t *o, vector_t *N, vector_t *point, unsigned hop, void *seed)
+static void light_in(space_t *s, color_t *dest, object_t *o, vector_t *N, vector_t *eye, vector_t *point, unsigned hop, void *seed)
{
- if (s->gfx->globallight_samples == 0) {
- return;
- }
// Init hemisphere translation
csystem_t cs;
@@ -345,55 +251,31 @@ static void global_light(space_t *s, color_t *dest, object_t *o, vector_t *N, ve
ray_t r;
r.start = point;
- // Value for accumilating colors
- color_t acc;
- color_set(&acc, 0, 0, 0);
+ // Calculate the random direction vector
+ vector_t randdir;
+ csystem_hemisphere_random(&cs, ray_rand(seed), ray_rand(seed), &randdir);
- // Samples is lowered for every hop
- unsigned samples;
- if (hop < s->gfx->gl_opt_depth) {
- samples = s->gfx->globallight_samples / (hop + 1);
- } else {
- samples = s->gfx->globallight_samples / (s->gfx->gl_opt_depth + 1);
- }
+ // Convert to world cordinates using the calculated N vectors.
+ csystem_calc_real(&cs, &randdir, &randdir);
- for (unsigned i = 0; i < samples; i++) {
- COORD_T r1 = ray_rand(seed);
-
- // Calculate the random direction vector
- vector_t randdir;
- csystem_hemisphere_random(&cs, r1, ray_rand(seed), &randdir);
+ r.direction = &randdir;
+ COORD_T cl = 2 * vector_dot(&randdir, N) * o->m->defuse;
- // Convert to world cordinates using the calculated N vectors.
- csystem_calc_real(&cs, &randdir, &randdir);
+ vector_t V;
+ vector_sub(&V, eye, point);
- // Check the direction for obstacles
- r.direction = &randdir;
- COORD_T cl = vector_dot(&randdir, N);
-
- // Only recurse if neccesary
- if (cl > 0.01) {
- // Cast ray in direction if we have more hops
- color_t tmp;
- color_set(&tmp, 0, 0, 0);
- if (hop < s->gfx->depth) {
- ray_trace_recur(s, &tmp, &r, hop+1, r1, seed);
- }
-
- // Calculate Deffuse light
- color_scale(&tmp, &tmp, cl * o->m->defuse);
- color_add(&acc, &tmp, &acc);
+ path_trace_recur(s, dest, &r, hop+1, cl, seed);
+
+ light_t *light = s->lights;
+ while (light) {
+ if (light->type) {
+ contribution_from_pointlight(s, dest, o, light, point, &V, N);
+ light = light->next;
}
}
-
- // Devide by number of samples and pdf
- color_scale(&acc, &acc, ((COORD_T) 1/ samples) * (2 * PI));
-
- // Add to dest
- color_add(dest, dest, &acc);
}
-int ray_trace_recur(space_t *s, color_t *dest, ray_t *ray, unsigned hop, COORD_T scale, void *seed)
+int path_trace_recur(space_t *s, color_t *dest, ray_t *ray, unsigned hop, COORD_T scale, void *seed)
{
COORD_T dist;
@@ -415,123 +297,40 @@ 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
+ // Check if emissive
if (o->m->emissive > ZERO_APROX) {
color_set(&c, o->m->emissive, o->m->emissive, o->m->emissive);
goto exit;
}
- // 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
- direct_light(s, &c, o, &N, ray->start, r.start, seed);
- global_light(s, &c, o, &N, r.start, hop, seed);
- }
-
- // Calculate environmental light
- if (s->env_enabled) {
- env_light(s, &c, o, &N, r.start, seed);
- }
-
-
- // Calculate reflection vector
- if (hop < 10 && o->m->reflective > ZERO_APROX) {
- vector_scale(r.direction, &N, 2 * vector_dot(ray->direction, &N));
- vector_sub(r.direction, ray->direction, r.direction);
-
- ray_trace_recur(s, &c, &r, hop+1, o->m->reflective, seed);
- }
-
-
- // Scale by the objects own color.
- color_scale_vector(&c, &c, &o->m->color);
-
-exit:
- // Add it to the result
- color_scale(&c, &c, scale);
- color_add(dest, dest, &c);
-
- return 0;
-}
-
-int path_trace_recur(space_t *s, color_t *dest, ray_t *ray, unsigned hop, COORD_T scale, void *seed)
-{
- COORD_T dist;
-
- object_t *o = ray_cast(s, ray, &dist, false, 0);
- if (!o) {
+ if (hop >= s->gfx->depth) {
return 1;
- }
-
- color_t c;
- color_set(&c, 0, 0, 0);
-
- vector_t rdir, rstart;
- ray_t r = {.start = &rstart, .direction = &rdir};
-
- vector_scale(r.start, ray->direction, dist);
- vector_add(r.start, r.start, ray->start);
-
- // Calculate normal vector
- vector_t N;
- obj_norm_at(o, &N, r.start, ray->direction);
+ }
- // Check if emissive
- if (o->m->emissive > ZERO_APROX) {
- printf("Emisive\n");
- color_set(&c, o->m->emissive, o->m->emissive, o->m->emissive);
- goto exit;
+ // Check if we should calculate light
+ if (o->m->defuse + o->m->specular > ZERO_APROX) {
+ light_in(s, &c, o, &N, ray->start, r.start, hop, seed);
}
if (o->m->reflective > ZERO_APROX) {
- printf("reflective\n");
vector_scale(r.direction, &N, 2 * vector_dot(ray->direction, &N));
vector_sub(r.direction, ray->direction, r.direction);
path_trace_recur(s, &c, &r, hop+1, o->m->reflective, seed);
- goto exit;
- }
-
- printf("random\n");
- // Init hemisphere translation
- csystem_t cs;
- csystem_init(&cs, &N);
-
- COORD_T r1 = ray_rand(seed);
- // Calculate the random direction vector
- vector_t randdir;
- csystem_hemisphere_random(&cs, r1, ray_rand(seed), &randdir);
-
- // Convert to world cordinates using the calculated N vectors.
- csystem_calc_real(&cs, &randdir, &randdir);
-
- // Probability of the raydirection
- COORD_T p = 1.0/(PI * 2);
-
- // Calculate the defuse reflection
- r.direction = &randdir;
- COORD_T cl = vector_dot(&randdir, &N) / p;
-
- // Cast ray in direction if we have more hops
- if (hop < s->gfx->depth) {
- path_trace_recur(s, &c, &r, hop+1, r1, seed);
}
// Scale by own color
color_scale_vector(&c, &c, &o->m->color);
- // Calculate Deffuse light
- color_scale(&c, &c, cl * o->m->defuse);
-
exit:
-
color_scale(&c, &c, scale);
color_add(dest, &c, dest);
+ //printf("Adding color "); pgm_write_pixel(stdout, &c);
return 0;
}
-void ray_trace(space_t *s, unsigned int x, unsigned int y, color_t *c, void *seed)
+void path_trace(space_t *s, unsigned int x, unsigned int y, color_t *c, void *seed)
{
// Init return color. Will be accumilated with all the detected light.
color_set(c, 0, 0, 0);
@@ -544,8 +343,7 @@ void ray_trace(space_t *s, unsigned int x, unsigned int y, color_t *c, void *see
r.direction = vector_set(&dir, 0, 0, 0);
// Multiple samples for antialias
- // TODO better distribution of antialias probes
- for (unsigned i = 0; i < s->gfx->antialias_samples; i++) {
+ for (unsigned i = 0; i < s->gfx->samples; i++) {
color_t ctmp;
color_set(&ctmp, 0, 0, 0);
@@ -556,23 +354,22 @@ void ray_trace(space_t *s, unsigned int x, unsigned int y, color_t *c, void *see
viewpoint_ray(&s->view, r.direction, x + r1, y + r2);
// Run the recursive ray trace
+ //printf("New ray x: %f, y: %f\n", x + r1, y + r2);
if (path_trace_recur(s, &ctmp, &r, 0, 1, seed)) {
- printf("Hit nothing");
// Hit nothing add back
color_add(&ctmp, &ctmp, &s->back);
}
// Color_add will not go above 1. In this case we don't want that.
c->r += ctmp.r; c->g += ctmp.g; c->b += ctmp.b;
- printf("i: %d ", i);
- vector_print(c);
+ //printf("Total r: %f, g: %f, b: %f\n", c->r, c->g, c->b);
}
// Take the median
- if (s->gfx->antialias_samples > 1) {
+ if (s->gfx->samples > 1) {
// Same as deviding by samples
- color_scale(c, c, 1.0/ (COORD_T) s->gfx->antialias_samples);
+ color_scale(c, c, 1.0/ (COORD_T) s->gfx->samples);
}
// Add ambient
diff --git a/ray.h b/ray.h
index 124311a..35dcd6b 100644
--- a/ray.h
+++ b/ray.h
@@ -20,6 +20,6 @@ COORD_T ray_intersect_sphere(sphere_t *s, ray_t *ray, bool skip_dist);
COORD_T ray_intersect_plane(plane_t *p, ray_t *ray, bool skip_dist);
object_t *ray_cast(space_t *s, ray_t *r, COORD_T *dist_ret, bool chk, COORD_T chk_dist);
-void ray_trace(space_t *s, unsigned int x, unsigned int y, color_t *c, void *seed);
+void path_trace(space_t *s, unsigned int x, unsigned int y, color_t *c, void *seed);
#endif
diff --git a/scene.h b/scene.h
index e7ee95f..7cd388e 100644
--- a/scene.h
+++ b/scene.h
@@ -14,7 +14,10 @@
#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))
+#define CONTAINER_SIZE(objs, mats, ligs) (sizeof(container_t) + \
+ objs * sizeof(object_t) + \
+ mats * sizeof(material_t) + \
+ ligs * sizeof(light_t))
typedef struct {
vector_t center;
@@ -69,18 +72,11 @@ typedef struct light_s{
struct light_s *next;
} light_t;
-light_t l;
-
// Graphics settings
// Should actually sit in ray.c
typedef struct {
- unsigned arealight_samples;
- unsigned antialias_samples;
- unsigned envlight_samples;
- unsigned globallight_samples;
-
+ unsigned samples;
unsigned depth;
- unsigned gl_opt_depth;
} settings_t;
typedef struct {