slang-shaders/procedural/fizzer-the-popular-shader.slang
2018-02-23 18:44:56 +01:00

434 lines
9.9 KiB
Plaintext

#version 450
#
//I remade my other shader (https://www.shadertoy.com/view/ldjGWD) inspired by "The Popular Demo", to make it more accurate
//I added a tiling effect to make the robot look faceted, but it seems to somehow over-complicate the shader so it doesn't compile.
// fizzer - 2014-01-04
layout(std140, set = 0, binding = 0) uniform UBO
{
mat4 MVP;
vec4 OutputSize;
vec4 OriginalSize;
vec4 SourceSize;
uint FrameCount;
} global;
#pragma stage vertex
layout(location = 0) in vec4 Position;
layout(location = 1) in vec2 TexCoord;
layout(location = 0) out vec2 vTexCoord;
const vec2 madd = vec2(0.5, 0.5);
void main()
{
gl_Position = global.MVP * Position;
vTexCoord = gl_Position.xy;
}
#pragma stage fragment
layout(location = 0) in vec2 vTexCoord;
layout(location = 0) out vec4 FragColor;
float iGlobalTime = float(global.FrameCount)*0.025;
vec2 iResolution = global.OutputSize.xy;
#define USE_IQ_SMIN 0
float time;
vec2 leg0[3];
vec2 leg1[3];
vec2 arm0[3];
vec2 arm1[3];
float wlen=15.0;
float bob;
float wc_scale=0.5;
float scroll;
float scene_scale=15.0;
// Finds the entry and exit points of a 2D ray with a circle of radius 1
// centered at the origin.
vec2 intersectCircle(vec2 ro, vec2 rd)
{
float a = dot(rd, rd);
float b = 2.0 * dot(rd, ro);
float ds = b * b - 4.0 * a * (dot(ro, ro) - 1.0);
if(ds < 0.0)
return vec2(1e3);
return ((-b - sqrt(ds) * vec2(-1.0, 1.0))) / (2.0 * a);
}
mat3 rotateXMat(float a)
{
return mat3(1.0, 0.0, 0.0, 0.0, cos(a), -sin(a), 0.0, sin(a), cos(a));
}
mat3 rotateYMat(float a)
{
return mat3(cos(a), 0.0, -sin(a), 0.0, 1.0, 0.0, sin(a), 0.0, cos(a));
}
// Adapted from https://www.shadertoy.com/view/ldlGR7
vec2 solve( vec2 p, float l1, float l2, float side )
{
vec2 q = p*( 0.5 + 0.5*(l1*l1-l2*l2)/dot(p,p) );
float s = l1*l1/dot(q,q) - 1.0;
if( s<0.0 ) return vec2(-100.0);
return q + q.yx*vec2(-1.0,1.0)*side*sqrt( s );
}
// Returns a pyramid-like periodic signal.
float pyramid(float x)
{
x = fract(x);
return min(x * 2.0, (1.0 - x) * 2.0);
}
// Returns a semicircular periodic signal.
float circ(float x)
{
x = fract(x) * 2.0 - 1.0;
return sqrt(1.0 - x * x);
}
#if USE_IQ_SMIN
float smin(float a,float b,float k){ return -log(exp(-k*a)+exp(-k*b))/k;}//from iq
#else
// http://www.johndcook.com/blog/2010/01/20/how-to-compute-the-soft-maximum/
float smin(in float a, in float b, in float k) { return a - log(1.0+exp(k*(a-b))) / k; }
#endif
float mp(float x)
{
float y=0.3;
return clamp((pyramid(x)-0.5)*2.0-0.4,-y,y);
}
float mosaic(vec3 p)
{
// Disabled because it causes a compilation failure due to time-out or size limit.
return 0.0;//max(mp(p.y*10.0),mp(p.z*10.0))*0.01;
}
/*
mat3 transpose(mat3 m)
{
return mat3(vec3(m[0].x,m[1].x,m[2].x),
vec3(m[0].y,m[1].y,m[2].y),
vec3(m[0].z,m[1].z,m[2].z));
}*/
float capsuleDist(vec3 p,vec3 o,vec3 d,float h0,float h1,float r0,float r1)
{
vec3 u=cross(d,vec3(1.0,0.0,0.0));
vec3 v=cross(u,d);
u=cross(v,d);
mat3 m=transpose(mat3(normalize(u),normalize(v),normalize(d)));
d=normalize(d);
float t=clamp(dot(p-o,d),h0,h1);
vec3 np=o+t*d;
return distance(np,p)-mix(r0,r1,t)+mosaic(m*(p-o));
}
float boxDist(vec3 p,vec3 s,float r)
{
return length(max(vec3(0.0),abs(p)-s))-r+mosaic(p);
}
float sphereDist(vec3 p,vec3 o,float r)
{
return distance(p,o)-r+mosaic(p-o);
}
float sceneDist(vec3 p)
{
float d=1e3;
p+=vec3(0.0,0.07,0.0)*scene_scale;
p=rotateYMat(3.1415926*0.5)*p;
p.z+=cos(p.y*2.0+time)*0.1;
float tm=fract(time*wc_scale*2.0-0.1);
p.x-=(smoothstep(0.0,0.3,tm)-smoothstep(0.4,1.0,tm))*smoothstep(0.5,2.0,p.y)*0.2+scroll;
// Leg 0
{
float g=0.08;
vec3 o=vec3(0.0,0.0,0.2);
float d0=capsuleDist(p+o,vec3(leg0[0],0.0),vec3(leg0[1]-leg0[0],0.0),0.0,1.0-g,0.1,0.1);
float d1=capsuleDist(p+o,vec3(leg0[1],0.0),vec3(leg0[2]-leg0[1],0.0),g,1.0,0.1,0.2);
d=min(d,smin(d0,d1,15.0));
}
// Leg 1
{
float g=0.08;
vec3 o=vec3(0.0,0.0,-0.2);
float d0=capsuleDist(p+o,vec3(leg1[0],0.0),vec3(leg1[1]-leg1[0],0.0),0.0,1.0-g,0.1,0.1);
float d1=capsuleDist(p+o,vec3(leg1[1],0.0),vec3(leg1[2]-leg1[1],0.0),g,1.0,0.1,0.2);
d=min(d,smin(d0,d1,15.0));
}
p.y-=bob;
// Arm 0
{
float g=0.08;
vec3 o=vec3(0.0,0.0,0.4);
mat3 m=rotateXMat(-0.3)*rotateYMat((cos((time*wc_scale+0.5)*3.1415926*2.0)-0.6)*0.5);
float d0=capsuleDist(p+o,vec3(arm0[0],0.0),m*vec3(arm0[1]-arm0[0],0.0),0.0,0.7-g,0.03,0.03);
float d1=capsuleDist(p+o,vec3(arm0[0],0.0)+m*vec3(arm0[1]-arm0[0],0.0),m*vec3(arm0[2]-arm0[1],0.0),g,0.7,0.03,0.06);
d=min(d,smin(d0,d1,15.0));
}
// Arm 1
{
float g=0.08;
vec3 o=vec3(0.0,0.0,-0.4);
mat3 m=rotateXMat(0.3)*rotateYMat(-(cos(time*wc_scale*3.1415926*2.0)-0.6)*0.5);
float d0=capsuleDist(p+o,vec3(arm1[0],0.0),m*vec3(arm1[1]-arm1[0],0.0),0.0,0.7-g,0.03,0.03);
float d1=capsuleDist(p+o,vec3(arm1[0],0.0)+m*vec3(arm1[1]-arm1[0],0.0),m*vec3(arm1[2]-arm1[1],0.0),g,0.7,0.03,0.06);
d=min(d,smin(d0,d1,15.0));
}
// Torso
d=smin(d,boxDist(p+vec3(0.0,-0.7,0.0),vec3(0.05,0.7,0.15),0.1),15.0);
d=smin(d,boxDist(p+vec3(-0.1,-1.1,0.0),vec3(0.05,0.2,0.15)*0.1,0.1),5.0);
// Head
d=smin(d,sphereDist(p,vec3(0.0,1.825,0.0),0.2),15.0);
return d;
}
vec3 sceneNorm(vec3 p)
{
p*=scene_scale;
float c=sceneDist(p);
float e=1e-3;
return normalize(vec3(sceneDist(p+vec3(e,0,0))-c,
sceneDist(p+vec3(0,e,0))-c,
sceneDist(p+vec3(0,0,e))-c));
}
float robot(vec3 ro,vec3 rd)
{
float t=0.0;
float tm;
tm=time*wc_scale;
leg0[0]=vec2(0.0,bob);
leg0[2]=vec2(pyramid(tm)-0.3,-1.8+0.3*circ(tm*2.0)*step(fract(tm),0.5));
leg0[1]=(leg0[0]+solve(leg0[2]-leg0[0],1.0,1.0,1.0));
arm1[0]=vec2(0.0,1.4);
arm1[2]=vec2(pyramid(tm)-0.3,0.1+pow(pyramid(tm),2.0)*0.7);
arm1[1]=(arm1[0]+solve(arm1[2]-arm1[0],0.7,0.7,-1.0));
tm+=0.5;
leg1[0]=vec2(0.0,bob);
leg1[2]=vec2(pyramid(tm)-0.3,-1.8+0.3*circ(tm*2.0)*step(fract(tm),0.5));
leg1[1]=(leg1[0]+solve(leg1[2]-leg1[0],1.0,1.0,1.0));
arm0[0]=vec2(0.0,1.4);
arm0[2]=vec2(pyramid(tm)-0.3,0.1+pow(pyramid(tm),2.0)*0.7);
arm0[1]=(arm0[0]+solve(arm0[2]-arm0[0],0.7,0.7,-1.0));
float rt=1e4;
ro*=scene_scale;
rd*=scene_scale;
for(int i=0;i<15;i+=1)
{
vec3 rp=ro+rd*t;
float d=sceneDist(rp);
if(d<1e-2)
{
rt=t;
}
t+=d/scene_scale;
}
return rt;
}
vec2 unitSquareInterval(vec2 ro, vec2 rd)
{
vec2 slabs0 = (vec2(+1.0) - ro) / rd;
vec2 slabs1 = (vec2(-1.0) - ro) / rd;
vec2 mins = min(slabs0, slabs1);
vec2 maxs = max(slabs0, slabs1);
return vec2(max(mins.x, mins.y),
min(maxs.x, maxs.y));
}
vec3 squaresColours(vec2 p)
{
p+=vec2(time*0.2);
vec3 orange=vec3(1.0,0.4,0.1)*2.0;
vec3 purple=vec3(1.0,0.2,0.5)*0.8;
float l=pow(0.5+0.5*cos(p.x*7.0+cos(p.y)*8.0)*sin(p.y*2.0),4.0)*2.0;
vec3 c=pow(l*(mix(orange,purple,0.5+0.5*cos(p.x*40.0+sin(p.y*10.0)*3.0))+
mix(orange,purple,0.5+0.5*cos(p.x*20.0+sin(p.y*3.0)*3.0))),vec3(1.2))*0.7;
c+=vec3(1.0,0.8,0.4)*pow(0.5+0.5*cos(p.x*20.0)*sin(p.y*12.0),20.0)*2.0;
c+=vec3(0.1,0.5+0.5*cos(p*20.0))*vec3(0.05,0.1,0.4).bgr*0.7;
return c;
}
vec3 squaresTex(vec2 p,float border)
{
float sm=0.02;
vec2 res=vec2(8.0);
vec2 ip=floor(p*res)/res;
vec2 fp=fract(p*res);
float m=1.0-max(smoothstep(border-sm,border,abs(fp.x-0.5)),smoothstep(border-sm,border,abs(fp.y-0.5)));
m+=1.0-smoothstep(0.0,0.56,distance(fp,vec2(0.5)));
return m*squaresColours(ip);
}
vec3 room(vec3 ro,vec3 rd,out vec3 rp,out vec3 n)
{
vec2 box_size=vec2(1.0,5.0+3.0/8.0);
vec2 cp=vec2(0.0),ct=vec2(1e3);
for(int i=0;i<4;i+=1)
{
float cr=0.03;
vec2 tcp=vec2(2.5/8.0*float(-1),float(i)-2.0+0.5/8.0);
vec2 tct=intersectCircle((ro.xz-tcp)/cr,rd.xz/cr);
if(tct.y > 0.0 && tct.y<ct.y)
{
ct=tct;
cp=tcp;
}
}
for(int i=0;i<4;i+=1)
{
float cr=0.03;
vec2 tcp=vec2(2.5/8.0*float(+1),float(i)-2.0+0.5/8.0);
vec2 tct=intersectCircle((ro.xz-tcp)/cr,rd.xz/cr);
if(tct.y > 0.0 && tct.y<ct.y)
{
ct=tct;
cp=tcp;
}
}
ct.y=max(0.0,ct.y);
vec3 ci=ro+rd*ct.y;
vec2 cu=vec2(atan(ci.z-cp.y,ci.x-cp.x)/3.1415926*0.5,(ci.y+0.5/8.0)*4.0);
float wt=max(0.0,unitSquareInterval(ro.xy * box_size, rd.xy * box_size).y);
float t=min(ct.y,wt);
rp=ro+rd*(t-1e-4);
n.z=0.0;
if(abs(rp.x*box_size.x)>abs(rp.y*box_size.y))
n.xy=vec2(rp.x/abs(rp.x),0.0);
else
n.xy=vec2(0.0,rp.y/abs(rp.y));
if(ct.y<wt)
{
n.y=0.0;
n.xz=normalize(rp.xz-ci.xz);
}
float l=1.0-smoothstep(0.0,3.0,abs(rp.z-ro.z));
vec3 wc=mix(squaresTex(rp.zy+vec2(0.0,0.5/8.0),0.5),squaresTex(rp.xz,0.44),step(0.999/box_size.y,abs(rp.y)));
vec3 cc=squaresTex(cu,0.45)+0.8*vec3(smoothstep(0.83/5.0,0.86/5.0,abs(rp.y)));
return l*mix(cc,wc,step(wt,t));
}
vec3 scene(vec2 p)
{
mat3 cam = rotateXMat(cos(time * 0.2) * 0.1) * rotateYMat(time * 0.5);
float lt=mod(time*wc_scale,wlen)/wlen;
vec3 ro = cam*vec3(0.0,-0.15+lt*0.15, 0.15+lt*0.2)+vec3(0.0,0.0,scroll/scene_scale);
vec3 rd = cam*vec3(p, -1.0);
rd=normalize(rd);
float robot_t=robot(ro,rd);
vec3 n,rp;
vec3 c;
vec3 c0=room(ro,rd,rp,n);
if(robot_t < distance(ro,rp))
{
rp=ro+rd*robot_t;
n=sceneNorm(rp);
vec3 r=reflect(rd,n);
c=vec3(0.5+0.5*n.y)*0.5*vec3(1.0,0.8,0.5);
vec3 c1=room(rp,r,rp,n);
c+=c1*0.5;
}
else
{
vec3 r=reflect(rd,n);
vec3 c1=room(rp,r,rp,n);
c=c0+c1*c0*0.4;
}
vec3 ll=vec3(1.0-(smoothstep(0.0,0.07,lt)-smoothstep(0.93,1.0,lt)));
return ll+c+
0.6*((sin(p.y)*cos(p.x+time*2.0)*0.5+0.5)*
pow(mix(vec3(1.0,0.7,0.1),vec3(1.0,0.2,0.6),0.5+0.5*cos(p.x+sin(time*3.0+p.y*2.0))),vec3(2.0)));
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
time=iGlobalTime+1.0;
bob=cos(time*12.0)*0.05;
scroll=-15.0+mod(time*wc_scale,wlen)*2.0;
vec2 uv = fragCoord.xy / iResolution.xy;
vec2 q=uv;
vec2 t=uv*2.0-vec2(1.0);
t.x*=iResolution.x/iResolution.y;
fragColor.a = 1.0f;
fragColor.rgb = scene(t.xy) * 1.3;
// vignet
fragColor.rgb *= 0.5 + 0.5*pow( 16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.1 );
}
void main(void)
{
//just some shit to wrap shadertoy's stuff
vec2 FragCoord = vTexCoord.xy*global.OutputSize.xy;
FragCoord.y = -FragCoord.y;
mainImage(FragColor,FragCoord);
}