// 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 }