From dbba33fcd07c9e81e3ca9bc4f5e8185d364fb792 Mon Sep 17 00:00:00 2001 From: Julian T Date: Sat, 25 Jul 2020 00:09:53 +0200 Subject: Further experimentation with pathtracing Probably starting over in cpp --- ray.c | 273 +++++++++--------------------------------------------------------- 1 file changed, 35 insertions(+), 238 deletions(-) (limited to 'ray.c') 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 -- cgit v1.2.3