Last active
May 6, 2019 17:08
-
-
Save hikiko/af4c179a1ca3954585a855307ab92f7e to your computer and use it in GitHub Desktop.
A vkrunner compatible shader test that renders a mandelbulb fractal (ray marching).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[require] | |
vulkan 1.1.3 | |
fbsize 800 600 | |
[vertex shader passthrough] | |
[fragment shader] | |
#version 450 | |
#define T 0.001 //threshold | |
#define MAX_POS 1000.0 | |
#define MAX_STEPS 500 | |
#define MAX_STEP_SIZE 0.3 | |
#define DELTA 0.001 | |
#define M_PI 3.14168 | |
#define NUM_ITER 50 | |
#define POWER 9.0 | |
#define MAX_ITER 100.0 | |
#define AO_STEP 0.05 | |
#define AO_MAGIC 8.0 | |
const vec3 bcolor = vec3(0.0, 0.0, 0.03); | |
const vec3 ldir = vec3(1.0, 1.0, -1.5); | |
const vec3 fcolor = vec3(0.1, 0.46, 0.52); | |
const vec2 iResolution = vec2(800.0, 600.0); | |
vec3 get_ray_direction(in vec2 uv, in float z) | |
{ | |
float aspect = iResolution.x / iResolution.y; | |
return normalize(vec3(aspect * (uv.x - 0.5) * 2.0, (uv.y - 0.5) * 2.0, z)); | |
} | |
float frac_distance(vec3 pos) | |
{ | |
// from iq's blog post here: | |
// https://www.iquilezles.org/www/articles/mandelbulb/mandelbulb.htm | |
vec3 p = pos; | |
float dr = 1.0; | |
float r = 1.0; | |
for(int i=0; i<NUM_ITER; i++) { | |
r = length(p); | |
if(r > MAX_ITER) { | |
break; | |
} | |
// conversion to polar coordinates | |
float theta = acos(p.z/r); | |
float phi = atan(p.y, p.x); | |
dr = pow(r, POWER - 1.0) * POWER * dr + 1.0; | |
// scale and rotate the point | |
float pr = pow(r, POWER); | |
theta = theta * POWER; | |
phi = phi * POWER; | |
// conversion to cartesian coordinates | |
p = pr * vec3(sin(theta) * cos(phi), sin(phi) * sin(theta), cos(theta)); | |
p += pos; | |
} | |
return 0.5 * log(r) * r/dr; | |
} | |
float min_distance(vec3 position) | |
{ | |
return frac_distance(position); | |
// distance from sphere for test | |
vec3 fish_local_pos = position * vec3(0.4, 1.0, 2.0); //warped | |
float radius = 3.0; | |
float sph_distance = length(fish_local_pos) - radius; | |
return sph_distance; | |
} | |
float ambient_occlusion(in vec3 pos, in vec3 normal) | |
{ | |
float ao = 0.0; | |
for(int i=0; i<5; i++) { | |
// step away from the surface | |
float sample_dist = float(i) * AO_STEP; | |
vec3 new_pos = pos + sample_dist * normal; | |
float dist = frac_distance(new_pos); | |
float dist_diff = max(sample_dist - dist, T); | |
ao += 1.0 / pow(2.0, float(i)) * dist_diff; | |
} | |
ao = 1.0 - AO_MAGIC * ao; | |
return clamp(ao, 0.0, 1.0); | |
} | |
vec3 shade(in vec3 pos, in vec3 normal, in vec3 color) | |
{ | |
/* | |
float ndotl = max(dot(normal, normalize(ldir)), 0.0); | |
vec3 diffuse = fcolor * ndotl; | |
return diffuse; | |
*/ | |
return ambient_occlusion(pos, normal) * color; | |
} | |
vec3 ray_march(vec3 pos, vec3 dir, vec3 color) | |
{ | |
float dist; | |
int steps = 0; | |
while((dist = min_distance(pos)) > T) { | |
pos += dir * min(dist, MAX_STEP_SIZE); | |
++steps; | |
if((steps > MAX_STEPS) || (dot(pos, pos) > MAX_POS * MAX_POS)) { | |
return bcolor; | |
} | |
} | |
/* normal = grad = vec3(af/ax, af/ay, af/az) */ | |
float dfdx = min_distance(pos + vec3(DELTA, 0.0, 0.0)) - dist; | |
float dfdy = min_distance(pos + vec3(0.0, DELTA, 0.0)) - dist; | |
float dfdz = min_distance(pos + vec3(0.0, 0.0, DELTA)) - dist; | |
vec3 normal = normalize(vec3(dfdx, dfdy, dfdz)); | |
return shade(pos, normal, color); | |
} | |
layout(location = 0) out vec4 fragColor; | |
void main() | |
{ | |
vec2 uv = gl_FragCoord.xy / iResolution.xy; | |
vec3 rd = get_ray_direction(uv, 2.0); | |
vec3 origin = vec3(0.0, 0.0, -3.0); | |
float theta = M_PI; // -(iMouse.x / iResolution.x) * 8.0; | |
float phi = M_PI;//((iMouse.y / iResolution.y) * 2.0 - 1.0) * M_PI; | |
mat3 rot_x = mat3(cos(theta), 0.0, sin(theta), | |
0.0, 1.0, 0.0, | |
-sin(theta), 0.0, cos(theta)); | |
mat3 rot_y = mat3(1.0, 0.0, 0.0, | |
0.0, cos(phi), -sin(phi), | |
0.0, sin(phi), cos(phi)); | |
mat3 cam_trans = rot_x * rot_y; | |
vec3 color = vec3(1.0, 207.0 / 255.0, 0.0); //normalize(vec3(sin(theta) + 1.0 / AO_MAGIC, cos(phi) + 1.0 / AO_MAGIC, sin(phi + theta) + 1.0 / AO_MAGIC)); | |
fragColor.rgb = ray_march(/*cam_trans */ origin, cam_trans * rd, color); | |
fragColor.a = 1.0; | |
} | |
[test] | |
clear | |
draw rect -1 -1 2 2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment