summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFranklin Wei <me@fwei.tk>2017-04-02 22:14:11 -0400
committerFranklin Wei <me@fwei.tk>2017-04-02 22:14:11 -0400
commit929df060cbd9c0da04b8d9ce70dcea9879f42f4a (patch)
tree8d39c317c3448d0a83f60427610a6c641af8fdb5
parentd6e9b142e014c3d171932894dbb0db0410e91af7 (diff)
downloadraytrace-929df060cbd9c0da04b8d9ce70dcea9879f42f4a.zip
raytrace-929df060cbd9c0da04b8d9ce70dcea9879f42f4a.tar.gz
raytrace-929df060cbd9c0da04b8d9ce70dcea9879f42f4a.tar.bz2
raytrace-929df060cbd9c0da04b8d9ce70dcea9879f42f4a.tar.xz
lighting
-rw-r--r--main.c187
-rw-r--r--vector.c6
-rw-r--r--vector.h3
3 files changed, 144 insertions, 52 deletions
diff --git a/main.c b/main.c
index 8edd43c..e6b7f03 100644
--- a/main.c
+++ b/main.c
@@ -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;
diff --git a/vector.c b/vector.c
index da644fd..02cae58 100644
--- a/vector.c
+++ b/vector.c
@@ -108,3 +108,9 @@ scalar vect_dot(const vector *v1, const vector *v2)
vect_to_rect(&b);
return a.rect.x * b.rect.x + a.rect.y * b.rect.y + a.rect.z * b.rect.z;
}
+
+void vect_normalize(vector *v)
+{
+ scalar abs = vect_abs(v);
+ vect_mul(v, 1./abs);
+}
diff --git a/vector.h b/vector.h
index 24773c7..3838b63 100644
--- a/vector.h
+++ b/vector.h
@@ -1,6 +1,6 @@
#include <math.h>
-typedef double scalar;
+typedef float scalar;
typedef struct vector_t {
enum { RECT, SPH } type;
@@ -23,5 +23,6 @@ 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);