Skip to content

Instantly share code, notes, and snippets.

@mrange
Last active October 9, 2019 04:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrange/00ffeac975a195295797f742242592c7 to your computer and use it in GitHub Desktop.
Save mrange/00ffeac975a195295797f742242592c7 to your computer and use it in GitHub Desktop.
impulse box
#version 150
in VertexData
{
vec4 v_position;
vec3 v_normal;
vec2 v_texcoord;
} inData;
out vec4 fragColor;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
uniform vec2 iResolution;
uniform float iTime;
uniform float iTimeDelta;
uniform int iFrame;
uniform vec4 iMouse;
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform sampler2D iChannel2;
uniform sampler2D iChannel3;
uniform vec4 iDate;
uniform float iSampleRate;
void mainImage(out vec4, in vec2);
void main(void) { mainImage(fragColor,inData.v_texcoord * iResolution.xy); }
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// Based of https://www.shadertoy.com/view/4sX3Rn
// Raymarching explained: http://9bitscience.blogspot.com/2013/07/raymarching-distance-fields_14.html
// Distance Estimators: www.iquilezles.org/www/articles/distfunctions/distfunctions.htm
#define TOLERANCE 0.001
#define NORM_OFF 0.001
#define MAX_RAY_LENGTH 6.0
#define MAX_RAY_MARCHES 70
#define PI 3.141592654
#define TAU (2.0*PI)
#define BOXSIZE 0.2
#define FADE_BOX_ROTATE_BEGIN 10.0
#define FADE_BOX_ROTATE_END 20.0
#define TIME (iTime*0.2)
vec3 saturate(in vec3 a) { return clamp(a, 0.0, 1.0); }
vec2 saturate(in vec2 a) { return clamp(a, 0.0, 1.0); }
float saturate(in float a) { return clamp(a, 0.0, 1.0); }
vec3 toSpherical(vec3 p)
{
float l = length(p);
return vec3(length(p), acos(p.z/l), atan(p.y, p.x));
}
vec3 toRectangular(vec3 p)
{
float l = length(p);
return vec3(p.x*sin(p.y)*cos(p.z), p.x*sin(p.y)*sin(p.z), p.x*cos(p.y));
}
vec3 mod3(inout vec3 p, vec3 size)
{
vec3 c = floor((p + size*0.5)/size);
p = mod(p + size*0.5, size) - size*0.5;
return c;
}
float maxComp(in vec3 p)
{
return max(p.x,max(p.y,p.z));
}
float maxComp(in vec2 p)
{
return max(p.x, p.y);
}
void rot(inout vec2 v, in float a)
{
float c = cos(a);
float s = sin(a);
v.xy = vec2(v.x*c + v.y*s, -v.x*s + v.y*c);
}
float unionRound(float a, float b, float r)
{
vec2 u = max(vec2(r - a,r - b), vec2(0));
return max(r, min (a, b)) - length(u);
}
float softMin(in float a, in float b, in float k)
{
float res = exp( -k*a ) + exp( -k*b );
return -log( res )/k;
}
float sdSphere(in vec3 p, in float r)
{
return length(p) - r;
}
float sdBox(in vec3 p, in vec3 b)
{
vec3 di = abs(p) - b;
float mc = maxComp(di);
return min(mc,length(max(di,0.0)));
}
float sdSoftBox(in vec3 p, in float r)
{
p *= p;
p *= p;
p *= p;
return pow(p.x + p.y + p.z, 1.0/8.0) - r;
}
float sdCross(in vec3 p)
{
float da = maxComp(abs(p.xy));
float db = maxComp(abs(p.yz));
float dc = maxComp(abs(p.zx));
return min(da,min(db,dc))-1.0;
}
float sdPlane(in vec3 p, in vec3 n, in float m)
{
return dot(p, n) + m;
}
void nerdRotate(inout vec3 p)
{
float a2 = 2.0*TIME/sqrt(2.0);
float a3 = 1.0*TIME/sqrt(3.0);
float a5 = 0.5*TIME/sqrt(5.0);
rot(p.yz, a5);
rot(p.xy, -a3);
rot(p.xz, -a2);
}
float impulseCube(in vec3 p, in float celld, in float celll, out int m)
{
vec3 bp = p;
float cs = BOXSIZE*0.8;
float cd = max(length(p.xy) - cs*0.3, sdSphere(bp, 1.2*BOXSIZE));
float hbd = min(max(sdSoftBox(bp, BOXSIZE), -sdCross(bp/cs)*cs), cd);
float bbd = sdBox(bp, vec3(cs));
vec3 rbp = toSpherical(bp);
rbp.y += TIME*0.5;
bp = toRectangular(rbp);
vec3 cell = mod3(bp, vec3(cs*celld));
float id = sdSoftBox(bp, cs*celll);
float mbd = max(bbd, id);
float d = unionRound(hbd, mbd, BOXSIZE*0.15);
if (abs(hbd - d) < 0.01)
{
m = 2;
}
else
{
m = 1;
}
return d;
}
float map(in vec3 p, out int m)
{
const float scale = BOXSIZE;
p *= scale;
float d = MAX_RAY_LENGTH;
nerdRotate(p);
d = impulseCube(p, 0.1, 0.03 + 0.02*cos(TIME*0.1), m);
return d/scale;
}
float rayMarch(in vec3 ro, in vec3 rd, out int mat, out int iter)
{
float t = 0.0;
float distance;
for (int i = 0; i < MAX_RAY_MARCHES; i++)
{
iter = i;
distance = map(ro + rd*t, mat);
if (distance < TOLERANCE || t > MAX_RAY_LENGTH) break;
t += distance;
}
if (abs(distance) > 100.0*TOLERANCE) return MAX_RAY_LENGTH;
return t;
}
vec3 normal(in vec3 pos)
{
vec3 eps = vec3(NORM_OFF,0.0,0.0);
vec3 nor;
int mat;
nor.x = map(pos+eps.xyy, mat) - map(pos-eps.xyy, mat);
nor.y = map(pos+eps.yxy, mat) - map(pos-eps.yxy, mat);
nor.z = map(pos+eps.yyx, mat) - map(pos-eps.yyx, mat);
return normalize(nor);
}
const vec3 lightPos1 = 100.0*vec3(-0.3, 0.15, 1.0);
const vec3 lightPos2 = 100.0*vec3(-0.33, -0.2, -1.0);
const vec3 lightCol1 = vec3(8.0/8.0,7.0/8.0,6.0/8.0);
const vec3 lightCol2 = vec3(8.0/8.0,6.0/8.0,7.0/8.0);
vec3 skyColor(vec3 rayDir)
{
vec3 lightDir1 = normalize(lightPos1);
vec3 lightDir2 = normalize(lightPos2);
float ld1 = max(dot(lightDir1, rayDir), 0.0);
float ld2 = max(dot(lightDir2, rayDir), 0.0);
vec3 final = vec3(0.125);
if ((rayDir.y > abs(rayDir.x)*1.0) && (rayDir.y > abs(rayDir.z*0.25))) final = vec3(2.0)*rayDir.y;
float roundBox = length(max(abs(rayDir.xz/max(0.0,rayDir.y))-vec2(0.9, 4.0),0.0))-0.1;
final += vec3(0.8)* pow(saturate(1.0 - roundBox*0.5), 6.0);
final += 1.0*pow(lightCol1, vec3(2.0, 1.5, 1.5)) * pow(ld1, 8.0);
final += 1.0*lightCol1 * pow(ld1, 200.0);
final += 1.0*pow(lightCol2, vec3(2.0, 1.5, 1.5)) * pow(ld2, 8.0);
final += 1.0*lightCol2 * pow(ld2, 200.0);
return final;
}
vec3 render(in vec3 ro, in vec3 rd)
{
vec3 color = vec3(0.0);
int mat = 0;
int iter = 0;
float t = rayMarch(ro,rd, mat, iter);
vec3 pos = ro + t*rd;
vec3 nor = vec3(0.0, 1.0, 0.0);
float ndif = 1.0;
float nref = 0.8;
vec3 mref = vec3(1.0);
if (t < MAX_RAY_LENGTH)
{
nor = normal(pos);
float d2 = abs(dot(-rd, nor));
if (mat == 0)
{
color = mix(vec3(1.0), nor*nor, 0.5);
ndif = 0.75;
nref = 0.7;
}
else if (mat == 1)
{
color = vec3(0.9) + abs(nor.zxy)*0.1;
ndif = 1.75;
nref = 0.7;
mref = vec3(1.5, 1.5, 1.75);
}
else if (mat == 2)
{
color = vec3(0.25) + abs(nor.zxy)*0.05;
ndif = 0.5;
nref = 0.9;
}
}
else
{
return skyColor(rd);
}
vec3 ref = reflect(rd, nor);
vec3 rcol = skyColor(ref);
vec3 ld0 = vec3(0.0, 1.0, 0.0);
vec3 ld1 = normalize(lightPos1 - pos);
vec3 ld2 = normalize(lightPos2 - pos);
int rmat = 0;
int riter = 0;
float st = rayMarch(pos + ref*10.0*TOLERANCE, ref, rmat, riter);
float sha = st < MAX_RAY_LENGTH ? 0.0 : 1.0;
float dif0 = pow(max(dot(nor,ld0),0.0), ndif);
float dif1 = pow(max(dot(nor,ld1),0.0), ndif);
float dif2 = pow(max(dot(nor,ld2),0.0), ndif);
float occ = float(MAX_RAY_MARCHES + MAX_RAY_MARCHES - iter) / 2.0*float(MAX_RAY_MARCHES);
vec3 col0 = mix(vec3(1.0), dif0*vec3(1.0), 0.8);
vec3 col1 = mix(vec3(1.0), dif1*lightCol1, 0.8);
vec3 col2 = mix(vec3(1.0), dif2*lightCol2, 0.8);
vec3 col = mix(pow(rcol, vec3(mref))*sha, color*(col0 + col1 + col2)/3.0, nref);
return col;
}
vec3 postProcess(in vec3 col, in vec2 q)
{
col*=0.5+0.5*pow(19.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.7);
return col;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
vec2 q=fragCoord.xy/iResolution.xy;
vec2 p = -1.0 + 2.0*q;
p.x *= iResolution.x/iResolution.y;
float br = smoothstep(FADE_BOX_ROTATE_BEGIN, FADE_BOX_ROTATE_END, TIME);
br = 0.0;
vec3 ro = mix(1.5, 1.0, br)*vec3(2.0, 1.0, 0.2);
vec3 la = mix(vec3(0.0, 0.0, 0.0), vec3(0.0, 1.5/BOXSIZE, 0.0), br);
vec3 up = vec3(0.0, 1.0, 0.0);
rot(ro.xz, TAU*TIME/30.0);
// rot(ro.xz, (iMouse.x + 1.0)/300);
vec3 ww = normalize(la - ro);
vec3 uu = normalize(cross(up, ww ));
vec3 vv = normalize(cross(ww,uu));
vec3 rd = normalize(p.x*uu + p.y*vv + 2.5*ww);
vec3 col = render(ro, rd);
fragColor = vec4(postProcess(col, q),1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment