Blender V4.3
ocean_spectrum.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BKE_ocean.h"
10#include "ocean_intern.h"
11
12#include <cmath>
13
14#ifdef WITH_OCEANSIM
15
16/* -------------------------------------------------------------------- */
20/*
21 * Original code from EncinoWaves project Copyright (c) 2015 Christopher Jon Horvath
22 * Modifications made to work within blender.
23 *
24 * Licensed under the Apache License, Version 2.0 (the "License");
25 * you may not use this file except in compliance with the License.
26 * You may obtain a copy of the License at
27 *
28 * http://www.apache.org/licenses/LICENSE-2.0
29 */
30
35static float alpha_beta_spectrum(const float alpha,
36 const float beta,
37 const float gamma,
38 const float omega,
39 const float peakomega)
40{
41 return (alpha * sqrt(gamma) / pow(omega, 5.0)) * exp(-beta * pow(peakomega / omega, 4.0));
42}
43
44static float peak_sharpen(const float omega, const float m_peakomega, const float m_gamma)
45{
46 const float peak_sharpening_sigma = (omega < m_peakomega) ? 0.07 : 0.09;
47 const float peak_sharpening = pow(
48 m_gamma, exp(-sqrt((omega - m_peakomega) / (peak_sharpening_sigma * m_peakomega)) / 2.0));
49
50 return peak_sharpening;
51}
52
56static float ocean_spectrum_wind_and_damp(const Ocean *oc,
57 const float kx,
58 const float kz,
59 const float val)
60{
61 const float k2 = kx * kx + kz * kz;
62 const float k_mag_inv = 1.0f / k2;
63 const float k_dot_w = (kx * k_mag_inv * oc->_wx) + (kz * k_mag_inv * oc->_wz);
64
65 /* Bias towards wind direction. */
66 float newval = val * pow(fabs(k_dot_w), oc->_wind_alignment);
67
68 /* Eliminate wavelengths smaller than cutoff. */
69 // val *= exp(-k2 * m_cutoff);
70
71 /* Reduce reflected waves. */
72 if (k_dot_w < 0.0f) {
73 if (oc->_wind_alignment > 0.0) {
74 newval *= oc->_damp_reflections;
75 }
76 }
77
78 return newval;
79}
80
81static float jonswap(const Ocean *oc, const float k2)
82{
83 /* Get our basic JONSWAP value from #alpha_beta_spectrum. */
84 const float k_mag = sqrt(k2);
85
86 const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth);
87 const float omega = sqrt(m_omega);
88
89 const float m_fetch = oc->_fetch_jonswap;
90
91 /* Strictly, this should be a random value from a Gaussian (mean 3.3, variance 0.67),
92 * clamped 1.0 to 6.0. */
93 float m_gamma = oc->_sharpen_peak_jonswap;
94 if (m_gamma < 1.0) {
95 m_gamma = 1.00;
96 }
97 if (m_gamma > 6.0) {
98 m_gamma = 6.0;
99 }
100
101 const float m_windspeed = oc->_V;
102
103 const float m_dimensionlessFetch = fabs(GRAVITY * m_fetch / sqrt(m_windspeed));
104 const float m_alpha = 0.076 * pow(m_dimensionlessFetch, -0.22);
105
106 const float m_tau = M_PI * 2;
107 const float m_peakomega = m_tau * 3.5 * fabs(GRAVITY / oc->_V) *
108 pow(m_dimensionlessFetch, -0.33);
109
110 const float beta = 1.25f;
111
112 float val = alpha_beta_spectrum(m_alpha, beta, GRAVITY, omega, m_peakomega);
113
114 /* Peak sharpening. */
115 val *= peak_sharpen(m_omega, m_peakomega, m_gamma);
116
117 return val;
118}
119
120float BLI_ocean_spectrum_piersonmoskowitz(const Ocean *oc, const float kx, const float kz)
121{
122 const float k2 = kx * kx + kz * kz;
123
124 if (k2 == 0.0f) {
125 /* No DC component. */
126 return 0.0f;
127 }
128
129 /* Get Pierson-Moskowitz value from #alpha_beta_spectrum. */
130 const float peak_omega_PM = 0.87f * GRAVITY / oc->_V;
131
132 const float k_mag = sqrt(k2);
133 const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth);
134
135 const float omega = sqrt(m_omega);
136 const float alpha = 0.0081f;
137 const float beta = 1.291f;
138
139 float val = alpha_beta_spectrum(alpha, beta, GRAVITY, omega, peak_omega_PM);
140
141 val = ocean_spectrum_wind_and_damp(oc, kx, kz, val);
142
143 return val;
144}
145
146float BLI_ocean_spectrum_texelmarsenarsloe(const Ocean *oc, const float kx, const float kz)
147{
148 const float k2 = kx * kx + kz * kz;
149
150 if (k2 == 0.0f) {
151 /* No DC component. */
152 return 0.0f;
153 }
154
155 float val = jonswap(oc, k2);
156
157 val = ocean_spectrum_wind_and_damp(oc, kx, kz, val);
158
159 /* TMA modifications to JONSWAP. */
160 const float m_depth = oc->_depth;
161 const float gain = sqrt(m_depth / GRAVITY);
162
163 const float k_mag = sqrt(k2);
164
165 const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth);
166 const float omega = sqrt(m_omega);
167
168 const float kitaigorodskiiDepth_wh = omega * gain;
169 const float kitaigorodskiiDepth = 0.5 + (0.5 * tanh(1.8 * (kitaigorodskiiDepth_wh - 1.125)));
170
171 val *= kitaigorodskiiDepth;
172
173 val = ocean_spectrum_wind_and_damp(oc, kx, kz, val);
174
175 return val;
176}
177
178float BLI_ocean_spectrum_jonswap(const Ocean *oc, const float kx, const float kz)
179{
180 const float k2 = kx * kx + kz * kz;
181
182 if (k2 == 0.0f) {
183 /* No DC component. */
184 return 0.0f;
185 }
186
187 float val = jonswap(oc, k2);
188
189 val = ocean_spectrum_wind_and_damp(oc, kx, kz, val);
190
191 return val;
192}
193
196#endif /* WITH_OCEANSIM */
float BLI_ocean_spectrum_piersonmoskowitz(const struct Ocean *oc, float kx, float kz)
float BLI_ocean_spectrum_jonswap(const struct Ocean *oc, float kx, float kz)
float BLI_ocean_spectrum_texelmarsenarsloe(const struct Ocean *oc, float kx, float kz)
sqrt(x)+1/max(0
#define M_PI
btVector3 m_depth
pow(value.r - subtrahend, 2.0)") .do_static_compilation(true)
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline float3 exp(float3 v)
INLINE Rall1d< T, V, S > tanh(const Rall1d< T, V, S > &arg)
Definition rall1d.h:422
ccl_device_inline float beta(float x, float y)
Definition util/math.h:833