PeriDyno 1.0.0
Loading...
Searching...
No Matches
OceanPatch.cu
Go to the documentation of this file.
1#include "OceanPatch.h"
2
3#include "Topology/HeightField.h"
4
5#include "Mapping/HeightFieldToTriangleSet.h"
6
7#include "Algorithm/CudaRand.h"
8
9#include "GLSurfaceVisualModule.h"
10
11#include "Math/Lerp.h"
12
13#include <math_constants.h>
14
15#include <fstream>
16
17namespace dyno
18{
19 template<typename TDataType>
20 OceanPatch<TDataType>::OceanPatch()
21 : Node()
22 {
23 this->setAutoHidden(true);
24
25 auto heights = std::make_shared<HeightField<TDataType>>();
26 this->stateHeightField()->setDataPtr(heights);
27
28 std::ifstream input(getAssetPath() + "windparam.txt", std::ios::in);
29 for (int i = 0; i <= 12; i++)
30 {
31 WindParam param;
32 int dummy;
33 input >> dummy;
34 input >> param.windSpeed;
35 input >> param.A;
36 input >> param.choppiness;
37 input >> param.global;
38 mParams.push_back(param);
39 }
40 mSpectrumWidth = this->varResolution()->getValue() + 1;
41 mSpectrumHeight = this->varResolution()->getValue() + 4;
42
43 auto callback = std::make_shared<FCallBackFunc>(std::bind(&OceanPatch<TDataType>::resetWindType, this));
44
45 this->varWindType()->attach(callback);
46 this->varWindType()->setRange(0, 12);
47 this->varWindType()->setValue(5);
48
49 this->varWindDirection()->setRange(0, 360);
50
51 auto mapper = std::make_shared<HeightFieldToTriangleSet<DataType3f>>();
52 this->stateHeightField()->connect(mapper->inHeightField());
53 this->graphicsPipeline()->pushModule(mapper);
54
55 auto sRender = std::make_shared<GLSurfaceVisualModule>();
56 sRender->varBaseColor()->setValue(Color::Blue1());
57 sRender->varUseVertexNormal()->setValue(true);
58 mapper->outTriangleSet()->connect(sRender->inTriangleSet());
59 this->graphicsPipeline()->pushModule(sRender);
60 }
61
62 template<typename TDataType>
63 OceanPatch<TDataType>::~OceanPatch()
64 {
65 mH0.clear();
66 mHt.clear();
67 mDxt.clear();
68 mDzt.clear();
69 }
70
71 template<typename Real>
72 __device__ Complex<Real> complex_exp(Real arg)
73 {
74 return Complex<Real>(cosf(arg), sinf(arg));
75 }
76
77 // generate wave heightfield at time t based on initial heightfield and dispersion relationship
78 template <typename Real, typename Complex>
79 __global__ void OP_GenerateSpectrumKernel(
80 DArray2D<Complex> h0,
81 DArray2D<Complex> ht,
82 unsigned int in_width,
83 unsigned int out_width,
84 unsigned int out_height,
85 Real t,
86 Real patchSize)
87 {
88 unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
89 unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
90 unsigned int in_index = y * in_width + x;
91 unsigned int in_mindex = (out_height - y) * in_width + (out_width - x); // mirrored
92 unsigned int out_index = y * out_width + x;
93
94 // calculate wave vector
95 Complex k((-(int)out_width / 2.0f + x) * (2.0f * CUDART_PI_F / patchSize), (-(int)out_width / 2.0f + y) * (2.0f * CUDART_PI_F / patchSize));
96
97 // calculate dispersion w(k)
98 Real k_len = k.normSquared();
99 Real w = sqrtf(9.81f * k_len);
100
101 if ((x < out_width) && (y < out_height))
102 {
103 Complex h0_k = h0(x, y);
104 Complex h0_mk = h0(out_width - x, out_height - y);
105
106 // output frequency-space complex values
107 ht[out_index] = h0_k * complex_exp(w * t) + h0_mk.conjugate() * complex_exp(-w * t);
108 }
109 }
110
111 template <typename Real, typename Complex>
112 __global__ void OP_GenerateDispalcementKernel(
113 DArray2D<Complex> ht,
114 DArray2D<Complex> Dxt,
115 DArray2D<Complex> Dzt,
116 unsigned int width,
117 unsigned int height,
118 Real patchSize)
119 {
120 unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
121 unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
122
123 // calculate wave vector
124 Real kx = (-(int)width / 2.0f + x) * (2.0f * CUDART_PI_F / patchSize);
125 Real ky = (-(int)height / 2.0f + y) * (2.0f * CUDART_PI_F / patchSize);
126 Real k_squared = kx * kx + ky * ky;
127 if (k_squared == 0.0f)
128 {
129 k_squared = 1.0f;
130 }
131 kx = kx / sqrtf(k_squared);
132 ky = ky / sqrtf(k_squared);
133
134 Complex ht_ij = ht(x, y);
135 Complex idoth = Complex(-ht_ij.imagPart(), ht_ij.realPart());
136
137 Dxt(x, y) = kx * idoth;
138 Dzt(x, y) = ky * idoth;
139 }
140
141 template<typename TDataType>
142 void OceanPatch<TDataType>::resetWindType()
143 {
144 int windType = this->varWindType()->getValue();
145 this->varAmplitude()->setValue(mParams[windType].A);
146 this->varWindSpeed()->setValue(mParams[windType].windSpeed);
147 this->varChoppiness()->setValue(mParams[windType].choppiness);
148 this->varGlobalShift()->setValue(mParams[windType].global);
149 }
150
151 template <typename Real, typename Complex>
152 __global__ void OP_GenerateH0(
153 DArray2D<Complex> h0,
154 Real winDir,
155 Real winSpeed,
156 Real winDirDependence,
157 Real amplitude,
158 Real patchSize,
159 Real G,
160 uint res)
161 {
162 unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
163 unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
164 if (x >= h0.nx() || y >= h0.ny()) return;
165
166 Real scaledWinDir = winDir * (M_PI / Real(180));
167
168 RandNumber rd(x * y);
169
170 auto phillips = [=](Real Kx, Real Ky, Real Vdir, Real V, Real A, Real dir_depend) -> Real
171 {
172 Real k_squared = Kx * Kx + Ky * Ky;
173
174 if (k_squared == 0.0f)
175 {
176 return 0.0f;
177 }
178
179 // largest possible wave from constant wind of velocity v
180 Real L = V * V / G;
181
182 Real k_x = Kx / std::sqrt(k_squared);
183 Real k_y = Ky / std::sqrt(k_squared);
184 Real w_dot_k = k_x * std::cos(Vdir) + k_y * std::sin(Vdir);
185
186 Real phillips = A * std::exp(-1.0f / (k_squared * L * L)) / (k_squared * k_squared) * w_dot_k * w_dot_k;
187
188 // filter out waves moving opposite to wind
189 if (w_dot_k < 0.0f)
190 {
191 phillips *= dir_depend;
192 }
193
194 return phillips;
195 };
196
197 auto gauss = [&]() -> Real
198 {
199 Real u1 = rd.Generate();
200 Real u2 = rd.Generate();
201
202 if (u1 < EPSILON)
203 {
204 u1 = EPSILON;
205 }
206
207 return glm::sqrt(-2 * glm::log(u1)) * glm::cos(2 * CUDART_PI_F * u2);
208 };
209
210 Real kx = (-(int)res / 2.0f + x) * (2.0f * CUDART_PI_F / patchSize);
211 Real ky = (-(int)res / 2.0f + y) * (2.0f * CUDART_PI_F / patchSize);
212
213 Real P = glm::sqrt(phillips(kx, ky, scaledWinDir, winSpeed, amplitude, winDirDependence));
214
215 if (glm::abs(kx) < EPSILON && glm::abs(ky) == EPSILON)
216 {
217 P = 0.0f;
218 }
219
220 Real Er = gauss();
221 Real Ei = gauss();
222
223 Real h0_re = Er * P * CUDART_SQRT_HALF_F;
224 Real h0_im = Ei * P * CUDART_SQRT_HALF_F;
225
226 h0(x, y) = Complex(h0_re, h0_im);
227 }
228
229 template<typename TDataType>
230 void OceanPatch<TDataType>::resetStates()
231 {
232 uint res = this->varResolution()->getValue();
233
234 cufftPlan2d(&fftPlan, res, res, CUFFT_C2C);
235
236 int spectrumSize = mSpectrumWidth * mSpectrumHeight * sizeof(Complex);
237 mH0.resize(mSpectrumWidth, mSpectrumHeight);
238
239// Complex* host_h0 = (Complex*)malloc(spectrumSize);
240// generateH0(host_h0);
241//
242// cuSafeCall(cudaMemcpy(mH0.begin(), host_h0, spectrumSize, cudaMemcpyHostToDevice));
243
244 cuExecute2D(make_uint2(mSpectrumWidth, mSpectrumHeight),
245 OP_GenerateH0,
246 mH0,
247 this->varWindDirection()->getValue(),
248 this->varWindSpeed()->getValue(),
249 mDirDepend,
250 this->varAmplitude()->getValue(),
251 this->varPatchSize()->getValue(),
252 g,
253 res);
254
255 mHt.resize(res, res);
256 mDxt.resize(res, res);
257 mDzt.resize(res, res);
258 mDisp.resize(res, res);
259
260 auto topo = this->stateHeightField()->getDataPtr();
261 Real h = this->varPatchSize()->getValue() / res;
262 topo->setExtents(res, res);
263 topo->setGridSpacing(h);
264 topo->setOrigin(Vec3f(-0.5 * h * topo->width(), 0, -0.5 * h * topo->height()));
265
266 this->update();
267 }
268
269 template<typename TDataType>
270 void OceanPatch<TDataType>::updateStates()
271 {
272 Real timeScaled = this->varTimeScale()->getValue() * this->stateElapsedTime()->getValue();
273
274 uint res = this->varResolution()->getValue();
275
276 cuExecute2D(make_uint2(res, res),
277 OP_GenerateSpectrumKernel,
278 mH0,
279 mHt,
280 mSpectrumWidth,
281 res,
282 res,
283 timeScaled,
284 this->varPatchSize()->getData());
285
286 cuExecute2D(make_uint2(res, res),
287 OP_GenerateDispalcementKernel,
288 mHt,
289 mDxt,
290 mDzt,
291 res,
292 res,
293 this->varPatchSize()->getData());
294
295 cufftExecC2C(fftPlan, (float2*)mHt.begin(), (float2*)mHt.begin(), CUFFT_INVERSE);
296 cufftExecC2C(fftPlan, (float2*)mDxt.begin(), (float2*)mDxt.begin(), CUFFT_INVERSE);
297 cufftExecC2C(fftPlan, (float2*)mDzt.begin(), (float2*)mDzt.begin(), CUFFT_INVERSE);
298
299 cuExecute2D(make_uint2(res, res),
300 O_UpdateDisplacement,
301 mDisp,
302 mHt,
303 mDxt,
304 mDzt,
305 res);
306 }
307
308 template<typename TDataType>
309 void OceanPatch<TDataType>::postUpdateStates()
310 {
311 auto choppiness = this->varChoppiness()->getValue();
312
313 auto topo = this->stateHeightField()->getDataPtr();
314
315 auto h = topo->getGridSpacing();
316 auto origin = topo->getOrigin();
317
318 auto& shifts = topo->getDisplacement();
319
320 uint2 extent;
321 extent.x = shifts.nx();
322 extent.y = shifts.ny();
323 cuExecute2D(extent,
324 CW_UpdateHeightDisp,
325 shifts,
326 mDisp,
327 origin,
328 h,
329 choppiness);
330
331 // topo->rasterize();
332 }
333
334 template<typename Coord, typename Complex>
335 __global__ void O_UpdateDisplacement(
336 DArray2D<Coord> displacement,
337 DArray2D<Complex> Dh,
338 DArray2D<Complex> Dx,
339 DArray2D<Complex> Dz,
340 int patchSize)
341 {
342 unsigned int i = blockIdx.x * blockDim.x + threadIdx.x;
343 unsigned int j = blockIdx.y * blockDim.y + threadIdx.y;
344 if (i < patchSize && j < patchSize)
345 {
346 Real sign_correction = ((i + j) & 0x01) ? -1.0f : 1.0f;
347 Real h_ij = sign_correction * Dh(i, j).realPart();
348 Real x_ij = sign_correction * Dx(i, j).realPart();
349 Real z_ij = sign_correction * Dz(i, j).realPart();
350
351 displacement(i, j) = Coord(x_ij, h_ij, z_ij);
352 }
353 }
354
355 template <typename Real, typename Coord>
356 __global__ void CW_UpdateHeightDisp(
357 DArray2D<Coord> heights,
358 DArray2D<Coord> dis,
359 Coord origin,
360 Real h,
361 Real choppiness)
362 {
363 unsigned int i = blockIdx.x * blockDim.x + threadIdx.x;
364 unsigned int j = blockIdx.y * blockDim.y + threadIdx.y;
365 if (i < heights.nx() && j < heights.ny())
366 {
367 Real x = (i * h - origin.x) / h;
368 Real y = (j * h - origin.y) / h;
369
370 Coord Dij = bilinear(dis, x, y, LerpMode::REPEAT);
371
372 Coord v;
373 v[0] = choppiness * Dij[0];
374 v[1] = Dij[1];
375 v[2] = choppiness * Dij[2];
376
377 heights(i, j) = v;
378 }
379 }
380
381 DEFINE_CLASS(OceanPatch);
382}