diff options
Diffstat (limited to 'src/modules/ray/ray_render.c')
-rw-r--r-- | src/modules/ray/ray_render.c | 251 |
1 files changed, 0 insertions, 251 deletions
diff --git a/src/modules/ray/ray_render.c b/src/modules/ray/ray_render.c deleted file mode 100644 index 8b930f6..0000000 --- a/src/modules/ray/ray_render.c +++ /dev/null @@ -1,251 +0,0 @@ -#include <stdlib.h> -#include <math.h> - -#include "fb.h" - -#include "ray_camera.h" -#include "ray_color.h" -#include "ray_render_object.h" -#include "ray_ray.h" -#include "ray_scene.h" - -#define MAX_RECURSION_DEPTH 4 -#define MIN_RELEVANCE 0.05f - -typedef struct ray_render_t { - const ray_scene_t *scene; /* scene being rendered */ - const ray_camera_t *camera; /* camera rendering the scene */ - - ray_color_t ambient_light; - ray_camera_frame_t frame; - - ray_render_object_t objects[]; -} ray_render_t; - -/* Determine if the ray is obstructed by an object within the supplied distance, for shadows */ -static inline int ray_is_obstructed(ray_render_t *render, unsigned depth, ray_ray_t *ray, float distance) -{ - ray_render_object_t *object; - - for (object = render->objects; object->type; object++) { - float ood; - - if (ray_render_object_intersects_ray(object, depth, ray, &ood) && - ood < distance) { - return 1; - } - } - - return 0; -} - - -/* shadow test */ -static inline int point_is_shadowed(ray_render_t *render, unsigned depth, ray_3f_t *light_direction, float distance, ray_3f_t *point) -{ - ray_ray_t shadow_ray; - - shadow_ray.direction = *light_direction; - shadow_ray.origin = *point; - - if (ray_is_obstructed(render, depth + 1, &shadow_ray, distance)) - return 1; - - return 0; -} - - -/* a faster powf() that's good enough for our purposes. - * XXX: note there's a faster technique which exploits the IEEE floating point format: - * https://github.com/ekmett/approximate/blob/master/cbits/fast.c#L185 - */ -static inline float approx_powf(float x, float y) -{ - return expf(y * logf(x)); -} - - -/* Determine the color @ distance on ray on object viewed from origin */ -static inline ray_color_t shade_intersection(ray_render_t *render, ray_render_object_t *object, ray_ray_t *ray, ray_3f_t *intersection, ray_3f_t *normal, unsigned depth, float *res_reflectivity) -{ - ray_surface_t surface = ray_render_object_surface(object, intersection); - ray_color_t color = ray_3f_mult(&surface.color, &render->ambient_light); - ray_object_t *light; - - /* visit lights for shadows and illumination */ - for (light = render->scene->lights; light->type; light++) { - ray_3f_t lvec = ray_3f_sub(&light->light.emitter.point.center, intersection); - float ldist = ray_3f_length(&lvec); - float lvec_normal_dot; - - lvec = ray_3f_mult_scalar(&lvec, (1.0f / ldist)); /* normalize lvec */ -#if 1 - if (point_is_shadowed(render, depth, &lvec, ldist, intersection)) - continue; -#endif - lvec_normal_dot = ray_3f_dot(normal, &lvec); - - if (lvec_normal_dot > 0) { -#if 1 - float rvec_lvec_dot = ray_3f_dot(&ray->direction, &lvec); - float intensity = light->light.brightness * (1.0 / (ldist * ldist)); - ray_color_t diffuse; - - diffuse = ray_3f_mult_scalar(&surface.color, lvec_normal_dot); - diffuse = ray_3f_mult_scalar(&diffuse, surface.diffuse); - color = ray_3f_add(&color, &diffuse); - - if (rvec_lvec_dot > 0) { - ray_color_t specular; - - /* FIXME: assumes light is a point for its color */ - specular = ray_3f_mult_scalar(&light->light.emitter.point.surface.color, approx_powf(rvec_lvec_dot, surface.highlight_exponent)); - specular = ray_3f_mult_scalar(&specular, surface.specular); - color = ray_3f_add(&color, &specular); - } - - color = ray_3f_mult_scalar(&color, intensity); -#else - ray_color_t diffuse; - - diffuse = ray_3f_mult_scalar(&surface.color, lvec_normal_dot); - color = ray_3f_add(&color, &diffuse); -#endif - } - } - - /* for now just treat specular as the reflectivity */ - *res_reflectivity = surface.specular; - - return color; -} - - -static inline ray_render_object_t * find_nearest_intersection(ray_render_t *render, ray_render_object_t *reflector, ray_ray_t *ray, unsigned depth, float *res_distance) -{ - ray_render_object_t *nearest_object = NULL; - float nearest_object_distance = INFINITY; - ray_render_object_t *object; - - for (object = render->objects; object->type; object++) { - float distance; - - /* Don't bother checking if a reflected ray intersects the object reflecting it, - * reflector = NULL for primary rays, which will never compare as true here. */ - if (object == reflector) - continue; - - /* Does this ray intersect object? */ - if (ray_render_object_intersects_ray(object, depth, ray, &distance)) { - /* Is it the nearest intersection? */ - if (distance < nearest_object_distance) { - nearest_object = object; - nearest_object_distance = distance; - } - } - } - - if (nearest_object) - *res_distance = nearest_object_distance; - - return nearest_object; -} - - -static inline ray_color_t trace_ray(ray_render_t *render, ray_ray_t *primary_ray) -{ - ray_color_t color = { .x = 0.0f, .y = 0.0f, .z = 0.0f }; - ray_3f_t intersection, normal; - ray_render_object_t *reflector = NULL; - float relevance = 1.0f, reflectivity; - unsigned depth = 0; - ray_ray_t reflected_ray, *ray = primary_ray; - - do { - ray_render_object_t *nearest_object; - float nearest_distance; - - if (reflector) { - float dot = ray_3f_dot(&ray->direction, &normal); - ray_3f_t new_direction = ray_3f_mult_scalar(&normal, dot * 2.0f); - - new_direction = ray_3f_sub(&ray->direction, &new_direction); - - reflected_ray.origin = intersection; - reflected_ray.direction = new_direction; - - ray = &reflected_ray; - } - - nearest_object = find_nearest_intersection(render, reflector, ray, depth, &nearest_distance); - if (nearest_object) { - ray_3f_t more_color; - ray_3f_t rvec; - - rvec = ray_3f_mult_scalar(&ray->direction, nearest_distance); - intersection = ray_3f_add(&ray->origin, &rvec); - normal = ray_render_object_normal(nearest_object, &intersection); - - more_color = shade_intersection(render, nearest_object, ray, &intersection, &normal, depth, &reflectivity); - more_color = ray_3f_mult_scalar(&more_color, relevance); - color = ray_3f_add(&color, &more_color); - } - - reflector = nearest_object; - } while (reflector && (++depth < MAX_RECURSION_DEPTH) && (relevance *= reflectivity) >= MIN_RELEVANCE); - - return color; -} - - -void ray_render_trace_fragment(ray_render_t *render, fb_fragment_t *fb_fragment) -{ - uint32_t *buf = fb_fragment->buf; - ray_camera_fragment_t fragment; - ray_ray_t ray; - - ray_camera_fragment_begin(&render->frame, fb_fragment, &ray, &fragment); - do { - do { - *buf = ray_color_to_uint32_rgb(trace_ray(render, &ray)); - buf++; - } while (ray_camera_fragment_x_step(&fragment)); - - buf = ((void *)buf) + fb_fragment->stride; - } while (ray_camera_fragment_y_step(&fragment)); -} - - -/* prepare the scene for rendering with camera, must be called whenever anything in the scene+camera pair has been changed. */ -/* this is basically a time for the raytracer to precompute whatever it can which otherwise ends up occurring per-ray */ -/* the camera is included so primary rays which all have a common origin may be optimized for */ -ray_render_t * ray_render_new(const ray_scene_t *scene, const ray_camera_t *camera) -{ - ray_render_t *render; - ray_object_t *object; - unsigned i; - - for (i = 0, object = scene->objects; object->type; object++) - i++; - - render = malloc(sizeof(ray_render_t) + i * sizeof(ray_render_object_t)); - if (!render) - return NULL; - - render->scene = scene; - render->camera = camera; - - render->ambient_light = ray_3f_mult_scalar(&scene->ambient_color, scene->ambient_brightness); - ray_camera_frame_prepare(camera, &render->frame); - - for (i = 0, object = scene->objects; object->type; object++) - render->objects[i++] = ray_render_object_prepare(object, camera); - - return render; -} - - -void ray_render_free(ray_render_t *render) -{ - free(render); -} |