Skip to content

Instantly share code, notes, and snippets.

@ufna
Created September 16, 2022 10:16
Show Gist options
  • Save ufna/d28b84efa5afec90b8401fbb83c409d3 to your computer and use it in GitHub Desktop.
Save ufna/d28b84efa5afec90b8401fbb83c409d3 to your computer and use it in GitHub Desktop.
Coastal Landscape Shadertoy UE4
// Author: bitless
// Title: Coastal Landscape
// Thanks to Patricio Gonzalez Vivo & Jen Lowe for "The Book of Shaders"
// and Fabrice Neyret (FabriceNeyret2) for https://shadertoyunofficial.wordpress.com/
// and Inigo Quilez (iq) for https://iquilezles.org/www/index.htm
// and whole Shadertoy community for inspiration.
#define p(t, a, b, c, d) ( a + b*cos( 6.28318*(c*t+d) ) ) //IQ's palette function (https://www.iquilezles.org/www/articles/palettes/palettes.htm)
#define sp(t) p(t,float3(.26,.76,.77),float3(1,.3,1),float3(.8,.4,.7),float3(0,.12,.54)) //sky palette
#define hue(v) ( .6 + .76 * cos(6.3*(v) + float4(0,23,21,0) ) ) //hue
struct Functions
{
// "Hash without Sine" by Dave_Hoskins.
// https://www.shadertoy.com/view/4djSRW
float hash12(float2 p)
{
float3 p3 = frac(float3(p.xyx) * .1031);
p3 += dot(p3, p3.yzx + 33.33);
return frac((p3.x + p3.y) * p3.z);
}
float2 hash22(float2 p)
{
float3 p3 = frac(float3(p.xyx) * float3(.1031, .1030, .0973));
p3 += dot(p3, p3.yzx+33.33);
return frac((p3.xx+p3.yz)*p3.zy);
}
////////////////////////
float2 rotate2D (float2 st, float a){
return mul(float2x2(cos(a),-sin(a),sin(a),cos(a)), st);
}
float st(float a, float b, float s) //AA bar
{
return smoothstep (a-s, a+s, b);
}
float noise( in float2 p ) //gradient noise
{
float2 i = floor( p );
float2 f = frac( p );
float2 u = f*f*(3.-2.*f);
return lerp( lerp( dot( hash22( i+float2(0,0) ), f-float2(0,0) ),
dot( hash22( i+float2(1,0) ), f-float2(1,0) ), u.x),
lerp( dot( hash22( i+float2(0,1) ), f-float2(0,1) ),
dot( hash22( i+float2(1,1) ), f-float2(1,1) ), u.x), u.y);
}
};
Functions func;
float4 O;
float2 g = fragCoord;//(fragCoord.xy * 2.0 - iResolution.xy) / min(iResolution.x, iResolution.y);
float2 r = iResolution.xy
,uv = (g+g-r)/r.y
,sun_pos = float2(r.x/r.y*.42,-.53) //sun position
,tree_pos = float2(-r.x/r.y*.42,-.2) //tree position
,sh, u, id, lc, t;
float3 f = float3(0,0,0);
float3 c;
float xd, yd, h, a, l;
float4 C;
float sm = 3./r.y; //smoothness factor for AA
sh = func.rotate2D(sun_pos, func.noise(uv+iTime*.25)*.3); //big noise on the sky
if (uv.y > -.4) //drawing the sky
{
u = uv + sh;
yd = 60.; //number of rings
id = float2((length(u)+.01)*yd,0); //segment id: x - ring number, y - segment number in the ring
xd = floor(id.x)*.09; //number of ring segments
h = (func.hash12(floor(id.xx))*.5+.25)*(iTime+10.)*.25; //ring shift
t = func.rotate2D (u,h); //rotate the ring to the desired angle
id.y = atan2(t.y,t.x)*xd;
lc = frac(id); //segment local coordinates
id -= lc;
// determining the coordinates of the center of the segment in uv space
t = float2(cos((id.y+.5)/xd)*(id.x+.5)/yd,sin((id.y+.5)/xd)*(id.x+.5)/yd);
t = func.rotate2D(t,-h) - sh;
h = func.noise(t*float2(.5,1)-float2(iTime*.2,0)) //clouds
* step(-.25,t.y); //do not draw clouds below -.25
h = smoothstep (.052,.055, h);
lc += (func.noise(lc*float2(1,4)+id))*float2(.7,.2); //add fine noise
f = lerp (sp(sin(length(u)-.1))*.35, //sky background
lerp(sp(sin(length(u)-.1)+(func.hash12(id)-.5)*.15),float3(1,1,1),h), //lerp sky color and clouds
func.st(abs(lc.x-.5),.4,sm*yd)*func.st(abs(lc.y-.5),.48,sm*xd));
};
if (uv.y < -.35) //drawing water
{
float cld = func.noise(-sh*float2(.5,1) - float2(iTime*.2,0)); //cloud density opposite the center of the sun
cld = 1.- smoothstep(.0,.15,cld)*.5;
u = uv*float2(1,15);
id = floor(u);
for (float i = 1.; i > -1.; i--) //drawing a wave and its neighbors from above and below
{
if (id.y+i < -5.)
{
lc = frac(u)-.5;
lc.y = (lc.y+(sin(uv.x*12.-iTime*3.+id.y+i))*.25-i)*4.; //set the waveform and divide it into four strips
h = func.hash12(float2(id.y+i,floor(lc.y))); //the number of segments in the strip and its horizontal offset
xd = 6.+h*4.;
yd = 30.;
lc.x = uv.x*xd+sh.x*9.; //divide the strip into segments
lc.x += sin(iTime * (.5 + h*2.))*.5; //add a cyclic shift of the strips horizontally
h = .8*smoothstep(5.,.0,abs(floor(lc.x)))*cld+.1; //determine brightness of the sun track
f = lerp(f,lerp(float3(0,.1,.5),float3(.35,.35,0),h),func.st(lc.y,0.,sm*yd)); //lerp the color of the water and the color of the track for the background of the water
lc += func.noise(lc*float2(3,.5))*float2(.1,.6); //add fine noise to the segment
f = lerp(f, //lerp the background color
lerp(hue(func.hash12(floor(lc))*.1+.56).rgb*(1.2+floor(lc.y)*.17),float3(1,1,0),h) //and the stroke color
,func.st(lc.y,0.,sm*xd)
*func.st(abs(frac(lc.x)-.5),.48,sm*xd)*func.st(abs(frac(lc.y)-.5),.3,sm*yd)
);
}
}
}
O = float4(f,1);
////////////////////// drawing the grass
a = 0.;
u = uv+func.noise(uv*2.)*.1 + float2(0,sin(uv.x*1.+3.)*.4+.8);
f = lerp(float3(.7,.6,.2),float3(0,1,0),sin(iTime*.2)*.5+.5); //color of the grass, changing from green to yellow and back again
O = lerp(O,float4(f*.4,1),step(u.y,.0)); //draw grass background
xd = 60.; //grass size
u = u*float2(xd,xd/3.5);
if (u.y < 1.2)
{
for (float y = 0.; y > -3.; y--)
{
for (float x = -2.; x <3.; x++)
{
id = floor(u) + float2(x,y);
lc = (frac(u) + float2(1.-x,-y))/float2(5,3);
h = (func.hash12(id)-.5)*.25+.5; //shade and length for an individual blade of grass
lc-= float2(.3,.5-h*.4);
lc.x += sin(((iTime*1.7+h*2.-id.x*.05-id.y*.05)*1.1+id.y*.5)*2.)*(lc.y+.5)*.5;
t = abs(lc)-float2(.02,.5-h*.5);
l = length(max(t,0.)) + min(max(t.x,t.y),0.); //distance to the segment (blade of grass)
l -= func.noise (lc*7.+id)*.1; //add fine noise
C = float4(f*.25,func.st(l,.1,sm*xd*.09)); //grass outline
C = lerp(C,float4(f //grass foregroud
*(1.2+lc.y*2.) //the grass is a little darker at the root
*(1.8-h*2.5),1.) //brightness variations for individual blades of grass
,func.st(l,.04,sm*xd*.09));
O = lerp (O,C,C.a*step (id.y,-1.));
a = max (a, C.a*step (id.y,-5.)); //a mask to cover the trunk of the tree with grasses in the foreground
}
}
}
float T = sin(iTime*.5); //tree swing cycle
if (abs(uv.x+tree_pos.x-.1-T*.1) < .6) // drawing the tree
{
u = uv + tree_pos;
// draw the trunk of the tree first
u.x -= sin(u.y+1.)*.2*(T+.75); //the trunk bends in the wind
u += func.noise(u*4.5-7.)*.25; //trunk curvature
xd = 10., yd = 60.;
t = u * float2(1,yd); //divide the trunk into segments
h = func.hash12(floor(t.yy)); //horizontal shift of the segments and the color tint of the segment
t.x += h*.01;
t.x *= xd;
lc = frac(t); //segment local coordinates
float m = func.st(abs(t.x-.5),.5,sm*xd)*step(abs(t.y+20.),45.); //trunk mask
C = lerp(float4(.07, .07, .07, .07) //outline color
,float4(.5,.3,0,1)*(.4+h*.4) //foreground color
,func.st(abs(lc.y-.5),.4,sm*yd)*func.st(abs(lc.x-.5),.45,sm*xd));
C.a = m;
xd = 30., yd = 15.;
for (float xs =0.;xs<4.;xs++) //drawing four layers of foliage
{
u = uv + tree_pos + float2 (xs/xd*.5 -(T +.75)*.15,-.7); //crown position
u += func.noise(u*float2(2,1)+float2(-iTime+xs*.05,0))*float2(-.25,.1)*smoothstep (.5,-1.,u.y+.7)*.75; //leaves rippling in the wind
t = u * float2(xd,1.);
h = func.hash12(floor(t.xx)+xs*1.4); //number of segments for the row
yd = 5.+ h*7.;
t.y *= yd;
sh = t;
lc = frac(t);
h = func.hash12(t-lc); //segment color shade
t = (t-lc)/float2(xd,yd)+float2(0,.7);
m = (step(0.,t.y)*step (length(t),.45) //the shape of the crown - the top
+ step (t.y,0.)*step (-0.7+sin((floor(u.x)+xs*.5)*15.)*.2,t.y)) //the bottom
*step (abs(t.x),.5) //crown size horizontally
*func.st(abs(lc.x-.5),.35,sm*xd*.5);
lc += func.noise((sh)*float2(1.,3.))*float2(.3,.3); //add fine noise
f = hue((h+(sin(iTime*.2)*.5+.5))*.2).rgb-t.x; //color of the segment changes cyclically
C = lerp(C,
float4(lerp(f*.15,f*.6*(.7+xs*.2), //lerp outline and foreground color
func.st(abs(lc.y-.5),.47,sm*yd)*func.st(abs(lc.x-.5),.2,sm*xd)),m)
,m);
}
O = lerp (O,C,C.a*(1.-a));
}
return O;
@ufna
Copy link
Author

ufna commented Sep 16, 2022

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment