Last active
February 27, 2020 13:30
-
-
Save hikiko/80b0d766dc8a9d67f6026a39eba9f51a to your computer and use it in GitHub Desktop.
A vkrunner compatible shader_test that draws a field of mushrooms by performing ray marching in distance fields. (WIP)
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] | |
fbsize 800 600 | |
[vertex shader passthrough] | |
[fragment shader] | |
#version 450 | |
layout(location = 0) out vec4 out_color; | |
#ifdef SDRVIEWER | |
uniform mat4 cam_xform; | |
#endif | |
#define T 0.0001 | |
#define STEP 0.02 | |
#define FOV 45.0 | |
#define M_PI 3.14159 | |
#define MAX_STEPS 1500 | |
#define GRAD_DELTA (STEP / 2.0) | |
#define OBJ_NULL 0 | |
#define OBJ_MUSHROOM_TOP 1 | |
#define OBJ_MUSHROOM_BOTTOM 2 | |
#define OBJ_MUSHROOM_STEM 3 | |
#define OBJ_GROUND 4 | |
const vec2 res = vec2(800.0, 600.0); | |
float pnoise(vec2 P, vec2 rep); | |
float cnoise(vec2 P); | |
float noised(vec2 P); | |
float ground_height(vec2 point) | |
{ | |
return noised(point * 0.1) * 3.0; | |
} | |
/* dist from nearest object */ | |
float calc_dist_mushroom(in vec3 point, out int obj_id) | |
{ | |
const float sph_radius = 1.0; | |
const float bigsph_radius = 50.0; | |
const float sep = 5.6; //dist between 2 mushrooms | |
const float hsep = sep / 2.0; | |
vec2 cell_pt = floor((point.xz + vec2(hsep, hsep)) / sep) * sep; | |
vec2 cell_pt2 = cell_pt * 7.32; | |
vec2 cell_noise = vec2(noised(cell_pt2 + 3.48), | |
noised(cell_pt2 + 25.72)); | |
vec3 scale = vec3(1.0, 1.0, 1.0); /* vec3(cell_noise.x, cell_noise.y, cell_noise.x) * | |
vec3(0.4, 0.6, 0.4) + vec3(1.0, 1.0, 1.0);*/ | |
vec2 xzoffs = cell_noise * (hsep - sph_radius * max(scale.x, scale.z)); | |
vec3 p = vec3(mod(point.x + hsep, sep) - hsep, point.y, | |
mod(point.z + hsep, sep) - hsep) * scale; | |
p.x += xzoffs.x; | |
p.z += xzoffs.y; | |
p.y -= ground_height(cell_pt - xzoffs); | |
vec3 cap_pt = p * vec3(1.0, 1.5, 1.0); | |
float dsph_small = sqrt(dot(cap_pt, cap_pt)) - sph_radius; | |
vec3 bigsph_center = vec3(0.0, bigsph_radius - 0.2, 0.0); | |
vec3 dvec = bigsph_center - cap_pt; | |
float dsph_big = sqrt(dot(dvec, dvec)) - bigsph_radius; | |
float stem_radius = 0.7; | |
vec3 stem_center = vec3(0.0, -0.3, 0.0); | |
float stem_scale = clamp((p.y - stem_center.y) / stem_radius + 2.0, 1.0, 3.0) * 1.1; | |
vec3 stem_pt = p * vec3(stem_scale, 1.0, stem_scale); | |
dvec = stem_center - stem_pt; | |
float dist_stem = sqrt(dot(dvec, dvec)) - stem_radius; | |
float dist; | |
if(dsph_small > dsph_big) { | |
obj_id = OBJ_MUSHROOM_TOP; | |
dist = dsph_small; | |
} else { | |
obj_id = OBJ_MUSHROOM_BOTTOM; | |
dist = dsph_big; | |
} | |
if(dist_stem < dist) { | |
obj_id = OBJ_MUSHROOM_STEM; | |
dist = dist_stem; | |
} | |
return dist; | |
} | |
float calc_dist_ground(in vec3 point, out int obj_id) | |
{ | |
obj_id = OBJ_GROUND; | |
const float ground_height = -0.9 + ground_height(point.xz); | |
return point.y - ground_height; | |
} | |
float calc_dist(in vec3 point, out int obj_id) | |
{ | |
int mush_id; | |
float mush_dist = calc_dist_mushroom(point, mush_id); | |
int ground_id; | |
float ground_dist = calc_dist_ground(point, ground_id); | |
float dist = ground_dist; | |
obj_id = ground_id; | |
if (mush_dist < dist) { | |
obj_id = mush_id; | |
dist = mush_dist; | |
} | |
return dist; | |
} | |
vec3 bg_color(in vec2 uv) | |
{ | |
return vec3(1.0, 0.8, 0.05); | |
} | |
vec3 shade(in vec3 pos, in vec3 normal, in int obj_id) | |
{ | |
return normal * 0.5 + 0.5; | |
switch(obj_id) { | |
case OBJ_MUSHROOM_TOP: | |
return vec3(0.9, 0.0, 0.0); | |
case OBJ_MUSHROOM_BOTTOM: | |
return vec3(0.15, 0.15, 0.3); | |
case OBJ_MUSHROOM_STEM: | |
return vec3(0.0, 0.6, 0.1); | |
case OBJ_GROUND: | |
return vec3(0.5, 0.25, 0.0); | |
default: | |
return vec3(0.1, 0.1, 0.1); | |
} | |
} | |
vec3 calc_normal(in vec3 pos, in float dist) | |
{ | |
int tmp; | |
float dfdx = calc_dist(pos + vec3(GRAD_DELTA, 0.0, 0.0), tmp) - dist; | |
float dfdy = calc_dist(pos + vec3(0.0, GRAD_DELTA, 0.0), tmp) - dist; | |
float dfdz = calc_dist(pos + vec3(0.0, 0.0, GRAD_DELTA), tmp) - dist; | |
return normalize(vec3(dfdx, dfdy, dfdz)); | |
} | |
void main() | |
{ | |
vec2 uv = gl_FragCoord.xy / res; | |
float aspect = res.x / res.y; | |
float half_fov = (FOV / 180.0 * M_PI) / 2.0; | |
float viewplane_dist = 1.0 / tan(half_fov); | |
vec3 dir; | |
dir.x = aspect * (uv.x * 2.0 - 1.0); | |
dir.y = 1.0 - uv.y * 2.0; | |
dir.z = viewplane_dist; | |
dir = normalize(dir); | |
#ifdef SDRVIEWER | |
dir = mat3(cam_xform) * dir; | |
vec3 pos = (cam_xform * vec4(0.0, 0.0, 0.0, 1.0)).xyz; | |
#else | |
vec3 pos = vec3(-5.14, 3.88, -10.46); //cam pos | |
#endif | |
int obj_id = OBJ_NULL; | |
float dist; | |
for(int i=0; i<MAX_STEPS; i++) { | |
int id; | |
dist = calc_dist(pos, id); | |
if(dist <= T) { | |
obj_id = id; | |
break; | |
} | |
pos += dir * STEP; | |
} | |
if(obj_id == OBJ_NULL) { | |
out_color = vec4(bg_color(uv), 1.0); | |
} else { | |
vec3 normal = calc_normal(pos, dist); | |
out_color = vec4(shade(pos, normal, obj_id), 1.0); | |
} | |
} | |
// These noise functions are modifications of these ones | |
// from Inigo Quilez: https://www.shadertoy.com/view/XsXfRH | |
float hash(in vec2 p) | |
{ | |
p = 50.0*fract( p*0.3183099 + vec2(0.71,0.113)); | |
return -1.0+2.0*fract(p.x*p.y*(p.x+p.y)); | |
} | |
float noised(in vec2 x) | |
{ | |
vec2 p = floor(x); | |
vec2 w = fract(x); | |
#if 0 | |
// quintic interpolation | |
vec2 u = w*w*w*(w*(w*6.0-15.0)+10.0); | |
vec2 du = 30.0*w*w*(w*(w-2.0)+1.0); | |
#else | |
// cubic interpolation | |
vec2 u = w*w*(3.0-2.0*w); | |
vec2 du = 6.0*w*(1.0-w); | |
#endif | |
float a = hash(p+vec2(0.0,0.0)); | |
float b = hash(p+vec2(1.0,0.0)); | |
float c = hash(p+vec2(0.0,1.0)); | |
float d = hash(p+vec2(1.0,1.0)); | |
float k0 = a; | |
float k1 = b - a; | |
float k2 = c - a; | |
float k3 = a - b - c + d; | |
return k0 + k1*u.x + k2*u.y + k3*u.x*u.y; | |
} | |
[test] | |
draw rect -1 -1 2 2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment