diff options
-rw-r--r-- | main.c | 46 | ||||
-rw-r--r-- | ray.c | 72 | ||||
-rw-r--r-- | ray.h | 2 | ||||
-rw-r--r-- | scene.h | 14 |
4 files changed, 107 insertions, 27 deletions
@@ -34,6 +34,21 @@ 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 = 8, + .depth = 16, +}; + +settings_t gfx_low = { + .arealight_samples = 16, + .envlight_samples = 16, + .antialias_samples = 2, + .globallight_samples = 5, + .depth = 1, +}; + // Implement random COORD_T ray_rand(void *seed) { @@ -51,17 +66,18 @@ int main() color_set(&s->ambient, 0.09, 0.09, 0.09); color_set(&s->back, 0.8, 0.8, 0.8); color_set(&s->env_color, 0.13, 0.13, 0.13); - s->env_samples = 0; + s->env_enabled = false; + s->gfx = &gfx_low; // Set viewpoint options - vector_set(&s->view.position, 0, 5, 5); + vector_set(&s->view.position, 0, 5, 4); vector_set(&s->view.target, 0, 5, 0); s->view.width = TESTW; s->view.height = TESTH; // Create materials material_t *m = add_material(cont); - vector_set(&m->color, 0.4, 0.4, 1); + vector_set(&m->color, 1, 1, 1); m->defuse = 1; m->specular = 0; m->shine = 80; @@ -74,8 +90,8 @@ int main() material_t *m2 = add_material(cont); vector_set(&m2->color, 1, 1, 1); m2->defuse = 0; - m2->specular = 0.5; - m2->shine = 50; + m2->specular = 0.1; + m2->shine = 1; m2->reflective = 1; material_t *mpl = add_material(cont); @@ -99,18 +115,18 @@ int main() object_t *o; o = add_object(cont, TYPE_SPHERE); - vector_set(&o->sph.center, -2, 7, 1); - o->sph.radius = 1.5; + vector_set(&o->sph.center, 2, 6, -1); + o->sph.radius = 1; o->m = m2; o = add_object(cont, TYPE_SPHERE); - vector_set(&o->sph.center, 0, 3, 1); - o->sph.radius = 1; + vector_set(&o->sph.center, 0, 4, -1); + o->sph.radius = 1.3; o->m = m; o = add_object(cont, TYPE_SPHERE); - vector_set(&o->sph.center, 2, 4, 1); - o->sph.radius = 1; + vector_set(&o->sph.center, -2, 5, -2); + o->sph.radius = 1.3; o->m = m; o = add_object(cont, TYPE_PLANE); @@ -145,15 +161,15 @@ int main() // Used for the light ball o = add_object(cont, TYPE_SPHERE); - vector_set(&o->sph.center, 2, 7, 0); - o->sph.radius = 1; + 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, 2, 8, -1); l->area = o; color_set(&l->color, 1, 1, 1); - l->radiance = 0.8; + l->radiance = 0.1; pgm_write_header(stdout, TESTW, TESTH); @@ -214,7 +230,7 @@ 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, 2, c, &seed); + ray_trace(&cont->space, TESTW - x, TESTH - y, c, &seed); color_clamp(c); } @@ -9,6 +9,8 @@ #define PI 3.14159265359 +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 // 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 @@ -212,7 +214,7 @@ static void contribution_from_arealight(space_t *s, color_t *dest, object_t *o, // 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 < 16; i++) { + 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); @@ -245,7 +247,7 @@ static void contribution_from_arealight(space_t *s, color_t *dest, object_t *o, } // Device by pdf - color_scale(&c, &c, ((COORD_T) 1 / 16) * (2 * PI)); + color_scale(&c, &c, ((COORD_T) 1 / s->gfx->arealight_samples) * (2 * PI)); color_add(dest, dest, &c); @@ -281,6 +283,9 @@ static void direct_light(space_t *s, color_t *dest, object_t *o, vector_t *N, ve // 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); @@ -292,7 +297,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->env_samples; i++) { + for (unsigned i = 0; i < s->gfx->envlight_samples; i++) { COORD_T r1 = ray_rand(seed); // Calculate the random direction vector @@ -318,13 +323,58 @@ 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->env_samples) * (2 * PI)); + color_scale(&acc, &acc, ((COORD_T) 1/ s->gfx->envlight_samples) * (2 * PI)); // Add to dest color_add(dest, dest, &acc); } +// 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) +{ + if (s->gfx->globallight_samples == 0) { + return; + } + + // Init hemisphere translation + csystem_t cs; + csystem_init(&cs, N); + + // Prepare ray + ray_t r; + r.start = point; + + // Value for accumilating colors + color_t acc; + color_set(&acc, 0, 0, 0); + + for (unsigned i = 0; i < s->gfx->globallight_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); + + // Convert to world cordinates using the calculated N vectors. + csystem_calc_real(&cs, &randdir, &randdir); + + // Check the direction for obstacles + r.direction = &randdir; + + // Cast ray in direction if we have more hops + if (hop < s->gfx->depth) { + ray_trace_recur(s, &acc, &r, hop+1, r1, seed); + } + } + + // Devide by number of samples and pdf + color_scale(&acc, &acc, ((COORD_T) 1/ s->gfx->globallight_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) { COORD_T dist; @@ -359,10 +409,12 @@ int ray_trace_recur(space_t *s, color_t *dest, ray_t *ray, unsigned hop, COORD_T } // Calculate environmental light - if (s->env_samples) { + if (s->env_enabled) { env_light(s, &c, o, &N, r.start, seed); } + global_light(s, &c, o, &N, r.start, hop, seed); + // Calculate reflection vector if (hop < 10 && o->m->reflective > ZERO_APROX) { vector_scale(r.direction, &N, 2 * vector_dot(ray->direction, &N)); @@ -383,7 +435,7 @@ exit: return 0; } -void ray_trace(space_t *s, unsigned int x, unsigned int y, unsigned samples, color_t *c, void *seed) +void ray_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); @@ -397,13 +449,13 @@ void ray_trace(space_t *s, unsigned int x, unsigned int y, unsigned samples, col // Multiple samples for antialias // TODO better distribution of antialias probes - for (int i = 0; i < samples; i++) { + for (int i = 0; i < s->gfx->antialias_samples; i++) { color_t ctmp; color_set(&ctmp, 0, 0, 0); //memset(&ctmp, 0, sizeof(color_t)); // Multiple samples inside same pixel - COORD_T tmp = (COORD_T) i/ (COORD_T) samples; + COORD_T tmp = (COORD_T) i/ (COORD_T) s->gfx->antialias_samples; viewpoint_ray(&s->view, r.direction, x + tmp, y + tmp); // Run the recursive ray trace @@ -415,9 +467,9 @@ void ray_trace(space_t *s, unsigned int x, unsigned int y, unsigned samples, col } // Take the median - if (samples > 1) { + if (s->gfx->antialias_samples > 1) { // Same as deviding by samples - color_scale(c, c, 1.0/ (COORD_T) samples); + color_scale(c, c, 1.0/ (COORD_T) s->gfx->antialias_samples); } // Add ambient @@ -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, unsigned samples, color_t *c, void *seed); +void ray_trace(space_t *s, unsigned int x, unsigned int y, color_t *c, void *seed); #endif @@ -71,6 +71,17 @@ typedef struct light_s{ 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 depth; +} settings_t; + typedef struct { viewpoint_t view; @@ -80,10 +91,11 @@ typedef struct { color_t ambient; color_t back; + settings_t *gfx; // Environment light // TODO make more general // Slows things down alot - unsigned env_samples; + bool env_enabled; color_t env_color; } space_t; |