-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgerstner.cginc
198 lines (175 loc) · 5.99 KB
/
gerstner.cginc
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#include "globals.cginc"
#include "math.cginc"
#include "pema99.cginc"
#ifndef __GERSTNER_INC
#define __GERSTNER_INC
#if defined(_GIMMICK_GERSTNER_WATER)
struct GerstnerParams {
// # of components considered
uint M;
// amplitudes
float4 a;
// phases
float4 p;
// wavenumbers
float4 k_x;
float4 k_y;
// time factor
float4 t_f;
#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP)
float4 ramp_mask;
#endif
#if defined(_GIMMICK_GERSTNER_WATER_OCTAVE_1)
float4 a1;
float4 p1;
float4 k_x1;
float4 k_y1;
float4 t_f1;
#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP)
float4 ramp_mask1;
#endif
#endif
// mean water depth
float h;
// gravity
float g;
float3 scale;
};
struct GerstnerFragResult {
float4 tangent;
float3 normal;
#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP)
float3 color;
#endif
};
GerstnerParams getGerstnerParams() {
GerstnerParams p;
p.M = _Gimmick_Gerstner_Water_M;
p.a = _Gimmick_Gerstner_Water_a;
p.p = _Gimmick_Gerstner_Water_p;
// Dumb artistic shit
float k_x_time_distortion = _SinTime[2] * .0002;
p.k_x = _Gimmick_Gerstner_Water_k_x + k_x_time_distortion;
p.k_y = _Gimmick_Gerstner_Water_k_y;
p.h = _Gimmick_Gerstner_Water_h;
p.g = _Gimmick_Gerstner_Water_g;
p.scale = _Gimmick_Gerstner_Water_Scale;
p.t_f = _Gimmick_Gerstner_Water_t_f;
#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP)
p.ramp_mask = _Gimmick_Gerstner_Water_Color_Ramp_Mask;
#endif
#if defined(_GIMMICK_GERSTNER_WATER_OCTAVE_1)
p.a1 = _Gimmick_Gerstner_Water_a1;
p.p1 = _Gimmick_Gerstner_Water_p1;
p.k_x1 = _Gimmick_Gerstner_Water_k_x1;
p.k_x1 += k_x_time_distortion;
p.k_y1 = _Gimmick_Gerstner_Water_k_y1;
p.t_f1 = _Gimmick_Gerstner_Water_t_f1;
#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP)
p.ramp_mask1 = _Gimmick_Gerstner_Water_Color_Ramp_Mask1;
#endif
#endif
return p;
}
struct GerstnerInternalResult {
float3 world_pos;
float color_ramp_pos;
};
GerstnerInternalResult compute_gerstner(float3 pp, GerstnerParams p)
{
const float g_alpha = pp.x * p.scale.x;
const float g_beta = pp.y * p.scale.y;
float g_xi = g_alpha;
float g_eta = g_beta;
float g_zeta = 0;
float g_zeta_color_ramp = 0;
for (uint i = 0; i < p.M; i++) {
uint i_mod_4 = glsl_mod(i, 4);
switch (floor(i/4)) {
case 0:
{
const float g_t = _Time[1] * p.t_f[i];
// wavenumber
const float g_k = length(float2(p.k_x[i], p.k_y[i]));
// angular frequency
const float g_w = sqrt(p.g * g_k * tanh(g_k * p.h));
// angular frequency
const float g_theta = p.k_x[i] * g_alpha + p.k_y[i] * g_beta - g_w * g_t - p.p[i];
g_xi -= (p.k_x[i] / g_k) * (p.a[i] / tanh(g_k * p.h)) * sin(g_theta);
g_eta -= (p.k_y[i] / g_k) * (p.a[i] / tanh(g_k * p.h)) * sin(g_theta);
g_zeta += p.a[i] * cos(g_theta);
#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP)
g_zeta_color_ramp += p.a[i] * cos(g_theta) * p.ramp_mask[i];
#endif
break;
}
#if defined(_GIMMICK_GERSTNER_WATER_OCTAVE_1)
case 1:
{
const float g_t = _Time[1] * p.t_f1[i_mod_4];
// wavenumber
const float g_k = length(float2(p.k_x1[i_mod_4], p.k_y1[i_mod_4]));
// angular frequency
const float g_w = sqrt(p.g * g_k * tanh(g_k * p.h));
const float g_theta = p.k_x1[i_mod_4] * g_alpha + p.k_y1[i_mod_4] * g_beta - g_w * g_t - p.p1[i_mod_4];
g_xi -= (p.k_x1[i_mod_4] / g_k) * (p.a1[i_mod_4] / tanh(g_k * p.h)) * sin(g_theta);
g_eta -= (p.k_y1[i_mod_4] / g_k) * (p.a1[i_mod_4] / tanh(g_k * p.h)) * sin(g_theta);
g_zeta += p.a1[i_mod_4] * cos(g_theta);
#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP)
g_zeta_color_ramp += p.a1[i_mod_4] * cos(g_theta) * p.ramp_mask1[i_mod_4];
#endif
break;
}
#endif
}
}
const float3 raw_result = float3(g_xi / p.scale.x, g_eta / p.scale.y, g_zeta * p.scale.z);
g_zeta_color_ramp *= p.scale.z;
const float3 raw_result_world = mul(unity_ObjectToWorld, float4(raw_result, 1)).xyz;
float3 result_world = raw_result_world;
if (_Gimmick_Gerstner_Water_Origin_Damping_Direction > 0) {
result_world.y = dmax(_Gimmick_Gerstner_Water_Origin_Damping_Direction, result_world.y, 1);
} else {
result_world.y = dmin(_Gimmick_Gerstner_Water_Origin_Damping_Direction, result_world.y, 1);
}
float3 result_obj = mul(unity_WorldToObject, float4(result_world, 1)).xyz;
result_obj = lerp(result_obj, raw_result,
// If within cylindrical distance, apply damping.
// TODO parameterize this!
dsaturate((length(raw_result_world.xz) - 15), 1) *
// Only enable if mesh is on the wrong side of the damping vector.
// TODO make this differentiable. As is, there's a visible seam.
dsaturate(-(raw_result_world.y - _Gimmick_Gerstner_Water_Origin_Damping_Direction) * sign(_Gimmick_Gerstner_Water_Origin_Damping_Direction), 1));
GerstnerInternalResult r;
r.world_pos = result_obj;
r.color_ramp_pos = g_zeta_color_ramp;
return r;
}
float3 gerstner_vert(float3 pp, GerstnerParams p)
{
return compute_gerstner(pp, p).world_pos;
}
GerstnerFragResult gerstner_frag(float3 pp, GerstnerParams p)
{
const GerstnerInternalResult r0 = compute_gerstner(pp, p);
const float3 g0 = r0.world_pos;
const float3 e = float3(1E-7, 0, 0);
const float3 g0_da = compute_gerstner(pp + e.xyz, p).world_pos;
const float3 g0_db = compute_gerstner(pp + e.yxz, p).world_pos;
const float3 ds_da = g0_da - g0;
const float3 ds_db = g0_db - g0;
GerstnerFragResult r;
r.normal = normalize(cross(
ds_da, ds_db));
r.tangent = float4(normalize(ds_da), 1);
#if defined(_GIMMICK_GERSTNER_WATER_COLOR_RAMP)
float ramp_phase = r0.color_ramp_pos;
ramp_phase *= _Gimmick_Gerstner_Water_Color_Ramp_Scale;
ramp_phase += _Gimmick_Gerstner_Water_Color_Ramp_Offset;
float3 ramp_color = _Gimmick_Gerstner_Water_Color_Ramp.Sample(linear_clamp_s, float2(ramp_phase, 0.5));
r.color = ramp_color;
#endif
return r;
}
#endif // _GIMMICK_GERSTNER_WATER
#endif // __GERSTNER_INC