diff options
| author | Franklin Wei <me@fwei.tk> | 2017-04-02 22:14:11 -0400 |
|---|---|---|
| committer | Franklin Wei <me@fwei.tk> | 2017-04-02 22:14:11 -0400 |
| commit | 929df060cbd9c0da04b8d9ce70dcea9879f42f4a (patch) | |
| tree | 8d39c317c3448d0a83f60427610a6c641af8fdb5 /main.c | |
| parent | d6e9b142e014c3d171932894dbb0db0410e91af7 (diff) | |
| download | raytrace-929df060cbd9c0da04b8d9ce70dcea9879f42f4a.zip raytrace-929df060cbd9c0da04b8d9ce70dcea9879f42f4a.tar.gz raytrace-929df060cbd9c0da04b8d9ce70dcea9879f42f4a.tar.bz2 raytrace-929df060cbd9c0da04b8d9ce70dcea9879f42f4a.tar.xz | |
lighting
Diffstat (limited to 'main.c')
| -rw-r--r-- | main.c | 187 |
1 files changed, 136 insertions, 51 deletions
@@ -3,11 +3,16 @@ #include <assert.h> #include <stdio.h> #include "vector.h" + #include <SDL/SDL.h> #include <SDL/SDL_video.h> #define WIDTH 320 #define HEIGHT 240 +#define MAX(a, b) ((a>b)?(a):(b)) +#define MIN(a, b) ((a<b)?(a):(b)) +#define SQR(a) ((a)*(a)) +#define MAX_BOUNCES 5 struct rgb_t { unsigned char r, g, b; }; @@ -32,6 +37,7 @@ struct scene_t { size_t n_objects; struct light_t *lights; size_t n_lights; + scalar ambient; }; struct camera_t { @@ -40,11 +46,6 @@ struct camera_t { scalar fov_x, fov_y; /* radians */ }; -#define MAX(a, b) ((a>b)?(a):(b)) -#define MIN(a, b) ((a<b)?(a):(b)) -#define SQR(a) ((a)*(a)) -#define MAX_BOUNCES 0 - /* { o, d } form a ray */ bool object_intersects(struct object_t *obj, const vector* o, const vector* d, scalar *t) { @@ -55,8 +56,10 @@ bool object_intersects(struct object_t *obj, const vector* o, const vector* d, s case SPHERE: { scalar a = SQR(d->rect.x) + SQR(d->rect.y) + SQR(d->rect.z), - b = 2 * (o->rect.x * d->rect.x + o->rect.y * d->rect.y + o->rect.z * d->rect.z), - c = SQR(o->rect.x) + SQR(o->rect.y) + SQR(o->rect.z) - SQR(obj->sphere.radius); + b = 2 * ((o->rect.x - obj->sphere.center.rect.x) * d->rect.x + + (o->rect.y - obj->sphere.center.rect.y) * d->rect.y + + (o->rect.z - obj->sphere.center.rect.z) * d->rect.z), + c = SQR(o->rect.x - obj->sphere.center.rect.x) + SQR(o->rect.y - obj->sphere.center.rect.y) + SQR(o->rect.z - obj->sphere.center.rect.z) - SQR(obj->sphere.radius); scalar disc = b*b - 4*a*c; if(disc < 0) { @@ -87,8 +90,7 @@ bool object_intersects(struct object_t *obj, const vector* o, const vector* d, s } } -/* return the direction of the reflected ray */ -vector reflect_ray(const vector *pt, const vector *d, const struct object_t *obj) +vector normal_at_point(const vector *pt, const struct object_t *obj) { vector normal; switch(obj->type) @@ -103,9 +105,15 @@ vector reflect_ray(const vector *pt, const vector *d, const struct object_t *obj default: assert(false); } + vect_normalize(&normal); + return normal; +} - scalar c = -2 * vect_dot(d, &normal); - vector reflected = normal; +/* return the direction of the reflected ray */ +vector reflect_ray(const vector *pt, const vector *d, const vector *normal, const struct object_t *obj) +{ + scalar c = -2 * vect_dot(d, normal); + vector reflected = *normal; vect_mul(&reflected, c); vect_add(&reflected, d); return reflected; @@ -114,50 +122,91 @@ vector reflect_ray(const vector *pt, const vector *d, const struct object_t *obj struct rgb_t blend(struct rgb_t a, struct rgb_t b, int alpha) { struct rgb_t ret; - ret.r = ((a.r * alpha) + (b.r * (255 - alpha))) >> 8; - ret.g = ((a.g * alpha) + (b.g * (255 - alpha))) >> 8; - ret.b = ((a.b * alpha) + (b.b * (255 - alpha))) >> 8; + unsigned long r1, g1, b1; + r1 = (((int)a.r * alpha) + ((int)b.r * (255 - alpha))) / 255; + g1 = (((int)a.g * alpha) + ((int)b.g * (255 - alpha))) / 255; + b1 = (((int)a.b * alpha) + ((int)b.b * (255 - alpha))) / 255; + ret = (struct rgb_t){r1, g1, b1}; return ret; } -struct rgb_t trace_ray(const struct scene_t *scene, const vector *orig, const vector *d, int max_iters) +static const struct object_t *scene_intersections(const struct scene_t *scene, + const vector *orig, const vector *d, scalar *closest) { - struct rgb_t primary = scene->bg; - scalar closest = -1; /* distance from camera in terms of d */ - const struct object_t *closest_obj = NULL; - + *closest = -1; + const struct object_t *obj = NULL; /* check intersections */ for(int i = 0; i < scene->n_objects; ++i) { scalar t; if(object_intersects(scene->objects + i, orig, d, &t)) { - if(closest < 0 || t < closest) + if(*closest < 0 || t < *closest) { - closest = t; - closest_obj = scene->objects + i; + *closest = t; + obj = scene->objects + i; } } } + return obj; +} + +struct rgb_t trace_ray(const struct scene_t *scene, const vector *orig, const vector *d, int max_iters) +{ + struct rgb_t primary = scene->bg; + scalar closest; /* distance from camera in terms of d */ + const struct object_t *closest_obj = scene_intersections(scene, orig, d, &closest); + struct rgb_t reflected = {0, 0, 0}; if(closest_obj) { //printf("pow!\n"); primary = closest_obj->color; - } - struct rgb_t reflected = {0, 0, 0}; - /* shade */ - if(closest_obj && closest_obj->specularity && max_iters > 0) - { + /* shade */ + scalar shade_total = 0; + vector pt = *d; vect_mul(&pt, closest); vect_add(&pt, orig); - vector ref = reflect_ray(&pt, d, closest_obj); - reflected = trace_ray(scene, &pt, &ref, max_iters - 1); + + vector normal = normal_at_point(&pt, closest_obj); + + for(int i = 0; i < scene->n_lights; ++i) + { + /* get vector to light */ + vector light_dir = scene->lights[i].position; + vect_sub(&light_dir, &pt); + + scalar light_dist = vect_abs(&light_dir); + + vect_normalize(&light_dir); + + /* see if light is occluded */ + scalar nearest; + if(scene_intersections(scene, &pt, &light_dir, &nearest)) + if(nearest < light_dist) + continue; + + scalar shade = vect_dot(&normal, &light_dir); + if(shade > 0) + shade_total += shade; + } + + scalar diffuse = 1 - scene->ambient; + primary.r *= (scene->ambient + diffuse * shade_total); + primary.g *= (scene->ambient + diffuse * shade_total); + primary.b *= (scene->ambient + diffuse * shade_total); + + /* reflections */ + if(closest_obj->specularity && max_iters > 0) + { + vector ref = reflect_ray(&pt, d, &normal, closest_obj); + reflected = trace_ray(scene, &pt, &ref, max_iters - 1); + } } - return blend(primary, reflected, closest_obj?(255 - closest_obj->specularity):255); + return blend(primary, reflected, closest_obj ? (255 - closest_obj->specularity) : 255); } unsigned char *render_scene(int w, int h, const struct scene_t *scene, @@ -208,26 +257,43 @@ int main() //return 0; struct scene_t scene; - scene.bg.r = 0xff; - scene.bg.g = 0x00; - scene.bg.b = 0xff; - - struct object_t sph; - sph.type = SPHERE; - sph.sphere.center = (vector) { RECT, {0, 0, 0 } }; - sph.sphere.radius = 1; - sph.color = (struct rgb_t){0, 0, 0xff}; - sph.specularity = 100; - - scene.objects = &sph; - scene.n_objects = 1; - scene.n_lights = 0; + scene.bg.r = 0xa0; + scene.bg.g = 0xa0; + scene.bg.b = 0xa0; + scene.ambient = .2; + + struct object_t sph[3]; + sph[0].type = SPHERE; + sph[0].sphere.center = (vector) { RECT, {0, 0, 1 } }; + sph[0].sphere.radius = 1; + sph[0].color = (struct rgb_t){0, 0, 0xff}; + sph[0].specularity = 0; + + sph[1].type = SPHERE; + sph[1].sphere.center = (vector) { RECT, {0, 0, -1 } }; + sph[1].sphere.radius = 1; + sph[1].color = (struct rgb_t){0, 0xe0, 0}; + sph[1].specularity = 0x60; + + sph[2].type = SPHERE; + sph[2].sphere.center = (vector) { RECT, {0, 0, -3 } }; + sph[2].sphere.radius = 1; + sph[2].color = (struct rgb_t){0, 0xe0, 0}; + sph[2].specularity = 0x60; + + struct light_t lights[1]; + lights[0].position = (vector) { RECT, {0, 10, -10} }; + + scene.objects = sph; + scene.n_objects = 3; + scene.lights = lights; + scene.n_lights = 1; struct camera_t cam; cam.origin = (vector){ RECT, {-5, 0, 0} }; cam.offset = (vector){ RECT, {0, 0, 1} }; cam.fov_x = M_PI / 2; - cam.fov_y = M_PI / 2; + cam.fov_y = M_PI / 2 * HEIGHT / WIDTH; #if 0 unsigned char *fb = render_scene(WIDTH, HEIGHT, &scene, &cam); @@ -240,7 +306,7 @@ int main() #else SDL_Init(SDL_INIT_VIDEO); SDL_Surface *screen = SDL_SetVideoMode(WIDTH, HEIGHT, 24, SDL_SWSURFACE); - SDL_EnableKeyRepeat(500, 100); + SDL_EnableKeyRepeat(500, 50); while(1) { @@ -249,7 +315,7 @@ int main() SDL_UpdateRect(screen, 0, 0, 0, 0); free(fb); SDL_Event e; - printf("camera at %f, %f, %f\n", cam.origin.rect.x, cam.origin.rect.y, cam.origin.rect.z); + //printf("camera at %f, %f, %f\n", cam.origin.rect.x, cam.origin.rect.y, cam.origin.rect.z); while(SDL_PollEvent(&e)) { switch(e.type) @@ -260,10 +326,10 @@ int main() switch(e.key.keysym.sym) { case SDLK_LEFT: - cam.origin.rect.x -= .1; + cam.origin.rect.z += .1; break; case SDLK_RIGHT: - cam.origin.rect.x += .1; + cam.origin.rect.z -= .1; break; case SDLK_UP: cam.origin.rect.y += .1; @@ -272,10 +338,29 @@ int main() cam.origin.rect.y -= .1; break; case SDLK_w: - cam.origin.rect.z += .1; + cam.origin.rect.x += .1; break; case SDLK_s: - cam.origin.rect.z -= .1; + cam.origin.rect.x -= .1; + break; + case SDLK_MINUS: + cam.fov_x += M_PI/36; + cam.fov_y = cam.fov_x * HEIGHT/WIDTH; + break; + case SDLK_EQUALS: + cam.fov_x -= M_PI/36; + cam.fov_y = cam.fov_x * HEIGHT/WIDTH; + break; + case SDLK_d: + vect_to_sph(&cam.offset); + cam.offset.sph.elevation -= M_PI/720; + printf("elevation is %f\n", cam.offset.sph.elevation); + vect_to_rect(&cam.offset); + break; + case SDLK_a: + vect_to_sph(&cam.offset); + cam.offset.sph.elevation += M_PI/720; + vect_to_rect(&cam.offset); break; } break; |