Created
December 28, 2018 16:03
-
-
Save jamis/6d291ab009067c77cf1ff0e14d924e87 to your computer and use it in GitHub Desktop.
Sphere of spheres, stress test for my ray tracer from "The Ray Tracer Challenge" (C implementation)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> /* file */ | |
#include <stdlib.h> /* free */ | |
#include <math.h> /* M_PI, cos, sin */ | |
#include <limits.h> /* INT_MAX */ | |
#include "rtc/camera.h" | |
#include "rtc/shapes/shape.h" | |
#include "rtc/shapes/sphere.h" | |
#include "rtc/shapes/group.h" | |
#include "rtc/shapes/plane.h" | |
#include "rtc/material.h" | |
#include "rtc/parallel.h" | |
#define SCALE ( 1 ) | |
#define MAX_SPHERES ( 2000 ) | |
#define RADIUS ( 12.0 ) | |
#define frand() (1.0 * rand() / INT_MAX) | |
void glass_material(RTCMaterial *m, RTCTuple *color) { | |
rtc_material(m); | |
rtc_tuple_copy(&m->color, color); | |
m->diffuse = 0.1; | |
m->ambient = 0.0; | |
m->specular = 0.5; | |
m->shininess = 100; | |
m->reflective = 0.9; | |
m->transparency = 0.9; | |
m->refractive_index = 1.5; | |
} | |
void metal_material(RTCMaterial *m, RTCTuple *color) { | |
rtc_material(m); | |
rtc_tuple_copy(&m->color, color); | |
m->diffuse = 0.6; | |
m->ambient = 0.1; | |
m->specular = 0.4; | |
m->shininess = 7; | |
m->reflective = 0.1; | |
} | |
RTCTuple *random_color(RTCTuple *color) { | |
color->r = 0.5 + frand() * 0.5; | |
color->g = 0.5 + frand() * 0.5; | |
color->b = 0.5 + frand() * 0.5; | |
return color; | |
} | |
RTCMaterial *random_material(RTCMaterial *m) { | |
RTCTuple color; | |
if (rand() % 10 == 0) | |
glass_material(m, random_color(&color)); | |
else | |
metal_material(m, random_color(&color)); | |
return m; | |
} | |
int main(void) { | |
RTCWorld* world = rtc_world_create(); | |
srand(1); | |
/* === LIGHT =================== */ | |
rtc_world_add_light(world, rtc_point_light(1.0, 1.0, 1.0, -100, 100, -100)); | |
rtc_world_add_light(world, rtc_point_light(0.2, 0.2, 0.2, 150, 30, -50)); | |
rtc_world_add_light(world, rtc_point_light(0.5, 0.5, 0.5, 0, 0, 0)); | |
/* === SPHERES =================== */ | |
struct { | |
double x, y, z, r; | |
} spheres[MAX_SPHERES]; | |
int sphere_count = 0; | |
RTCShape *group = rtc_group_create(); | |
rtc_world_add_object(world, group); | |
RTCMaterial material; | |
spheres[0].x = 0.0; | |
spheres[0].y = RADIUS; | |
spheres[0].z = 0.0; | |
spheres[0].r = 1.0; | |
sphere_count++; | |
RTCShape *sphere = rtc_shape_describe(RTC_SPHERE, | |
RTC_ARG_TRANSLATE, 0.0, RADIUS, 0.0, | |
RTC_ARG_MATERIAL, random_material(&material), | |
RTC_ARG_END); | |
rtc_group_add(group, sphere); | |
int attempts = 0; | |
while (sphere_count < MAX_SPHERES && attempts < 10000) { | |
double min_r = 0.5; | |
double max_r = 1.5; | |
if (attempts > 1000) { | |
min_r *= 0.5; | |
max_r *= 0.5; | |
} else if (attempts > 3000) { | |
min_r *= 0.25; | |
max_r *= 0.25; | |
} else if (attempts > 5000) { | |
min_r *= 0.125; | |
max_r *= 0.125; | |
} | |
double theta = frand() * M_PI; | |
double phi = frand() * M_PI * 2; | |
double r = min_r + (frand() * (max_r - min_r)); | |
double x = RADIUS * sin(theta) * cos(phi); | |
double y = RADIUS * cos(theta); | |
double z = RADIUS * sin(theta) * sin(phi); | |
int ok = 1; | |
for(int j = 0; j < sphere_count; j++) { | |
double x2 = spheres[j].x; | |
double y2 = spheres[j].y; | |
double z2 = spheres[j].z; | |
double r2 = spheres[j].r; | |
double xd = x - x2; | |
double yd = y - y2; | |
double zd = z - z2; | |
double rd = r + r2; | |
ok = (xd * xd + yd * yd + zd * zd > rd * rd); | |
if (!ok) break; | |
} | |
if (ok) { | |
spheres[sphere_count].x = x; | |
spheres[sphere_count].y = y; | |
spheres[sphere_count].z = z; | |
spheres[sphere_count].r = r; | |
sphere_count++; | |
sphere = rtc_shape_describe(RTC_SPHERE, | |
RTC_ARG_SCALE, r, r, r, | |
RTC_ARG_TRANSLATE, x, y, z, | |
RTC_ARG_MATERIAL, random_material(&material), | |
RTC_ARG_END); | |
rtc_group_add(group, sphere); | |
attempts = 0; | |
printf("spheres: %d (latest @ %f,%f,%f <%f>)\n", sphere_count, x, y, z, r); | |
} else { | |
attempts++; | |
} | |
} | |
rtc_group_subdivide(group, 25); | |
/* === CAMERA =================== */ | |
RTCCamera camera; | |
RTCTuple from, to, up; | |
rtc_camera(&camera, 250*SCALE, 250*SCALE, M_PI/6); | |
rtc_point(&from, 50, 15, -50); | |
rtc_point(&to, 0, 0, 0); | |
rtc_vector(&up, 0, 1, 0); | |
rtc_matrix_view(&camera.transform, &from, &to, &up); | |
//camera.aa_subsamples = 3; | |
/* === RENDER =================== */ | |
RTCCanvas* canvas = rtc_camera_render_parallel(&camera, world, 32); | |
char *ppm = rtc_canvas_to_ppm(canvas); | |
rtc_canvas_destroy(&canvas); | |
rtc_world_destroy(&world); | |
FILE *f = fopen("sphere-sphere.ppm", "wt"); | |
fputs(ppm, f); | |
fclose(f); | |
free(ppm); | |
printf("wrote image to sphere-sphere.ppm\n"); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is probably the most readable chunk of C I’ve seen in 10 years. 👏