-
Notifications
You must be signed in to change notification settings - Fork 15
/
Protean clouds.sksl
143 lines (118 loc) · 5.05 KB
/
Protean clouds.sksl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Protean clouds
// Original: https://www.shadertoy.com/view/3l23Rh
// Created by nimitz in 2019-05-27
// License Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
/*
Technical details:
The main volume noise is generated from a deformed periodic grid, which can produce
a large range of noise-like patterns at very cheap evalutation cost. Allowing for multiple
fetches of volume gradient computation for improved lighting.
To further accelerate marching, since the volume is smooth, more than half the the density
information isn't used to rendering or shading but only as an underlying volume distance to
determine dynamic step size, by carefully selecting an equation (polynomial for speed) to
step as a function of overall density (not necessarily rendered) the visual results can be
the same as a naive implementation with ~40% increase in rendering performance.
Since the dynamic marching step size is even less uniform due to steps not being rendered at all
the fog is evaluated as the difference of the fog integral at each rendered step.
*/
const int MAX_ITERATIONS = 80;
uniform vec2 iResolution;
uniform float iTime;
mat2 rot(in float a) {
float c = cos(a), s = sin(a);
return mat2(c,s,-s,c);
}
const mat3 m3 = mat3(0.33338, 0.56034, -0.71817, -0.87887, 0.32651, -0.15323, 0.15162, 0.69596, 0.61339) * 1.93;
float mag2(vec2 p) { return dot(p,p); }
float linstep(in float mn, in float mx, in float x) { return clamp((x - mn)/(mx - mn), 0., 1.); }
float prm1 = 0.;
vec2 disp(float t) { return vec2(sin(t*0.22)*1., cos(t*0.175)*1.)*2.; }
vec2 map(vec3 p) {
vec3 p2 = p;
p2.xy -= disp(p.z).xy;
p.xy *= rot(sin(p.z + iTime) * (0.1 + prm1 * 0.05) + iTime * 0.09);
float cl = mag2(p2.xy);
float d = 0.;
p *= .61;
float z = 1.;
float trk = 1.;
float dspAmp = 0.1 + prm1 * 0.2;
for(int i = 0; i < 5; i++) {
p += sin(p.zxy * 0.75 * trk + iTime * trk * .8) * dspAmp;
d -= abs(dot(cos(p), sin(p.yzx)) * z);
z *= 0.57;
trk *= 1.4;
p = p * m3;
}
d = abs(d + prm1 * 3.) + prm1 * .3 - 2.5;
return vec2(d + cl * .2 + 0.25, cl);
}
vec4 render(in vec3 ro, in vec3 rd, float time) {
vec4 rez = vec4(0);
const float ldst = 8.;
vec3 lpos = vec3(disp(time + ldst) * 0.5, time + ldst);
float t = 1.5;
float fogT = 0.;
for(int i = 0; i < MAX_ITERATIONS; i++) {
if(rez.a > 0.99) break;
vec3 pos = ro + t * rd;
vec2 mpv = map(pos);
float den = clamp(mpv.x - 0.3, 0., 1.) * 1.12;
float dn = clamp((mpv.x + 2.), 0., 3.);
vec4 col = vec4(0);
if(mpv.x > 0.6) {
col = vec4(sin(vec3(5.,0.4,0.2) + mpv.y * 0.1 + sin(pos.z * 0.4) * 0.5 + 1.8) * 0.5 + 0.5, 0.08);
col *= den * den * den;
col.rgb *= linstep(4., -2.5, mpv.x) * 2.3;
float dif = clamp((den - map(pos + .8).x) / 9., 0.001, 1.);
dif += clamp((den - map(pos + .35).x) / 2.5, 0.001, 1.);
col.xyz *= den * (vec3(0.005, .045, .075) + 1.5 * vec3(0.033, 0.07, 0.03) * dif);
}
float fogC = exp(t * 0.2 - 2.2);
col.rgba += vec4(0.06, 0.11, 0.11, 0.1) * clamp(fogC - fogT, 0., 1.);
fogT = fogC;
rez = rez + col * (1. - rez.a);
t += clamp(0.5 - dn * dn * .05, 0.09, 0.3);
}
return clamp(rez, 0.0, 1.0);
}
float getsat(vec3 c) {
float mi = min(min(c.x, c.y), c.z);
float ma = max(max(c.x, c.y), c.z);
return (ma - mi) / (ma + 1e-7);
}
// from my "Will it blend" shader (https://www.shadertoy.com/view/lsdGzN)
vec3 iLerp(in vec3 a, in vec3 b, in float x) {
vec3 ic = mix(a, b, x) + vec3(1e-6, 0., 0.);
float sd = abs(getsat(ic) - mix(getsat(a), getsat(b), x));
vec3 dir = normalize(vec3(2. * ic.x - ic.y - ic.z, 2. * ic.y - ic.x - ic.z, 2. * ic.z - ic.y - ic.x));
float lgt = dot(vec3(1.0), ic);
float ff = dot(dir, normalize(ic));
ic += 1.5 * dir * sd * ff * lgt;
return clamp(ic, 0., 1.);
}
vec4 main(vec2 fragCoord) {
vec4 fragColor = vec4(0.0);
vec2 q = fragCoord / iResolution;
vec2 p = (fragCoord - 0.5 * iResolution) / iResolution.y;
float time = iTime * 3.;
vec3 ro = vec3(0, 0, time);
ro += vec3(sin(iTime) * 0.5, sin(iTime * 1.) * 0., 0);
float dspAmp = .85;
ro.xy += disp(ro.z) * dspAmp;
float tgtDst = 3.5;
vec3 target = normalize(ro - vec3(disp(time + tgtDst) * dspAmp, time + tgtDst));
vec3 rightdir = normalize(cross(target, vec3(0, 1, 0)));
vec3 updir = normalize(cross(rightdir, target));
rightdir = normalize(cross(updir, target));
vec3 rd = normalize((p.x * rightdir + p.y * updir) * 1. - target);
rd.xy *= rot(-disp(time + 3.5).x * 0.2);
prm1 = smoothstep(-0.4, 0.4, sin(iTime * 0.3));
vec4 scn = render(ro, rd, time);
vec3 col = scn.rgb;
col = iLerp(col.bgr, col.rgb, clamp(1. - prm1, 0.05, 1.));
col = pow(col, vec3(.55, 0.65, 0.6)) * vec3(1., .97, .9);
col *= pow(16.0 * q.x * q.y * (1.0 - q.x) * (1.0 - q.y), 0.12) * 0.7 + 0.3; // Vign
fragColor = vec4(col, 1.0);
return fragColor;
}