From 06da9fcac8383905f863bafc94155b2ae264167d Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 23 Feb 2018 18:44:56 +0100 Subject: [PATCH] Add plethora of new shaders from shadertoy --- procedural/fizzer-kirby-jump.slang | 286 +++++++++ procedural/fizzer-power-coils.slang | 80 +++ procedural/fizzer-the-popular-shader.slang | 433 +++++++++++++ procedural/hlorenzi-super-mario-bros.slang | 541 +++++++++++++++++ procedural/iq-julia-quaternion.slang | 213 +++++++ procedural/nrx-voxel-pacman.slang | 330 ++++++++++ procedural/reinder-alotofspheres.slang | 281 +++++++++ procedural/reinder-tokyo.slang | 403 ++++++++++++ procedural/reinder-wolfenstein3d.slang | 6 +- procedural/shane-fractal-flythrough.slang | 573 ++++++++++++++++++ procedural/shane-raymarched-reflections.slang | 386 ++++++++++++ 11 files changed, 3529 insertions(+), 3 deletions(-) create mode 100644 procedural/fizzer-kirby-jump.slang create mode 100644 procedural/fizzer-power-coils.slang create mode 100644 procedural/fizzer-the-popular-shader.slang create mode 100644 procedural/hlorenzi-super-mario-bros.slang create mode 100644 procedural/iq-julia-quaternion.slang create mode 100644 procedural/nrx-voxel-pacman.slang create mode 100644 procedural/reinder-alotofspheres.slang create mode 100644 procedural/reinder-tokyo.slang create mode 100644 procedural/shane-fractal-flythrough.slang create mode 100644 procedural/shane-raymarched-reflections.slang diff --git a/procedural/fizzer-kirby-jump.slang b/procedural/fizzer-kirby-jump.slang new file mode 100644 index 0000000..5a74815 --- /dev/null +++ b/procedural/fizzer-kirby-jump.slang @@ -0,0 +1,286 @@ +#version 450 +//kirby jump +// fizzer 2018-01-31 +// https://www.shadertoy.com/view/lt2fD3 + +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; + +// polynomial smooth min (from IQ) +float smin( float a, float b, float k ) +{ + float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 ); + return mix( b, a, h ) - k*h*(1.0-h); +} + + +float smax(float a,float b, float k) +{ + return -smin(-a,-b,k); +} + +mat2 rotmat(float a) +{ + return mat2(cos(a),sin(a),-sin(a),cos(a)); +} + +float shoesDist(vec3 p) +{ + vec3 op=p; + float d=1e4; + + p.y-=1.5; + + // right shoe + op=p; + p-=vec3(-.5,-.6,-.9); + p.yz=rotmat(-.7)*p.yz; + p.xz=rotmat(0.1)*p.xz; + d=min(d,-smin(p.y,-(length(p*vec3(1.6,1,1))-.64),.2)); + p=op; + + // left shoe + op=p; + p-=vec3(.55,-.8,0.4); + p.x=-p.x; + p.yz=rotmat(1.4)*p.yz; + d=min(d,-smin(p.y,-(length(p*vec3(1.6,1,1))-.73),.2)); + p=op; + return d; +} + +float sceneDist(vec3 p) +{ + vec3 op=p; + float d=shoesDist(p); + + d=min(d,p.y); + p.y-=1.5; + + // torso + d=min(d,length(p)-1.); + + + // left arm + op=p; + p-=vec3(.66,.7,0); + p.xz=rotmat(-0.1)*p.xz; + d=smin(d,(length(p*vec3(1.8,1,1))-.58),.07); + p=op; + + // right arm + op=p; + p-=vec3(-.75,0.2,0); + d=smin(d,(length(p*vec3(1,1.5,1))-.54),.03); + p=op; + + // mouth + p.y-=.11; + float md=smax(p.z+.84,smax(smax(p.x-.2,p.y-.075,.2),dot(p,vec3(.7071,-.7071,0))-.1,.08),.04); + p.x=-p.x; + md=smax(md,smax(p.z+.84,smax(smax(p.x-.2,p.y-.075,.2),dot(p,vec3(.7071,-.7071,0))-.1,.08),.01),.13); + d=smax(d,-md,.012); + + // tongue + p=op; + d=smin(d,length((p-vec3(0,.03,-.75))*vec3(1,1,1))-.16,.01); + + return min(d,10.); +} + + + +vec3 sceneNorm(vec3 p) +{ + vec3 e=vec3(1e-3,0,0); + float d = sceneDist(p); + return normalize(vec3(sceneDist(p + e.xyy) - sceneDist(p - e.xyy), sceneDist(p + e.yxy) - sceneDist(p - e.yxy), + sceneDist(p + e.yyx) - sceneDist(p - e.yyx))); +} + + +// from simon green and others +float ambientOcclusion(vec3 p, vec3 n) +{ + const int steps = 4; + const float delta = 0.15; + + float a = 0.0; + float weight = 4.; + for(int i=1; i<=steps; i++) { + float d = (float(i) / float(steps)) * delta; + a += weight*(d - sceneDist(p + n*d)); + weight *= 0.5; + } + return clamp(1.0 - a, 0.0, 1.0); +} + +// a re-shaped cosine, to make the peaks more pointy +float cos2(float x){return cos(x-sin(x)/3.);} + +float starShape(vec2 p) +{ + float a=atan(p.y,p.x)+iGlobalTime/3.; + float l=pow(length(p),.8); + float star=1.-smoothstep(0.,(3.-cos2(a*5.*2.))*.02,l-.5+cos2(a*5.)*.1); + return star; +} + + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + // Normalized pixel coordinates (from 0 to 1) + vec2 uv = fragCoord/iResolution.xy; + + float an=cos(iGlobalTime)*.1; + + vec2 ot=uv*2.-1.; + ot.y*=iResolution.y/iResolution.x; + vec3 ro=vec3(0.,1.4,4.); + vec3 rd=normalize(vec3(ot.xy,-1.3)); + + rd.xz=mat2(cos(an),sin(an),sin(an),-cos(an))*rd.xz; + ro.xz=mat2(cos(an),sin(an),sin(an),-cos(an))*ro.xz; + + float s=20.; + + // primary ray + float t=0.,d=0.; + for(int i=0;i<80;++i) + { + d=sceneDist(ro+rd*t); + if(d<1e-4) + break; + if(t>10.) + break; + t+=d*.9; + } + + t=min(t,10.0); + + // shadow ray + vec3 rp=ro+rd*t; + vec3 n=sceneNorm(rp); + float st=5e-3; + vec3 ld=normalize(vec3(2,4,-4)); + for(int i=0;i<20;++i) + { + d=sceneDist(rp+ld*st); + if(d<1e-5) + break; + if(st>5.) + break; + st+=d*2.; + } + + // ambient occlusion and shadowing + vec3 ao=vec3(ambientOcclusion(rp, n)); + float shad=mix(.85,1.,step(5.,st)); + + ao*=mix(.3,1.,.5+.5*n.y); + + // soft floor shadow + if(rp.y<1e-3) + ao*=mix(mix(vec3(1,.5,.7),vec3(1),.4)*.6,vec3(1),smoothstep(0.,1.6,length(rp.xz))); + + + + vec3 diff=vec3(1); + vec3 emit=vec3(0); + + // skin + diff*=vec3(1.15,.3,.41)*1.4; + diff+=.4*mix(1.,0.,smoothstep(0.,1.,length(rp.xy-vec2(0.,1.9)))); + diff+=.5*mix(1.,0.,smoothstep(0.,.5,length(rp.xy-vec2(.7,2.5)))); + diff+=.36*mix(1.,0.,smoothstep(0.,.5,length(rp.xy-vec2(-1.1,1.8)))); + + if(rp.y<1e-3) + diff=vec3(.6,1,.6); + + // mouth + diff*=mix(vec3(1,.3,.2),vec3(1),smoothstep(.97,.99,length(rp-vec3(0,1.5,0)))); + + // shoes + diff=mix(vec3(1.,.05,.1),diff,smoothstep(0.,0.01,shoesDist(rp))); + diff+=.2*mix(1.,0.,smoothstep(0.,.2,length(rp.xy-vec2(-0.5,1.4)))); + diff+=.12*mix(1.,0.,smoothstep(0.,.25,length(rp.xy-vec2(0.57,.3)))); + + // bounce light from the floor + diff+=vec3(.25,1.,.25)*smoothstep(-.3,1.7,-rp.y+1.)*max(0.,-n.y)*.7; + + vec3 orp=rp; + rp.y-=1.5; + rp.x=abs(rp.x); + + // blushes + diff*=mix(vec3(1,.5,.5),vec3(1),smoothstep(.1,.15,length((rp.xy-vec2(.4,.2))*vec2(1,1.65)))); + + rp.xy-=vec2(.16,.45); + rp.xy*=.9; + orp=rp; + rp.y=pow(abs(rp.y),1.4)*sign(rp.y); + + // eye outline + diff*=smoothstep(.058,.067,length((rp.xy)*vec2(.9,.52))); + + rp=orp; + rp.y+=.08; + rp.y-=pow(abs(rp.x),2.)*16.; + + // eye reflections + emit+=vec3(.1,.5,1.)*(1.-smoothstep(.03,.036,length((rp.xy)*vec2(.7,.3))))*max(0.,-rp.y)*10.; + + rp=orp; + rp.y-=.12; + + // eye highlights + emit+=vec3(1)*(1.-smoothstep(.03,.04,length((rp.xy)*vec2(1.,.48)))); + + // fresnel + diff+=pow(clamp(1.-dot(-rd,n),0.,.9),4.)*.5; + + // background and floor fade + vec3 backg=vec3(1.15,.3,.41)*.9; + ot.x+=.6+iGlobalTime/50.; + ot.y+=cos(floor(ot.x*2.)*3.)*.1+.2; + ot.x=mod(ot.x,.5)-.25; + backg=mix(backg,vec3(1.,1.,.5),.1*starShape((ot-vec2(0.,.6))*8.)*smoothstep(9.,10.,t)); + diff=mix(diff,backg,smoothstep(.9,10.,t)); + + fragColor.rgb=mix(vec3(.15,0,0),vec3(1),ao)*shad*diff*1.1; + fragColor.rgb+=emit; + fragColor.a = 1.0f; + + fragColor.rgb=pow(fragColor.rgb,vec3(1./2.4)); +} + +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); +} diff --git a/procedural/fizzer-power-coils.slang b/procedural/fizzer-power-coils.slang new file mode 100644 index 0000000..30eae3a --- /dev/null +++ b/procedural/fizzer-power-coils.slang @@ -0,0 +1,80 @@ +#version 450 +# +//Playing with inversion and volumetric light. +//fizer 2015-06-06 + +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; + +void mainImage(out vec4 c, vec2 q) +{ + float a=iGlobalTime*.1+1.,b=.5,g,e,t=0.,s; + vec3 r=vec3(0.,0.,3.),w=normalize(vec3((q-iResolution.xy/2.)/iResolution.y,-.5)),p; + + mat2 x=mat2(cos(a),sin(a),sin(a),-cos(a)),y=mat2(cos(b),sin(b),sin(b),-cos(b)); + + w.xz=y*w.xz; + r.xz=y*r.xz; + + w.yz=x*w.yz; + r.yz=x*r.yz; + + c.rgb=vec3(0.,0.,.02); + + for(int i=0;i<150;++i) + { + p=r+w*t; + + float f=.25,d=1e4; + for(int j=0;j<2;++j) + { + s=.2*dot(p,p); + p=p/s; + f*=s; + g=p.z; + e=atan(p.y,p.x); + p=(mod(p,2.)-1.)*1.25; + } + + d=min((length(abs(p.xy)-1.3)-.1)*f,1e2); + + if(d<1e-3) + break; + + c.rgb+=vec3(.3,.4,.8)*(pow(.5+.5*cos(g*.5+a*77.+cos(e*10.)),16.))* + (1.-smoothstep(0.,1.,70.*d))*.25; + + t+=d; + } +} + +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); +} diff --git a/procedural/fizzer-the-popular-shader.slang b/procedural/fizzer-the-popular-shader.slang new file mode 100644 index 0000000..83b8cae --- /dev/null +++ b/procedural/fizzer-the-popular-shader.slang @@ -0,0 +1,433 @@ +#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 0.0 && tct.yabs(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 15) return RGB(107,140,255); + + col = SELECT(mod(float(x),8.0),col); + if (col == 0.0) return RGB(231,90,16); + if (col == 1.0) return RGB(255,165,66); + if (col == 2.0) return RGB(0,0,0); + return RGB(107,140,255); +} + +vec4 sprUsedBlock(int x, int y) +{ + float col = 0.0; + if (y == 15) col = SPRROW(x,3.,0.,0.,0.,0.,0.,0.,0., 0.,0.,0.,0.,0.,0.,0.,3.); + if (y == 14) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + if (y == 13) col = SPRROW(x,0.,1.,0.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,0.,1.,0.); + if (y == 12) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + if (y == 11) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + if (y == 10) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + if (y == 9) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + if (y == 8) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + + if (y == 7) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + if (y == 6) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + if (y == 5) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + if (y == 4) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + if (y == 3) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + if (y == 2) col = SPRROW(x,0.,1.,0.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,0.,1.,0.); + if (y == 1) col = SPRROW(x,0.,1.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,1.,0.); + if (y == 0) col = SPRROW(x,3.,0.,0.,0.,0.,0.,0.,0., 0.,0.,0.,0.,0.,0.,0.,3.); + + if (y < 0 || y > 15) return RGB(107,140,255); + + col = SELECT(mod(float(x),8.0),col); + if (col == 0.0) return RGB(0,0,0); + if (col == 1.0) return RGB(231,90,16); + return RGB(107,140,255); +} + +vec4 sprMarioJump(int x, int y) +{ + float col = 0.0; + if (y == 15) col = SPRROW(x,0.,0.,0.,0.,0.,0.,0.,0., 0.,0.,0.,0.,0.,2.,2.,2.); + if (y == 14) col = SPRROW(x,0.,0.,0.,0.,0.,0.,1.,1., 1.,1.,1.,0.,0.,2.,2.,2.); + if (y == 13) col = SPRROW(x,0.,0.,0.,0.,0.,1.,1.,1., 1.,1.,1.,1.,1.,1.,2.,2.); + if (y == 12) col = SPRROW(x,0.,0.,0.,0.,0.,3.,3.,3., 2.,2.,3.,2.,0.,3.,3.,3.); + if (y == 11) col = SPRROW(x,0.,0.,0.,0.,3.,2.,3.,2., 2.,2.,3.,2.,2.,3.,3.,3.); + if (y == 10) col = SPRROW(x,0.,0.,0.,0.,3.,2.,3.,3., 2.,2.,2.,3.,2.,2.,2.,3.); + if (y == 9) col = SPRROW(x,0.,0.,0.,0.,3.,3.,2.,2., 2.,2.,3.,3.,3.,3.,3.,0.); + if (y == 8) col = SPRROW(x,0.,0.,0.,0.,0.,0.,2.,2., 2.,2.,2.,2.,2.,3.,0.,0.); + + if (y == 7) col = SPRROW(x,0.,0.,3.,3.,3.,3.,3.,1., 3.,3.,3.,1.,3.,0.,0.,0.); + if (y == 6) col = SPRROW(x,0.,3.,3.,3.,3.,3.,3.,3., 1.,3.,3.,3.,1.,0.,0.,3.); + if (y == 5) col = SPRROW(x,2.,2.,3.,3.,3.,3.,3.,3., 1.,1.,1.,1.,1.,0.,0.,3.); + if (y == 4) col = SPRROW(x,2.,2.,2.,0.,1.,1.,3.,1., 1.,2.,1.,1.,2.,1.,3.,3.); + if (y == 3) col = SPRROW(x,0.,2.,0.,3.,1.,1.,1.,1., 1.,1.,1.,1.,1.,1.,3.,3.); + if (y == 2) col = SPRROW(x,0.,0.,3.,3.,3.,1.,1.,1., 1.,1.,1.,1.,1.,1.,3.,3.); + if (y == 1) col = SPRROW(x,0.,3.,3.,3.,1.,1.,1.,1., 1.,1.,1.,0.,0.,0.,0.,0.); + if (y == 0) col = SPRROW(x,0.,3.,0.,0.,1.,1.,1.,1., 0.,0.,0.,0.,0.,0.,0.,0.); + + col = SELECT(mod(float(x),8.0),col); + if (col == 0.0) return RGB(0,0,0); + if (col == 1.0) return RGB(177,52,37); + if (col == 2.0) return RGB(227,157,37); + if (col == 3.0) return RGB(106,107,4); + return RGB(0,0,0); +} + +vec4 sprMarioWalk3(int x, int y) +{ + float col = 0.0; + if (y == 15) col = SPRROW(x,0.,0.,0.,0.,0.,1.,1.,1., 1.,1.,0.,0.,0.,0.,0.,0.); + if (y == 14) col = SPRROW(x,0.,0.,0.,0.,1.,1.,1.,1., 1.,1.,1.,1.,1.,0.,0.,0.); + if (y == 13) col = SPRROW(x,0.,0.,0.,0.,3.,3.,3.,2., 2.,3.,2.,0.,0.,0.,0.,0.); + if (y == 12) col = SPRROW(x,0.,0.,0.,3.,2.,3.,2.,2., 2.,3.,2.,2.,2.,0.,0.,0.); + if (y == 11) col = SPRROW(x,0.,0.,0.,3.,2.,3.,3.,2., 2.,2.,3.,2.,2.,2.,0.,0.); + if (y == 10) col = SPRROW(x,0.,0.,0.,3.,3.,2.,2.,2., 2.,3.,3.,3.,3.,0.,0.,0.); + if (y == 9) col = SPRROW(x,0.,0.,0.,0.,0.,2.,2.,2., 2.,2.,2.,2.,0.,0.,0.,0.); + if (y == 8) col = SPRROW(x,0.,0.,3.,3.,3.,3.,1.,1., 3.,3.,0.,0.,0.,0.,0.,0.); + + if (y == 7) col = SPRROW(x,2.,2.,3.,3.,3.,3.,1.,1., 1.,3.,3.,3.,2.,2.,2.,0.); + if (y == 6) col = SPRROW(x,2.,2.,2.,0.,3.,3.,1.,2., 1.,1.,1.,3.,3.,2.,2.,0.); + if (y == 5) col = SPRROW(x,2.,2.,0.,0.,1.,1.,1.,1., 1.,1.,1.,0.,0.,3.,0.,0.); + if (y == 4) col = SPRROW(x,0.,0.,0.,1.,1.,1.,1.,1., 1.,1.,1.,1.,3.,3.,0.,0.); + if (y == 3) col = SPRROW(x,0.,0.,1.,1.,1.,1.,1.,1., 1.,1.,1.,1.,3.,3.,0.,0.); + if (y == 2) col = SPRROW(x,0.,3.,3.,1.,1.,1.,0.,0., 0.,1.,1.,1.,3.,3.,0.,0.); + if (y == 1) col = SPRROW(x,0.,3.,3.,3.,0.,0.,0.,0., 0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 0) col = SPRROW(x,0.,0.,3.,3.,3.,0.,0.,0., 0.,0.,0.,0.,0.,0.,0.,0.); + + col = SELECT(mod(float(x),8.0),col); + if (col == 0.0) return RGB(0,0,0); + if (col == 1.0) return RGB(177,52,37); + if (col == 2.0) return RGB(227,157,37); + if (col == 3.0) return RGB(106,107,4); + return RGB(0,0,0); +} + + +vec4 sprMarioWalk2(int x, int y) +{ + float col = 0.0; + if (y == 15) col = SPRROW(x,0.,0.,0.,0.,0.,1.,1.,1., 1.,1.,0.,0.,0.,0.,0.,0.); + if (y == 14) col = SPRROW(x,0.,0.,0.,0.,1.,1.,1.,1., 1.,1.,1.,1.,1.,0.,0.,0.); + if (y == 13) col = SPRROW(x,0.,0.,0.,0.,3.,3.,3.,2., 2.,3.,2.,0.,0.,0.,0.,0.); + if (y == 12) col = SPRROW(x,0.,0.,0.,3.,2.,3.,2.,2., 2.,3.,2.,2.,2.,0.,0.,0.); + if (y == 11) col = SPRROW(x,0.,0.,0.,3.,2.,3.,3.,2., 2.,2.,3.,2.,2.,2.,0.,0.); + if (y == 10) col = SPRROW(x,0.,0.,0.,3.,3.,2.,2.,2., 2.,3.,3.,3.,3.,0.,0.,0.); + if (y == 9) col = SPRROW(x,0.,0.,0.,0.,0.,2.,2.,2., 2.,2.,2.,2.,0.,0.,0.,0.); + if (y == 8) col = SPRROW(x,0.,0.,0.,0.,3.,3.,1.,3., 3.,3.,0.,0.,0.,0.,0.,0.); + + if (y == 7) col = SPRROW(x,0.,0.,0.,3.,3.,3.,3.,1., 1.,3.,3.,0.,0.,0.,0.,0.); + if (y == 6) col = SPRROW(x,0.,0.,0.,3.,3.,3.,1.,1., 2.,1.,1.,2.,0.,0.,0.,0.); + if (y == 5) col = SPRROW(x,0.,0.,0.,3.,3.,3.,3.,1., 1.,1.,1.,1.,0.,0.,0.,0.); + if (y == 4) col = SPRROW(x,0.,0.,0.,1.,3.,3.,2.,2., 2.,1.,1.,1.,0.,0.,0.,0.); + if (y == 3) col = SPRROW(x,0.,0.,0.,0.,1.,3.,2.,2., 1.,1.,1.,0.,0.,0.,0.,0.); + if (y == 2) col = SPRROW(x,0.,0.,0.,0.,0.,1.,1.,1., 3.,3.,3.,0.,0.,0.,0.,0.); + if (y == 1) col = SPRROW(x,0.,0.,0.,0.,0.,3.,3.,3., 3.,3.,3.,3.,0.,0.,0.,0.); + if (y == 0) col = SPRROW(x,0.,0.,0.,0.,0.,3.,3.,3., 3.,0.,0.,0.,0.,0.,0.,0.); + + col = SELECT(mod(float(x),8.0),col); + if (col == 0.0) return RGB(0,0,0); + if (col == 1.0) return RGB(177,52,37); + if (col == 2.0) return RGB(227,157,37); + if (col == 3.0) return RGB(106,107,4); + return RGB(0,0,0); +} + + +vec4 sprMarioWalk1(int x, int y) +{ + float col = 0.0; + if (y == 15) col = SPRROW(x,0.,0.,0.,0.,0.,0.,0.,0., 0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 14) col = SPRROW(x,0.,0.,0.,0.,0.,0.,1.,1., 1.,1.,1.,0.,0.,0.,0.,0.); + if (y == 13) col = SPRROW(x,0.,0.,0.,0.,0.,1.,1.,1., 1.,1.,1.,1.,1.,1.,0.,0.); + if (y == 12) col = SPRROW(x,0.,0.,0.,0.,0.,3.,3.,3., 2.,2.,3.,2.,0.,0.,0.,0.); + if (y == 11) col = SPRROW(x,0.,0.,0.,0.,3.,2.,3.,2., 2.,2.,3.,2.,2.,2.,0.,0.); + if (y == 10) col = SPRROW(x,0.,0.,0.,0.,3.,2.,3.,3., 2.,2.,2.,3.,2.,2.,2.,0.); + if (y == 9) col = SPRROW(x,0.,0.,0.,0.,3.,3.,2.,2., 2.,2.,3.,3.,3.,3.,0.,0.); + if (y == 8) col = SPRROW(x,0.,0.,0.,0.,0.,0.,2.,2., 2.,2.,2.,2.,2.,0.,0.,0.); + + if (y == 7) col = SPRROW(x,0.,0.,0.,0.,0.,3.,3.,3., 3.,1.,3.,0.,2.,0.,0.,0.); + if (y == 6) col = SPRROW(x,0.,0.,0.,0.,2.,3.,3.,3., 3.,3.,3.,2.,2.,2.,0.,0.); + if (y == 5) col = SPRROW(x,0.,0.,0.,2.,2.,1.,3.,3., 3.,3.,3.,2.,2.,0.,0.,0.); + if (y == 4) col = SPRROW(x,0.,0.,0.,3.,3.,1.,1.,1., 1.,1.,1.,1.,0.,0.,0.,0.); + if (y == 3) col = SPRROW(x,0.,0.,0.,3.,1.,1.,1.,1., 1.,1.,1.,1.,0.,0.,0.,0.); + if (y == 2) col = SPRROW(x,0.,0.,3.,3.,1.,1.,1.,0., 1.,1.,1.,0.,0.,0.,0.,0.); + if (y == 1) col = SPRROW(x,0.,0.,3.,0.,0.,0.,0.,3., 3.,3.,0.,0.,0.,0.,0.,0.); + if (y == 0) col = SPRROW(x,0.,0.,0.,0.,0.,0.,0.,3., 3.,3.,3.,0.,0.,0.,0.,0.); + + col = SELECT(mod(float(x),8.0),col); + if (col == 0.0) return RGB(0,0,0); + if (col == 1.0) return RGB(177,52,37); + if (col == 2.0) return RGB(227,157,37); + if (col == 3.0) return RGB(106,107,4); + return RGB(0,0,0); +} + +vec4 getTile(int t, int x, int y) +{ + if (t == 0) return RGB(107,140,255); + if (t == 1) return sprGround(x,y); + if (t == 2) return sprQuestionBlock(x,y); + if (t == 3) return sprUsedBlock(x,y); + + return RGB(107,140,255); +} + +int getSection(int s, int x, int y) +{ + float col = 0.0; + if (s == 0) { + if (y == 6) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 5) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 4) col = SECROW(x,0.,0.,3.,3.,3.,0.,0.,0.); + if (y == 3) col = SECROW(x,0.,0.,2.,2.,2.,0.,0.,0.); + if (y == 2) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 1) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y <= 0) col = SECROW(x,1.,1.,1.,1.,1.,1.,1.,1.); + } + if (s == 1) { + if (y == 6) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 5) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 4) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 3) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 2) col = SECROW(x,0.,0.,0.,0.,0.,1.,0.,0.); + if (y == 1) col = SECROW(x,0.,0.,0.,1.,1.,1.,0.,0.); + if (y <= 0) col = SECROW(x,1.,1.,1.,1.,1.,1.,1.,1.); + } + if (s == 2) { + if (y == 6) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 5) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 4) col = SECROW(x,0.,0.,3.,0.,0.,3.,0.,0.); + if (y == 3) col = SECROW(x,0.,0.,2.,0.,0.,2.,0.,0.); + if (y == 2) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 1) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y <= 0) col = SECROW(x,1.,1.,1.,1.,1.,1.,1.,1.); + } + if (s == 3) { + if (y == 6) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 5) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 4) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 3) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 2) col = SECROW(x,0.,0.,0.,1.,1.,0.,0.,0.); + if (y == 1) col = SECROW(x,0.,0.,0.,1.,1.,1.,0.,0.); + if (y <= 0) col = SECROW(x,1.,1.,1.,1.,1.,1.,1.,1.); + } + if (s == 4) { + if (y == 6) col = SECROW(x,0.,0.,0.,0.,3.,0.,0.,0.); + if (y == 5) col = SECROW(x,0.,0.,0.,0.,2.,0.,0.,0.); + if (y == 4) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 3) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 2) col = SECROW(x,0.,0.,0.,1.,1.,1.,0.,0.); + if (y == 1) col = SECROW(x,0.,0.,0.,1.,1.,1.,0.,0.); + if (y <= 0) col = SECROW(x,1.,1.,1.,1.,1.,1.,1.,1.); + } + if (s == 5) { + if (y == 6) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 5) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 4) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 3) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 2) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y == 1) col = SECROW(x,0.,0.,0.,0.,0.,0.,0.,0.); + if (y <= 0) col = SECROW(x,1.,1.,1.,0.,0.,1.,1.,1.); + } + + + + return int(SELECTSEC(mod(float(x),4.0),col)); +} + +int getBlock(int x, int y) +{ +#ifdef TOTALLY_RANDOM_LEVEL + int height = 1 + int(rand(vec2(int(float(x) / 3.0),2.3)) * 3.0); + return (y < height ? 1 : 0); +#else + if (y > 6) return 0; + + int section = int(rand(vec2(int(float(x) / 8.0),3.0)) * 6.0); + int sectionX = int(mod(float(x), 8.0)); + + return getSection(section,sectionX,y - int(rand(vec2(section,2.0)) * 0.0)); +#endif +} + +bool isSolid(int b) +{ + return (b != 0); +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + const float gameSpeed = 60.0; + + // Get the current game pixel + // (Each game pixel is two screen pixels) + // (or four, if the screen is larger) + float x = fragCoord.x / 2.0; + float y = fragCoord.y / 2.0; + if (iResolution.y >= 640.0) { + x /= 2.0; + y /= 2.0; + } + if (iResolution.y < 200.0) { + x *= 2.0; + y *= 2.0; + } + + // Just move the screen up for half a block's size + y -= 8.0; + + // Get the grid index of the block at this pixel, + // and of the block at the screen's leftmost position + int firstBlockX = int((iGlobalTime * gameSpeed) / 16.0); + int blockX = int((x + iGlobalTime * gameSpeed) / 16.0); + int blockY = int(y / 16.0); + + // Ask for the block ID that exists in the current position + int block = getBlock(blockX,blockY); + + // Get the fractional position inside current block + int subx = int(mod((x + iGlobalTime * gameSpeed),16.0)); + int suby = int(mod(y,16.0)); + + // Animate block if it's a Question Block + if (block == 2) { + if (blockX - firstBlockX == 5) { + suby -= int(max(0.0,(sin(mod((iGlobalTime * gameSpeed / 16.0),1.0) * 3.141592 * 1.5) * 8.0))); + } + + if ((floor((x + iGlobalTime * gameSpeed) / 16.0) - (iGlobalTime * gameSpeed) / 16.0) < 4.25) block = 3; + // Animate block if it's on top of a Question Block + } else if (block == 3) { + block = 2; + suby += 16; + if (blockX - firstBlockX == 5) { + suby -= int(max(0.0,(sin(mod((iGlobalTime * gameSpeed / 16.0),1.0) * 3.141592 * 1.5) * 8.0))); + } + } + // Get the final color for this pixel + // (Mario can override this later on) + fragColor = getTile(block,subx,suby); + + + // If this is the column where Mario stops simulating... + // (it's the only column he can appear in) + if (x >= endX && x < endX + 16.0) { + + // Screen position in pixels: + // Every block is 16 pixels wide + float screenX = iGlobalTime * gameSpeed; + + // Mario's starting position and speed + float marioX = screenX + startX; + float marioY = 16.0; + float marioXSpd = 4.0; + float marioYSpd = 0.0; + + // Find out the first empty block in this column, + // starting from the bottom, as to put Mario on top of it + for(int i = 1; i < 4; i++) { + if (!isSolid(getBlock(int(marioX / 16.0), i))) { + marioY = float(i) * 16.0; + break; + } + } + + // Number of steps to simulate; + // We'll simulate at 15 FPS and interpolate later, + // hence the division by 4.0 + // (Mario should actually be walking 1 pixel every 1/60th of a second, + // but he'll be walking 4 pixels every 1/15th) + const int simSteps = int((endX - startX) / 4.0); + + // Previous position, as to interpolate later, for high frame rates + float lastX = 0.0; + float lastY = 0.0; + + // Start simulating + bool onGround = false; + for(int sim = 0; sim < simSteps; sim++) { + // Store the previous position + lastX = marioX; + lastY = marioY; + + // If Mario is inside a block, move him up + // (This happens only at the start of the simulation, + // sometimes because he is heads-up with a wall and + // cannot make a jump properly) + onGround = false; + if (isSolid(getBlock(int(marioX / 16.0) + 1, int(marioY / 16.0)))) { + marioY = (floor(marioY / 16.0) * 16.0) + 16.0; + } + + // Next, pretty standard platforming code + + // Apply gravity and move in the Y-axis + marioYSpd -= 2.5; + marioY += marioYSpd; + + // If he is going up, + // and if there is a block above him, + // align him with the grid (as to avoid getting inside the block), + // and invert his YSpeed, as to fall quickly (because he bounced his head) + if (marioYSpd > 0.0) { + if (isSolid(getBlock(int(floor((marioX + 12.0) / 16.0)), int(floor((marioY + 15.9) / 16.0))))) { + marioYSpd *= -0.5; + marioY = (floor(marioY / 16.0) * 16.0); + } + } + + // If he is going down, + // and if there is a block beneath him, + // align him with the grid (as to land properly on top of the block), + // and mark him as onGround (to be able to perform a jump) + if (marioYSpd < 0.0) { + if (isSolid(getBlock(int(floor((marioX) / 16.0)), int(floor(marioY / 16.0)))) || + isSolid(getBlock(int(floor((marioX + 15.9) / 16.0)), int(floor(marioY / 16.0))))) { + marioYSpd = 0.0; + marioY = (floor(marioY / 16.0) * 16.0) + 16.0; + onGround = true; + } + } + + // Finally, move him in the X-axis + // I assume here he'll never hit a block horizontally + marioX += marioXSpd; + + // Now, if he's onGround, + // and if there are blocks in front of him, + // or if there is a pit right next to him, + // set his YSpeed to jump + if (onGround) { + if (!isSolid(getBlock(int((marioX) / 16.0) + 1,0))) { + marioYSpd = 15.5; + } else if (isSolid(getBlock(int((marioX + 36.0) / 16.0), int((marioY + 24.0) / 16.0)))) { + marioYSpd = 15.5; + } else if (isSolid(getBlock(int((marioX) / 16.0) + 2, int((marioY + 8.0) / 16.0)))) { + marioYSpd = 12.5; + } else if (getBlock(int((marioX) / 16.0) + 1, int((marioY + 8.0) / 16.0) + 2) == 2) { + marioYSpd = 15.5; + } + + } + } + + // Interpolate Y-pos for smooth high-frame-rate movement + marioY = mix(lastY,marioY,mod(iGlobalTime * 15.0,1.0)) - 1.0; + + // Finally, if he appears at this row, fetch a pixel from his sprites + if (y >= marioY && y < marioY + 16.0) { + vec4 spr = vec4(0,0,0,0); + if (onGround) { + // Which frame? + int f = int(mod(iGlobalTime * 10.0, 3.0)); + if (f == 0) spr = sprMarioWalk1(int(x - (marioX - screenX)),int(y - marioY)); + if (f == 1) spr = sprMarioWalk2(int(x - (marioX - screenX)),int(y - marioY)); + if (f == 2) spr = sprMarioWalk3(int(x - (marioX - screenX)),int(y - marioY)); + } else { + spr = sprMarioJump(int(x - (marioX - screenX)),int(y - marioY)); + } + // Transparency check + if (spr.x != 0.0) fragColor = spr; + } + } +} + +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); +} diff --git a/procedural/iq-julia-quaternion.slang b/procedural/iq-julia-quaternion.slang new file mode 100644 index 0000000..647e6f9 --- /dev/null +++ b/procedural/iq-julia-quaternion.slang @@ -0,0 +1,213 @@ +#version 450 +// Created by inigo quilez - iq/2013 +// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. + +// A port of my 2007 demo Kindernoiser: https://www.youtube.com/watch?v=9AX8gNyrSWc (http://www.pouet.net/prod.php?which=32549) +// +// More info here: http://iquilezles.org/www/articles/juliasets3d/juliasets3d.htm + +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; + +// antialias level (1, 2, 3...) +#define AA 1 + +float map( in vec3 p, out vec4 oTrap, in vec4 c ) +{ + vec4 z = vec4(p,0.0); + float md2 = 1.0; + float mz2 = dot(z,z); + + vec4 trap = vec4(abs(z.xyz),dot(z,z)); + + for( int i=0; i<11; i++ ) + { + // |dz|^2 -> 4*|dz|^2 + md2 *= 4.0*mz2; + + // z -> z2 + c + z = vec4( z.x*z.x-dot(z.yzw,z.yzw), + 2.0*z.x*z.yzw ) + c; + + trap = min( trap, vec4(abs(z.xyz),dot(z,z)) ); + + mz2 = dot(z,z); + if(mz2>4.0) break; + } + + oTrap = trap; + + return 0.25*sqrt(mz2/md2)*log(mz2); +} + +// analytic normal for quadratic formula +vec3 calcNormal( in vec3 p, in vec4 c ) +{ + vec4 z = vec4(p,0.0); + + vec4 dz0 = vec4(1.0,0.0,0.0,0.0); + vec4 dz1 = vec4(0.0,1.0,0.0,0.0); + vec4 dz2 = vec4(0.0,0.0,1.0,0.0); + vec4 dz3 = vec4(0.0,0.0,0.0,1.0); + + for(int i=0;i<11;i++) + { + vec4 mz = vec4(z.x,-z.y,-z.z,-z.w); + + // derivative + dz0 = vec4(dot(mz,dz0),z.x*dz0.yzw+dz0.x*z.yzw); + dz1 = vec4(dot(mz,dz1),z.x*dz1.yzw+dz1.x*z.yzw); + dz2 = vec4(dot(mz,dz2),z.x*dz2.yzw+dz2.x*z.yzw); + dz3 = vec4(dot(mz,dz3),z.x*dz3.yzw+dz3.x*z.yzw); + + z = vec4( dot(z, mz), 2.0*z.x*z.yzw ) + c; + + if( dot(z,z)>4.0 ) break; + } + + return normalize(vec3(dot(z,dz0), + dot(z,dz1), + dot(z,dz2))); +} + +float intersect( in vec3 ro, in vec3 rd, out vec4 res, in vec4 c ) +{ + vec4 tmp; + float resT = -1.0; + float maxd = 10.0; + float h = 1.0; + float t = 0.0; + for( int i=0; i<150; i++ ) + { + if( h<0.002||t>maxd ) break; + h = map( ro+rd*t, tmp, c ); + t += h; + } + if( t 0.5) { + if (d.x < SQRT3 * 0.5) { + rayLengthCheckVoxel = rayLength + abs (d.x) + SQRT3 * 0.5; + d.x = max (rayLengthInVoxel - rayLength + DELTA, d.x - SQRT3 * 0.5); + } + } else if (d.x < DELTA) { + break; + } + } + rayLength += d.x; + if (rayLength > rayLengthMax) { + break; + } + p += d.x * ray; + } + return vec4 (d, rayLength, rand (P)); +} + +// Normal at a given point +vec3 normal (in vec3 p, in float voxelized) { + vec2 h = vec2 (DELTA, -DELTA); + vec3 n; + if (voxelized > 0.5) { + p = fract (p + 0.5) - 0.5; + n = h.xxx * distVoxel (p + h.xxx) + + h.xyy * distVoxel (p + h.xyy) + + h.yxy * distVoxel (p + h.yxy) + + h.yyx * distVoxel (p + h.yyx); + } else { + n = h.xxx * distScene (p + h.xxx, n).x + + h.xyy * distScene (p + h.xyy, n).x + + h.yxy * distScene (p + h.yxy, n).x + + h.yyx * distScene (p + h.yyx, n).x; + } + return normalize (n); +} + +// HSV to RGB +vec3 hsv2rgb (in vec3 hsv) { + #ifdef HSV2RGB_SAFE + hsv.yz = clamp (hsv.yz, 0.0, 1.0); + #endif + #ifdef HSV2RGB_FAST + return hsv.z * (1.0 + 0.5 * hsv.y * (cos (2.0 * PI * (hsv.x + vec3 (0.0, 2.0 / 3.0, 1.0 / 3.0))) - 1.0)); + #else + return hsv.z * (1.0 + hsv.y * clamp (abs (fract (hsv.x + vec3 (0.0, 2.0 / 3.0, 1.0 / 3.0)) * 6.0 - 3.0) - 2.0, -1.0, 0.0)); + #endif +} + +// Main function +void mainImage (out vec4 fragColor, in vec2 fragCoord) { + + // Get the fragment + vec2 frag = (2.0 * fragCoord.xy - iResolution.xy) / iResolution.y; + + // Define the rendering mode + float modeTiming = iGlobalTime * 0.234; + float modeAngle = PI * cos (iGlobalTime * 0.2); + modeAngle = dot (frag - vec2 (cos (iGlobalTime * 2.0), 0.0), vec2 (cos (modeAngle), sin (modeAngle))); + float modeVoxel = step (0.5, fract (modeTiming / (4.0 * PI))); + modeTiming = cos (modeTiming); + float mode3D = smoothstep (0.8, 0.5, modeTiming); + float modeSwitch = smoothstep (0.995, 1.0, modeTiming) + smoothstep (0.02, 0.0, abs (modeAngle)) * (1.0 - modeVoxel); + modeVoxel += step (0.0, modeAngle) * (1.0 - modeVoxel); + + // Define the ray corresponding to this fragment + vec3 ray = normalize (vec3 (frag, mix (8.0, CAMERA_FOCAL_LENGTH, mode3D))); + + // Compute the orientation of the camera + float yawAngle = PI * (1.2 + 0.2 * cos (iGlobalTime * 0.5)); + float pitchAngle = PI * (0.1 * cos (iGlobalTime * 0.3) - 0.05); + #ifdef MOUSE + yawAngle += 4.0 * PI * iMouse.x / iResolution.x; + pitchAngle += PI * 0.3 * (1.0 - iMouse.y / iResolution.y); + #endif + yawAngle = mix (PI * 1.5, yawAngle, mode3D); + pitchAngle *= mode3D; + + float cosYaw = cos (yawAngle); + float sinYaw = sin (yawAngle); + float cosPitch = cos (pitchAngle); + float sinPitch = sin (pitchAngle); + + mat3 cameraOrientation; + cameraOrientation [0] = vec3 (cosYaw, 0.0, -sinYaw); + cameraOrientation [1] = vec3 (sinYaw * sinPitch, cosPitch, cosYaw * sinPitch); + cameraOrientation [2] = vec3 (sinYaw * cosPitch, -sinPitch, cosYaw * cosPitch); + + ray = cameraOrientation * ray; + + // Compute the origin of the ray + float cameraDist = mix (300.0, 95.0 + 50.0 * cos (iGlobalTime * 0.8), mode3D); + vec3 origin = (vec3 (0.0, 0.0, 40.0 * sin (iGlobalTime * 0.2)) - cameraOrientation [2] * cameraDist) / VOXEL_RESOLUTION; + + // Compute the distance to the scene + glowCounter = 0.0; + vec4 d = dist (origin, ray, modeVoxel, RAY_LENGTH_MAX / VOXEL_RESOLUTION); + + // Set the background color + vec3 finalColor = hsv2rgb (vec3 (0.2 * ray.y + 0.4 * modeVoxel - 0.37, 1.0, mode3D * BACKGROUND)); + vec3 glowColor = GLOW * vec3 (1.0, 0.3, 0.0) * glowCounter / RAY_STEP_MAX; + if (d.x < DELTA) { + + // Set the object color + vec3 color = hsv2rgb (vec3 (d.y + 0.1 * d.w * modeVoxel, 0.5 + 0.5 * modeVoxel, 1.0)); + + // Lighting + vec3 l = normalize (mix (vec3 (1.0, 0.0, 0.0), vec3 (1.25 + cos (iGlobalTime * 0.2), 1.0, 1.0), mode3D)); + #ifdef VOXEL_LIGHTING + if (modeVoxel > 0.5) { + vec3 n = normal (floor (origin + 0.5), 0.0); + float diffuse = max (0.0, dot (n, l)); + float specular = pow (max (0.0, dot (reflect (ray, n), l)), SPECULAR_POWER) * SPECULAR_INTENSITY; + color = (AMBIENT + diffuse) * color + specular; + } + #endif + vec3 n = normal (origin, modeVoxel); + float diffuse = dot (n, l); + float specular; + if (diffuse < 0.0) { + diffuse = 0.0; + specular = 0.0; + } else { + specular = pow (max (0.0, dot (reflect (ray, n), l)), SPECULAR_POWER) * SPECULAR_INTENSITY; + #ifdef SHADOW + origin += n * DELTA * 2.0; + vec4 shadow = dist (origin, l, modeVoxel, SHADOW_LENGTH / VOXEL_RESOLUTION); + if (shadow.x < DELTA) { + shadow.z = pow (min (1.0, shadow.z * VOXEL_RESOLUTION / SHADOW_LENGTH), SHADOW_POWER); + diffuse *= shadow.z; + specular *= shadow.z; + } + #endif + } + color = (AMBIENT + diffuse) * color + specular; + + // Fading + float fade = pow (max (0.0, 1.0 - d.z * VOXEL_RESOLUTION / RAY_LENGTH_MAX), FADE_POWER); + finalColor = mix (finalColor, color, fade); + } + + // Set the fragment color + finalColor = mix (pow (finalColor, vec3 (GAMMA)) + glowColor, vec3 (1.0), modeSwitch); + fragColor = vec4 (finalColor, 1.0); +} + +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); +} diff --git a/procedural/reinder-alotofspheres.slang b/procedural/reinder-alotofspheres.slang new file mode 100644 index 0000000..e758ae0 --- /dev/null +++ b/procedural/reinder-alotofspheres.slang @@ -0,0 +1,281 @@ +#version 450 +// A lot of spheres. Created by Reinder Nijhoff 2013 +// @reindernijhoff +// +// https://www.shadertoy.com/view/lsX3WH +// + +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 SHADOW +#define REFLECTION + + +#define RAYCASTSTEPS 40 + +#define EXPOSURE 0.9 +#define EPSILON 0.0001 +#define MAXDISTANCE 400. +#define GRIDSIZE 8. +#define GRIDSIZESMALL 5. +#define MAXHEIGHT 10. +#define SPEED 0.5 + +#define time iGlobalTime + +// +// math functions +// + +const mat2 mr = mat2 (0.84147, 0.54030, + 0.54030, -0.84147 ); +float hash( float n ) { + return fract(sin(n)*43758.5453); +} +vec2 hash2( float n ) { + return fract(sin(vec2(n,n+1.0))*vec2(2.1459123,3.3490423)); +} +vec2 hash2( vec2 n ) { + return fract(sin(vec2( n.x*n.y, n.x+n.y))*vec2(2.1459123,3.3490423)); +} +vec3 hash3( float n ) { + return fract(sin(vec3(n,n+1.0,n+2.0))*vec3(3.5453123,4.1459123,1.3490423)); +} +vec3 hash3( vec2 n ) { + return fract(sin(vec3(n.x, n.y, n+2.0))*vec3(3.5453123,4.1459123,1.3490423)); +} +// +// intersection functions +// + +bool intersectPlane(vec3 ro, vec3 rd, float height, out float dist) { + if (rd.y==0.0) { + return false; + } + + float d = -(ro.y - height)/rd.y; + d = min(100000.0, d); + if( d > 0. ) { + dist = d; + return true; + } + return false; +} + +bool intersectUnitSphere ( in vec3 ro, in vec3 rd, in vec3 sph, out float dist, out vec3 normal ) { + vec3 ds = ro - sph; + float bs = dot( rd, ds ); + float cs = dot( ds, ds ) - 1.0; + float ts = bs*bs - cs; + + if( ts > 0.0 ) { + ts = -bs - sqrt( ts ); + if( ts>0. ) { + normal = normalize( (ro+ts*rd)-sph ); + dist = ts; + return true; + } + } + + return false; +} + +// +// Scene +// + +void getSphereOffset( vec2 grid, inout vec2 center ) { + center = (hash2( grid+vec2(43.12,1.23) ) - vec2(0.5) )*(GRIDSIZESMALL); +} +void getMovingSpherePosition( vec2 grid, vec2 sphereOffset, inout vec3 center ) { + // falling? + float s = 0.1+hash( grid.x*1.23114+5.342+754.324231*grid.y ); + float t = 14.*s + time/s; + + float y = s * MAXHEIGHT * abs( cos( t ) ); + vec2 offset = grid + sphereOffset; + + center = vec3( offset.x, y, offset.y ) + 0.5*vec3( GRIDSIZE, 2., GRIDSIZE ); +} +void getSpherePosition( vec2 grid, vec2 sphereOffset, inout vec3 center ) { + vec2 offset = grid + sphereOffset; + center = vec3( offset.x, 0., offset.y ) + 0.5*vec3( GRIDSIZE, 2., GRIDSIZE ); +} +vec3 getSphereColor( vec2 grid ) { + return normalize( hash3( grid+vec2(43.12*grid.y,12.23*grid.x) ) ); +} + +vec3 trace(vec3 ro, vec3 rd, out vec3 intersection, out vec3 normal, out float dist, out int material) { + material = 0; // sky + dist = MAXDISTANCE; + float distcheck; + + vec3 sphereCenter, col, normalcheck; + + if( intersectPlane( ro, rd, 0., distcheck) && distcheck < MAXDISTANCE ) { + dist = distcheck; + material = 1; + normal = vec3( 0., 1., 0. ); + col = vec3( 1. ); + } else { + col = vec3( 0. ); + } + + + // trace grid + vec3 pos = floor(ro/GRIDSIZE)*GRIDSIZE; + vec3 ri = 1.0/rd; + vec3 rs = sign(rd) * GRIDSIZE; + vec3 dis = (pos-ro + 0.5 * GRIDSIZE + rs*0.5) * ri; + vec3 mm = vec3(0.0); + vec2 offset; + + for( int i=0; i 1 || distance( ro.xz, pos.xz ) > dist+GRIDSIZE ) break; + vec2 offset; + getSphereOffset( pos.xz, offset ); + + getMovingSpherePosition( pos.xz, -offset, sphereCenter ); + + if( intersectUnitSphere( ro, rd, sphereCenter, distcheck, normalcheck ) && distcheck < dist ) { + dist = distcheck; + normal = normalcheck; + material = 2; + } + + getSpherePosition( pos.xz, offset, sphereCenter ); + if( intersectUnitSphere( ro, rd, sphereCenter, distcheck, normalcheck ) && distcheck < dist ) { + dist = distcheck; + normal = normalcheck; + col = vec3( 2. ); + material = 3; + } + mm = step(dis.xyz, dis.zyx); + dis += mm * rs * ri; + pos += mm * rs; + } + + vec3 color = vec3( 0. ); + if( material > 0 ) { + intersection = ro + rd*dist; + vec2 map = floor(intersection.xz/GRIDSIZE)*GRIDSIZE; + + if( material == 1 || material == 3 ) { + // lightning + vec3 c = vec3( -GRIDSIZE,0., GRIDSIZE ); + for( int x=0; x<3; x++ ) { + for( int y=0; y<3; y++ ) { + vec2 mapoffset = map+vec2( c[x], c[y] ); + vec2 offset; + getSphereOffset( mapoffset, offset ); + vec3 lcolor = getSphereColor( mapoffset ); + vec3 lpos; + getMovingSpherePosition( mapoffset, -offset, lpos ); + + float shadow = 1.; +#ifdef SHADOW + if( material == 1 ) { + for( int sx=0; sx<3; sx++ ) { + for( int sy=0; sy<3; sy++ ) { + if( shadow < 1. ) continue; + + vec2 smapoffset = map+vec2( c[sx], c[sy] ); + vec2 soffset; + getSphereOffset( smapoffset, soffset ); + vec3 slpos, sn; + getSpherePosition( smapoffset, soffset, slpos ); + float sd; + if( intersectUnitSphere( intersection, normalize( lpos - intersection ), slpos, sd, sn ) ) { + shadow = 0.; + } + } + } + } +#endif + color += col * lcolor * ( shadow * max( dot( normalize(lpos-intersection), normal ), 0.) * + (1. - clamp( distance( lpos, intersection )/GRIDSIZE, 0., 1.) ) ); + } + } + } else { + // emitter + color = (1.5+dot(normal, vec3( 0.5, 0.5, -0.5) )) *getSphereColor( map ); + } + } + return color; +} + + +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; + + // camera + vec3 ce = vec3( cos( 0.232*time) * 10., 6.+3.*cos(0.3*time), GRIDSIZE*(time/SPEED) ); + vec3 ro = ce; + vec3 ta = ro + vec3( -sin( 0.232*time) * 10., -2.0+cos(0.23*time), 10.0 ); + + float roll = -0.15*sin(0.5*time); + + // camera tx + vec3 cw = normalize( ta-ro ); + vec3 cp = vec3( sin(roll), cos(roll),0.0 ); + vec3 cu = normalize( cross(cw,cp) ); + vec3 cv = normalize( cross(cu,cw) ); + vec3 rd = normalize( p.x*cu + p.y*cv + 1.5*cw ); + + // raytrace + int material; + vec3 normal, intersection; + float dist; + + vec3 col = trace(ro, rd, intersection, normal, dist, material); + +#ifdef REFLECTION + if( material > 0 ) { + vec3 ro = intersection + EPSILON*normal; + rd = reflect( rd, normal ); + col += 0.05 * trace(ro, rd, intersection, normal, dist, material); + } +#endif + + col = pow( col, vec3(EXPOSURE, EXPOSURE, EXPOSURE) ); + col = clamp(col, 0.0, 1.0); + + // vigneting + col *= 0.25+0.75*pow( 16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.15 ); + + fragColor = vec4( col,1.0); +} + +void main(void) +{ + //just some shit to wrap shadertoy's stuff + vec2 FragmentCoord = vTexCoord.xy*global.OutputSize.xy; + FragmentCoord.y = -FragmentCoord.y; + mainImage(FragColor,FragmentCoord); +} diff --git a/procedural/reinder-tokyo.slang b/procedural/reinder-tokyo.slang new file mode 100644 index 0000000..72f4b66 --- /dev/null +++ b/procedural/reinder-tokyo.slang @@ -0,0 +1,403 @@ +#version 450 +// Created by Reinder Nijhoff 2014 +// @reindernijhoff +// +// https://www.shadertoy.com/view/Xtf3zn +// +// car model is made by Eiffie +// shader 'Shiny Toy': https://www.shadertoy.com/view/ldsGWB + +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 BUMPMAP +#define MARCHSTEPS 128 +#define MARCHSTEPSREFLECTION 48 +#define LIGHTINTENSITY 5. + +//---------------------------------------------------------------------- + +const vec3 backgroundColor = vec3(0.2,0.4,0.6) * 0.09; +#define time (iGlobalTime + 90.) + +//---------------------------------------------------------------------- +// noises + +float hash( float n ) { + return fract(sin(n)*687.3123); +} + +float noise( in vec2 x ) { + vec2 p = floor(x); + vec2 f = fract(x); + f = f*f*(3.0-2.0*f); + float n = p.x + p.y*157.0; + return mix(mix( hash(n+ 0.0), hash(n+ 1.0),f.x), + mix( hash(n+157.0), hash(n+158.0),f.x),f.y); +} + +const mat2 m2 = mat2( 0.80, -0.60, 0.60, 0.80 ); + +float fbm( vec2 p ) { + float f = 0.0; + f += 0.5000*noise( p ); p = m2*p*2.02; + f += 0.2500*noise( p ); p = m2*p*2.03; + f += 0.1250*noise( p ); p = m2*p*2.01; +// f += 0.0625*noise( p ); + + return f/0.9375; +} + +//---------------------------------------------------------------------- +// distance primitives + +float udRoundBox( vec3 p, vec3 b, float r ) { + return length(max(abs(p)-b,0.0))-r; +} + +float sdBox( in vec3 p, in vec3 b ) { + vec3 d = abs(p) - b; + return min(max(d.x,max(d.y,d.z)),0.0) + length(max(d,0.0)); +} + +float sdSphere( in vec3 p, in float s ) { + return length(p)-s; +} + +float sdCylinder( in vec3 p, in vec2 h ) { + vec2 d = abs(vec2(length(p.xz),p.y)) - h; + return min(max(d.x,d.y),0.0) + length(max(d,0.0)); +} + +//---------------------------------------------------------------------- +// distance operators + +float opU( float d2, float d1 ) { return min( d1,d2); } +float opS( float d2, float d1 ) { return max(-d1,d2); } +float smin( float a, float b, float k ) { return -log(exp(-k*a)+exp(-k*b))/k; } //from iq + +//---------------------------------------------------------------------- +// Map functions + +// car model is made by Eiffie +// shader 'Shiny Toy': https://www.shadertoy.com/view/ldsGWB + +float mapCar(in vec3 p0){ + vec3 p=p0+vec3(0.0,1.24,0.0); + float r=length(p.yz); + float d= length(max(vec3(abs(p.x)-0.35,r-1.92,-p.y+1.4),0.0))-0.05; + d=max(d,p.z-1.0); + p=p0+vec3(0.0,-0.22,0.39); + p.xz=abs(p.xz)-vec2(0.5300,0.9600);p.x=abs(p.x); + r=length(p.yz); + d=smin(d,length(max(vec3(p.x-0.08,r-0.25,-p.y-0.08),0.0))-0.04,8.0); + d=max(d,-max(p.x-0.165,r-0.24)); + float d2=length(vec2(max(p.x-0.13,0.0),r-0.2))-0.02; + d=min(d,d2); + + return d; +} + +float dL; // minimal distance to light + +float map( const in vec3 p ) { + vec3 pd = p; + float d; + + pd.x = abs( pd.x ); + pd.z *= -sign( p.x ); + + float ch = hash( floor( (pd.z+18.*time)/40. ) ); + float lh = hash( floor( pd.z/13. ) ); + + vec3 pdm = vec3( pd.x, pd.y, mod( pd.z, 10.) - 5. ); + dL = sdSphere( vec3(pdm.x-8.1,pdm.y-4.5,pdm.z), 0.1 ); + + dL = opU( dL, sdBox( vec3(pdm.x-12., pdm.y-9.5-lh, mod( pd.z, 91.) - 45.5 ), vec3(0.2,4.5, 0.2) ) ); + dL = opU( dL, sdBox( vec3(pdm.x-12., pdm.y-11.5+lh, mod( pd.z, 31.) - 15.5 ), vec3(0.22,5.5, 0.2) ) ); + dL = opU( dL, sdBox( vec3(pdm.x-12., pdm.y-8.5-lh, mod( pd.z, 41.) - 20.5 ), vec3(0.24,3.5, 0.2) ) ); + + if( lh > 0.5 ) { + dL = opU( dL, sdBox( vec3(pdm.x-12.5,pdm.y-2.75-lh, mod( pd.z, 13.) - 6.5 ), vec3(0.1,0.25, 3.2) ) ); + } + + vec3 pm = vec3( mod( pd.x + floor( pd.z * 4. )*0.25, 0.5 ) - 0.25, pd.y, mod( pd.z, 0.25 ) - 0.125 ); + d = udRoundBox( pm, vec3( 0.245,0.1, 0.12 ), 0.005 ); + + d = opS( d, -(p.x+8.) ); + d = opU( d, pd.y ); + + vec3 pdc = vec3( pd.x, pd.y, mod( pd.z+18.*time, 40.) - 20. ); + + // car + if( ch > 0.75 ) { + pdc.x += (ch-0.75)*4.; + dL = opU( dL, sdSphere( vec3( abs(pdc.x-5.)-1.05, pdc.y-0.55, pdc.z ), 0.025 ) ); + dL = opU( dL, sdSphere( vec3( abs(pdc.x-5.)-1.2, pdc.y-0.65, pdc.z+6.05 ), 0.025 ) ); + + d = opU( d, mapCar( (pdc-vec3(5.,-0.025,-2.3))*0.45 ) ); + } + + d = opU( d, 13.-pd.x ); + d = opU( d, sdCylinder( vec3(pdm.x-8.5, pdm.y, pdm.z), vec2(0.075,4.5)) ); + d = opU( d, dL ); + + return d; +} + +//---------------------------------------------------------------------- + +vec3 calcNormalSimple( in vec3 pos ) { + const vec2 e = vec2(1.0,-1.0)*0.005; + + vec3 n = normalize( e.xyy*map( pos + e.xyy ) + + e.yyx*map( pos + e.yyx ) + + e.yxy*map( pos + e.yxy ) + + e.xxx*map( pos + e.xxx ) ); + return n; +} + +vec3 calcNormal( in vec3 pos ) { + vec3 n = calcNormalSimple( pos ); + if( pos.y > 0.12 ) return n; + +#ifdef BUMPMAP + vec2 oc = floor( vec2(pos.x+floor( pos.z * 4. )*0.25, pos.z) * vec2( 2., 4. ) ); + + if( abs(pos.x)<8. ) { + oc = pos.xz; + } + + vec3 p = pos * 250.; + vec3 xn = 0.05*vec3(noise(p.xz)-0.5,0.,noise(p.zx)-0.5); + xn += 0.1*vec3(fbm(oc.xy)-0.5,0.,fbm(oc.yx)-0.5); + + n = normalize( xn + n ); +#endif + + return n; +} + +vec3 integer1, integer2, nor1; +vec4 lint1, lint2; + +float intersect( in vec3 ro, in vec3 rd ) { + const float precis = 0.001; + float h = precis*2.0; + float t = 0.; + integer1 = integer2 = vec3( -500. ); + lint1 = lint2 = vec4( -500. ); + float mld = 100.; + + for( int i=0; i < MARCHSTEPS; i++ ) { + h = map( ro+rd*t ); + if(dL < mld){ + mld=dL; + lint1.xyz = ro+rd*t; + lint1.w = abs(dL); + } + if( h < precis ) { + integer1.xyz = ro+rd*t; + break; + } + t += max(h, precis*2.); + } + + if( integer1.z < -400. || t > 300.) { + // check intersection with plane y = -0.1; + float d = -(ro.y + 0.1)/rd.y; + if( d > 0. ) { + integer1.xyz = ro+rd*d; + } else { + return -1.; + } + } + + ro = ro + rd*t; + nor1 = calcNormal(ro); + ro += 0.01*nor1; + rd = reflect( rd, nor1 ); + t = 0.0; + h = precis*2.0; + mld = 100.; + + for( int i=0; i < MARCHSTEPSREFLECTION; i++ ) { + h = map( ro+rd*t ); + if(dL < mld){ + mld=dL; + lint2.xyz = ro+rd*t; + lint2.w = abs(dL); + } + if( h < precis ) { + integer2.xyz = ro+rd*t; + return 1.; + } + t += max(h, precis*2.); + } + + return 0.; +} + +//---------------------------------------------------------------------- +// shade + +vec3 shade( in vec3 ro, in vec3 pos, in vec3 nor ) { + vec3 col = vec3(0.5); + + if( abs(pos.x) > 15. || abs(pos.x) < 8. ) col = vec3( 0.02 ); + if( pos.y < 0.01 ) { + if( abs( integer1.x ) < 0.1 ) col = vec3( 0.9 ); + if( abs( abs( integer1.x )-7.4 ) < 0.1 ) col = vec3( 0.9 ); + } + + float sh = clamp( dot( nor, normalize( vec3( -0.3, 0.3, -0.5 ) ) ), 0., 1.); + col *= (sh * backgroundColor); + + if( abs( pos.x ) > 12.9 && pos.y > 9.) { // windows + float ha = hash( 133.1234*floor( pos.y / 3. ) + floor( (pos.z) / 3. ) ); + if( ha > 0.95) { + col = ( (ha-0.95)*10.) * vec3( 1., 0.7, 0.4 ); + } + } + + col = mix( backgroundColor, col, exp( min(max(0.1*pos.y,0.25)-0.065*distance(pos, ro),0.) ) ); + + return col; +} + +vec3 getLightColor( in vec3 pos ) { + vec3 lcol = vec3( 1., .7, .5 ); + + vec3 pd = pos; + pd.x = abs( pd.x ); + pd.z *= -sign( pos.x ); + + float ch = hash( floor( (pd.z+18.*time)/40. ) ); + vec3 pdc = vec3( pd.x, pd.y, mod( pd.z+18.*time, 40.) - 20. ); + + if( ch > 0.75 ) { // car + pdc.x += (ch-0.75)*4.; + if( sdSphere( vec3( abs(pdc.x-5.)-1.05, pdc.y-0.55, pdc.z ), 0.25) < 2. ) { + lcol = vec3( 1., 0.05, 0.01 ); + } + } + if( pd.y > 2. && abs(pd.x) > 10. && pd.y < 5. ) { + float fl = floor( pd.z/13. ); + lcol = 0.4*lcol+0.5*vec3( hash( .1562+fl ), hash( .423134+fl ), 0. ); + } + if( abs(pd.x) > 10. && pd.y > 5. ) { + float fl = floor( pd.z/2. ); + lcol = 0.5*lcol+0.5*vec3( hash( .1562+fl ), hash( .923134+fl ), hash( .423134+fl ) ); + } + + return lcol; +} + +float randomStart(vec2 co){return 0.8+0.2*hash(dot(co,vec2(123.42,117.853))*412.453);} + +//---------------------------------------------------------------------- +// main + +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; + + if (q.y < .12 || q.y >= .88) { + fragColor=vec4(0.,0.,0.,1.); + return; + } + + // camera + float z = time; + float x = -10.9+1.*sin(time*0.2); + vec3 ro = vec3(x, 1.3+.3*cos(time*0.26), z-1.); + vec3 ta = vec3(-8.,1.3+.4*cos(time*0.26), z+4.+cos(time*0.04)); + + vec3 ww = normalize( ta - ro ); + vec3 uu = normalize( cross(ww,vec3(0.0,1.0,0.0) ) ); + vec3 vv = normalize( cross(uu,ww)); + vec3 rd = normalize( -p.x*uu + p.y*vv + 2.2*ww ); + + vec3 col = backgroundColor; + + // raymarch + float ints = intersect(ro+randomStart(p)*rd ,rd ); + if( ints > -0.5 ) { + + // calculate reflectance + float r = 0.09; + if( integer1.y > 0.129 ) r = 0.025 * hash( 133.1234*floor( integer1.y / 3. ) + floor( integer1.z / 3. ) ); + if( abs(integer1.x) < 8. ) { + if( integer1.y < 0.01 ) { // road + r = 0.007*fbm(integer1.xz); + } else { // car + r = 0.02; + } + } + if( abs( integer1.x ) < 0.1 ) r *= 4.; + if( abs( abs( integer1.x )-7.4 ) < 0.1 ) r *= 4.; + + r *= 2.; + + col = shade( ro, integer1.xyz, nor1 ); + + if( ints > 0.5 ) { + col += r * shade( integer1.xyz, integer2.xyz, calcNormalSimple(integer2.xyz) ); + } + if( lint2.w > 0. ) { + col += (r*LIGHTINTENSITY*exp(-lint2.w*7.0)) * getLightColor(lint2.xyz); + } + } + + // Rain (by Dave Hoskins) + vec2 st = 256. * ( p* vec2(.5, .01)+vec2(time*.13-q.y*.6, time*.13) ); + float f = noise( st ) * noise( st*0.773) * 1.55; + f = 0.25+ clamp(pow(abs(f), 13.0) * 13.0, 0.0, q.y*.14); + + if( lint1.w > 0. ) { + col += (f*LIGHTINTENSITY*exp(-lint1.w*7.0)) * getLightColor(lint1.xyz); + } + + col += 0.25*f*(0.2+backgroundColor); + + // post processing + col = pow( clamp(col,0.0,1.0), vec3(0.4545) ); + col *= 1.2*vec3(1.,0.99,0.95); + col = clamp(1.06*col-0.03, 0., 1.); + q.y = (q.y-.12)*(1./0.76); + col *= 0.5 + 0.5*pow( 16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.1 ); + + fragColor = vec4( col, 1.0 ); +} + +void main(void) +{ + //just some shit to wrap shadertoy's stuff + vec2 FragmentCoord = vTexCoord.xy*global.OutputSize.xy; + FragmentCoord.y = -FragmentCoord.y; + mainImage(FragColor,FragmentCoord); +} diff --git a/procedural/reinder-wolfenstein3d.slang b/procedural/reinder-wolfenstein3d.slang index b681ac7..d7db23d 100644 --- a/procedural/reinder-wolfenstein3d.slang +++ b/procedural/reinder-wolfenstein3d.slang @@ -464,7 +464,7 @@ void mainImage( out vec4 fragColor, in vec2 fragCoord ) { 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); + vec2 FragmentCoord = vTexCoord.xy*global.OutputSize.xy; + FragmentCoord.y = -FragmentCoord.y; + mainImage(FragColor,FragmentCoord); } diff --git a/procedural/shane-fractal-flythrough.slang b/procedural/shane-fractal-flythrough.slang new file mode 100644 index 0000000..00bfea4 --- /dev/null +++ b/procedural/shane-fractal-flythrough.slang @@ -0,0 +1,573 @@ +#version 450 +/* + Quasi Infinite Zoom Voronoi + --------------------------- + + The infinite zoom effect has been keeping me amused for years. + + This one is based on something I wrote some time ago, but was inspired by Fabrice Neyret's + "Infinite Fall" shader. I've aired on the side of caution and called it "quasi infinite," + just in case it doesn't adhere to his strict infinite zoom standards. :) + + Seriously though, I put together a couple of overly optimized versions a couple of days ago, + just for fun, and Fabrice's comments were pretty helpful. I also liked the way he did the + layer rotation in his "Infinite Fall" version, so I'm using that. The rest is stock standard + infinite zoom stuff that has been around for years. + + Most people like to use noise for this effect, so I figured I'd do something different + and use Voronoi. I've also bump mapped it, added specular highlights, etc. It was + tempting to add a heap of other things, but I wanted to keep the example relatively simple. + + By the way, most of the code is basic bump mapping and lighting. The infinite zoom code + takes up just a small portion. + + + Fabrice Neyret's versions: + + infinite fall - short + https://www.shadertoy.com/view/ltjXWW + + infinite fall - FabriceNeyret2 + https://www.shadertoy.com/view/4sl3RX + + Other examples: + + Fractal Noise - mu6k + https://www.shadertoy.com/view/Msf3Wr + + Infinite Sierpinski - gleurop + https://www.shadertoy.com/view/MdfGR8 + + Infinite Zoom - fizzer + https://www.shadertoy.com/view/MlXGW7 + + Private link to a textured version of this. + Bumped Infinite Zoom Texture - Shane + https://www.shadertoy.com/view/Xl2XWw +*/ + + +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; + +/* + + Fractal Flythrough + ------------------ + + Moving a camera through a fractal object. It's a work in progress. + + I was looking at one of Dr2's shaders that involved moving a camera through a set of way points (set + out on the XZ plane), and thought it'd be cool to do a similar 3D version. The idea was to create a + repetitive kind of fractal object, give the open space nodes a set random direction, create some + spline points, then run a smooth camera through them. Simple... right? It always seems simple in my + head, but gets progressively harder when I try it in a shader. :) + + I've run into that classic up-vector, camera flipping problem... At least, I think that's the problem? + Anyway, I'm hoping the solution is simple, and that someone reading this will be able to point me in + the right direction. + + For now, I've set up a set of 16 random looping points that the camera seems reasonably comfortable + with. Just for the record, the general setup works nicely, until the camera loops back on itself in + the YZ plane. I'm guessing that increasing the number of way points may eradicate some of the + intermittent camera spinning, but I figured I'd leave things alone and treat it as a feature. :) + + By the way, I was thankful to have Otavio Good's spline setup in his "Alien Beacon" shader as a + reference. On a side note, that particular shader is one of my all time favorites on this site. + + The rendering materials are slightly inspired by the Steampunk genre. Timber, granite, brass, etc. + It needs spinning turbines, gears, rivots, and so forth, but that stuff's expensive. Maybe later. + Tambako Jaguar did a really cool shader in the Steampunk aesthetic. The link is below. + + Besides camera path, there's a whole bunch of improvements I'd like to make to this. I've relied on + occlusion to mask the fact that there are no shadows. I'm hoping to free up some cycles, so I can put + them back in. I'd also like to add extra detail, but that also slows things down. As for the comments, + they're very rushed, but I'll tidy those up as well. + + References: + + Alien Beacon - Otavio Good + https://www.shadertoy.com/view/ld2SzK + + Steampunk Turbine - TambakoJaguar + https://www.shadertoy.com/view/lsd3zf + + // The main inspiration for this shader. + Mandelmaze in Daylight - dr2 + https://www.shadertoy.com/view/MdVGRc + +*/ + +const float FAR = 50.0; // Far plane. + +// Used to identify individual scene objects. In this case, there are only three: The metal framework, the gold +// and the timber. +float objID = 0.; // Wood = 1., Metal = 2., Gold = 3.. + +// Simple hash function. +float hash( float n ){ return fract(cos(n)*45758.5453); } + + + +// Tri-Planar blending function. Based on an old Nvidia writeup: +// GPU Gems 3 - Ryan Geiss: https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch01.html +vec3 tex3D(sampler2D t, in vec3 p, in vec3 n ){ + + n = max(abs(n), 0.001); + n /= dot(n, vec3(1)); + vec3 tx = texture(t, p.yz).xyz; + vec3 ty = texture(t, p.zx).xyz; + vec3 tz = texture(t, p.xy).xyz; + + // Textures are stored in sRGB (I think), so you have to convert them to linear space + // (squaring is a rough approximation) prior to working with them... or something like that. :) + // Once the final color value is gamma corrected, you should see correct looking colors. + return (tx*tx*n.x + ty*ty*n.y + tz*tz*n.z); + +} + +// Common formula for rounded squares, for all intended purposes. +float lengthN(in vec2 p, in float n){ p = pow(abs(p), vec2(n)); return pow(p.x + p.y, 1.0/n); } + + +// The camera path: There are a few spline setups on Shadertoy, but this one is a slight variation of +// Otavio Good's spline setup in his "Alien Beacon" shader: https://www.shadertoy.com/view/ld2SzK +// +// Spline point markers ("cp" for camera point). The camera visits each point in succession, then loops +// back to the first point, when complete, in order to repeat the process. In case it isn't obvious, each +// point represents an open space juncture in the object that links to the previous and next point. +// Of course, running a camera in a straight line between points wouldn't produce a smooth camera effect, +// so we apply the Catmull-Rom equation to the line segment. +vec3 cp[16]; + +void setCamPath(){ + + // The larger fractal object has nodes in a 4x4x4 grid. + // The smaller one in a 2x2x2 grid. The following points + // map a path to various open areas throughout the object. + const float sl = 2.*.96; + const float bl = 4.*.96; + + cp[0] = vec3(0, 0, 0); + cp[1] = vec3(0, 0, bl); + cp[2] = vec3(sl, 0, bl); + cp[3] = vec3(sl, 0, sl); + cp[4] = vec3(sl, sl, sl); + cp[5] = vec3(-sl, sl, sl); + cp[6] = vec3(-sl, 0, sl); + cp[7] = vec3(-sl, 0, 0); + + cp[8] = vec3(0, 0, 0); + cp[9] = vec3(0, 0, -bl); + cp[10] = vec3(0, bl, -bl); + cp[11] = vec3(-sl, bl, -bl); + cp[12] = vec3(-sl, 0, -bl); + cp[13] = vec3(-sl, 0, 0); + cp[14] = vec3(-sl, -sl, 0); + cp[15] = vec3(0, -sl, 0); + + // Tighening the radius a little, so that the camera doesn't hit the walls. + // I should probably hardcode this into the above... Done. + //for(int i=0; i<16; i++) cp[i] *= .96; + +} + +// Standard Catmull-Rom equation. The equation takes in the line segment end points (p1 and p2), the +// points on either side (p0 and p3), the current fractional distance (t) along the segment, then +// returns the the smooth (cubic interpolated) position. The end result is a smooth transition +// between points... Look up a diagram on the internet. That should make it clearer. +vec3 Catmull(vec3 p0, vec3 p1, vec3 p2, vec3 p3, float t){ + + return (((-p0 + p1*3. - p2*3. + p3)*t*t*t + (p0*2. - p1*5. + p2*4. - p3)*t*t + (-p0 + p2)*t + p1*2.)*.5); + +} + +// Camera path. Determine the segment number (segNum), and how far - timewise - we are along it (segTime). +// Feed the segment, the appropriate adjoining segments, and the segment time into the Catmull-Rom +// equation to produce a camera position. The process is pretty simple, once you get the hang of it. +vec3 camPath(float t){ + + const int aNum = 16; + + t = fract(t/float(aNum))*float(aNum); // Repeat every 16 time units. + + // Segment number. Range: [0, 15], in this case. + float segNum = floor(t); + // Segment portion. Analogous to how far we are alone the individual line segment. Range: [0, 1]. + float segTime = t - segNum; + + + if (segNum == 0.) return Catmull(cp[aNum-1], cp[0], cp[1], cp[2], segTime); + + for(int i=1; iFAR) break; // Alternative: 0.001*max(t*.25, 1.) + t += h*.8; + + } + + return t; +} + + +// The reflections are pretty subtle, so not much effort is being put into them. Only eight iterations. +float refTrace(vec3 ro, vec3 rd){ + + float t = 0.0; + for(int i=0; i<16; i++){ + float d = map(ro + rd*t); + if (d < 0.0025*(t*.25 + 1.) || t>FAR) break; + t += d; + } + return t; +} + + + +/* +// Tetrahedral normal, to save a couple of "map" calls. Courtesy of IQ. +vec3 calcNormal(in vec3 p){ + + // Note the slightly increased sampling distance, to alleviate artifacts due to hit point inaccuracies. + vec2 e = vec2(0.0025, -0.0025); + return normalize(e.xyy * map(p + e.xyy) + e.yyx * map(p + e.yyx) + e.yxy * map(p + e.yxy) + e.xxx * map(p + e.xxx)); +} +*/ + +// Standard normal function. It's not as fast as the tetrahedral calculation, but more symmetrical. Due to +// the intricacies of this particular scene, it's kind of needed to reduce jagged effects. +vec3 calcNormal(in vec3 p) { + const vec2 e = vec2(0.005, 0); + return normalize(vec3(map(p + e.xyy) - map(p - e.xyy), map(p + e.yxy) - map(p - e.yxy), map(p + e.yyx) - map(p - e.yyx))); +} + +// I keep a collection of occlusion routines... OK, that sounded really nerdy. :) +// Anyway, I like this one. I'm assuming it's based on IQ's original. +float calcAO(in vec3 pos, in vec3 nor) +{ + float sca = 2.0, occ = 0.0; + for( int i=0; i<5; i++ ){ + + float hr = 0.01 + float(i)*0.5/4.0; + float dd = map(nor * hr + pos); + occ += (hr - dd)*sca; + sca *= 0.7; + } + return clamp( 1.0 - occ, 0.0, 1.0 ); +} + + +// Texture bump mapping. Four tri-planar lookups, or 12 texture lookups in total. I tried to +// make it as concise as possible. Whether that translates to speed, or not, I couldn't say. +vec3 texBump( sampler2D tx, in vec3 p, in vec3 n, float bf){ + + const vec2 e = vec2(0.001, 0); + + // Three gradient vectors rolled into a matrix, constructed with offset greyscale texture values. + mat3 m = mat3( tex3D(tx, p - e.xyy, n), tex3D(tx, p - e.yxy, n), tex3D(tx, p - e.yyx, n)); + + vec3 g = vec3(0.299, 0.587, 0.114)*m; // Converting to greyscale. + g = (g - dot(tex3D(tx, p , n), vec3(0.299, 0.587, 0.114)) )/e.x; g -= n*dot(n, g); + + return normalize( n + g*bf ); // Bumped normal. "bf" - bump factor. + +} + + +void mainImage( out vec4 fragColor, in vec2 fragCoord ){ + + + // Screen coordinates. + vec2 u = (fragCoord - iResolution.xy*0.5)/iResolution.y; + + float speed = iGlobalTime*0.35 + 8.; + + // Initiate the camera path spline points. Kind of wasteful not making this global, but I wanted + // it self contained... for better or worse. I'm not really sure what the GPU would prefer. + setCamPath(); + + + // Camera Setup. + vec3 ro = camPath(speed); // Camera position, doubling as the ray origin. + vec3 lk = camPath(speed + .5); // "Look At" position. + vec3 lp = camPath(speed + .5) + vec3(0, .25, 0); // Light position, somewhere near the moving camera. + + + // Using the above to produce the unit ray-direction vector. + float FOV = 1.57; // FOV - Field of view. + vec3 fwd = normalize(lk-ro); + vec3 rgt = normalize(vec3(fwd.z, 0, -fwd.x)); + vec3 up = (cross(fwd, rgt)); + + // Unit direction ray. + vec3 rd = normalize(fwd + FOV*(u.x*rgt + u.y*up)); + + + // Raymarch the scene. + float t = trace(ro, rd); + + // Initialize the scene color. + vec3 col = vec3(0); + + // Scene hit, so color the pixel. Technically, the object should always be hit, so it's tempting to + // remove this entire branch... but I'll leave it, for now. + if(t1.5 && rSaveObjID<2.5){ + rCol = vec3(1)*dot(rCol, vec3(.299, .587, .114))*.7 + rCol*.15;//*.7+.2 + //rDiff *= 1.35; + } + if(rSaveObjID>2.5){ + //float rc = dot(rCol, vec3(.299, .587, .114)); + vec3 rFire = pow(vec3(1.5, 1, 1)*rCol, vec3(8, 2, 1.5));//*.5+rc*.5; + rCol = min(mix(vec3(1.5, .9, .375), vec3(.75, .375, .3), rFire), 2.)*.5 + rCol; + } + + rCol *= (rDiff + .35)*rAtten; // Reflected color. Not accurate, but close enough. + + + + // Grey metal inner tubing. + if(saveObjID>1.5 && saveObjID<2.5){ + + // Grey out the limestone wall color. + col = vec3(1)*dot(col, vec3(.299, .587, .114))*.7 + col*.15; + + refl = .5; + //dif *= 1.35; + //spe2 *= 1.35; + + } + + // Gold trimming properties. More effort should probably be put in here. + // I could just write "saveObjID == 3.," but I get a little paranoid where floats are concerned. :) + if(saveObjID>2.5){ + + // For the screen image, we're interested in the offset height and depth positions. Ie: pOffs.zy. + + // Pixelized dot pattern shade. + //float c = dot(col, vec3(.299, .587, .114)); + + vec3 fire = pow(vec3(1.5, 1, 1)*col, vec3(8, 2, 1.5));//*.5+c*.5; + col = min(mix(vec3(1, .9, .375), vec3(.75, .375, .3), fire), 2.)*.5 + col;// + + refl = .65; + //dif *= 1.5; + //spe2 *= 1.5; + + } + + + // Combining everything together to produce the scene color. + col = col*(dif + .35 + vec3(.35, .45, .5)*spe) + vec3(.7, .9, 1)*spe2 + rCol*refl; + col *= occ*atten; // Applying occlusion. + + + } + + + // Applying some very slight fog in the distance. This is technically an inside scene... + // Or is it underground... Who cares, it's just a shader. :) + col = mix(min(col, 1.), vec3(0), 1.-exp(-t*t/FAR/FAR*20.));//smoothstep(0., FAR-20., t) + //col = mix(min(col, 1.), vec3(0), smoothstep(0., FAR-35., t));//smoothstep(0., FAR-20., t) + + + + // Done. + fragColor = vec4(sqrt(max(col, 0.)), 1.0); + +} + +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); +} diff --git a/procedural/shane-raymarched-reflections.slang b/procedural/shane-raymarched-reflections.slang new file mode 100644 index 0000000..5fa3dd2 --- /dev/null +++ b/procedural/shane-raymarched-reflections.slang @@ -0,0 +1,386 @@ +#version 450 +/* + Raymarched Reflections + ---------------------- + + A very basic demonstration of raymarching a distance field with reflections + and reasonably passable shadows. Definitely not cutting edge, but hopefully, + interesting to anyone who isn't quite familiar with the process. + + Reflections are pretty easy: Raymarch to the hit point, then obtain the color + at that point. Continue on from the hit point in the direction of the reflected + ray until you reach a new hit point. Obtain the color at the new point, then + add a portion of it to your original color. Repeat the process. + + Unfortunately, the extra work can slow things down, especially when you apply + shadows, which is probably why you don't see too many shadowed, reflected + examples. However, for relatively simple distance fields, it's pretty doable. + + It was tempting to do this up, but I figured a simpler example would be more + helpful. Take away the rambling comments, and there isn't a great deal of code. + I'll post a more sophisticated one later. + + // Reasonably simple examples featuring reflection: + + To the road of ribbon - XT95 + https://www.shadertoy.com/view/MsfGzr + + 704.2 - PauloFalcao + https://www.shadertoy.com/view/Xdj3Dt + + // Reflections and refraction. Really cool. + Glass Polyhedron - Nrx + https://www.shadertoy.com/view/4slSzj + +*/ + +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; + +/* + Raymarched Reflections + ---------------------- + + A very basic demonstration of raymarching a distance field with reflections + and reasonably passable shadows. Definitely not cutting edge, but hopefully, + interesting to anyone who isn't quite familiar with the process. + + Reflections are pretty easy: Raymarch to the hit point, then obtain the color + at that point. Continue on from the hit point in the direction of the reflected + ray until you reach a new hit point. Obtain the color at the new point, then + add a portion of it to your original color. Repeat the process. + + Unfortunately, the extra work can slow things down, especially when you apply + shadows, which is probably why you don't see too many shadowed, reflected + examples. However, for relatively simple distance fields, it's pretty doable. + + It was tempting to do this up, but I figured a simpler example would be more + helpful. Take away the rambling comments, and there isn't a great deal of code. + I'll post a more sophisticated one later. + + // Reasonably simple examples featuring reflection: + + To the road of ribbon - XT95 + https://www.shadertoy.com/view/MsfGzr + + 704.2 - PauloFalcao + https://www.shadertoy.com/view/Xdj3Dt + + // Reflections and refraction. Really cool. + Glass Polyhedron - Nrx + https://www.shadertoy.com/view/4slSzj + +*/ + +#define FAR 30. + +// Distance function. This one is pretty simple. I chose rounded +// spherical boxes, because they're cheap and they display the +// reflections reasonably well. +float map(vec3 p) +{ + + // Positioning the rounded cubes a little off center, in order + // to break up the space a little. + // + // "floor(p)" represents a unique number (ID) for each cube + // (based on its unique position). Take that number and produce + // a randomized 3D offset, then add it to it's regular position. + // Simple. + float n = sin(dot(floor(p), vec3(7, 157, 113))); + vec3 rnd = fract(vec3(2097152, 262144, 32768)*n)*.16-.08; + + // Repeat factor. If irregularity isn't your thing, you can get + // rid of "rnd" to line things up again. + p = fract(p + rnd) - .5; + + + // Rounded spherical boxes. The following is made up, but kind of + // makes sense. Box, minus a bit of sphericalness, gives you a + // rounded box. + p = abs(p); + return max(p.x, max(p.y, p.z)) - 0.25 + dot(p, p)*0.5; + + //return length(p) - 0.225; // Just spheres. +} + +// Standard raymarching routine. +float trace(vec3 ro, vec3 rd){ + + float t = 0., d; + + for (int i = 0; i < 96; i++){ + + d = map(ro + rd*t); + + if(abs(d)<.002 || t>FAR) break; // Normally just "d<.0025" + + t += d*.75; // Using more accuracy, in the first pass. + } + + return t; +} + +// Second pass, which is the first, and only, reflected bounce. +// Virtually the same as above, but with fewer iterations and less +// accuracy. +// +// The reason for a second, virtually identical equation is that +// raymarching is usually a pretty expensive exercise, so since the +// reflected ray doesn't require as much detail, you can relax things +// a bit - in the hope of speeding things up a little. +float traceRef(vec3 ro, vec3 rd){ + + float t = 0., d; + + for (int i = 0; i < 48; i++){ + + d = map(ro + rd*t); + + if(abs(d)<.0025 || t>FAR) break; + + t += d; + } + + return t; +} + + +// Cheap shadows are hard. In fact, I'd almost say, shadowing repeat objects - in a setting like this - with limited +// iterations is impossible... However, I'd be very grateful if someone could prove me wrong. :) +float softShadow(vec3 ro, vec3 lp, float k){ + + // More would be nicer. More is always nicer, but not really affordable... Not on my slow test machine, anyway. + const int maxIterationsShad = 24; + + vec3 rd = (lp-ro); // Unnormalized direction ray. + + float shade = 1.; + float dist = .005; + float end = max(length(rd), 0.001); + float stepDist = end/float(maxIterationsShad); + + rd /= end; + + // Max shadow iterations - More iterations make nicer shadows, but slow things down. Obviously, the lowest + // number to give a decent shadow is the best one to choose. + for (int i=0; i end) break; + //if (h<0.001 || dist > end) break; // If you're prepared to put up with more artifacts. + } + + // I've added 0.5 to the final shade value, which lightens the shadow a bit. It's a preference thing. + // Really dark shadows look too brutal to me. + return min(max(shade, 0.) + 0.25, 1.0); +} + +/* +// Standard normal function. It's not as fast as the tetrahedral calculation, but more symmetrical. Due to +// the intricacies of this particular scene, it's kind of needed to reduce jagged effects. +vec3 getNormal(in vec3 p) { + const vec2 e = vec2(0.002, 0); + return normalize(vec3(map(p + e.xyy) - map(p - e.xyy), map(p + e.yxy) - map(p - e.yxy), map(p + e.yyx) - map(p - e.yyx))); +} +*/ + +// Tetrahedral normal, to save a couple of "map" calls. Courtesy of IQ. +vec3 getNormal( in vec3 p ){ + + // Note the slightly increased sampling distance, to alleviate + // artifacts due to hit point inaccuracies. + vec2 e = vec2(0.0035, -0.0035); + return normalize( + e.xyy * map(p + e.xyy) + + e.yyx * map(p + e.yyx) + + e.yxy * map(p + e.yxy) + + e.xxx * map(p + e.xxx)); +} + +// Alternating the cube colors in a 3D checkered arrangement. +// You could just return a single color, if you wanted, but I +// thought I'd mix things up a bit. +// +// Color scheme mildly influenced by: Sound Experiment 3 - aiekick +// https://www.shadertoy.com/view/Ml2XWt +vec3 getObjectColor(vec3 p){ + + vec3 col = vec3(1); + + // "floor(p)" is analogous to a unique ID - based on position. + // This could be stepped, but it's more intuitive this way. + if(fract(dot(floor(p), vec3(.5))) > 0.001) col = vec3(0.6, 0.3, 1.0); + + return col; + +} + +// Using the hit point, unit direction ray, etc, to color the +// scene. Diffuse, specular, falloff, etc. It's all pretty +// standard stuff. +vec3 doColor(in vec3 sp, in vec3 rd, in vec3 sn, in vec3 lp){ + + vec3 ld = lp-sp; // Light direction vector. + float lDist = max(length(ld), 0.001); // Light to surface distance. + ld /= lDist; // Normalizing the light vector. + + // Attenuating the light, based on distance. + float atten = 1. / (1.0 + lDist*0.2 + lDist*lDist*0.1); + + // Standard diffuse term. + float diff = max(dot(sn, ld), 0.); + // Standard specualr term. + float spec = pow(max( dot( reflect(-ld, sn), -rd ), 0.0 ), 8.0); + + // Coloring the object. You could set it to a single color, to + // make things simpler, if you wanted. + vec3 objCol = getObjectColor(sp); + + // Combining the above terms to produce the final scene color. + vec3 sceneCol = (objCol*(diff + 0.15) + vec3(1., .6, .2)*spec*2.) * atten; + + + // Return the color. Performed once every pass... of which there are + // only two, in this particular instance. + return sceneCol; + +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ){ + + // Screen coordinates. + vec2 uv = (fragCoord.xy - iResolution.xy*.5) / iResolution.y; + + // Unit direction ray. + vec3 rd = normalize(vec3(uv, 1.0)); + + + // Some cheap camera movement, for a bit of a look around. I use this far + // too often. I'm even beginning to bore myself, at this point. :) + float cs = cos(iGlobalTime * 0.25), si = sin(iGlobalTime * 0.25); + rd.xy = mat2(cs, si, -si, cs)*rd.xy; + rd.xz = mat2(cs, si, -si, cs)*rd.xz; + + // Ray origin. Doubling as the surface position, in this particular example. + // I hope that doesn't confuse anyone. + vec3 ro = vec3(0., 0., iGlobalTime*1.5); + + // Light position. Set in the vicinity the ray origin. + vec3 lp = ro + vec3(0., 1., -.5); + + + // FIRST PASS. + + float t = trace(ro, rd); + + // Fog based off of distance from the camera. + float fog = smoothstep(0., .95, t/FAR); + + // Advancing the ray origin, "ro," to the new hit point. + ro += rd*t; + + // Retrieving the normal at the hit point. + vec3 sn = getNormal(ro); + + // Retrieving the color at the hit point, which is now "ro." I agree, reusing + // the ray origin to describe the surface hit point is kind of confusing. The reason + // we do it is because the reflective ray will begin from the hit point in the + // direction of the reflected ray. Thus the new ray origin will be the hit point. + // See "traceRef" below. + vec3 sceneColor = doColor(ro, rd, sn, lp); + + // Checking to see if the surface is in shadow. Ideally, you'd also check to + // see if the reflected surface is in shadow. However, shadows are expensive, so + // it's only performed on the first pass. If you pause and check the reflections, + // you'll see that they're not shadowed. OMG! - Better call the shadow police. :) + float sh = softShadow(ro, lp, 16.); + + + // SECOND PASS - REFLECTED RAY + + // Standard reflected ray, which is just a reflection of the unit + // direction ray off of the intersected surface. You use the normal + // at the surface point to do that. Hopefully, it's common sense. + rd = reflect(rd, sn); + + + // The reflected pass begins where the first ray ended, which is the suface + // hit point, or in a few cases, beyond the far plane. By the way, for the sake + // of simplicity, we'll perform a reflective pass for non hit points too. Kind + // of wasteful, but not really noticeable. The direction of the new ray will + // obviously be in the direction of the reflected ray. See just above. + // + // To anyone who's new to this, don't forgot to nudge the ray off of the + // initial surface point. Otherwise, you'll intersect with the surface + // you've just hit. After years of doing this, I still forget on occasion. + t = traceRef(ro + rd*.01, rd); + + // Advancing the ray origin, "ro," to the new reflected hit point. + ro += rd*t; + + // Retrieving the normal at the reflected hit point. + sn = getNormal(ro); + + // Coloring the reflected hit point, then adding a portion of it to the final scene color. + // How much you add is up to you, but I'm going with 35 percent. + sceneColor += doColor(ro, rd, sn, lp)*.35; + + + // APPLYING SHADOWS + // + // Multiply the shadow from the first pass by the final scene color. Ideally, you'd check to + // see if the reflected point was in shadow, and incorporate that too, but we're cheating to + // save cycles and skipping it. It's not really noticeable anyway. By the way, ambient + // occlusion would make it a little nicer, but we're saving cycles and keeping things simple. + sceneColor *= sh; + + // Technically, it should be applied on the reflection pass too, but it's not that + // noticeable, in this case. + sceneColor = mix(sceneColor, vec3(0), fog); + + + + + // Clamping the scene color, performing some rough gamma correction (the "sqrt" bit), then + // presenting it to the screen. + fragColor = vec4(sqrt(clamp(sceneColor, 0.0, 1.0)), 1.0); +} + +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); +}