A tiny software raymarcher that attempts to render "n-dimension" manofold insertions as an image appearing to be a non-euclidean 3-dimensional space. Written for the uqcs hackathon 2020. This repo is a mirror of: https://github.com/ailrst/blackpink
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

364 lines
9.5 KiB

#include "main.h"
#include "types.h"
#include "vect.h"
#include "camera.h"
#define SOFT_LIGHT 1
#define HARD_LIGHT 2
#define WHITE_LIGHT 2
double divid_fp(double a, double b) {
return a / b;
}
/*
*
* float sdEllipsoid( vec3 p, vec3 r )
{
float k0 = length(p/r);
float k1 = length(p/(r*r));
return k0*(k0-1.0)/k1;
}
*
*/
double sdf_4ellipsoid(struct vec *x) {
double r = 1;
struct vec *shape = new_vec4(1.5,3,1,4);
struct vec *v = copy_vec(x);
double dim = 0;
for (int i = 0 ; i < v->dimension; i ++) {
v->elements[i] = v->elements[i] / shape->elements[i];
}
double k0 = magnitude_vec(v);
free_vec(v);
v = copy_vec(x);
for (int i = 0 ; i < v->dimension; i ++) {
v->elements[i] = v->elements[i] / pow(shape->elements[i], 2);
}
double k1 = magnitude_vec(v);
double result = k0 * (k0 - 1.0) / k1;
free_vec(v);
return result;
}
double sdf_3ellipsoid(struct vec *x) {
double r = 1;
struct vec *shape = new_vec3(1.5,3,1);
struct vec *v = copy_vec(x);
double dim = 0;
for (int i = 0 ; i < 3; i ++) {
v->elements[i] = v->elements[i] / shape->elements[i];
}
double k0 = magnitude_vec(v);
free_vec(v);
v = copy_vec(x);
for (int i = 0 ; i < 3; i ++) {
v->elements[i] = v->elements[i] / pow(shape->elements[i], 2);
}
double k1 = magnitude_vec(v);
double result = k0 * (k0 - 1.0) / k1;
free_vec(v);
free_vec(shape);
return result;
}
double sdf_sphere(struct vec *x) {
static const double r = 1.4;
struct vec *v = copy_vec(x);
// v->elements[2] -= 5;
// v->elements[1] += (SDL_GetTicks()/1000.0) - 5;
// v->elements[2] -= 2;
// v->elements[1] += (SDL_GetTicks()/1000.0) - 5;
double res = magnitude_vec(v) - r;
free_vec(v);
return res;
}
double sdf_hplane(struct vec *x) {
static const double h = -0.5;
return -(x->elements[1] + h);
}
double clamp(double val, double min, double max) {
if (val < min)
return min;
if (val > max)
return max;
return val;
}
/*
double sdf_cone(struct vec *x) {
double height = 3;
struct vec *v = copy_vec(x);
double cx = 1;
double cy = 1;
static struct vec *cone = NULL;
static struct vec *w, *a, *b;
if (!cone) {
cone = scalar_multiply_vec_ip(new_vec2(cx/cy, -1), height);
}
struct vec *temp;
double cone2 =
struct vec * temp = new_vec2(v->e->x, v->e->z);
double aaa = magnitude_vec(temp);
free_vec(temp);
w = new_vec2(aaa, v->e->y);
double t2 = clamp((dot_product_vec(w, v) / dot_product_vec(cone, cone)), 0.0, 1.0);
temp = scalar_multiply_vec(cone, t2);
a = subtract_vec(w, temp);
free_vec(temp);
temp = new_vec2(clamp(w->e->x / cone->e->x, 0.0, 1.0), 1.0);
scalar_multiply_vec_ip(temp, )
double result = -1;
free_vec(v);
return result;
}
*/
double is_pos(double a) {
if (a > 0) {
return a;
}
return 0;
}
double sdf_phat_vert_line(struct vec *x) {
static const double h = 2;
static const double r = 0.5;
struct vec *v = copy_vec(x);
v->e->y -= clamp(v->e->y, 0.0, h);
double val = magnitude_vec(v) - r;
free_vec(v);
return val;
}
/* https://www.alanzucconi.com/2016/07/01/signed-distance-functions/#part3 */
/* http://mercury.sexy/hg_sdf/ */
double sdf_box(struct vec *x) {
struct vec *v = copy_vec(x);
do_on_vec_ip(v, fabs);
struct vec * box_shape = new_vec_of(v->dimension, 5);
subtract_vec_ip(box_shape, v);
do_on_vec_ip(v, is_pos);
double result = magnitude_vec(v);
free_vec(v);
free(box_shape);
return result;
}
struct colour yeet_pho(struct ray *ray, struct object *o) {
double specular = 0.8;
double diffuse = 0.55;
double ambient = 0.3;
double shin = 51;
int light_type = SOFT_LIGHT;
struct colour light_col = {.r = 200, .g = 0, .b = 100, .sp = CS_RGB};
//struct vec *light = new_vec4(-1, 1, 1, 0);
struct vec *light = copy_vec(camera->light);
//struct vec *light = add_vec_ip(new_vec4(50,50,-50,0), &o->sol.pos);
//struct vec *colour = new_vec3(o->base_col.r, o->base_col.g, o->base_col.b);
/* ambient */
//scalar_multiply_vec_ip(colour, ambient);
double intensity = ambient;
struct vec *surf_norm = estimateNormal(ray->pos, &o->sol);
// struct vec *light_vec = normalise_vec_ip(subtract_vec(ray->pos, light));
struct vec *light_vec = normalise_vec_ip(subtract_vec_ip(scalar_multiply_vec(light, -1), ray->pos));
double diffuse_val = clamp(dot_product_vec(light_vec, surf_norm) * diffuse, 0, 1);
// r = 2 * (l . n) * n - L
struct vec *camera_vec = normalise_vec_ip(scalar_multiply_vec(ray->pos, -1));
struct vec *reflection = scalar_multiply_vec(surf_norm,
2 * dot_product_vec(light_vec, surf_norm));
subtract_vec_ip(reflection, light_vec);
double spec_val = clamp(pow(clamp(dot_product_vec(reflection, camera_vec),-1,1), shin) * specular, 0, 1);
struct colour c = get_hsl(o->base_col);
intensity = ambient + diffuse_val + spec_val;
light_col = get_hsl(light_col);
light_col.l = spec_val;
light_col = get_rgb(light_col);
c.l = intensity;
c = get_rgb(c);
if (1 && spec_val > 0.0) {
if (light_type == HARD_LIGHT) {
c.r = light_col.r > c.r ? c.r + (light_col.r - c.r) / 2 : c.r;
c.g = light_col.g > c.g ? c.g + (light_col.g - c.g) / 2 : c.g;
c.b = light_col.b > c.b ? c.b + (light_col.b - c.b) / 2 : c.b;
} else if (light_type == SOFT_LIGHT) {
c.r = light_col.r > c.r ? light_col.r: c.r;
c.b = light_col.b > c.b ? light_col.b: c.b;
c.g = light_col.g > c.g ? light_col.g: c.g;
}
}
free_vec(camera_vec);
free_vec(reflection);
free_vec(surf_norm);
free_vec(light_vec);
free_vec(light);
return c;
}
struct colour yeet_col_og(struct ray *ray, struct object *obj) {
struct vec *l = new_vec4(1,1,1,1);
struct vec *n = subtract_vec_ip(l, ray->pos);
struct vec *nl = normalise_vec(l);
struct colour c = {.r = nl->e->x * 555, .g = nl->e->y * 555, .b = nl->e->z * 555, .a = 255, .sp=CS_RGB};
free_vec(n);
return (c);
}
/*
struct object new_sphere(double radius) {
struct object s;
struct vec * v = new_vec4(0,0,5,0);
s.base_col = get_random_color();
s.sol.pos = *v;
s.sol.op = B_ADD;
s.col = yeet_pho;
s.sol.dist = sdf_sphere;
return s;
*/
/**
* Creates a new struct object with the given parameters. The position passed
* in should be a vec4 as this is converted to a vec3 when the object is added
* to the scene.
*/
struct object
new_object(struct vec* position, double rotation, double scale,
double (*dist)(struct vec*), struct colour (*col)(struct ray *, struct object *))
{
struct object new_obj;
struct colour default_col = {.r = 255, .g=255, .b=255, .a=255, .sp=CS_RGB};
new_obj.base_col = default_col;
new_obj.col = col;
new_obj.sol.dist = dist;
new_obj.sol.pos = *position;
new_obj.sol.rotation = rotation;
new_obj.sol.scale = scale;
new_obj.sol.op = B_ADD;
return new_obj;
}
struct colour yeet_whit(struct ray *ray, struct object* obj) {
struct colour c = {.r = 200, .g = 200, .b = 0, .a = 255, .sp=CS_RGB};
return c;
}
struct object new_plane(struct vec* position, double rotation, double scale) {
return new_object(position, rotation, scale, sdf_hplane, yeet_whit);
}
struct object new_sphere(struct vec* position, double rotation, double scale) {
return new_object(position, rotation, scale, sdf_sphere, yeet_pho);
}
struct object new_ellipse(struct vec* position, double rotation, double scale) {
return new_object(position, rotation, scale, sdf_3ellipsoid, yeet_pho);
}
struct object new_box(struct vec* position, double rotation, double scale) {
return new_object(position, rotation, scale, sdf_box, yeet_pho);
}
/* DON'T CALL THIS */
struct object new_cone(struct vec* position, double rotation, double scale) {
return new_object(position, rotation, scale, NULL, NULL);
}
struct object new_vert_line(struct vec* position, double rotation, double scale) {
return new_object(position, rotation, scale, sdf_phat_vert_line, yeet_pho);
}
struct colour yeet_green(struct ray *ray, struct object* obj) {
struct colour c = {.r = 0, .g = (rand() % 127) + 127, .b = 0, .a = 255, .sp=CS_RGB};
return c;
}
struct colour yeet_brown(struct ray *ray, struct object* obj) {
struct colour c = {.r = 210, .g = 105, .b = 30, .sp=CS_RGB};
return c;
}
/**
* The absolute jankiest way to make a tree but I couldn't think of anything
* better.
*
* Returns a pointer to the first element of an array of the components of the
* tree (trunk and leaves). Iterate over the array when adding to a scene.
*/
struct object* new_tree(struct vec* position, double rotation, double scale) {
struct object* tree = malloc(2 * sizeof(struct object));
struct object trunk = new_object(position, rotation, scale, sdf_phat_vert_line, yeet_pho);
trunk.base_col = (struct colour){.r = 0x92, .g = 0x2D, .b = 0x50, .sp = CS_RGB};
trunk.base_col.g += rand() % 20;
struct vec* leaf_pos = add_vec_ip(new_vec3(0, -1.5, 0), position);
struct object leaves = new_object(leaf_pos, rotation, scale, sdf_3ellipsoid, yeet_pho);
leaves.base_col = (struct colour){.r = 0xC0, .g = 0xDA, .b = 0x74, .sp = CS_RGB};
// leaves.base_col = (struct colour){.r = 30 + random() % 20, .g = 155 + random() % 100, .b = random() % 90, .sp = CS_RGB};
tree[0] = trunk;
tree[1] = leaves;
return tree;
}