Skip to content

Instantly share code, notes, and snippets.

@hikiko
Last active February 27, 2020 13:30
Show Gist options
  • Save hikiko/80b0d766dc8a9d67f6026a39eba9f51a to your computer and use it in GitHub Desktop.
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)
[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