summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <me@fwei.tk>2017-04-03 22:03:53 -0400
committerFranklin Wei <me@fwei.tk>2017-04-03 22:03:53 -0400
commit7cc4ae7bf8fc1283d4f82e6a8beb5c93beb76d7f (patch)
tree356a61e80c5d4bff9c02ed953fdddac1b1f892c9
parentf1aebd377a2f1ca3aebd3cec47bb9d00f284d381 (diff)
downloadraytrace-7cc4ae7bf8fc1283d4f82e6a8beb5c93beb76d7f.zip
raytrace-7cc4ae7bf8fc1283d4f82e6a8beb5c93beb76d7f.tar.gz
raytrace-7cc4ae7bf8fc1283d4f82e6a8beb5c93beb76d7f.tar.bz2
raytrace-7cc4ae7bf8fc1283d4f82e6a8beb5c93beb76d7f.tar.xz
fancy stuff
-rw-r--r--main.c205
-rw-r--r--vector.c15
2 files changed, 160 insertions, 60 deletions
diff --git a/main.c b/main.c
index 8fc10e3..b2f63ce 100644
--- a/main.c
+++ b/main.c
@@ -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(&copy);
+
+ 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;
diff --git a/vector.c b/vector.c
index 7c45f26..6a19cc9 100644
--- a/vector.c
+++ b/vector.c
@@ -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;
}