Shader ported from shadertoy.com to use as card illustration in Fragment Forge.


License is under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License as is standard in Shadertoy.

Feed it iTime variable from gdscript

Pass it two textures for iChannel0 and iChannel1. You might have to experiment a bit to find some textures that work well.


Shader code
shader_type canvas_item;
// Using code from

// evvvvil for the Monster Things shader
// https://www.shadertoy.com/view/wdSfzh
// Ported to Godot and customized for FragmentForge by Db0

// Licence: Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// https://creativecommons.org/licenses/by-nc-sa/3.0/deed.en_US

uniform bool is_card = true;
uniform float iTime;
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;

// Monster Things - Result of an improvised live code session on Twitch
// LIVE SHADER CODING, SHADER SHOWDOWN STYLE, EVERY TUESDAYS 21:00 Uk time: https://www.twitch.tv/evvvvil_
// Thankx to Haptix and canadianCornDog for the suggestions!
// Music by OddJohn / HANDSOME HOOLIGANS - https://soundcloud.com/oddjohnofficial

// "Motherfuckers stole my 80s style!" - Steven Spielberg

float smin(float a,float b,float h){float k=clamp((a-b)/h*.5+.5,0.,1.); return mix(a,b,k)-k*(1.-k)*h;} //Add geometries with smooth blend. Yeah this is what Sade talks about in the song "Smoothhhhhhh Operatooooor"
float smax(float d1,float d2,float k){float h=clamp(0.5-0.5*(d2+d1)/k,0.,1.);return mix(d2,-d1,h)+k*h*(1.0-h);}//Remove geometries with smooth blend. yeah sorry couldn't make a lamer joke than the one above...
mat2 r2(float r){return mat2(vec2(cos(r),sin(r)),vec2(-sin(r),cos(r)));}//Rotate function. Short and sweet, just like how Kim Jung Un could be, if he had been given enough attention as a child.
vec4 texNoise(vec2 uv){ 
	float f = 0.; 
	f+=texture(iChannel0,uv*.125).r*.5; //Rough shadertoy approximation of the bonzomatic noise texture by yx - https://www.shadertoy.com/view/tdlXW4
	return vec4(f*.45+.05);
vec2 mp( vec3 p, inout vec3 op, inout vec3 tp, inout vec3 sp, inout vec3 hp, inout vec3 ep, inout float g, inout float gg)
  float tt=mod(iTime,62.82); 
  op=p;//Remember original position in op
  p.z=mod(p.z+tt*6.,78.)-39.;//Modulo and animate everything else along the z axis
  tp=p;//Tunnel position is moduloed and animated (line above) but NOT twisted along z axis (next line)    
  p.xy*=r2(sin(op.z*.2+tt*2.)*.5);//Twist everything else along the z axis and animnate
  sp=p;//Sp is spine position used everywhere for monster
  float dis=sin(op.z*.2+tt*1.2)*1.+sin(op.z*.1+tt*.6)*.5; //dis is deformer / displacement along z axis with sin
  float zf=sin(p.z*15.)*0.03; //zf is z axis frill adding nice details like rib cage and crest
  float xf=sin(p.x*15.)*0.03; //xf is x axis frill adding nice details on edges etc
  float tnoi=texNoise(p.yz*.1).r*.8; //tnoi is texture noise displacement by sampling texture and making perlin, adds great curnchy organic details
  float fft=texture( iChannel1, vec2(min(abs(op.z*.002)*.15,5.),0)).x; //Audio sync along z limited to first 5 fft samples (bass)
  sp.xy+=dis;//add deformer to spine position
  vec2 h,t=vec2(length(sp.xy+xf)-(2.-dis+tnoi),5); //make main spline with deformer also influencing the radius not just position + texture displacement
  t.x=smin(t.x,length(abs(sp.xy+xf)-(1.5-dis))-(.5+tnoi),.5); //Add 4 cylinder to create edges again with deformer and texture displacement
  t.x=smin(t.x,length(abs(sp.xy+zf)-vec2(0,2.1-dis))-(.5+tnoi),.5);  //CREST made of two cylinder above and bellow with deformer and texture displacement
  t.x=smax((length(abs(sp.xy+zf)-vec2(2.-dis,0))-(1.-dis+tnoi)),t.x,.3);//RIBS made by carving out 2 cylinders on side and adding x axis frill
  hp=ep=sp; //horn positions and electricitings position
  hp.z=mod(hp.z,3.)-1.5; //modulo horn position along z to have loads of them on the crest
  t.x=smax(length(abs(hp-vec3(0,0,.2))-vec3(0,2.1-dis,0))-(.6+tnoi-dis*.4),t.x,.5); //HOLES FOR HORNS by reusing hp and shifting a bit
  hp.z-=min(pow(hp.y*.1,2.)*5.,5.);//HORN DEFORMER. Bend them forward menacingly. This could also be said in a BDSM scenario, involving people, also wearing horns.
  h=vec2(length(hp.xz+xf)-(.5+tnoi-dis*.4-abs(pow(hp.y*.09,2.)*4.)),6);  //HORNS made using hp postion and horn deformer
  h.x*=0.7; //We gotta increase the definition of horn geometry as they are deformed a lot, this avoids artifact
  t=t.x<h.x?t:h; //Add horns geometry to the scene while retinaing material id
  sp.y*=0.5;//EGGS position is reusing spine position but scaled along y to make spheres a taller egg shape
  sp.z=mod(sp.z,3.)-1.5; //Modulo along z to create many eggs along z axis, it's the same modulo frequency as for the horn position to align holes, horns and eggs. "Align holes, horns and eggs" sounds like a very good Peter Greenaway film!
  h=vec2(length(sp)-(max(.8,1.-dis*.5)),6);  //Make the actual eggs geometry and use displacement variable to change radius
  g+=0.1/(0.1+h.x*h.x*40.);//Add eggs distance field to red glow variable (added at the end)
  t=t.x<h.x?t:h;  //Add eggs to the scene
  for(int i=0;i<2;i++){//ELECTRICITINGS KIFS
   ep=abs(ep)-2.;//Each iter pull apart by 2 on xyz 
   ep.xy*=r2(-.3); //Rotate bit on XY
   ep.yz*=r2(.5);  //Rotate more on YZ
  h=vec2(length(ep.xz+tnoi*5.),3);  //Make electricitings, please note the lack of radius, -0 in fact so ignored, that is how you get pure LASER. let's be pedantic about these things, this isn't Stepney Green Bingo Hall
  gg+=0.4/(0.1+h.x*h.x*1.+1.*abs(sin(ep.y*.4-tt*2.)));//Add electricitings distance field to blue glow variable (added at the end)
  t=t.x<h.x?t:h;  //Add electricitings to scene  
  h=vec2(length(tp.xy)-27.,6);  //OUTTER CYLINDER FOR TUNNEL
  tnoi=texNoise(vec2(abs(atan(tp.x,tp.y)),tp.z*.1-76.)*(.07)).r*14.;//REDEFINE texture noise with polar uvs
  h.x=max(h.x,-(length(tp.xy)-14.+tnoi+fft*3.)); //CUT HOLE IN TUNNEL
  h.x=smax((length(abs(tp)-vec3(0,15.-fft*2.,0))-(4.+tnoi)),h.x,1.);//HOLES FOR BLUE SPHERES
  h.x*=0.8; t=t.x<h.x?t:h; //Tweak disitance field to remove artifact and add to the scene
  h=vec2((length(abs(tp)-vec3(0,15.-fft*2.,0))-(3.+tnoi)),7);//BLUE SPHERES 
  gg+=0.4/(0.1+h.x*h.x*1.+1.*abs(sin(ep.y*.4-tt*2.-.7))); //Add blue spheres distance field to blue glow variable (added right at end)
  t=t.x<h.x?t:h; //Add blue spheres to scene 
  t.x*=0.6; return t;
vec2 tr( inout vec3 ro, inout vec3 rd, inout vec3 op, inout vec3 tp, inout vec3 sp, inout vec3 hp, inout vec3 ep, inout float g, inout float gg) // main trace / raycast / raymarching loop function 
  vec2 h,t= vec2(.1); //Near plane because when it all started the hipsters still lived in Norwich and they only wore tweed.
  for(int i=0;i<128;i++){ //Main loop de loop 
    h=mp(ro+rd*t.x, op, tp,  sp, hp, ep,  g, gg); //Marching forward like any good fascist army: without any care for culture theft. (get distance to geom)
    if(h.x<.00001||t.x>120.) break;//Conditional break we hit something or gone too far. Don't let the bastards break you down!
    t.x+=h.x;t.y=h.y; //Huge step forward and remember material id. Let me hold the bottle of gin while you count the colours.
  if(t.x>120.) t.y=0.;//If we've gone too far then we stop, you know, like Alexander The Great did when he realised his wife was sexting some Turkish bloke. (10 points whoever gets the reference)
  return t;
//#define a(d) clamp(mp(po+no*d).x/d,0.,1.)
//#define s(d) smoothstep(0.,1.,mp(po+ld*d).x/d)
void fragment()//2 lines above are a = ambient occlusion and s = sub surface scattering
//	vec2 z=vec2(.01,-.01);
//	vec2 v=vec2(.01,-.01);
	vec2 e=vec2(.01,-.01);
	float g;
	float gg;
	vec3 sp;
	vec3 tp;
	vec3 ep;
	vec3 op;
	vec3 hp;
  vec2 iResolution =  1.0 / SCREEN_PIXEL_SIZE;
//  vec2 uv=(FRAGCOORD.xy/iResolution.xy-0.5)/vec2(iResolution.y/iResolution.x,1); //get UVs, nothing fancy, 
  vec2 uv = -UV;
  uv *= 1.2;
  uv += 0.5 * 1.2; 
    uv.x *= iResolution.x/iResolution.y;
  float tt=mod(iTime,62.82);  //Time variable, modulo'ed to avoid ugly artifact. Imagine moduloing your timeline, you would become a cry baby straight after dying a bitter old man. Christ, that's some fucking life you've lived, Steve.
  vec2 v=mix(vec2(3.,8.8),vec2(12.,16.),ceil(cos(tt*.4)));//Reuse the v variable as holder of camera variables
  vec3 ro=vec3(cos(tt*.4)*7.,sin(tt*.4)*7.,-10.);//Ro=ray origin=camera position We build camera right here broski. Gotta be able to see, to peep through the keyhole.
  vec3 cw=normalize(vec3(0,0,cos(tt*.6)*8.)-ro);
  vec3 cu=normalize(cross(cw,vec3(sin(tt*.3)*.5,1,0)));
  vec3 cv=normalize(cross(cu,cw)); //camera forward, left and up vector.
  vec3 rd=mat3(cu,cv,cw)*normalize(vec3(uv,.5));//rd=ray direction (where the camera is pointing), co=final color, fo=fog color
  vec3 ld=normalize(vec3(.2,.5,-.3));//ld=light direction
  vec3 co=vec3(.1)-length(uv)*.1;//background is dark with vignette
  vec3 fo=vec3(.1)-length(uv)*.1;//background is dark with vignette
  vec2 z=tr(ro,rd,op,tp,sp,hp,ep,g,gg);
  float t=z.x; //Trace the trace in the loop de loop. Sow those fucking ray seeds and reap them fucking pixels.
  if(z.y>0.){ //Yeah we hit something, unlike you trying to throw a spear at a pig. We wouldnt have survive the ice age with you and your nerdy mates.
    vec3 po=ro+rd*t; //Get ray pos, know where you at, be where you is.
    vec3 no=normalize(e.xyy*mp(po+e.xyy,op,tp,sp,hp,ep,g,gg).x+e.yyx*mp(po+e.yyx,op,tp,sp,hp,ep,g,gg).x+e.yxy*mp(po+e.yxy,op,tp,sp,hp,ep,g,gg).x+e.xxx*mp(po+e.xxx,op,tp,sp,hp,ep,g,gg).x); //Make some fucking normals. You do the maths while I count how many brain cells I lost during my mid 2000s raving haydays.
    vec3 al=mix(vec3(.4,.5,.6),vec3(.6,.3,.2),.5+.5*sin(tp.z*.3-1.5));//albedo is base colour by default it's greyish to redish gradient
    if(z.y<5.) al=vec3(0); //material system if less than 5 make it black
    if(z.y>5.) al=vec3(1); //material system if more than 5 make it white
    if(z.y>6.) al=vec3(.1,.2,.4);//Material Id more than 6 makes it blue
    float dif=max(0.,dot(no,ld)); //Dumb as fuck diffuse lighting
    float fr=pow(1.+dot(no,rd),4.);
	float sp2=pow(max(dot(reflect(-ld,no),-rd),0.),50.);//Sp=specular, stolen from shane
    co=mix(sp2+al*(clamp(mp(po+no*.1,op,tp,sp,hp,ep,g,gg).x/.1,0.,1.)*clamp(mp(po+no*.3,op,tp,sp,hp,ep,g,gg).x/.3,0.,1.)+.2)*(vec3(.5,.2,.1)*dif+smoothstep(0.,1.,mp(po+ld*.5,op,tp,sp,hp,ep,g,gg).x/.5)*1.5),fo,min(fr,.5));//Building the final lighting result, compressing the fuck outta everything above into an RGB shit sandwich
    co=mix(fo,co,exp(-.00007*t*t*t)); //Fog soften things, but it won't stop your annoying uncle from thinking "Bloody fiddling with bloody numbers, ain't gonna get you a job, son. Real graft is what ye need, wee man."(last sentence read with Scottish accent if you can)
  COLOR = vec4(pow(co+g*.2*vec3(.5,.2,.1)+gg*.1*vec3(.1,.2,.4),vec3(.55)),1); //Add glow at the end. g & gg are red and blue glow global variables containg distance fields see lines 42,50,58
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from db0




Inline Feedbacks
View all comments