precision highp float; #define lofi(i,j) (floor((i)/(j))*(j)) #define saturate(i) clamp(i,0.,1.) // 200 is recommended, use 400 if your machine is a beef const int ITER=400; const float FOG_START=30.0; const float FAR=40.0; const vec3 FOG_COLOR=vec3(1,2,3); const float PI=acos(-1.); const float TAU=2.*PI; const float SQRT3=sqrt(3.); uniform vec2 resolution; uniform float time; uniform int frame; uniform sampler2D backbuffer; out vec4 outColor; uvec3 seed; uvec3 hash3u(uvec3 s){ s=s*1145141919u+1919810u; s.x+=s.y*s.z; s.y+=s.z*s.x; s.z+=s.x*s.y; s^=s>>16; s.x+=s.y*s.z; s.y+=s.z*s.x; s.z+=s.x*s.y; return s; } vec3 hash3f(vec3 s){ uvec3 r=hash3u(floatBitsToUint(s)); return vec3(r)/float(0xffffffffu); } vec3 random3(){ seed=hash3u(seed); return vec3(seed)/float(0xffffffffu); } float random(){ return random3().x; } float easein(float x,float k){ x=saturate(x); return (k+1.)*pow(x,k)-k*pow(x,k+1.); } float easeout(float x,float k){ return 1.-easein(1.-x,k); } vec2 cis(float t){ return vec2(cos(t),sin(t)); } mat2 rotate2d(float t){ float c=cos(t),s=sin(t); return mat2(c,s,-s,c); } mat3 orthbas(vec3 z){ z=normalize(z); float isveryy=step(.999,abs(z.y)); vec3 up=vec3(0,1.-isveryy,isveryy); vec3 x=normalize(cross(up,z)); return mat3(x,cross(z,x),z); } vec2 dohex(vec2 p){ mat2 MAT_SKEW=mat2(1,1./SQRT3,0,2./SQRT3); mat2 INV_MAT_SKEW=mat2(1,-.5,0,SQRT3/2.); vec2 pt=p*MAT_SKEW; vec2 cell=floor(pt); cell.y-=mod(cell.y+cell.x+2.,3.)-1.; vec2 coord=pt-cell; float istop=step(coord.x,coord.y); cell+=vec2(1.-istop,istop); return cell*INV_MAT_SKEW; } vec4 gridt(vec3 ro,vec3 rd){ vec3 cell=vec3(dohex(ro.xy+rd.xy*1E-2),0); vec3 dice=hash3f(cell.xyy); float zoffset=dice.x; cell.z=lofi(ro.z+rd.z*1E-2-zoffset,1.)+.5+zoffset; mat4 dir=mat4( vec4(SQRT3*.5,.5,0,0), vec4(0,1,0,0), vec4(-SQRT3*.5,.5,0,0), vec4(0,0,1,0) ); vec4 rdd=vec4(rd,0)*dir; vec4 src=-(vec4(ro-cell,0)*dir)/rdd; vec4 dst=abs(vec2(SQRT3/2.,.5).xxxy/rdd); vec4 bv=src+dst; float b=min(min(bv.x,bv.y),min(bv.z,bv.w)); return vec4(cell,b); } vec4 isectmin(vec4 a,vec4 b){ return mix(a,b,step(b.w,a.w)); } vec4 isectbox(vec3 ro,vec3 rd,vec3 s){ vec3 src=-ro/rd; vec3 dst=abs(s/rd); vec3 fv=src-dst; vec3 bv=src+dst; float f=max(max(fv.x,fv.y),fv.z); float b=min(min(bv.x,bv.y),bv.z); vec3 n=-sign(rd)*step(f,fv); float isvalid=step(f,b)*step(0.,f); return vec4( n, mix(FAR,f,isvalid) ); } vec4 isecthex(vec3 ro,vec3 rd,float r,float l){ mat4 dir=mat4( vec4(SQRT3*.5,.5,0,0), vec4(0,1,0,0), vec4(-SQRT3*.5,.5,0,0), vec4(0,0,1,0) ); vec4 rdd=vec4(rd,0)*dir; vec4 src=-(vec4(ro,0)*dir)/rdd; vec4 dst=abs(vec2((SQRT3/2.)*r,l).xxxy/rdd); vec4 bv=src+dst; float b=min(min(bv.x,bv.y),min(bv.z,bv.w)); vec4 fv=src-dst; float f=max(max(fv.x,fv.y),max(fv.z,fv.w)); vec4 mask=step(f,fv); vec3 n=-(dir*mask).xyz*sign(dot(rdd,mask)); float isvalid=step(f,b)*step(0.,f); return vec4( n, mix(FAR,f,isvalid) ); } vec3 sampleggx(vec3 n,float aa){ vec3 xi=random3(); float costheta=sqrt((1.-xi.y)/(1.+(aa-1.)*xi.y)); float sintheta=sqrt(1.-costheta*costheta); return orthbas(n)*vec3( sintheta*cis(TAU*xi.x), costheta ); } void main() { seed=uvec3(gl_FragCoord.xy,frame); vec2 uv=gl_FragCoord.xy/resolution.xy; vec2 p=uv*2.-1.; p.x*=resolution.x/resolution.y; vec3 co; vec3 ro; vec3 rd; float rl; vec3 col=vec3(0); vec3 colrem=vec3(0); float samples=0.; for(int i=0;i1.&&dice.z<.1){ float showz=grid.z-co.z+mix(0.,40.,dice.x); float size=easeout(showz/5.,5.)-easeout((showz-20.)/5.,3.); vec4 isect2=isecthex(ro-grid.xyz,rd,size*.7,size*.2); if(isect2.w1.){ float mt=PI/3.*floor(mod(dice.x*18.,6.)); mat2 m=rotate2d(mt); vec3 rpt=ro-grid.xyz; rpt.xy*=m; vec3 rdt=rd; rdt.xy*=m; vec4 isect2=isectmin( isecthex(rpt-vec3(.72,.0,.0),rdt,.01,.49), isecthex(rpt-vec3(-.72,.0,.0),rdt,.01,.49) ); isect2.xy*=rotate2d(-mt); if(isect2.w1.&&dice.z<.54){ float mt=PI/3.*floor(dice.x*3.); mat2 m=rotate2d(mt); vec3 rpt=ro-grid.xyz; rpt.xy*=m; vec3 rdt=rd; rdt.xy*=m; vec4 isect2=isectmin( isectbox(rpt-vec3(0,0.8,0.),rdt,vec3(.5,0.02,.45)), isectbox(rpt-vec3(0,-0.8,0.),rdt,vec3(.5,0.02,.45)) ); bool isface=abs(isect2.y)>.5; isect2.xy*=rotate2d(-mt); if(isect2.w=FAR){ col+=colrem*FOG_COLOR; colrem*=0.; } continue; } // update ray ro+=isect.w*rd; rl+=isect.w; // do the shading vec3 n=isect.xyz; // fog float fog=smoothstep(FOG_START,FAR,rl); col+=colrem*fog*FOG_COLOR; colrem*=1.-fog; // ggx vec3 h=sampleggx(n,alpha*alpha); float dotvh=dot(-rd,h); rd=reflect(rd,h); // fresnel float f=mix(f0,1.,pow(saturate(1.-dotvh),5.)); // emissive col+=colrem*(1.-f)*ecol; // albedo colrem*=f*step(0.,dot(rd,n)); // fresnel, visibility } // post processing col/=samples; // sum -> average col=pow(col/(col+1.),vec3(.4545)); // reinhard, oetf // col*=1.-.2*length(p)*length(p); // vignette col=smoothstep(vec3(0.0,-0.1,-0.3),vec3(1.0,1.0,1.1),col); // color grading // temporal accumulation vec4 prev=texture(backbuffer,uv); outColor=mix(vec4(col,1),prev,.5*prev.w); // debug // outColor.xyz=cos(PI*(saturate(samples/10.)-vec3(.5,1.5,2.5)/3.)); // blue == enough samples, red == too few samples }