diff options
author | Franklin Wei <me@fwei.tk> | 2017-04-03 22:03:53 -0400 |
---|---|---|
committer | Franklin Wei <me@fwei.tk> | 2017-04-03 22:03:53 -0400 |
commit | 7cc4ae7bf8fc1283d4f82e6a8beb5c93beb76d7f (patch) | |
tree | 356a61e80c5d4bff9c02ed953fdddac1b1f892c9 | |
parent | f1aebd377a2f1ca3aebd3cec47bb9d00f284d381 (diff) | |
download | raytrace-7cc4ae7bf8fc1283d4f82e6a8beb5c93beb76d7f.zip raytrace-7cc4ae7bf8fc1283d4f82e6a8beb5c93beb76d7f.tar.gz raytrace-7cc4ae7bf8fc1283d4f82e6a8beb5c93beb76d7f.tar.bz2 raytrace-7cc4ae7bf8fc1283d4f82e6a8beb5c93beb76d7f.tar.xz |
fancy stuff
-rw-r--r-- | main.c | 205 | ||||
-rw-r--r-- | vector.c | 15 |
2 files changed, 160 insertions, 60 deletions
@@ -15,7 +15,7 @@ #define SQR(a) ((a)*(a)) #define SIGN(x) ((x)<0?-1:1) -#define MAX_BOUNCES 10 +#define MAX_BOUNCES 2 #define MOVE_FACTOR .1 @@ -24,10 +24,10 @@ struct rgb_t { unsigned char r, g, b; }; struct object_t { - enum { SPHERE, TRI } type; + enum { SPHERE, PLANE } type; union { struct { vector center; scalar radius; } sphere; - struct { vector points[3]; } tri; + struct { vector point, normal; } plane; }; struct rgb_t color; int specularity; /* 0-255 */ @@ -55,9 +55,10 @@ struct camera_t { /* { o, d } form a ray */ /* point of intersection is *t * d units away */ -bool object_intersects(struct object_t *obj, vector o, vector d, scalar *t) +inline bool object_intersects(const struct object_t *obj, vector o, vector d, scalar *t) { assert(o.type == RECT); + vect_to_rect(&d); assert(d.type == RECT); switch(obj->type) { @@ -67,7 +68,9 @@ bool object_intersects(struct object_t *obj, vector o, vector d, scalar *t) 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); + 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) { @@ -95,6 +98,17 @@ bool object_intersects(struct object_t *obj, vector o, vector d, scalar *t) *t = MIN(t1, t2); return true; } + case PLANE: + { + scalar denom = vect_dot(obj->plane.normal, d); + if(!denom) + return false; + scalar t1 = vect_dot(obj->plane.normal, vect_sub(obj->plane.point, o)) / denom; + if(t1 <= 0) + return false; + *t = t1; + return true; + } } } @@ -104,14 +118,15 @@ vector normal_at_point(vector pt, const struct object_t *obj) switch(obj->type) { case SPHERE: - { normal = vect_sub(pt, obj->sphere.center); break; - } + case PLANE: + normal = obj->plane.normal; + break; default: assert(false); } - return vect_normalize(normal); + return normal; } /* return the direction of the reflected ray */ @@ -158,21 +173,30 @@ static const struct object_t *scene_intersections(const struct scene_t *scene, return obj; } +#define ABS(x) ((x)<0?-(x):(x)) + struct rgb_t trace_ray(const struct scene_t *scene, vector orig, vector d, int max_iters, const struct object_t *avoid) { - struct rgb_t primary = scene->bg; + vector copy = d; + vect_to_sph(©); + + struct rgb_t primary = blend((struct rgb_t) {0xff, 0xff, 0xff}, (struct rgb_t) { 0x00, 0x00, 0xff }, + ABS(copy.sph.elevation * 2 / M_PI * 255)); scalar hit_dist; /* distance from camera in terms of d */ const struct object_t *hit_obj = scene_intersections(scene, orig, d, &hit_dist, avoid); struct rgb_t reflected = {0, 0, 0}; int specular = 255; + + /* by default */ + scalar shade_total = 1.0; + if(hit_obj) { //printf("pow!\n"); primary = hit_obj->color; /* shade */ - scalar shade_total = 0; vector pt = d; pt = vect_mul(pt, hit_dist); @@ -180,11 +204,12 @@ struct rgb_t trace_ray(const struct scene_t *scene, vector orig, vector d, int m vector normal = normal_at_point(pt, hit_obj); + shade_total = 0; + for(int i = 0; i < scene->n_lights; ++i) { /* get vector to light */ - vector light_dir = scene->lights[i].position; - light_dir = vect_sub(light_dir, pt); + vector light_dir = vect_sub(scene->lights[i].position, pt); scalar light_dist = vect_abs(light_dir); @@ -205,11 +230,6 @@ struct rgb_t trace_ray(const struct scene_t *scene, vector orig, vector d, int m if(shade_total > 1) shade_total = 1; - 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); - specular = 255 - hit_obj->specularity; /* reflections */ if(specular != 255 && max_iters > 0) @@ -219,16 +239,27 @@ struct rgb_t trace_ray(const struct scene_t *scene, vector orig, vector d, int m } } - return blend(primary, reflected, specular); + struct rgb_t mixed = blend(primary, reflected, specular); + + scalar diffuse = 1 - scene->ambient; + mixed.r *= (scene->ambient + diffuse * shade_total); + mixed.g *= (scene->ambient + diffuse * shade_total); + mixed.b *= (scene->ambient + diffuse * shade_total); + + return mixed; } -unsigned char *render_scene(int w, int h, const struct scene_t *scene, - const struct camera_t *cam) +void render_lines(unsigned char *fb, int w, int h, + const struct scene_t *scene, + const struct camera_t *cam, + int start, int end) { - unsigned char *fb = malloc(w * h * 3); scalar scale_x = cam->fov_x / w, scale_y = cam->fov_y / h; - for(int y = 0; y < h; ++y) + vector direction = cam->direction; + vect_to_sph(&direction); + + for(int y = start; y < end; ++y) { for(int x = 0; x < w; ++x) { @@ -240,9 +271,8 @@ unsigned char *render_scene(int w, int h, const struct scene_t *scene, scalar rot_x = (x - w / 2) * scale_x, rot_y = (y - h / 2) * scale_y; /* rotate the offset vector */ - vector d = cam->direction; - vect_to_sph(&d); + vector d = direction; d.sph.elevation -= rot_y; d.sph.azimuth += rot_x; @@ -254,52 +284,92 @@ unsigned char *render_scene(int w, int h, const struct scene_t *scene, struct rgb_t color = trace_ray(scene, cam->origin, d, MAX_BOUNCES, NULL); - fb[y * w * 3 + 3 * x] = color.r; + fb[y * w * 3 + 3 * x] = color.b; fb[y * w * 3 + 3 * x + 1] = color.g; - fb[y * w * 3 + 3 * x + 2] = color.b; + fb[y * w * 3 + 3 * x + 2] = color.r; } } - return fb; } -int main() +struct renderinfo_t { + unsigned char *fb; + int w, h; + const struct scene_t *scene; + const struct camera_t *cam; + int start, end; + +}; + +void *thread(void *ptr) { - vector test = (vector) { RECT, { 0, 1, 1 } }; - vect_to_sph(&test); - //printf("1, 0, 0, is r = %f, elev = %f, azi = %f", test.sph.r, test.sph.elevation, test.sph.azimuth); - //return 0; + struct renderinfo_t *info = ptr; + render_lines(info->fb, info->w, info->h, info->scene, info->cam, info->start, info->end); + return NULL; +} + +void render_scene(unsigned char *fb, int w, int h, + const struct scene_t *scene, + const struct camera_t *cam, int n_threads) +{ + struct renderinfo_t *info = malloc(sizeof(struct renderinfo_t) * n_threads); + pthread_t *threads = malloc(sizeof(pthread_t) * n_threads); + for(int i = 0; i < n_threads; ++i) + { + info[i].fb = fb; + info[i].w = w; + info[i].h = h; + info[i].scene = scene; + info[i].cam = cam; + info[i].start = h * i / n_threads; + info[i].end = h * (i + 1) / n_threads; + pthread_create(threads + i, NULL, thread, info + i); + } + + for(int i = 0; i < n_threads; ++i) + pthread_join(threads[i], NULL); + free(info); +} + +int main() +{ struct scene_t scene; - scene.bg.r = 0xa0; - scene.bg.g = 0xa0; - scene.bg.b = 0xa0; + scene.bg.r = 0x87; + scene.bg.g = 0xce; + scene.bg.b = 0xeb; scene.ambient = .2; - struct object_t sph[3]; + struct object_t sph[4]; sph[0].type = SPHERE; - sph[0].sphere.center = (vector) { RECT, {0, 0, 1 } }; + sph[0].sphere.center = (vector) { RECT, {0, 1, 1 } }; sph[0].sphere.radius = 1; sph[0].color = (struct rgb_t){0, 0, 0xff}; - sph[0].specularity = 20; + sph[0].specularity = 40; sph[1].type = SPHERE; - sph[1].sphere.center = (vector) { RECT, {0, 0, -1 } }; + sph[1].sphere.center = (vector) { RECT, {0, 1, -1 } }; sph[1].sphere.radius = 1; - sph[1].color = (struct rgb_t){0, 0xe0, 0}; - sph[1].specularity = 0xef; + sph[1].color = (struct rgb_t){0, 0, 0xff}; + sph[1].specularity = 40; sph[2].type = SPHERE; - sph[2].sphere.center = (vector) { RECT, {0, 0, -3 } }; + sph[2].sphere.center = (vector) { RECT, {0, 1, -3 } }; sph[2].sphere.radius = 1; - sph[2].color = (struct rgb_t){0, 0xe0, 0}; - sph[2].specularity = 0x60; + sph[2].color = (struct rgb_t){0xff, 0xff, 0xff}; + sph[2].specularity = 0xf0; + + sph[3].type = PLANE; + sph[3].plane.point = (vector) { RECT, {0, 0, 100 } }; + sph[3].plane.normal = (vector) { RECT, {0, 1, 0 } }; + sph[3].color = (struct rgb_t) {0, 0xff, 0}; + sph[3].specularity = 0; struct light_t lights[1]; - lights[0].position = (vector) { RECT, {0, 10, -10} }; + lights[0].position = (vector) { RECT, {0, 10, 0} }; lights[0].intensity = 2; scene.objects = sph; - scene.n_objects = 3; + scene.n_objects = 4; scene.lights = lights; scene.n_lights = 1; @@ -309,8 +379,10 @@ int main() cam.fov_x = M_PI / 2; cam.fov_y = M_PI / 2 * HEIGHT / WIDTH; + unsigned char *fb = malloc(WIDTH * HEIGHT * 3); + #if 0 - unsigned char *fb = render_scene(WIDTH, HEIGHT, &scene, &cam); + render_scene(fb, WIDTH, HEIGHT, &scene, &cam, 2); FILE *f = fopen("test.ppm", "w"); fprintf(f, "P6\n%d %d\n%d\n", WIDTH, HEIGHT, 255); fwrite(fb, WIDTH * HEIGHT, 3, f); @@ -320,11 +392,12 @@ int main() #else SDL_Init(SDL_INIT_VIDEO); - SDL_Surface *screen = SDL_SetVideoMode(WIDTH, HEIGHT, 24, SDL_SWSURFACE); + SDL_Surface *screen = SDL_SetVideoMode(WIDTH, HEIGHT, 24, SDL_HWSURFACE | SDL_FULLSCREEN); SDL_EnableKeyRepeat(500, 50); while(1) { + lights[0].position.rect.z += .05; #ifdef MOUSELOOK /* mouse look */ int x, y; @@ -336,10 +409,9 @@ int main() cam.direction.sph.elevation += M_PI/30 * SIGN(y)*SQR((scalar)y / HEIGHT); #endif - unsigned char *fb = render_scene(WIDTH, HEIGHT, &scene, &cam); + render_scene(fb, WIDTH, HEIGHT, &scene, &cam, 2); memcpy(screen->pixels, fb, WIDTH * HEIGHT * 3); 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); while(SDL_PollEvent(&e)) @@ -347,22 +419,33 @@ int main() switch(e.type) { case SDL_QUIT: + free(fb); return 0; case SDL_KEYDOWN: switch(e.key.keysym.sym) { - case SDLK_LEFT: - cam.origin.rect.z += .1; - break; - case SDLK_RIGHT: - cam.origin.rect.z -= .1; - break; + case SDLK_ESCAPE: + free(fb); + SDL_Quit(); + return 0; case SDLK_UP: cam.origin.rect.y += .1; break; case SDLK_DOWN: cam.origin.rect.y -= .1; break; + case SDLK_a: + vect_to_sph(&cam.direction); + cam.direction.sph.azimuth += M_PI/2; + cam.origin = vect_sub(cam.origin, vect_mul(cam.direction, MOVE_FACTOR)); + cam.direction.sph.azimuth -= M_PI/2; + break; + case SDLK_d: + vect_to_sph(&cam.direction); + cam.direction.sph.azimuth -= M_PI/2; + cam.origin = vect_sub(cam.origin, vect_mul(cam.direction, MOVE_FACTOR)); + cam.direction.sph.azimuth += M_PI/2; + break; case SDLK_w: cam.origin = vect_add(cam.origin, vect_mul(cam.direction, MOVE_FACTOR)); break; @@ -377,13 +460,19 @@ int main() cam.fov_x -= M_PI/36; cam.fov_y = cam.fov_x * HEIGHT/WIDTH; break; - case SDLK_a: + case SDLK_SPACE: + cam.origin.rect.y += .1; + break; + case SDLK_LSHIFT: + cam.origin.rect.y -= .1; + break; + case SDLK_LEFT: { vect_to_sph(&cam.direction); cam.direction.sph.azimuth -= M_PI/180; break; } - case SDLK_d: + case SDLK_RIGHT: { vect_to_sph(&cam.direction); cam.direction.sph.azimuth += M_PI/180; @@ -109,6 +109,17 @@ scalar vect_dot(vector v1, vector v2) vector vect_normalize(vector v) { - scalar a = vect_abs(v); - return vect_mul(v, 1./a); + switch(v.type) + { + case RECT: + { + scalar a = vect_abs(v); + v = vect_mul(v, 1./a); + break; + } + case SPH: + v.sph.r = 1; + break; + } + return v; } |