Skip to content

Instantly share code, notes, and snippets.

@jamis
Created December 28, 2018 16:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jamis/6d291ab009067c77cf1ff0e14d924e87 to your computer and use it in GitHub Desktop.
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)
#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;
}
@wndxlori
Copy link

This is probably the most readable chunk of C I’ve seen in 10 years. 👏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment