summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <me@fwei.tk>2017-04-03 18:02:38 -0400
committerFranklin Wei <me@fwei.tk>2017-04-03 18:02:38 -0400
commitf1aebd377a2f1ca3aebd3cec47bb9d00f284d381 (patch)
tree7222228c53930f61dd6d0847c96ff2dd3f779292
parent929df060cbd9c0da04b8d9ce70dcea9879f42f4a (diff)
downloadraytrace-f1aebd377a2f1ca3aebd3cec47bb9d00f284d381.zip
raytrace-f1aebd377a2f1ca3aebd3cec47bb9d00f284d381.tar.gz
raytrace-f1aebd377a2f1ca3aebd3cec47bb9d00f284d381.tar.bz2
raytrace-f1aebd377a2f1ca3aebd3cec47bb9d00f284d381.tar.xz
stuff
-rw-r--r--main.c169
-rw-r--r--vector.c78
-rw-r--r--vector.h15
3 files changed, 144 insertions, 118 deletions
diff --git a/main.c b/main.c
index e6b7f03..8fc10e3 100644
--- a/main.c
+++ b/main.c
@@ -9,10 +9,17 @@
#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
+#define SIGN(x) ((x)<0?-1:1)
+
+#define MAX_BOUNCES 10
+#define MOVE_FACTOR .1
+
+
+#define MOUSELOOK
struct rgb_t { unsigned char r, g, b; };
@@ -27,8 +34,8 @@ struct object_t {
};
struct light_t {
- struct rgb_t color;
vector position;
+ scalar intensity;
};
struct scene_t {
@@ -42,24 +49,25 @@ struct scene_t {
struct camera_t {
vector origin;
- vector offset; /* direction to center of camera */
+ vector direction; /* direction to center of camera */
scalar fov_x, fov_y; /* radians */
};
/* { o, d } form a ray */
-bool object_intersects(struct object_t *obj, const vector* o, const vector* d, scalar *t)
+/* point of intersection is *t * d units away */
+bool object_intersects(struct object_t *obj, vector o, vector d, scalar *t)
{
- assert(o->type == RECT);
- assert(d->type == RECT);
+ assert(o.type == RECT);
+ assert(d.type == RECT);
switch(obj->type)
{
case SPHERE:
{
- scalar a = SQR(d->rect.x) + SQR(d->rect.y) + SQR(d->rect.z),
- 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 a = SQR(d.rect.x) + SQR(d.rect.y) + SQR(d.rect.z),
+ 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)
{
@@ -80,9 +88,9 @@ bool object_intersects(struct object_t *obj, const vector* o, const vector* d, s
*t = MAX(t1, t2);
return true;
}
- vector prod = *d;
- vect_mul(&prod, t2);
- vect_add(&prod, o);
+ vector prod = d;
+ prod = vect_mul(prod, t2);
+ prod = vect_add(prod, o);
//printf("ray from (%f, %f, %f) intersects sphere at point %f, %f, %f (%f)\n", o->rect.x, o->rect.y, o->rect.z, prod.rect.x, prod.rect.y, prod.rect.z, vect_abs(&prod));
*t = MIN(t1, t2);
return true;
@@ -90,60 +98,59 @@ bool object_intersects(struct object_t *obj, const vector* o, const vector* d, s
}
}
-vector normal_at_point(const vector *pt, const struct object_t *obj)
+vector normal_at_point(vector pt, const struct object_t *obj)
{
vector normal;
switch(obj->type)
{
case SPHERE:
{
- vector p = *pt;
- vect_sub(&p, &obj->sphere.center);
- normal = p;
+ normal = vect_sub(pt, obj->sphere.center);
break;
}
default:
assert(false);
}
- vect_normalize(&normal);
- return normal;
+ return vect_normalize(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)
+vector reflect_ray(vector pt, vector d, 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);
+ vector reflected = normal;
+ reflected = vect_mul(reflected, c);
+ reflected = vect_add(reflected, d);
return reflected;
}
-struct rgb_t blend(struct rgb_t a, struct rgb_t b, int alpha)
+struct rgb_t blend(struct rgb_t a, struct rgb_t b, unsigned char alpha)
{
struct rgb_t ret;
- 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};
+ unsigned char r1, g1, b1;
+ ret.r = (((int)a.r * alpha) + ((int)b.r * (255 - alpha))) / 255;
+ ret.g = (((int)a.g * alpha) + ((int)b.g * (255 - alpha))) / 255;
+ ret.b = (((int)a.b * alpha) + ((int)b.b * (255 - alpha))) / 255;
return ret;
}
static const struct object_t *scene_intersections(const struct scene_t *scene,
- const vector *orig, const vector *d, scalar *closest)
+ vector orig, vector d, scalar *dist, const struct object_t *avoid)
{
- *closest = -1;
+ *dist = -1;
const struct object_t *obj = NULL;
/* check intersections */
for(int i = 0; i < scene->n_objects; ++i)
{
+ /* avoid intersections with the same object */
+ if(avoid == scene->objects + i)
+ continue;
scalar t;
if(object_intersects(scene->objects + i, orig, d, &t))
{
- if(*closest < 0 || t < *closest)
+ if(*dist < 0 || t < *dist)
{
- *closest = t;
+ *dist = t;
obj = scene->objects + i;
}
}
@@ -151,62 +158,68 @@ static const struct object_t *scene_intersections(const struct scene_t *scene,
return obj;
}
-struct rgb_t trace_ray(const struct scene_t *scene, const vector *orig, const vector *d, int max_iters)
+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;
- scalar closest; /* distance from camera in terms of d */
- const struct object_t *closest_obj = scene_intersections(scene, orig, d, &closest);
+ 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};
- if(closest_obj)
+ int specular = 255;
+ if(hit_obj)
{
//printf("pow!\n");
- primary = closest_obj->color;
+ primary = hit_obj->color;
/* shade */
scalar shade_total = 0;
- vector pt = *d;
- vect_mul(&pt, closest);
- vect_add(&pt, orig);
+ vector pt = d;
+ pt = vect_mul(pt, hit_dist);
+ pt = vect_add(pt, orig);
- vector normal = normal_at_point(&pt, closest_obj);
+ vector normal = normal_at_point(pt, hit_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);
+ light_dir = vect_sub(light_dir, pt);
- scalar light_dist = vect_abs(&light_dir);
+ scalar light_dist = vect_abs(light_dir);
- vect_normalize(&light_dir);
+ 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;
+ const struct object_t *obj = scene_intersections(scene, pt, light_dir, &nearest, hit_obj);
- scalar shade = vect_dot(&normal, &light_dir);
+ if(obj && nearest < light_dist)
+ continue;
+
+ scalar shade = vect_dot(normal, light_dir);
if(shade > 0)
- shade_total += shade;
+ shade_total += shade * scene->lights[i].intensity;
}
+ 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(closest_obj->specularity && max_iters > 0)
+ if(specular != 255 && max_iters > 0)
{
- vector ref = reflect_ray(&pt, d, &normal, closest_obj);
- reflected = trace_ray(scene, &pt, &ref, max_iters - 1);
+ vector ref = reflect_ray(pt, d, normal, hit_obj);
+ reflected = trace_ray(scene, pt, ref, max_iters - 1, hit_obj);
}
}
- return blend(primary, reflected, closest_obj ? (255 - closest_obj->specularity) : 255);
+ return blend(primary, reflected, specular);
}
unsigned char *render_scene(int w, int h, const struct scene_t *scene,
@@ -227,7 +240,7 @@ 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->offset;
+ vector d = cam->direction;
vect_to_sph(&d);
d.sph.elevation -= rot_y;
@@ -239,7 +252,7 @@ unsigned char *render_scene(int w, int h, const struct scene_t *scene,
/* cam->origin and d now form the camera ray */
- struct rgb_t color = trace_ray(scene, &cam->origin, &d, MAX_BOUNCES);
+ 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 + 1] = color.g;
@@ -267,13 +280,13 @@ int main()
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[0].specularity = 20;
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[1].specularity = 0xef;
sph[2].type = SPHERE;
sph[2].sphere.center = (vector) { RECT, {0, 0, -3 } };
@@ -283,6 +296,7 @@ int main()
struct light_t lights[1];
lights[0].position = (vector) { RECT, {0, 10, -10} };
+ lights[0].intensity = 2;
scene.objects = sph;
scene.n_objects = 3;
@@ -291,7 +305,7 @@ int main()
struct camera_t cam;
cam.origin = (vector){ RECT, {-5, 0, 0} };
- cam.offset = (vector){ RECT, {0, 0, 1} };
+ cam.direction = (vector){ RECT, {0, 0, 1} };
cam.fov_x = M_PI / 2;
cam.fov_y = M_PI / 2 * HEIGHT / WIDTH;
@@ -301,6 +315,7 @@ int main()
fprintf(f, "P6\n%d %d\n%d\n", WIDTH, HEIGHT, 255);
fwrite(fb, WIDTH * HEIGHT, 3, f);
fclose(f);
+ free(fb);
return 0;
#else
@@ -310,6 +325,17 @@ int main()
while(1)
{
+#ifdef MOUSELOOK
+ /* mouse look */
+ int x, y;
+ unsigned mouse = SDL_GetMouseState(&x, &y);
+ x -= WIDTH / 2;
+ y -= HEIGHT / 2;
+ vect_to_sph(&cam.direction);
+ cam.direction.sph.azimuth += M_PI/30 * SIGN(x)*SQR((scalar)x / WIDTH);
+ cam.direction.sph.elevation += M_PI/30 * SIGN(y)*SQR((scalar)y / HEIGHT);
+#endif
+
unsigned char *fb = render_scene(WIDTH, HEIGHT, &scene, &cam);
memcpy(screen->pixels, fb, WIDTH * HEIGHT * 3);
SDL_UpdateRect(screen, 0, 0, 0, 0);
@@ -338,10 +364,10 @@ int main()
cam.origin.rect.y -= .1;
break;
case SDLK_w:
- cam.origin.rect.x += .1;
+ cam.origin = vect_add(cam.origin, vect_mul(cam.direction, MOVE_FACTOR));
break;
case SDLK_s:
- cam.origin.rect.x -= .1;
+ cam.origin = vect_sub(cam.origin, vect_mul(cam.direction, MOVE_FACTOR));
break;
case SDLK_MINUS:
cam.fov_x += M_PI/36;
@@ -351,18 +377,19 @@ int main()
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);
+ {
+ vect_to_sph(&cam.direction);
+ cam.direction.sph.azimuth -= M_PI/180;
+ break;
+ }
+ case SDLK_d:
+ {
+ vect_to_sph(&cam.direction);
+ cam.direction.sph.azimuth += M_PI/180;
break;
}
+ }
break;
}
}
diff --git a/vector.c b/vector.c
index 02cae58..7c45f26 100644
--- a/vector.c
+++ b/vector.c
@@ -28,7 +28,7 @@ void vect_to_sph(vector *v)
{
vector old = *v;
v->type = SPH;
- v->sph.r = vect_abs(&old);
+ v->sph.r = vect_abs(old);
v->sph.elevation = atan2(old.rect.y, sqrt(old.rect.x*old.rect.x + old.rect.z*old.rect.z));
v->sph.azimuth = atan2(old.rect.z, old.rect.x);
break;
@@ -36,81 +36,79 @@ void vect_to_sph(vector *v)
}
}
-scalar vect_abs(const vector *v)
+scalar vect_abs(vector v)
{
- switch(v->type)
+ switch(v.type)
{
case SPH:
- return v->sph.r;
+ return v.sph.r;
case RECT:
- return sqrt(v->rect.x * v->rect.x + v->rect.y * v->rect.y + v->rect.z * v->rect.z);
+ return sqrt(v.rect.x * v.rect.x + v.rect.y * v.rect.y + v.rect.z * v.rect.z);
}
}
-void vect_mul(vector *v, scalar s)
+vector vect_mul(vector v, scalar s)
{
- switch(v->type)
+ switch(v.type)
{
case SPH:
- v->sph.r *= s;
+ v.sph.r *= s;
break;
case RECT:
- v->rect.x *= s;
- v->rect.y *= s;
- v->rect.z *= s;
+ v.rect.x *= s;
+ v.rect.y *= s;
+ v.rect.z *= s;
break;
}
+ return v;
}
-void vect_add(vector *v1, const vector *v2)
+vector vect_add(vector v1, vector v2)
{
- int old_type = v1->type;
- vector tmp1 = *v1;
- vector tmp2 = *v2;
- vect_to_rect(&tmp1);
- vect_to_rect(&tmp2);
- tmp1.rect.x += tmp2.rect.x;
- tmp1.rect.y += tmp2.rect.y;
- tmp1.rect.z += tmp2.rect.z;
+ int old_type = v1.type;
+ vect_to_rect(&v1);
+ vect_to_rect(&v2);
+ v1.rect.x += v2.rect.x;
+ v1.rect.y += v2.rect.y;
+ v1.rect.z += v2.rect.z;
- *v1 = tmp1;
if(old_type == SPH)
- vect_to_sph(v1);
+ vect_to_sph(&v1);
+ return v1;
}
-void vect_negate(vector *v)
+vector vect_negate(vector v)
{
- switch(v->type)
+ switch(v.type)
{
case SPH:
- v->sph.r = -v->sph.r;
+ v.sph.r = -v.sph.r;
break;
case RECT:
- v->rect.x = -v->rect.x;
- v->rect.y = -v->rect.y;
- v->rect.z = -v->rect.z;
+ v.rect.x = -v.rect.x;
+ v.rect.y = -v.rect.y;
+ v.rect.z = -v.rect.z;
break;
}
+ return v;
}
/* v1 = v1 - v2 */
-void vect_sub(vector *v1, const vector *v2)
+vector vect_sub(vector v1, vector v2)
{
- vector neg = *v2;
- vect_negate(&neg);
- vect_add(v1, &neg);
+ v2 = vect_negate(v2);
+ return vect_add(v1, v2);
}
-scalar vect_dot(const vector *v1, const vector *v2)
+scalar vect_dot(vector v1, vector v2)
{
- vector a = *v1, b = *v2;
- vect_to_rect(&a);
- vect_to_rect(&b);
- return a.rect.x * b.rect.x + a.rect.y * b.rect.y + a.rect.z * b.rect.z;
+ vect_to_rect(&v1);
+ vect_to_rect(&v2);
+ return v1.rect.x * v2.rect.x + v1.rect.y * v2.rect.y + v1.rect.z * v2.rect.z;
}
-void vect_normalize(vector *v)
+vector vect_normalize(vector v)
{
- scalar abs = vect_abs(v);
- vect_mul(v, 1./abs);
+ scalar a = vect_abs(v);
+ return vect_mul(v, 1./a);
}
diff --git a/vector.h b/vector.h
index 3838b63..f7b3949 100644
--- a/vector.h
+++ b/vector.h
@@ -14,15 +14,16 @@ typedef struct vector_t {
};
} vector;
-scalar vect_abs(const vector*);
+scalar vect_abs(vector);
-void vect_mul(vector*, scalar);
-void vect_add(vector*, const vector*);
+vector vect_mul(vector, scalar);
+vector vect_add(vector, vector);
+vector vect_sub(vector, vector);
+
+vector vect_normalize(vector);
+vector vect_negate(vector);
void vect_to_rect(vector*);
void vect_to_sph(vector*);
-void vect_sub(vector*, const vector*);
-void vect_negate(vector*);
-void vect_normalize(vector*);
-scalar vect_dot(const vector *v1, const vector *v2);
+scalar vect_dot(vector v1, vector v2);