@ -1,4 +1,5 @@
|
|||||||
*.bmp
|
*.bmp
|
||||||
*.png
|
*.png
|
||||||
*.out
|
*.out
|
||||||
out/
|
obj
|
||||||
|
out
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
[submodule "images"]
|
[submodule "images"]
|
||||||
path = images
|
path = images
|
||||||
url = gitlab@git.datenvorr.at:anton/images.h.git
|
url = https://git.datenvorr.at/anton/images.h.git
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||||
|
</project>
|
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/raymarcher.iml" filepath="$PROJECT_DIR$/.idea/raymarcher.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/images" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
|
||||||
|
OPTIMIZATION=-O3 -flto
|
||||||
|
CC=gcc
|
||||||
|
CFLAGS=-Isrc/ -lm -lpthread -Wall -Wextra -pedantic-errors $(OPTIMIZATION) -DPOINT_DTYPE=float
|
||||||
|
|
||||||
|
.PHONY: directories
|
||||||
|
|
||||||
|
directories:
|
||||||
|
mkdir -p obj out
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf obj/* out/*
|
||||||
|
|
||||||
|
obj/scene.o: src/scene.c src/scene.h src/point.h
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ src/scene.c
|
||||||
|
|
||||||
|
obj/camera.o: src/camera.c src/camera.h src/point.h
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ src/camera.c
|
||||||
|
|
||||||
|
obj/images.o: images/src/images.c images/src/images.h src/point.h
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ images/src/images.c
|
||||||
|
|
||||||
|
march: obj/camera.o obj/scene.o obj/images.o src/point.h
|
||||||
|
$(CC) $(CFLAGS) -o out/march $^ marcher.c
|
||||||
|
|
||||||
|
bench: obj/camera.o obj/scene.o obj/images.o src/point.h
|
||||||
|
$(CC) $(CFLAGS) -o out/bench $^ bench.c
|
||||||
|
|
||||||
|
gpu: obj/camera.o obj/images.o src/point.h
|
||||||
|
$(CC) -fopenacc $(CFLAGS) -o out/gpu $^ gpu.c
|
@ -0,0 +1,181 @@
|
|||||||
|
#include <math.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/sysinfo.h>
|
||||||
|
#include "images/src/images.h"
|
||||||
|
#include "src/scene.h"
|
||||||
|
#include "src/camera.h"
|
||||||
|
#include "src/point.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define BENCH_VERSION "1.0"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Mandelbulb scene object
|
||||||
|
|
||||||
|
Currently cannot be set at a specific location, always resides at origin (0,0,0)
|
||||||
|
|
||||||
|
Color function is just a flat shader, detail is displayed with ambient occlusion
|
||||||
|
|
||||||
|
*/
|
||||||
|
double mandelbulb_dist(struct point pt, struct scene_object *self) {
|
||||||
|
int iters = (int) self->args[0];
|
||||||
|
double power = self->args[1];
|
||||||
|
|
||||||
|
struct point z = pt;
|
||||||
|
double dr = 1.0;
|
||||||
|
double r = 0.0;
|
||||||
|
for (int i = 0; i < iters ; i++) {
|
||||||
|
r = pt_length(z);
|
||||||
|
|
||||||
|
if (r>2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to polar coordinates
|
||||||
|
double theta = acos(z.z/r);
|
||||||
|
double phi = atan2(z.y,z.x);
|
||||||
|
dr = pow(r, power-1.0)*power*dr + 1.0;
|
||||||
|
|
||||||
|
// scale and rotate the point
|
||||||
|
double zr = pow(r, power);
|
||||||
|
theta = theta*power;
|
||||||
|
phi = phi*power;
|
||||||
|
|
||||||
|
// convert back to cartesian coordinates
|
||||||
|
z = (struct point) {
|
||||||
|
.x = sin(theta)*cos(phi) * zr + pt.x,
|
||||||
|
.y = sin(phi)*sin(theta) * zr + pt.y,
|
||||||
|
.z = cos(theta) * zr + pt.z
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.5*log(r)*r/dr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Color mandelbulb_color(struct point hit, struct point direction, struct scene_object *self) {
|
||||||
|
return self->color;
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructs the scene object
|
||||||
|
struct scene_object mandelbulb_new(struct point location, int iters, double power) {
|
||||||
|
struct scene_object so;
|
||||||
|
so.location = location;
|
||||||
|
so.args = malloc(sizeof(double) * 3);
|
||||||
|
so.args[0] = iters; // iterations
|
||||||
|
so.args[1] = power; // power
|
||||||
|
so.args[2] = -1; // reserved for color calculations
|
||||||
|
so.distance = mandelbulb_dist;
|
||||||
|
so.get_color = mandelbulb_color;
|
||||||
|
so.color = color_new(255,255,255);
|
||||||
|
return so;
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_bench(int size, double pow, int threads, const char path[], int save) {
|
||||||
|
double cam_position = 1.15;
|
||||||
|
int steps = 2000;
|
||||||
|
int iters = 1000;
|
||||||
|
double threshold = 0.0001;
|
||||||
|
|
||||||
|
struct camera cam;
|
||||||
|
cam.fov = 90;
|
||||||
|
|
||||||
|
camera_set_looking_at(&cam, (struct point){.x = cam_position, .y = cam_position, .z = cam_position}, PT_ZERO);
|
||||||
|
|
||||||
|
// create basic scene with up to 10 objects
|
||||||
|
struct scene scene = scene_new(size, size, 1);
|
||||||
|
scene.perf_opts.max_steps = steps;
|
||||||
|
scene.perf_opts.threshold = threshold;
|
||||||
|
scene.perf_opts.speed_cutoff = 10;
|
||||||
|
scene.background = color_new(0,0,0);
|
||||||
|
|
||||||
|
scene_add_obj(&scene, mandelbulb_new(PT_ZERO, iters, pow));
|
||||||
|
|
||||||
|
Image *img = render_scene(&scene, &cam, threads);
|
||||||
|
|
||||||
|
if (save) {
|
||||||
|
image_save_bmp(*img, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
image_destroy(*img);
|
||||||
|
scene_destroy(scene);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timer {
|
||||||
|
struct timeval start;
|
||||||
|
struct timeval end;
|
||||||
|
char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
void timer_start(struct timer *t) {
|
||||||
|
printf("\nStarting bench %s\n", t->name);
|
||||||
|
gettimeofday(&t->start, NULL);
|
||||||
|
}
|
||||||
|
void timer_end(struct timer *t) {
|
||||||
|
gettimeofday(&t->end, NULL);
|
||||||
|
}
|
||||||
|
void timer_print(struct timer t) {
|
||||||
|
long time, secs, usecs;
|
||||||
|
secs = t.end.tv_sec - t.start.tv_sec;
|
||||||
|
usecs = t.end.tv_usec - t.start.tv_usec;
|
||||||
|
time = ((secs) * 1000 + usecs/1000.0) + 0.5;
|
||||||
|
printf("\nBenchmark %s took %ldms (%.2fs)\n", t.name, time, time / 1000.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int threads = get_nprocs() / 2;
|
||||||
|
struct timer bench;
|
||||||
|
|
||||||
|
printf("Mandelbulb Benchmark v%s\n\nDetected %d threads...\n", BENCH_VERSION, threads);
|
||||||
|
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
bench.name = "1080px render with saving";
|
||||||
|
timer_start(&bench);
|
||||||
|
run_bench(1080, 3.0, threads, "bench-pow3-1080p.bmp", 1);
|
||||||
|
timer_end(&bench);
|
||||||
|
timer_print(bench);
|
||||||
|
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
bench.name = "1080px render without saving";
|
||||||
|
timer_start(&bench);
|
||||||
|
run_bench(1080, 3.0, threads, "", 0);
|
||||||
|
timer_end(&bench);
|
||||||
|
timer_print(bench);
|
||||||
|
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
bench.name = "10 megapixel render with saving";
|
||||||
|
timer_start(&bench);
|
||||||
|
run_bench(3162, 3.0, threads, "bench-pow3-10mpx.bmp", 1);
|
||||||
|
timer_end(&bench);
|
||||||
|
timer_print(bench);
|
||||||
|
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
bench.name = "40 megapixel render with saving";
|
||||||
|
timer_start(&bench);
|
||||||
|
run_bench(6324, 3.0, threads, "bench-pow3-40mpx.bmp", 1);
|
||||||
|
timer_end(&bench);
|
||||||
|
timer_print(bench);
|
||||||
|
|
||||||
|
sleep(2);
|
||||||
|
|
||||||
|
bench.name = "1080px render single threaded without saving";
|
||||||
|
timer_start(&bench);
|
||||||
|
run_bench(1080, 3.0, 1, "", 0);
|
||||||
|
timer_end(&bench);
|
||||||
|
timer_print(bench);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -0,0 +1,186 @@
|
|||||||
|
// use floats instead of doubles
|
||||||
|
#define DTYPE float
|
||||||
|
// #define POINT_DTYPE DTYPE
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "src/point.h"
|
||||||
|
#include "src/camera.h"
|
||||||
|
#include "images/src/images.h"
|
||||||
|
|
||||||
|
#define ITERS 100
|
||||||
|
#define POWER 3
|
||||||
|
|
||||||
|
#define SIZE 1000
|
||||||
|
#define STEP_WIDTH (2 / ((DTYPE) (SIZE - 1)))
|
||||||
|
|
||||||
|
#define CAM_POSITION 1.35
|
||||||
|
|
||||||
|
#define STEPS 100
|
||||||
|
#define THRESHOLD 0.001
|
||||||
|
|
||||||
|
#include <openacc.h>
|
||||||
|
|
||||||
|
|
||||||
|
float mandelbulb_dist(struct point pt)
|
||||||
|
{
|
||||||
|
DTYPE power = POWER;
|
||||||
|
|
||||||
|
struct point z = pt;
|
||||||
|
DTYPE dr = 1.0;
|
||||||
|
DTYPE r = 0.0;
|
||||||
|
for (int i = 0; i < ITERS ; i++) {
|
||||||
|
r = pt_length(z);
|
||||||
|
|
||||||
|
if (r>2) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert to polar coordinates
|
||||||
|
DTYPE theta = acos(z.z/r);
|
||||||
|
DTYPE phi = atan2(z.y,z.x);
|
||||||
|
dr = pow(r, power-1.0)*power*dr + 1.0;
|
||||||
|
|
||||||
|
// scale and rotate the point
|
||||||
|
DTYPE zr = pow(r, power);
|
||||||
|
theta = theta*power;
|
||||||
|
phi = phi*power;
|
||||||
|
|
||||||
|
// convert back to cartesian coordinates
|
||||||
|
z = (struct point) {
|
||||||
|
.x = sin(theta)*cos(phi) * zr + pt.x,
|
||||||
|
.y = sin(phi)*sin(theta) * zr + pt.y,
|
||||||
|
.z = cos(theta) * zr + pt.z
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.5*log(r)*r/dr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct setup {
|
||||||
|
struct point p0; // origin
|
||||||
|
struct point direction; // ray direction
|
||||||
|
struct point x; // ray movement in col
|
||||||
|
struct point y; // ray movement in row
|
||||||
|
};
|
||||||
|
|
||||||
|
struct setup make_setup()
|
||||||
|
{
|
||||||
|
// set up camera
|
||||||
|
struct camera cam;
|
||||||
|
cam.fov = 90;
|
||||||
|
|
||||||
|
camera_set_looking_at(&cam, (struct point){.x=CAM_POSITION, .y= CAM_POSITION, .z = CAM_POSITION}, PT_ZERO);
|
||||||
|
|
||||||
|
struct point span_z, span_xy;
|
||||||
|
|
||||||
|
// get rotation axis
|
||||||
|
pt_orthogonal_plane(cam.direction, &span_z, &span_xy);
|
||||||
|
|
||||||
|
printf("rendering %ix%ipx\n", SIZE, SIZE);
|
||||||
|
|
||||||
|
// distance each ray has from anothe on the ortogonal plane
|
||||||
|
//DTYPE step_dist = 2 / (DTYPE) (width - 1);
|
||||||
|
|
||||||
|
// vectors to move on the projection plane
|
||||||
|
struct point move_right = pt_scale(span_xy, STEP_WIDTH);
|
||||||
|
struct point move_up = pt_scale(span_z, STEP_WIDTH);;
|
||||||
|
|
||||||
|
// set starting point
|
||||||
|
struct point starting_point = pt_normalize(cam.direction);
|
||||||
|
|
||||||
|
// rotate starting point to (0,0)
|
||||||
|
starting_point = pt_add(starting_point, pt_mult(move_right, - SIZE / (DTYPE) 2));
|
||||||
|
starting_point = pt_add(starting_point, pt_mult(move_up, - SIZE / (DTYPE) 2));
|
||||||
|
|
||||||
|
return (struct setup) {
|
||||||
|
cam.location, starting_point, span_xy, span_z
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
struct setup setup = make_setup();
|
||||||
|
struct point start = setup.p0;
|
||||||
|
|
||||||
|
//printf("device num acc_device_current: %d\n", acc_get_num_devices(acc_device_current));
|
||||||
|
//printf("device num acc_device_none: %d\n", acc_get_num_devices(acc_device_none));
|
||||||
|
//printf("device num acc_device_default: %d\n", acc_get_num_devices(acc_device_default));
|
||||||
|
//printf("device num acc_device_host: %d\n", acc_get_num_devices(acc_device_host));
|
||||||
|
//printf("device num acc_device_not_host: %d\n", acc_get_num_devices(acc_device_not_host));
|
||||||
|
//printf("device num acc_device_nvidia: %d\n", acc_get_num_devices(acc_device_nvidia));
|
||||||
|
//printf("device num acc_device_radeon: %d\n", acc_get_num_devices(acc_device_radeon));
|
||||||
|
|
||||||
|
// get backing buff
|
||||||
|
int* buff = calloc(sizeof(int), SIZE * SIZE);
|
||||||
|
|
||||||
|
// indicate malloc failure
|
||||||
|
if (buff == NULL)
|
||||||
|
return -255;
|
||||||
|
|
||||||
|
printf("Before kernel\n");
|
||||||
|
|
||||||
|
#pragma acc data copy(buff)
|
||||||
|
{
|
||||||
|
// kernel goes brr
|
||||||
|
#pragma acc kernels
|
||||||
|
for (int x = 0; x < SIZE; x++) {
|
||||||
|
for (int y = 0; y < SIZE; y++) {
|
||||||
|
// get direction
|
||||||
|
struct point offset = pt_add(pt_mult(setup.x, STEP_WIDTH * x), pt_mult(setup.y, STEP_WIDTH * y));
|
||||||
|
struct point direction = pt_add(setup.direction, offset);
|
||||||
|
// get start
|
||||||
|
struct point loc = start;
|
||||||
|
// march!
|
||||||
|
DTYPE dist;
|
||||||
|
int res = -1;
|
||||||
|
|
||||||
|
for (int i = 0; i < STEPS; i++) {
|
||||||
|
dist = mandelbulb_dist(loc);
|
||||||
|
if (dist < THRESHOLD) {
|
||||||
|
res = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (dist > 100) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
loc = pt_add(loc, pt_scale(direction, dist));
|
||||||
|
}
|
||||||
|
buff[y * SIZE + x] = res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("after kernel\n");
|
||||||
|
|
||||||
|
// convert distance field into image
|
||||||
|
|
||||||
|
Image img;
|
||||||
|
|
||||||
|
// initialize shared pixel buffer
|
||||||
|
image_new(SIZE, SIZE, &img);
|
||||||
|
|
||||||
|
#pragma acc parallel
|
||||||
|
for (unsigned int x = 0; x < SIZE; x++) {
|
||||||
|
#pragma acc loop
|
||||||
|
for (unsigned int y = 0; y < SIZE; y++) {
|
||||||
|
if (buff[y * SIZE + x] < 0) {
|
||||||
|
image_set_px(img, x, y, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
// float in range of [0,1]
|
||||||
|
DTYPE fac = buff[y * SIZE + x] / (DTYPE) STEPS;
|
||||||
|
// calc shade
|
||||||
|
int shade = ((1-fac) * 255);
|
||||||
|
image_set_px(img, x, y, shade, shade, shade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("after encoding\n");
|
||||||
|
|
||||||
|
|
||||||
|
image_save_bmp(img, "gpu-goes-brrrrrrr.bmp");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
Subproject commit e20f4cb891ae1f6ac34f7572ea6847957b7195db
|
Subproject commit f503f1835fd47de323b19d8f3f1ea0fc542dd6f6
|
@ -1,97 +0,0 @@
|
|||||||
#ifndef __MARCHER_H__
|
|
||||||
#define __MARCHER_H__
|
|
||||||
|
|
||||||
#include "images/images.h"
|
|
||||||
|
|
||||||
// define pi if not available
|
|
||||||
#ifndef M_PI
|
|
||||||
#define M_PI 3.14159265358979323846
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct __myvec;
|
|
||||||
struct __mymtrx;
|
|
||||||
struct __mycam;
|
|
||||||
struct __myobject;
|
|
||||||
struct __myscene;
|
|
||||||
|
|
||||||
typedef struct __myvec {
|
|
||||||
double x;
|
|
||||||
double y;
|
|
||||||
double z;
|
|
||||||
} Point;
|
|
||||||
|
|
||||||
typedef struct __mymtrx {
|
|
||||||
double entries[9];
|
|
||||||
} Matrix;
|
|
||||||
|
|
||||||
inline Point pt_new(double x, double y, double z);
|
|
||||||
inline Point pt_scale(Point pt, double length);
|
|
||||||
inline Point pt_normalize(Point pt);
|
|
||||||
inline double pt_length(Point pt);
|
|
||||||
inline void pt_add(Point* pt, Point add);
|
|
||||||
inline void pt_sub(Point* pt, Point sub);
|
|
||||||
inline double pt_dist(Point p1, Point p2);
|
|
||||||
inline Point pt_mod(Point pt, double mod);
|
|
||||||
inline double pt_dot(Point a, Point b);
|
|
||||||
inline Point pt_cross(Point a, Point b);
|
|
||||||
inline double pt_angle(Point a, Point b);
|
|
||||||
inline void pt_print(Point pt);
|
|
||||||
inline void pt_print_n(const char* name, Point pt);
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct __mycam {
|
|
||||||
Point location;
|
|
||||||
Point direction;
|
|
||||||
unsigned int fov;
|
|
||||||
} Camera;
|
|
||||||
|
|
||||||
Camera camera_new(Point direction, unsigned int fov);
|
|
||||||
void camera_set_looking_at(Camera *cam, Point origin, Point thing);
|
|
||||||
|
|
||||||
// Scene objects have a position, some args, and a distance calculation function
|
|
||||||
// the distance calc function has the following signature:
|
|
||||||
// double distanceTo(Point myLocation, double * myArgs, Point externalPoint)
|
|
||||||
// where myLocation is this.location, myArgs is this.args and externalPoint is the point from wich we want to know the distance
|
|
||||||
// the get_color function takes args: point_hit, direction_hit, myArgs, MyLocation, MyColor
|
|
||||||
typedef struct __myobject {
|
|
||||||
Point location;
|
|
||||||
double * args;
|
|
||||||
double (*distance)(Point, struct __myobject *);
|
|
||||||
Color (*get_color)(Point, Point, struct __myobject *);
|
|
||||||
Color color;
|
|
||||||
struct __myscene* scene;
|
|
||||||
} SceneObject;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct __perfopts {
|
|
||||||
int speed_cutoff;
|
|
||||||
int max_steps;
|
|
||||||
double threshold;
|
|
||||||
} PerformanceOptimizations;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct __myscene {
|
|
||||||
unsigned int width;
|
|
||||||
unsigned int height;
|
|
||||||
SceneObject * objects;
|
|
||||||
int object_count;
|
|
||||||
int allocated_space;
|
|
||||||
// performance opts
|
|
||||||
PerformanceOptimizations perf_opts;
|
|
||||||
// colors etc
|
|
||||||
Color background;
|
|
||||||
} Scene;
|
|
||||||
|
|
||||||
Image* render_scene(Scene *scene, Camera *camera, unsigned int threads);
|
|
||||||
|
|
||||||
Scene scene_new(unsigned int width, unsigned int height, int obj_count);
|
|
||||||
|
|
||||||
void scene_add_obj(Scene* scene, SceneObject object);
|
|
||||||
|
|
||||||
void scene_destroy(Scene scene);
|
|
||||||
|
|
||||||
#include "src/point.c"
|
|
||||||
#include "src/camera.c"
|
|
||||||
#include "src/scene.c"
|
|
||||||
|
|
||||||
#endif
|
|
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct camera {
|
||||||
|
struct point location;
|
||||||
|
struct point direction;
|
||||||
|
unsigned int fov;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct camera camera_new(struct point direction, unsigned int fov);
|
||||||
|
void camera_set_looking_at(struct camera *cam, struct point origin, struct point thing);
|
||||||
|
void camera_iterate_rays_const_dist(struct camera camera, int width, int height, int thread_count, void (*callback)(struct point, int, int));
|
@ -1,180 +0,0 @@
|
|||||||
#include <math.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
// basically a vector3
|
|
||||||
inline Point pt_new(double x, double y, double z) {
|
|
||||||
Point pt;
|
|
||||||
pt.x = x;
|
|
||||||
pt.y = y;
|
|
||||||
pt.z = z;
|
|
||||||
return pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
// scale vector to length
|
|
||||||
inline Point pt_scale(Point pt, double length) {
|
|
||||||
double f = length / pt_length(pt);
|
|
||||||
return pt_new(
|
|
||||||
pt.x * f,
|
|
||||||
pt.y * f,
|
|
||||||
pt.z * f
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Point pt_mult(Point pt, double scalar) {
|
|
||||||
return pt_new(
|
|
||||||
pt.x * scalar,
|
|
||||||
pt.y * scalar,
|
|
||||||
pt.z * scalar
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// return internal angle between a and b
|
|
||||||
inline double pt_angle(Point a, Point b) {
|
|
||||||
return acos(pt_dot(
|
|
||||||
pt_normalize(a),
|
|
||||||
pt_normalize(b)
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the length of vector
|
|
||||||
inline double pt_length(Point pt) {
|
|
||||||
return sqrt((pt.x * pt.x) + (pt.y * pt.y) + (pt.z * pt.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the vector add to the vector pt
|
|
||||||
inline void pt_add(Point* pt, Point add) {
|
|
||||||
pt->x = pt->x + add.x;
|
|
||||||
pt->y = pt->y + add.y;
|
|
||||||
pt->z = pt->z + add.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add the vector add to the vector pt
|
|
||||||
inline void pt_sub(Point* pt, Point sub) {
|
|
||||||
pt->x -= sub.x;
|
|
||||||
pt->y -= sub.y;
|
|
||||||
pt->z -= sub.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline double pt_dist(Point p1, Point p2) {
|
|
||||||
pt_sub(&p1, p2);
|
|
||||||
return pt_length(p1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// normalize a vector
|
|
||||||
inline Point pt_normalize(Point pt) {
|
|
||||||
return pt_scale(pt, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// dot product of two vectors
|
|
||||||
inline double pt_dot(Point a, Point b) {
|
|
||||||
return a.x*b.x + a.y*b.y + a.z*b.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
// cross product of two vectors
|
|
||||||
inline Point pt_cross(Point a, Point b) {
|
|
||||||
return pt_new(
|
|
||||||
a.y*b.z - a.z*b.y,
|
|
||||||
a.z*b.x - a.x*b.z,
|
|
||||||
a.x*b.y - a.y*b.x
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void pt_print(Point pt) {
|
|
||||||
printf("(%f, %f, %f)\n", pt.x, pt.y, pt.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void pt_print_n(const char* name, Point pt) {
|
|
||||||
printf("%s: (%f, %f, %f)\n", name, pt.x, pt.y, pt.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
// find two vectors that span the orthogonal plane, where
|
|
||||||
// span_xy is a vector lying on the xy-plane (and pointing left)
|
|
||||||
// and span_z is orthogonal to span_xy pointing "upwards"
|
|
||||||
void pt_orthogonal_plane(Point pt, Point *span_z, Point *span_xy) {
|
|
||||||
pt = pt_normalize(pt);
|
|
||||||
|
|
||||||
// get the vector lying on the xy axis
|
|
||||||
// this is done by
|
|
||||||
*span_xy = pt_normalize(pt_cross(pt_new(0,0,1), pt)); // points to the "left" (of the viewing direction)
|
|
||||||
|
|
||||||
// now use this, to find the vector
|
|
||||||
*span_z = pt_normalize(pt_cross(pt, *span_xy));
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Point pt_mod(Point pt, double mod) {
|
|
||||||
return pt_new(
|
|
||||||
fabs(fmod(pt.x, mod)),
|
|
||||||
fabs(fmod(pt.y, mod)),
|
|
||||||
fabs(fmod(pt.z, mod))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////
|
|
||||||
////// Matrix operations //////
|
|
||||||
///////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
/* create a new matrix with entries:
|
|
||||||
x1 x2 x3
|
|
||||||
y1 y2 y3
|
|
||||||
z1 z2 z3
|
|
||||||
*/
|
|
||||||
inline Matrix mtrx_new(double x1, double x2, double x3,
|
|
||||||
double y1, double y2, double y3,
|
|
||||||
double z1, double z2, double z3)
|
|
||||||
{
|
|
||||||
Matrix m;
|
|
||||||
m.entries[0] = x1;
|
|
||||||
m.entries[1] = y1;
|
|
||||||
m.entries[2] = z1;
|
|
||||||
m.entries[3] = x2;
|
|
||||||
m.entries[4] = y2;
|
|
||||||
m.entries[5] = z2;
|
|
||||||
m.entries[6] = x3;
|
|
||||||
m.entries[7] = y3;
|
|
||||||
m.entries[8] = z3;
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Point mtrx_mult(Matrix mtrx, Point pt) {
|
|
||||||
Point result;
|
|
||||||
|
|
||||||
double *m = mtrx.entries;
|
|
||||||
|
|
||||||
result.x = m[0] * pt.x + m[3] * pt.y + m[6] * pt.z;
|
|
||||||
result.y = m[1] * pt.x + m[4] * pt.y + m[7] * pt.z;
|
|
||||||
result.z = m[2] * pt.x + m[5] * pt.y + m[8] * pt.z;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create a rotation matrix around an axis given by the normalized axis vector (u)
|
|
||||||
// taken from https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
|
|
||||||
Matrix mtrx_rotation(Point u, double theta) {
|
|
||||||
double theta_rad = theta * (M_PI / 180);
|
|
||||||
double cost = cos(theta_rad);
|
|
||||||
double sint = sin(theta_rad);
|
|
||||||
|
|
||||||
return mtrx_new(
|
|
||||||
cost+u.x*u.x*(1-cost), u.x*u.y*(1-cost)-u.z*sint, u.x*u.z*(1-cost)+u.y*sint,
|
|
||||||
u.y*u.x*(1-cost)+u.z*sint, cost+u.y*u.y*(1-cost), u.y*u.z*(1-cost)-u.x*sint,
|
|
||||||
u.z*u.x*(1-cost)-u.y*sint, u.z*u.y*(1-cost)+u.x*sint, cost+u.z*u.z*(1-cost)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mtrx_print(Matrix mtrx) {
|
|
||||||
printf(" %8.2f %8.2f %8.2f\n %8.2f %8.2f %8.2f\n %8.2f %8.2f %8.2f\n",
|
|
||||||
mtrx.entries[0], mtrx.entries[3], mtrx.entries[6],
|
|
||||||
mtrx.entries[1], mtrx.entries[4], mtrx.entries[7],
|
|
||||||
mtrx.entries[2], mtrx.entries[5], mtrx.entries[8]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Matrix mtrx_outer_prod(Point a, Point b) {
|
|
||||||
return mtrx_new(
|
|
||||||
a.x*b.x, a.x*b.y, a.x*b.z,
|
|
||||||
a.y*b.x, a.y*b.y, a.y*b.z,
|
|
||||||
a.z*b.x, a.z*b.y, a.z*b.z
|
|
||||||
);
|
|
||||||
}
|
|
@ -0,0 +1,149 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef POINT_DTYPE
|
||||||
|
#define POINT_DTYPE double
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
struct point {
|
||||||
|
POINT_DTYPE x;
|
||||||
|
POINT_DTYPE y;
|
||||||
|
POINT_DTYPE z;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PT_ZERO ((struct point) {.x=0, .y=0, .z=0})
|
||||||
|
#define PT_NEW(x,y,z) ((struct point){(x), (y), (z)})
|
||||||
|
|
||||||
|
static struct point pt_scale(struct point pt, POINT_DTYPE length);
|
||||||
|
static struct point pt_normalize(struct point pt);
|
||||||
|
static struct point pt_mult(struct point pt, POINT_DTYPE scalar);
|
||||||
|
static POINT_DTYPE pt_length(struct point pt);
|
||||||
|
static struct point pt_add(struct point pt, struct point add);
|
||||||
|
static struct point pt_sub(struct point pt, struct point sub);
|
||||||
|
static POINT_DTYPE pt_dist(struct point p1, struct point p2);
|
||||||
|
static struct point pt_mod(struct point pt, POINT_DTYPE mod);
|
||||||
|
static POINT_DTYPE pt_dot(struct point a, struct point b);
|
||||||
|
static struct point pt_cross(struct point a, struct point b);
|
||||||
|
static POINT_DTYPE pt_angle(struct point a, struct point b);
|
||||||
|
static void pt_print(struct point pt);
|
||||||
|
static void pt_print_n(const char* name, struct point pt);
|
||||||
|
static void pt_orthogonal_plane(struct point pt, struct point *span_z, struct point *span_xy);
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "point.h"
|
||||||
|
|
||||||
|
// get the length of vector
|
||||||
|
static inline POINT_DTYPE pt_length_inline (struct point pt) __attribute__((always_inline));
|
||||||
|
|
||||||
|
static inline struct point pt_mult(struct point pt, POINT_DTYPE scalar) {
|
||||||
|
return (struct point) {
|
||||||
|
.x = pt.x * scalar,
|
||||||
|
.y = pt.y * scalar,
|
||||||
|
.z = pt.z * scalar
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// return internal angle between a and b
|
||||||
|
static inline POINT_DTYPE pt_angle(struct point a, struct point b) {
|
||||||
|
return acos(pt_dot(
|
||||||
|
pt_normalize(a),
|
||||||
|
pt_normalize(b)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the length of vector
|
||||||
|
static inline POINT_DTYPE pt_length_inline (struct point pt) {
|
||||||
|
return sqrt((pt.x * pt.x) + (pt.y * pt.y) + (pt.z * pt.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline POINT_DTYPE pt_length(struct point pt) {
|
||||||
|
return pt_length_inline(pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the vector add to the vector pt
|
||||||
|
static inline struct point pt_add(struct point pt, struct point add) {
|
||||||
|
return (struct point) {
|
||||||
|
.x = pt.x + add.x,
|
||||||
|
.y = pt.y + add.y,
|
||||||
|
.z = pt.z + add.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the vector add to the vector pt
|
||||||
|
static inline struct point pt_sub(struct point pt, struct point sub) {
|
||||||
|
return (struct point) {
|
||||||
|
.x = pt.x - sub.x,
|
||||||
|
.y = pt.y - sub.y,
|
||||||
|
.z = pt.z - sub.z,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline POINT_DTYPE pt_dist(struct point p1, struct point p2) {
|
||||||
|
return pt_length_inline(pt_sub(p1, p2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalize a vector
|
||||||
|
static inline struct point pt_normalize(struct point pt) {
|
||||||
|
POINT_DTYPE length = pt_length(pt);
|
||||||
|
|
||||||
|
return (struct point) {
|
||||||
|
.x = pt.x / length,
|
||||||
|
.y = pt.y / length,
|
||||||
|
.z = pt.z / length
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// scale vector to length
|
||||||
|
static inline struct point pt_scale(struct point pt, POINT_DTYPE length) {
|
||||||
|
POINT_DTYPE f = length / pt_length_inline(pt);
|
||||||
|
return (struct point) {
|
||||||
|
.x = pt.x * f,
|
||||||
|
.y = pt.y * f,
|
||||||
|
.z = pt.z * f
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// dot product of two vectors
|
||||||
|
static inline POINT_DTYPE pt_dot(struct point a, struct point b) {
|
||||||
|
return a.x*b.x + a.y*b.y + a.z*b.z;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cross product of two vectors
|
||||||
|
static inline struct point pt_cross(struct point a, struct point b) {
|
||||||
|
return (struct point) {
|
||||||
|
.x = a.y*b.z - a.z*b.y,
|
||||||
|
.y = a.z*b.x - a.x*b.z,
|
||||||
|
.z = a.x*b.y - a.y*b.x
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pt_print(struct point pt) {
|
||||||
|
printf("(%f, %f, %f)\n", pt.x, pt.y, pt.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pt_print_n(const char* name, struct point pt) {
|
||||||
|
printf("%s: (%f, %f, %f)\n", name, pt.x, pt.y, pt.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// find two vectors that span the orthogonal plane, where
|
||||||
|
// span_xy is a vector lying on the xy-plane (and pointing left)
|
||||||
|
// and span_z is orthogonal to span_xy pointing "upwards"
|
||||||
|
static inline void pt_orthogonal_plane(struct point pt, struct point *span_z, struct point *span_xy) {
|
||||||
|
pt = pt_normalize(pt);
|
||||||
|
|
||||||
|
// get the vector lying on the xy axis
|
||||||
|
// this is done by
|
||||||
|
*span_xy = pt_normalize(pt_cross(PT_NEW(0,0,1), pt)); // points to the "left" (of the viewing direction)
|
||||||
|
|
||||||
|
// now use this, to find the vector
|
||||||
|
*span_z = pt_normalize(pt_cross(pt, *span_xy));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline struct point pt_mod(struct point pt, POINT_DTYPE mod) {
|
||||||
|
return (struct point) {
|
||||||
|
.x = fabs(fmod(pt.x, mod)),
|
||||||
|
.y = fabs(fmod(pt.y, mod)),
|
||||||
|
.z = fabs(fmod(pt.z, mod))
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "point.h"
|
||||||
|
#include "camera.h"
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct scene;
|
||||||
|
|
||||||
|
// Scene objects have a position, some args, and a distance calculation function
|
||||||
|
// the distance calc function has the following signature:
|
||||||
|
// double distanceTo(struct point myLocation, double * myArgs, struct point externalPoint)
|
||||||
|
// where myLocation is this.location, myArgs is this.args and externalPoint is the point from wich we want to know the distance
|
||||||
|
// the get_color function takes args: point_hit, direction_hit, myArgs, MyLocation, MyColor
|
||||||
|
struct scene_object {
|
||||||
|
struct point location;
|
||||||
|
double * args;
|
||||||
|
double (*distance)(struct point, struct scene_object *);
|
||||||
|
Color (*get_color)(struct point, struct point, struct scene_object *);
|
||||||
|
Color color;
|
||||||
|
struct scene* scene;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct performance_optimization {
|
||||||
|
int speed_cutoff;
|
||||||
|
int max_steps;
|
||||||
|
double threshold;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct scene {
|
||||||
|
unsigned int width;
|
||||||
|
unsigned int height;
|
||||||
|
struct scene_object * objects;
|
||||||
|
int object_count;
|
||||||
|
int allocated_space;
|
||||||
|
// performance opts
|
||||||
|
struct performance_optimization perf_opts;
|
||||||
|
// colors etc
|
||||||
|
Color background;
|
||||||
|
};
|
||||||
|
|
||||||
|
Image* render_scene(struct scene *scene, struct camera *camera, unsigned int threads);
|
||||||
|
|
||||||
|
struct scene scene_new(unsigned int width, unsigned int height, int obj_count);
|
||||||
|
|
||||||
|
void scene_add_obj(struct scene* scene, struct scene_object object);
|
||||||
|
|
||||||
|
void scene_destroy(struct scene scene);
|
Loading…
Reference in New Issue