Initial commit, basic shading
commit
66f483e920
@ -0,0 +1,3 @@
|
|||||||
|
[submodule "images"]
|
||||||
|
path = images
|
||||||
|
url = gitlab@git.datenvorr.at:anton/images.h.git
|
@ -0,0 +1,10 @@
|
|||||||
|
# Raymarching in C
|
||||||
|
|
||||||
|
## Compiling:
|
||||||
|
|
||||||
|
```fish
|
||||||
|
# load requirements
|
||||||
|
nix-shell
|
||||||
|
# run gcc with flags
|
||||||
|
gcc (pkg-config --cflags --libs gtk+-3.0 | string split " ") -lm -Wall -Wextra -o march.out main.c
|
||||||
|
```
|
@ -0,0 +1,7 @@
|
|||||||
|
with import <nixpkgs> {};
|
||||||
|
stdenv.mkDerivation {
|
||||||
|
name = "raymarcher-dev-env";
|
||||||
|
buildInputs = [
|
||||||
|
gtk3 pkgconfig gdb
|
||||||
|
];
|
||||||
|
}
|
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 0ab4ae2be9f993f26759fc03d3186a51d2770d45
|
@ -0,0 +1,71 @@
|
|||||||
|
#include <gtk/gtk.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "images/images.h"
|
||||||
|
#include "marcher.h"
|
||||||
|
|
||||||
|
#define SCENE_MOD 2
|
||||||
|
|
||||||
|
// this is the circle distance function definition
|
||||||
|
double circle_dist(Point x, SceneObject *self) {
|
||||||
|
double r = self->args[0];
|
||||||
|
return pt_dist(pt_mod(x, SCENE_MOD), self->location) - r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color circle_color(Point hit, Point direction, SceneObject *self) {
|
||||||
|
Point obj_direction = self->location;
|
||||||
|
|
||||||
|
pt_sub(&obj_direction, pt_mod(hit, SCENE_MOD));
|
||||||
|
|
||||||
|
double angle = pt_angle(direction, obj_direction) / M_PI * 180;
|
||||||
|
Color color = self->color;
|
||||||
|
|
||||||
|
if (angle > 90) angle = 180 - angle ; // clamp angle to 0-90
|
||||||
|
color = color_mix(color, color_new(0,0,0), 1 - (angle / (double) 90));
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneObject circle_new(Point loc, double radius) {
|
||||||
|
SceneObject so;
|
||||||
|
so.location = loc;
|
||||||
|
so.args = malloc(sizeof(double) * 2);
|
||||||
|
so.args[0] = radius;
|
||||||
|
so.distance = circle_dist;
|
||||||
|
so.get_color = circle_color;
|
||||||
|
so.color = color_new(255,0,0);
|
||||||
|
return so;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
int threads = 1;
|
||||||
|
Camera cam;
|
||||||
|
cam.fov = 90;
|
||||||
|
camera_set_looking_at(&cam, pt_new(-.6,0,0), pt_new(-.5,1,0));
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
threads = atoi(argv[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("threads: %d\n", threads);
|
||||||
|
|
||||||
|
// create basic scene with up to 10 objects
|
||||||
|
Scene scene = scene_new(800, 600, 10);
|
||||||
|
scene.max_steps = 64;
|
||||||
|
scene.threshold = 0.02;
|
||||||
|
|
||||||
|
scene_add_obj(&scene, circle_new(pt_new(0,1,0), .2));
|
||||||
|
|
||||||
|
//scene_add_obj(&scene, circle_new(pt_new(0,2,0), 0.5));
|
||||||
|
//scene_add_obj(&scene, circle_new(pt_new(0,-2,0), 0.5));
|
||||||
|
//scene_add_obj(&scene, circle_new(pt_new(0,-4,0), 0.5));
|
||||||
|
|
||||||
|
Image *img = render_scene(&scene, &cam, threads);
|
||||||
|
|
||||||
|
image_save_bmp(*img, "render.bmp");
|
||||||
|
|
||||||
|
image_destroy_shared(*img);
|
||||||
|
scene_destroy(scene);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,83 @@
|
|||||||
|
#ifndef __MARCHER_H__
|
||||||
|
#define __MARCHER_H__
|
||||||
|
|
||||||
|
#include "images/images.h"
|
||||||
|
|
||||||
|
// define pi if not available
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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);
|
||||||
|
Point pt_scale(Point pt, double length);
|
||||||
|
inline Point pt_normalize(Point pt);
|
||||||
|
inline double pt_length(Point pt);
|
||||||
|
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;
|
||||||
|
} SceneObject;
|
||||||
|
|
||||||
|
typedef struct __myscene {
|
||||||
|
unsigned int width;
|
||||||
|
unsigned int height;
|
||||||
|
SceneObject * objects;
|
||||||
|
int object_count;
|
||||||
|
int allocated_space;
|
||||||
|
// some other settings
|
||||||
|
int max_steps;
|
||||||
|
double threshold;
|
||||||
|
// 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
|
Binary file not shown.
After Width: | Height: | Size: 1.4 MiB |
@ -0,0 +1,172 @@
|
|||||||
|
#include "../marcher.h"
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
|
||||||
|
Camera camera_new(Point direction, unsigned int fov) {
|
||||||
|
Camera camera;
|
||||||
|
camera.location = pt_new(0,0,0);
|
||||||
|
camera.fov = fov;
|
||||||
|
|
||||||
|
// normalize camera direction
|
||||||
|
camera.direction = pt_normalize(direction);
|
||||||
|
|
||||||
|
return camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
void camera_set_looking_at(Camera *cam, Point origin, Point thing) {
|
||||||
|
cam->location = origin;
|
||||||
|
pt_sub(&thing, origin);
|
||||||
|
cam->direction = pt_normalize(thing);
|
||||||
|
}
|
||||||
|
|
||||||
|
void camera_iterate_rays_const_angle(Camera camera, int width, int height, int threads, void (*callback)(Point, int, int)) {
|
||||||
|
// negative threads => single threaded.
|
||||||
|
if (threads < 0) threads = 0;
|
||||||
|
|
||||||
|
Point span_z, span_xy;
|
||||||
|
|
||||||
|
// get rotation axis
|
||||||
|
pt_orthogonal_plane(camera.direction, &span_z, &span_xy);
|
||||||
|
|
||||||
|
printf("rendering %ix%i px", width, height);
|
||||||
|
|
||||||
|
pt_print_n("span_xy", span_xy);
|
||||||
|
pt_print_n("span_z", span_z);
|
||||||
|
|
||||||
|
// angle between rays
|
||||||
|
double angle_step = camera.fov / (double) (width - 1);
|
||||||
|
|
||||||
|
// rotation applied to reach the outmost end of the view
|
||||||
|
double angle_start_h = - (camera.fov / 2.0);
|
||||||
|
double angle_start_v = ((angle_step * (height - 1)) / 2) ;
|
||||||
|
|
||||||
|
printf("step: %f\nstart_h: %f\nstart_v: %f\n", angle_step, angle_start_h, angle_start_v);
|
||||||
|
|
||||||
|
// calculate both rotation matrices (expensive!)
|
||||||
|
Matrix rot_z = mtrx_rotation(span_z, angle_step);
|
||||||
|
Matrix rot_xy = mtrx_rotation(span_xy, -angle_step);
|
||||||
|
|
||||||
|
// rotate vector to starting location (bot left of screen)
|
||||||
|
// (very expensive!)
|
||||||
|
Point starting_point = mtrx_mult(
|
||||||
|
mtrx_rotation(span_xy, angle_start_v),
|
||||||
|
mtrx_mult(
|
||||||
|
mtrx_rotation(span_z, angle_start_h),
|
||||||
|
camera.direction
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
// initialize threads
|
||||||
|
int thread_id = 0;
|
||||||
|
for (int i = 0; i < threads - 1; i++) {
|
||||||
|
if (fork() == 0) {
|
||||||
|
thread_id = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Thread %i reporting for duty\n", thread_id);
|
||||||
|
|
||||||
|
// this point is rotated for every pixel
|
||||||
|
Point curr_pt = starting_point;
|
||||||
|
// (0,0) screenspace is bottom left corner
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
curr_pt = mtrx_mult(rot_xy, starting_point);
|
||||||
|
// move starting point one row down
|
||||||
|
starting_point = curr_pt;
|
||||||
|
|
||||||
|
if (y % threads != thread_id) continue;
|
||||||
|
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
callback(curr_pt, x, y);
|
||||||
|
curr_pt = mtrx_mult(rot_z, curr_pt); // rotate point
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread_id != 0) {
|
||||||
|
printf("Thread %i is finished\n", thread_id);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int status;
|
||||||
|
for (int i = 0; i < threads - 1; i++) {
|
||||||
|
printf("Waiting for threads... %d/%d\n", i, threads);
|
||||||
|
while(wait(&status) > 0) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("got threads\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void camera_iterate_rays_const_dist(Camera camera, int width, int height, int threads, void (*callback)(Point, int, int)) {
|
||||||
|
// negative threads => single threaded.
|
||||||
|
if (threads < 0) threads = 0;
|
||||||
|
|
||||||
|
Point span_z, span_xy;
|
||||||
|
|
||||||
|
// get rotation axis
|
||||||
|
pt_orthogonal_plane(camera.direction, &span_z, &span_xy);
|
||||||
|
|
||||||
|
printf("rendering %ix%i px\n", width, height);
|
||||||
|
|
||||||
|
pt_print_n("span_xy", span_xy);
|
||||||
|
pt_print_n("span_z", span_z);
|
||||||
|
|
||||||
|
|
||||||
|
// distance each ray has from anothe on the ortogonal plane
|
||||||
|
double step_dist = 2 / (double) (width - 1);
|
||||||
|
|
||||||
|
// vectors to move on the projection plane
|
||||||
|
Point move_right = pt_scale(span_xy, step_dist);
|
||||||
|
Point move_up = pt_scale(span_z, step_dist);;
|
||||||
|
|
||||||
|
printf("step: %f\n", step_dist);
|
||||||
|
// set starting point
|
||||||
|
Point starting_point = pt_normalize(camera.direction);
|
||||||
|
|
||||||
|
// rotate starting point to (0,0)
|
||||||
|
pt_add(&starting_point, pt_mult(move_right, - width / (double) 2));
|
||||||
|
pt_add(&starting_point, pt_mult(move_up, - height / (double) 2));
|
||||||
|
|
||||||
|
// initialize threads
|
||||||
|
int thread_id = 0;
|
||||||
|
for (int i = 0; i < threads - 1; i++) {
|
||||||
|
if (fork() == 0) {
|
||||||
|
thread_id = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("Thread %i reporting for duty\n", thread_id);
|
||||||
|
|
||||||
|
// this point is moved for every pixel
|
||||||
|
Point curr_pt = starting_point;
|
||||||
|
|
||||||
|
// (0,0) screenspace is bottom left corner
|
||||||
|
for (int y = 0; y < height; y++) {
|
||||||
|
// move one row up (this has to be done in every thread!)
|
||||||
|
pt_add(&starting_point, move_up);
|
||||||
|
|
||||||
|
// only render the lines this thread is responsible for
|
||||||
|
if (y % threads != thread_id) continue;
|
||||||
|
|
||||||
|
// actually iterate this line
|
||||||
|
curr_pt = starting_point;
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
callback(curr_pt, x, y);
|
||||||
|
pt_add(&curr_pt, move_right); // move pt right to next pt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (thread_id != 0) {
|
||||||
|
printf("Thread %i is finished\n", thread_id);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int status;
|
||||||
|
for (int i = 0; i < threads - 1; i++) {
|
||||||
|
printf("Waiting for threads... %d/%d\n", i, threads);
|
||||||
|
while(wait(&status) > 0) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("got threads\n");
|
||||||
|
}
|
@ -0,0 +1,180 @@
|
|||||||
|
#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
|
||||||
|
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
|
||||||
|
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(
|
||||||
|
fmod(pt.x, mod),
|
||||||
|
fmod(pt.y, mod),
|
||||||
|
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,121 @@
|
|||||||
|
#include "../marcher.h"
|
||||||
|
#include "../images/images.h"
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
static Image* current_image;
|
||||||
|
static Scene* current_scene;
|
||||||
|
static Camera* current_camera;
|
||||||
|
|
||||||
|
Color march_ray(Point origin, Point direction, Scene* scene);
|
||||||
|
void camera_iter_callback(Point direction, int x, int y);
|
||||||
|
|
||||||
|
|
||||||
|
Scene scene_new(unsigned int width, unsigned int height, int obj_count) {
|
||||||
|
Scene scene;
|
||||||
|
scene.height = height;
|
||||||
|
scene.width = width;
|
||||||
|
scene.max_steps = 32;
|
||||||
|
scene.threshold = 0.02;
|
||||||
|
scene.object_count = 0;
|
||||||
|
scene.objects = malloc(obj_count * sizeof(SceneObject));
|
||||||
|
scene.allocated_space = obj_count;
|
||||||
|
scene.background = color_new(0,0,0);
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scene_add_obj(Scene* scene, SceneObject object) {
|
||||||
|
if (scene->object_count >= scene->allocated_space) return; // limit reached
|
||||||
|
// TODO realloc
|
||||||
|
|
||||||
|
scene->objects[scene->object_count] = object;
|
||||||
|
|
||||||
|
scene->object_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// render out the scene with threads
|
||||||
|
// creates a shared image, so destroy with image_destroy_shared then free struct with free_shared_memory
|
||||||
|
Image* render_scene(Scene *scene, Camera *camera, unsigned int threads) {
|
||||||
|
current_image = malloc(sizeof(Image));
|
||||||
|
current_scene = scene;
|
||||||
|
current_camera= camera;
|
||||||
|
|
||||||
|
// initialize shared pixel buffer
|
||||||
|
image_new_shared(scene->width, scene->height, current_image);
|
||||||
|
|
||||||
|
// iterate over the rays
|
||||||
|
camera_iterate_rays_const_dist(*camera, scene->width, scene->height, threads, camera_iter_callback);
|
||||||
|
// or camera_iterate_rays_const_angle for lense distortion (this might not work correctly tho)
|
||||||
|
|
||||||
|
// return the drawn image
|
||||||
|
return current_image;
|
||||||
|
}
|
||||||
|
|
||||||
|
// march the ray, set the color. repeated for each direction generated by the camera
|
||||||
|
void camera_iter_callback(Point direction, int x, int y) {
|
||||||
|
Color c = march_ray(current_camera->location, direction, current_scene);
|
||||||
|
image_set_px_c(*current_image, x, y, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Color march_ray(Point origin, Point direction, Scene* scene) {
|
||||||
|
// some local variables
|
||||||
|
Point pos = origin;
|
||||||
|
double closest_encounter = DBL_MAX;
|
||||||
|
double dist = closest_encounter;
|
||||||
|
// the closest object we have
|
||||||
|
SceneObject* closest_obj = scene->objects;
|
||||||
|
|
||||||
|
// get steps, threshold from scene
|
||||||
|
int steps = scene->max_steps;
|
||||||
|
double threshold = scene->threshold;
|
||||||
|
|
||||||
|
// as long as we did not max out steps, or got very close to an object
|
||||||
|
while (steps > 0 && dist > threshold) {
|
||||||
|
dist = 100;
|
||||||
|
|
||||||
|
// find distance to closest object
|
||||||
|
for(int i = 0; i < scene->object_count; i++) {
|
||||||
|
// get pointer to scene obj
|
||||||
|
SceneObject* obj = scene->objects + i;
|
||||||
|
double curr_dist = scene->objects[i].distance(pos, obj);
|
||||||
|
|
||||||
|
// if we are close
|
||||||
|
if (curr_dist < dist) {
|
||||||
|
dist = curr_dist;
|
||||||
|
closest_obj = obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write down our closest encounter
|
||||||
|
if (dist < closest_encounter) closest_encounter = dist;
|
||||||
|
|
||||||
|
// scale direction vector to distance, then add it to our position
|
||||||
|
Point step_vector = pt_scale(direction, dist);
|
||||||
|
pt_add(&pos, step_vector);
|
||||||
|
|
||||||
|
// one step taken...
|
||||||
|
steps--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for a hit
|
||||||
|
if (dist <= threshold) {
|
||||||
|
// a hit!
|
||||||
|
return closest_obj->get_color(pos, direction, closest_obj);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// a miss :(
|
||||||
|
// this should be 0!
|
||||||
|
return scene->background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void scene_destroy(Scene scene) {
|
||||||
|
for (int i = 0; i < scene.object_count; i++) {
|
||||||
|
// free args memory
|
||||||
|
free(scene.objects[i].args);
|
||||||
|
}
|
||||||
|
free(scene.objects);
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue