Skip to content

Instantly share code, notes, and snippets.

@benhardy
Created April 29, 2019 21:37
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 benhardy/b58b463d24d2249dd6e53bdbc24b9dde to your computer and use it in GitHub Desktop.
Save benhardy/b58b463d24d2249dd6e53bdbc24b9dde to your computer and use it in GitHub Desktop.
#define MAX_STEPS 100000
#define MAX_DIST 300.0f
#define EPSILON 0.001f
#define ID_SPHERE 1
#define ID_BIZZO 2
#define ID_FLOOR 3
#define ID_COLUMN 4
#define BIZZO_ITERATIONS 6
float measure_floor(float3 where);
float cmod(float x, float r);
float2 dist_bizzo(float3 where, float iTime);
float measure_column(float3 where);
float3 measure(float3 where, float iTime);
float3 calc_surface_normal(float3 hit, float iTime);
float dist_opening(float3 pos);
float dist_surrounding_sphere(float3 where);
float round_box(float3 where, float3 dims, float rounding);
float dist_balcony(float3 pos);
float measure_floor(float3 where) {
return where.y + 1.0f;
}
float cmod(float x, float r) {
x = x/r + 0.5;
return (x-floor(x)-0.5) * r;
}
float round_box(float3 where, float3 dims, float rounding) {
return length(fmax(0.0f, fabs(where) - dims)) - rounding;
}
float dist_balcony(float3 pos) {
float r_min = 95;
float r_max = 105;
float r = length(pos.xz);
float cyl = max(r - r_max, - (r - r_min));
return fmax(cyl, fmax(pos.y, -pos.y - 1));
}
float dist_opening(float3 pos) {
pos.y -= 6.0;
pos.xz = fabs(pos.xz);
//pos.x += 100.0;
float3 dims = { 120, 5.0, 50 };
float op = round_box(pos, dims, 1.0);
return op;
}
float dist_surrounding_sphere(float3 where) {
float ball = length(where) -100.0f;
//float clearing = fmax(fabs(where.y) - 3.0f;
float op = dist_opening(where);
float walls = fmax(-ball, -op);
float2 edging = { ball, op-0.9 };
float2 edgebox = { 0.9, 0.9 };
float edge_d = length(max(0.0,fabs(edging)-edgebox));
walls = fmin(walls, edge_d);
//where.y += 3.0;
//float with_b = fmin(walls, dist_balcony(fabs(where)));
float w = fmin(walls, dist_balcony(where));
return w;
}
__constant float3 box_size = { 1.7, 0.7, 2.7 };
__constant float3 hole_size = { 1, 0.5, 4 };
__constant float3 box_top_size = { 1, 0.5, 2.2 };
float2 dist_bizzo(float3 where, float iTime) {
float d = length(where) -1.0;
float ratio = 1.75 + 0.1 * sin(iTime * 0.13f);
float a2 = 1.0 + 1.0 * sin(iTime *0.49f) + 0.5f * where.y;
float s2 = sin(a2);
float c2 = cos(a2);
float a3 = 1.0 * sin(iTime *0.29f) + 0.15f * 0.5 * where.x ;
float s3 = sin(a3);
float c3 = cos(a3);
float a = 1.0 + sin(iTime * 0.39f) + 0.15f * cos(where.z);
float s = sin(a);
float c = cos(a);
float depth = 0.0;
float3 displacement = {
-2.2f + c,
2.5f + 0.9f * s,
-1.5f + 0.9f * sin(iTime * 0.13f)
};
for (int i = 0; i <BIZZO_ITERATIONS; i++) {
const float3 w2 = {
mad(c3, mad(c2, where.x, - s2 * where.z), - s3 * where.y),
mad(s3, mad(c2, where.x, - s2 * where.z), + c3 * where.y),
mad(s2, where.x, c2 * where.z)
};
// a bit of good old fashioned space foldin' & swizzlin'
where = -fabs(w2);
where.xz = -where.zx;
// shit gets real here, i guess you'd call it hyperbolic warping
where.y = -5.0/mad(length(where.yz), length(where.yz), 1.0f);
// shrink and displace for this fractal level
where = mad(where, ratio, displacement);
// actual measurement for this fractal level
float j = 0.5 * (length(where) -1.0) / ratio;
// blend function body, disassembled so we can make a fractional depth measurement for coloring
float k = 0.2;
float h = fmax( k - fabs(d - j), 0.0f );
float together = fmin(d, j);
d= together - h*h*0.25f/k;
float progress = clamp((j-d)/k, 0.0f, 1.0f);
depth+=progress;
}
return (float2)(d, depth+1);
}
float measure_column(float3 where) {
where.z = cmod(where.z, 25.0f);
where.x = cmod(where.x, 25.0f);
float s = sin(where.y);
float c = cos(where.y);
float3 w2 = {
c * where.x - s * where.z,
where.y,
s * where.x + c * where.z
};
float3 w3 = {
fabs(w2.x)-0.2,
w2.y,
fabs(w2.z)-0.2
};
return length(w3.xz) - 0.2f;
}
float3 measure(float3 where, float iTime) {
float closestDist = MAX_DIST;
float what = 0;
float d;
float extra = 0;
/*float d = measure_floor(where);
if (d < closestDist) {
closestDist = d;
what = ID_FLOOR;
}
*/
float2 biz = dist_bizzo(where, iTime);
if (biz.x < closestDist) {
closestDist = biz.x;
what = ID_BIZZO;
extra = biz.y;
}
d = dist_surrounding_sphere(where);
if (d < closestDist) {
closestDist = d;
what = ID_SPHERE;
}
/*
d = measure_column(where);
if (d < closestDist) {
closestDist = d;
what = ID_COLUMN;
}
*/
float3 res = { closestDist, what, extra };
return res;
}
__constant float4 color_box_top = { 0.2, 0.87, 0.9, 0.5 };
__constant float4 color_box_bot = { 0.40, 0.42, 0.6, 0.75 };
__constant float4 color_outer_walls = { 0.8, 0.8, 0.8, 0.75 };
__constant float4 bizzo_color = { 0.05, 0.2, 0.16, 0.2 };
__constant float4 bizzo_lightening_color = { 1,1,0.5,1 };
__kernel void raymarchDemo2(
__global uint *output,
int sizeX, int sizeY,
float eyeX, float eyeY, float eyeZ,
float lookX, float lookY, float lookZ,
float stepRatio,
float iTime
)
{
// pixel coordinates
const int ix = get_global_id(0);
const int iy = get_global_id(1);
const float3 eye = { eyeX, eyeY, eyeZ };
const float3 look = normalize((float3)(lookX, lookY, lookZ));
const float3 cameraUp = { 0, 1, 0 };
const float x_pixel = (float)ix / sizeX - 0.5;
const float y_pixel = -((float)iy / sizeY - 0.5) * (float)sizeY / sizeX;
const float3 right = normalize(cross(cameraUp, look));
const float3 actual_up = normalize(cross(look, right));
const float3 ray = normalize(look + (right * x_pixel) + (actual_up * y_pixel));
float t = 0.0;
int hitId = 0;
float3 hitInfo;
float3 where = eye;
for (int step = 0; step < MAX_STEPS && t < MAX_DIST; step++) {
where = eye + (t * ray);
hitInfo = measure(where, iTime);
if (hitInfo.x < EPSILON) {
hitId = (int)(hitInfo.y);
break;
}
t += (stepRatio * hitInfo.x);
}
float4 pigment;
switch(hitId) {
case ID_FLOOR: {
int level = ((int)floor(where.x) ^ (int)floor(where.z)) & 0x01;
pigment = (float4)(
1,
level,
level,
0.5
);
break;
}
case ID_BIZZO: {
pigment = bizzo_color + (hitInfo.z/BIZZO_ITERATIONS) * bizzo_lightening_color;
break;
}
case ID_SPHERE: {
float3 pp = where / 10.0f;
int level = ((int)floor(pp.x) ^ (int)floor(pp.y) ^ (int)floor(pp.z)) & 0x01;
pigment = color_outer_walls * (1.0f + 0.1f * level);
break;
}
case ID_COLUMN: {
pigment = (float4)(
1,
1,
0,
0.5
);
break;
}
default: {
pigment = (float4)(0,0,0,1);
break;
}
}
float3 lightDir = normalize((float3)( -1, 3, -2));
float3 norm = calc_surface_normal(where, iTime);
float ambient = pigment.w;
float diffuse = (1.0f - ambient) * fmax(0.0f, dot(lightDir, norm));
float3 reflected = norm * 2.0f * dot(lightDir, norm) - lightDir;
float specular = pow(fmax(0.0f, dot(-ray, reflected)), 32.0f);
float3 specColor = { specular, specular, specular };
float4 color = (pigment * (diffuse + ambient) + specular) * (1.0f - t/MAX_DIST);
color = clamp(color, 0.0f, 1.0f) * 255;
output[iy*sizeX+ix] = ((int)(color.x)<<16) | ((int)(color.y)<<8) | ((int)(color.z)) | ((int)(color.z)<<24);
}
#define NORMAL_DELTA 0.001
__constant float3 normalBumpX = { NORMAL_DELTA, 0, 0 };
__constant float3 normalBumpY = { 0, NORMAL_DELTA, 0 };
__constant float3 normalBumpZ = { 0, 0, NORMAL_DELTA };
float3 calc_surface_normal(float3 hit, float iTime) {
return normalize((float3)(
measure(hit+normalBumpX, iTime).x - measure(hit-normalBumpX, iTime).x,
measure(hit+normalBumpY, iTime).x - measure(hit-normalBumpY, iTime).x,
measure(hit+normalBumpZ, iTime).x - measure(hit-normalBumpZ, iTime).x
));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment