// Searching for the silver lining 1K by Seven/Fulcrum
//----------------------------------------------------
float v=gl_Color.x*600, // we use the build-in gl_Color to pass the time to the shader.
// The value set with glColor3us is a simple framecounter, assuming 60 FPS
t=smoothstep(26,40,v); // This global varies between 0 (dark & stormy) and 1 ( sunny and calm)
// This is the noise function that is used both for the macro shape of the clouds and the fluffy micro layer.
// It computes 5 octaves of sine-based noise. Note that using tons of sine/cosine functions is a lot slower
// on AMD card than on Nvidia cards (at least for the RX480/GTX1060 generations)
// The first parameter is a time-motion multiplier, use 0 for noise that shouldn't animate over time.
// The second parameter is the 3d position for which to evaluate the noise.
float p(float t,vec3 r)
{
float m=0,// Result
x=1,// scale factor
y=1;// speed factor
for(float s=0;s<5;s++) // 5 octaves of noise
r+=sin(r.zxy*.19*y+v*y*t), // distort future position with another layer of sine waves, based on current position and time
m+=abs(dot(cos(r),sin(r.yzx))*x), // add sine noise to result. The abs() call makes the noise cloudlike instead of blobby.
x*=.57, // For the next iteration, halve the scale (approximately)
y*=1.4, // For the next iteration, increase the motion speed ( smaller details move faster)
r.xy=.91*vec3(r.y,-r.x,0)+r.xy*-.42, // Rotate the current position around the Z-axis. Since the same angle is used every time, we can hardcode the sin/cos values,
// and then mess around with them. The code originally contained a vec2(r.y,-r.x), but replacing all vec2(A,B)s with vec3(A,B,0)s
// compressed better. Same for putting the -.42 after the multiply instead of in front. 1K compression is weird like that...
r=1.93*vec3(r.yzx); // For the next iteration, double the frequency, and swizzle the XYZ axes so the next rotation will be around a different axis.
return m;
}
// The distance function: returns distance to clouds, negative values once inside the cloud.
float p(vec3 r)
{
return-p((1-t)*.4,r)*.14 // This is the micro shape of the clouds, moving quite fast (.4) at the start and halting at the end
+r.y*.04 // Make more clouds at the bottom, less at the top
+sin(r.y*.28)*.5 // Make horizontal layers of clouds
+exp(p(.1+(1-t)*.2,r*.05)*-1+2.5); // Macro structure of clouds, moving very slow ( .05), with size 2.5
// The *-1 is there because my shader optimizer broke and I only now noticed it, while commenting this final version
}
void main()
{
vec3 r=vec3(-vec3(1,.55,0)+gl_FragCoord.xy*.0015,.5), // Direction of the ray for this pixel, for 1280*720 resolution
y=0; // total accumulated color on this ray
r.xy+=sin(cos(1+v*.5)*.2)*vec3(r.y,-r.x,0); // roll the camera slightly along the Z axis with a bastardized rotation formula
float m=1, // transparency, starts at 100%
x=1.5, // start distance
v=max(6.3,v); // local v is a copy of the time (in global v), frozen at the start to stay inside the cloud and have a 2D effect first.
for(float s=0;s<160;s++) // 160 steps maximum. Note I'm using the same variable name as in the other for loop, this helps compression a lot.
if(m>.02) // halt early if the transparency is almost 0
{
// cam path: Values chosen to stay in a cloud initially, then never hit the clouds again but graze them.
vec3 r=vec3(sin(v*.5)*30, // cam path: strafing left and right
cos(v*1.8)*.6-41-exp(-v*.67)*1156, // cam path: moving upwards, slow down once neat the top of the clouds.
5*v) // cam path: moving forward.
+x*normalize(r); // distance traveled * normalized direction
float v=p(r); // get current distance to or in clouds
if(v>=.05) // Still outside the cloud?
x+=max(.3,v); // march along, and take big enough steps.
else
y+=smoothstep(0,1,-v)* // The cloud-scattering is faked by a light-emitting fuzzy layer around the center. The deeper in the cloud, the less light is emitted.
mix(mix(vec3(.2), // storm clouds color, edge
vec3(.8,.6,.3),t), // sunny cloud color, edge
mix(vec3(.1), // storm clouds center, center
vec3(0,.3,.7),t), // sunny cloud color, center
smoothstep(0,1,-v) // blend between edge and center colors
)
*(max(0, // this max assures only the top side of the clouds is lit by the sun
v-(p(r-1)*.25+ // evaluate the density of the clouds 3 extra times diagonally from the current position, mix to get a shadow/sunlit effect.
p(r-2)*.25+
p(r-4)*.5
)
)*3+1
)
*max(.1,v+1) // limit the darkness of the center (don't go into negative intensity)
*m, // and take remaining transparency from current point to camera in account.
m-=smoothstep(0,1,-v)*m, // accumulate transparency, high at the edge,low at the center of the cloud
x+=.2; // march inside the cloud using small steps
}
gl_FragColor.xyz=pow(
mix(vec3(.1), // Sky background color when stormy
vec3(1,.88,.74),t) // sky background color when sunny
*m+y, // additive blend of background and emitted color
vec3(.55,.65,.6) // tinted gamma correction
)-.3*length(r.xy); // use ray direction to darken the corners, as cheap vignetting
}