You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
168 lines
4.2 KiB
C
168 lines
4.2 KiB
C
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "images/src/images.h"
|
|
#include "src/scene.h"
|
|
#include "src/camera.h"
|
|
#include "src/point.h"
|
|
|
|
#define SCENE_MOD 2
|
|
|
|
|
|
/*
|
|
|
|
Infinite circle scene object
|
|
|
|
This circle repeats every SCENE_MOD units in all directions
|
|
|
|
It has some basic shading, calculation the hit angle and making shallower impacts darker
|
|
|
|
*/
|
|
|
|
double circle_dist(struct point x, struct scene_object *self) {
|
|
double r = self->args[0];
|
|
return pt_dist(pt_mod(x, SCENE_MOD), self->location) - r;
|
|
}
|
|
|
|
Color circle_color(struct point hit, struct point direction, struct scene_object *self) {
|
|
struct point obj_direction = self->location;
|
|
|
|
obj_direction = 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) 120));
|
|
|
|
return color;
|
|
}
|
|
// constructs the scene object
|
|
struct scene_object circle_new(struct point loc, double radius) {
|
|
double * args = malloc(sizeof (double) * 2);
|
|
args[0] = radius;
|
|
return (struct scene_object) {
|
|
.location = loc,
|
|
.args = args,
|
|
.distance = circle_dist,
|
|
.get_color = circle_color,
|
|
.color = color_new(255, 255, 255),
|
|
};
|
|
}
|
|
|
|
|
|
/*
|
|
|
|
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 = self->args[0];
|
|
double power = self->args[1];
|
|
|
|
struct point z = pt;
|
|
float dr = 1.0;
|
|
float r = 0.0;
|
|
for (int i = 0; i < iters ; i++) {
|
|
r = pt_length(z);
|
|
|
|
if (r>2) {
|
|
break;
|
|
}
|
|
|
|
// convert to polar coordinates
|
|
float theta = acos(z.z/r);
|
|
float phi = atan2(z.y,z.x);
|
|
dr = pow(r, power-1.0)*power*dr + 1.0;
|
|
|
|
// scale and rotate the point
|
|
float zr = pow(r, power);
|
|
theta = theta*power;
|
|
phi = phi*power;
|
|
|
|
// convert back to cartesian coordinates, add zr and the old pt
|
|
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) {
|
|
double * args = malloc(sizeof(double) * 3);
|
|
args[0] = iters;
|
|
args[1] = power;
|
|
args[2] = -1;
|
|
|
|
return (struct scene_object) {
|
|
.location= location,
|
|
.args= args,
|
|
.distance= mandelbulb_dist,
|
|
.get_color= mandelbulb_color,
|
|
.color= color_new(255,255,255),
|
|
};
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
float dpi = 200;
|
|
|
|
int threads = 32;
|
|
int size = dpi * 27.56f; // 400dpi by 70cm size
|
|
float pow = 3;
|
|
float cam_position = 1.35;
|
|
int steps = 1000;
|
|
int iters = 500;
|
|
float threshold = 0.001;
|
|
char path[80];
|
|
|
|
|
|
// get params from cli
|
|
if (argc < 5) {
|
|
return 1;
|
|
}
|
|
pow = atof(argv[1]);
|
|
steps = atoi(argv[2]);
|
|
iters = atoi(argv[3]);
|
|
threshold = atof(argv[4]);
|
|
|
|
sprintf(path, "tries/pow%.2f-%ist-%iit-%.5fth-%.0fdpi.bmp", pow, steps, iters, threshold, dpi);
|
|
|
|
printf("Rendering to %s\n", path);
|
|
|
|
struct camera cam;
|
|
cam.fov = 90;
|
|
|
|
camera_set_looking_at(&cam, (struct point){.x=cam_position, .y= 0, .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, circle_new(pt_new(SCENE_MOD / 2.0, SCENE_MOD/ 2.0, SCENE_MOD / 2.0), .2));
|
|
|
|
scene_add_obj(&scene, mandelbulb_new(PT_ZERO, iters, pow));
|
|
|
|
Image *img = render_scene(&scene, &cam, threads);
|
|
|
|
image_save_bmp(*img, path);
|
|
|
|
image_destroy(*img);
|
|
scene_destroy(scene);
|
|
|
|
return 0;
|
|
}
|