Skip to content

Instantly share code, notes, and snippets.

@mrange
Created July 15, 2019 08:45
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 mrange/f3031701ab3ad163feb06a1d20f3bc57 to your computer and use it in GitHub Desktop.
Save mrange/f3031701ab3ad163feb06a1d20f3bc57 to your computer and use it in GitHub Desktop.
dodec
#version 150
in VertexData
{
vec4 v_position;
vec3 v_normal;
vec2 v_texcoord;
} inData;
out vec4 fragColor;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
precision highp float;
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.00001
#define NORM_OFF 0.0001
#define MAX_RAY_LENGTH 16.0
#define MAX_RAY_MARCHES 70
#define PI 3.141592654
#define TAU (2.0*PI)
#define BOXSIZE 0.2
#define PERIOD 15.0
#define CURRENT_PERIOD int(iTime/PERIOD)
#define TIME_IN_PERIOD mod(iTime,PERIOD)
#define FADE_BOX_ROTATE_BEGIN 10.0
#define FADE_BOX_ROTATE_END 20.0
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); }
float rand(vec3 r)
{
return fract(sin(dot(r.xy,vec2(1.38984*sin(r.z),1.13233*cos(r.z))))*653758.5453);
}
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;
}
vec4 mod4(inout vec4 p, vec4 size)
{
vec4 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 softMin2(in float a, in float b, in float k)
{
if (a*a + b*b > 4.0)
{
return min(a, b);
}
else
{
return softMin(a, b, 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;
}
float sdHoleyBox(in vec3 p)
{
vec3 bp = p;
float bd = sdSoftBox(bp, BOXSIZE);
mod3(bp, vec3(0.62*BOXSIZE));
float msd = sdSphere(bp, 0.38*BOXSIZE);
float hbd = max(bd, -msd);
return hbd;
}
mat4 mscale(vec3 s)
{
return mat4(
s.x, 0.0, 0.0, 0.0,
0.0, s.y, 0.0, 0.0,
0.0, 0.0, s.z, 0.0,
0.0, 0.0, 0.0, 1.0);
}
mat4 mrotX(in float a)
{
float c = cos(a);
float s = sin(a);
return mat4(
c,-s, 0, 0,
s, c, 0, 0,
0, 0, 1, 0,
0, 0, 0, 0);
}
mat4 mrotY(in float a)
{
float c = cos(a);
float s = sin(a);
return mat4(
c, 0,-s, 0,
0, 1, 0, 0,
s, 0, c, 0,
0, 0, 0, 1);
}
mat4 mrotZ(in float a)
{
float c = cos(a);
float s = sin(a);
return mat4(
1, 0, 0, 0,
0, c,-s, 0,
0, s, c, 0,
0, 0, 0, 1);
}
mat4 mtrans(in vec3 t)
{
return mat4(
1, 0, 0, t.x,
0, 1, 0, t.y,
0, 0, 1, t.z,
0, 0, 0, 1);
}
float sdCapsule(vec3 p, float r, float c)
{
return mix(length(p.xz) - r, length(vec3(p.x, abs(p.y) - c, p.z)) - r, step(c, abs(p.y)));
}
const float Size = 1;
const vec3 plnormal = normalize(vec3(1, 1, -1));
#define Phi (.5*(1.+sqrt(5.)))
const int Iterations = 1;
const vec3 n1 = normalize(vec3(-Phi,Phi-1.0,1.0));
const vec3 n2 = normalize(vec3(1.0,-Phi,Phi+1.0));
const vec3 n3 = normalize(vec3(0.0,0.0,-1.0));
float dodec(in vec3 z)
{
float t;
// Folds.
//Dodecahedral.. you can use other sets of foldings!
z = abs(z);
t=dot(z,n1); if (t>0.0) { z-=2.0*t*n1; }
t=dot(z,n2); if (t>0.0) { z-=2.0*t*n2; }
z = abs(z);
t=dot(z,n1); if (t>0.0) { z-=2.0*t*n1; }
t=dot(z,n2); if (t>0.0) { z-=2.0*t*n2; }
z = abs(z);
//combine DEs... explore different combinations ;)
//the base DE is the distance to the plane going through vec3(Size,0.,0.) and which normal is plnormal
float dmin=dot(z-vec3(Size,0.,0.),normalize(plnormal));
return (dmin);
}
void pR45(inout vec2 p) {
p = (p + vec2(p.y, -p.x))*sqrt(0.5);
}
float pMod1(inout float p, float size) {
float halfsize = size*0.5;
float c = floor((p + halfsize)/size);
p = mod(p + halfsize, size) - halfsize;
return c;
}
float fOpUnionColumns(float a, float b, float r, float n) {
if ((a < r) && (b < r)) {
vec2 p = vec2(a, b);
float columnradius = r*sqrt(2)/((n-1)*2+sqrt(2));
pR45(p);
p.x -= sqrt(2)/2*r;
p.x += columnradius*sqrt(2);
if (mod(n,2) == 1) {
p.y += columnradius;
}
// At this point, we have turned 45 degrees and moved at a point on the
// diagonal that we want to place the columns on.
// Now, repeat the domain along this direction and place a circle.
pMod1(p.y, columnradius*2);
float result = length(p) - columnradius;
result = min(result, p.x);
result = min(result, a);
return min(result, b);
} else {
return min(a, b);
}
}
float de(in vec3 p)
{
vec3 z = p;
float t;
z = abs(z);
t=dot(z,n1); if (t>0.0) { z-=2.0*t*n1; }
t=dot(z,n2); if (t>0.0) { z-=2.0*t*n2; }
z = abs(z);
t=dot(z,n1); if (t>0.0) { z-=2.0*t*n1; }
t=dot(z,n2); if (t>0.0) { z-=2.0*t*n2; }
z = abs(z);
//combine DEs... explore different combinations ;)
//the base DE is the distance to the plane going through vec3(Size,0.,0.) and which normal is plnormal
float lz = length(p);
vec3 pn1 = plnormal;
vec3 pn2 = vec3(1,0,0);
vec3 pn3 = normalize(vec3(1,1,1));
rot(pn1.yz, 0.45);
rot(pn2.xz, -1.7);
rot(pn3.xy, 0.5);
float dmin1=dot(z-vec3(Size,0,0),pn1);
float dmin2=dot(z-vec3(Size*0.4,1,0),pn2);
float dmin3=dot(z-vec3(Size*1.2,0,0),pn3);
float dmin = max(max(-dmin1, -dmin2), dmin3);
// dmin = dmin3;
return dmin;
}
float map(in vec3 p, out int m)
{
float d1 = de(p);
m = 1;
return d1;
}
float rayMarch(in vec3 ro, in vec3 rd, out int mat, out int iter)
{
float t = 0.0;
float distance;
int i;
for (i = 0; i < MAX_RAY_MARCHES; i++)
{
distance = map(ro + rd*t, mat);
if (distance < TOLERANCE || t > MAX_RAY_LENGTH) break;
t += distance;
}
iter = i;
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)
{
// background color
vec3 color = vec3(0.5, 0.8, 1.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;
if (t < MAX_RAY_LENGTH)
{
// Ray intersected object
nor = normal(pos);
float d2 = abs(dot(-rd, nor));
switch(mat)
{
case 0:
color = mix(vec3(1.0), nor*nor, 0.5);
ndif = 0.75;
nref = 0.7;
break;
case 1:
color = vec3(0.9) + abs(nor.zxy)*0.1;
ndif = 0.75;
nref = 0.7;
break;
case 2:
color = vec3(0.25) + abs(nor.zxy)*0.05;
ndif = 0.5;
nref = 0.9;
break;
default:
color = nor*nor;
break;
}
}
else
{
// Ray intersected sky
return skyColor(rd);
}
vec3 ref = reflect(rd, nor);
vec3 rcol = skyColor(ref);
vec3 ld0 = vec3(0.0, 1.0, 0.0);
vec3 lv1 = lightPos1 - pos;
float ll1 = length(lv1);
vec3 ld1 = lv1 / ll1;
vec3 lv2 = lightPos2 - pos;
float ll2 = length(lv2);
vec3 ld2 = lv2 / ll2;
int rmat = 0;
int riter = 0;
float st = rayMarch(pos + ref*10.0*TOLERANCE, ref, rmat, riter);
float sha1 = pow(st/MAX_RAY_LENGTH, 0.2);
float sha2 = 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 = (MAX_RAY_MARCHES + MAX_RAY_MARCHES - iter) / float(2.0*MAX_RAY_MARCHES);
// float spe = pow(max(dot(reflect(-ld, nor), -rd), 0.), nspe);
// float bac = max(0.4 + 0.6*dot(nor,vec3(-ld.x,ld.y,-ld.z)),0.0);
// float lin = mix(0.2, 1.0, pow(dif,ndif)*occ + 0.3*bac*(0.5+0.5*occ));
float bac = 0.2;
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);
// nref = 1.0;
vec3 col = mix(rcol*sha2, color*(col0 + col1 + col2)/2.0, nref);
return col;
}
vec3 postProcess(in vec3 col, in vec2 q)
{
col=pow(clamp(col,0.0,1.0),vec3(0.45));
col=col*0.6+0.4*col*col*(3.0-2.0*col); // contrast
col=mix(col, vec3(dot(col, vec3(0.33))), -0.4); // satuation
col*=0.5+0.5*pow(19.0*q.x*q.y*(1.0-q.x)*(1.0-q.y),0.7); // vigneting
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;
vec3 ro = mix(2.5, 1.0, 0.)*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), 0.0);
vec3 up = vec3(0.0, 1.0, 0.0);
rot(ro.xz, TAU*iTime/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);
float yy = -1 + 2.0*60*iTimeDelta;
if (yy > p.y)
{
// col += vec3(0.9);
}
fragColor = vec4(mix(col, vec3(1.0), 0.0),1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment