3#include "Topology/HeightField.h"
5#include "Mapping/HeightFieldToTriangleSet.h"
7#include "Algorithm/CudaRand.h"
9#include "GLSurfaceVisualModule.h"
13#include <math_constants.h>
19 template<typename TDataType>
20 OceanPatch<TDataType>::OceanPatch()
23 this->setAutoHidden(true);
25 auto heights = std::make_shared<HeightField<TDataType>>();
26 this->stateHeightField()->setDataPtr(heights);
28 std::ifstream input(getAssetPath() + "windparam.txt", std::ios::in);
29 for (int i = 0; i <= 12; i++)
34 input >> param.windSpeed;
36 input >> param.choppiness;
37 input >> param.global;
38 mParams.push_back(param);
40 mSpectrumWidth = this->varResolution()->getValue() + 1;
41 mSpectrumHeight = this->varResolution()->getValue() + 4;
43 auto callback = std::make_shared<FCallBackFunc>(std::bind(&OceanPatch<TDataType>::resetWindType, this));
45 this->varWindType()->attach(callback);
46 this->varWindType()->setRange(0, 12);
47 this->varWindType()->setValue(5);
49 this->varWindDirection()->setRange(0, 360);
51 auto mapper = std::make_shared<HeightFieldToTriangleSet<DataType3f>>();
52 this->stateHeightField()->connect(mapper->inHeightField());
53 this->graphicsPipeline()->pushModule(mapper);
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);
62 template<typename TDataType>
63 OceanPatch<TDataType>::~OceanPatch()
71 template<typename Real>
72 __device__ Complex<Real> complex_exp(Real arg)
74 return Complex<Real>(cosf(arg), sinf(arg));
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(
82 unsigned int in_width,
83 unsigned int out_width,
84 unsigned int out_height,
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;
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));
97 // calculate dispersion w(k)
98 Real k_len = k.normSquared();
99 Real w = sqrtf(9.81f * k_len);
101 if ((x < out_width) && (y < out_height))
103 Complex h0_k = h0(x, y);
104 Complex h0_mk = h0(out_width - x, out_height - y);
106 // output frequency-space complex values
107 ht[out_index] = h0_k * complex_exp(w * t) + h0_mk.conjugate() * complex_exp(-w * t);
111 template <typename Real, typename Complex>
112 __global__ void OP_GenerateDispalcementKernel(
113 DArray2D<Complex> ht,
114 DArray2D<Complex> Dxt,
115 DArray2D<Complex> Dzt,
120 unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
121 unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
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)
131 kx = kx / sqrtf(k_squared);
132 ky = ky / sqrtf(k_squared);
134 Complex ht_ij = ht(x, y);
135 Complex idoth = Complex(-ht_ij.imagPart(), ht_ij.realPart());
137 Dxt(x, y) = kx * idoth;
138 Dzt(x, y) = ky * idoth;
141 template<typename TDataType>
142 void OceanPatch<TDataType>::resetWindType()
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);
151 template <typename Real, typename Complex>
152 __global__ void OP_GenerateH0(
153 DArray2D<Complex> h0,
156 Real winDirDependence,
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;
166 Real scaledWinDir = winDir * (M_PI / Real(180));
168 RandNumber rd(x * y);
170 auto phillips = [=](Real Kx, Real Ky, Real Vdir, Real V, Real A, Real dir_depend) -> Real
172 Real k_squared = Kx * Kx + Ky * Ky;
174 if (k_squared == 0.0f)
179 // largest possible wave from constant wind of velocity v
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);
186 Real phillips = A * std::exp(-1.0f / (k_squared * L * L)) / (k_squared * k_squared) * w_dot_k * w_dot_k;
188 // filter out waves moving opposite to wind
191 phillips *= dir_depend;
197 auto gauss = [&]() -> Real
199 Real u1 = rd.Generate();
200 Real u2 = rd.Generate();
207 return glm::sqrt(-2 * glm::log(u1)) * glm::cos(2 * CUDART_PI_F * u2);
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);
213 Real P = glm::sqrt(phillips(kx, ky, scaledWinDir, winSpeed, amplitude, winDirDependence));
215 if (glm::abs(kx) < EPSILON && glm::abs(ky) == EPSILON)
223 Real h0_re = Er * P * CUDART_SQRT_HALF_F;
224 Real h0_im = Ei * P * CUDART_SQRT_HALF_F;
226 h0(x, y) = Complex(h0_re, h0_im);
229 template<typename TDataType>
230 void OceanPatch<TDataType>::resetStates()
232 uint res = this->varResolution()->getValue();
234 cufftPlan2d(&fftPlan, res, res, CUFFT_C2C);
236 int spectrumSize = mSpectrumWidth * mSpectrumHeight * sizeof(Complex);
237 mH0.resize(mSpectrumWidth, mSpectrumHeight);
239// Complex* host_h0 = (Complex*)malloc(spectrumSize);
240// generateH0(host_h0);
242// cuSafeCall(cudaMemcpy(mH0.begin(), host_h0, spectrumSize, cudaMemcpyHostToDevice));
244 cuExecute2D(make_uint2(mSpectrumWidth, mSpectrumHeight),
247 this->varWindDirection()->getValue(),
248 this->varWindSpeed()->getValue(),
250 this->varAmplitude()->getValue(),
251 this->varPatchSize()->getValue(),
255 mHt.resize(res, res);
256 mDxt.resize(res, res);
257 mDzt.resize(res, res);
258 mDisp.resize(res, res);
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()));
269 template<typename TDataType>
270 void OceanPatch<TDataType>::updateStates()
272 Real timeScaled = this->varTimeScale()->getValue() * this->stateElapsedTime()->getValue();
274 uint res = this->varResolution()->getValue();
276 cuExecute2D(make_uint2(res, res),
277 OP_GenerateSpectrumKernel,
284 this->varPatchSize()->getData());
286 cuExecute2D(make_uint2(res, res),
287 OP_GenerateDispalcementKernel,
293 this->varPatchSize()->getData());
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);
299 cuExecute2D(make_uint2(res, res),
300 O_UpdateDisplacement,
308 template<typename TDataType>
309 void OceanPatch<TDataType>::postUpdateStates()
311 auto choppiness = this->varChoppiness()->getValue();
313 auto topo = this->stateHeightField()->getDataPtr();
315 auto h = topo->getGridSpacing();
316 auto origin = topo->getOrigin();
318 auto& shifts = topo->getDisplacement();
321 extent.x = shifts.nx();
322 extent.y = shifts.ny();
331 // topo->rasterize();
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,
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)
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();
351 displacement(i, j) = Coord(x_ij, h_ij, z_ij);
355 template <typename Real, typename Coord>
356 __global__ void CW_UpdateHeightDisp(
357 DArray2D<Coord> heights,
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())
367 Real x = (i * h - origin.x) / h;
368 Real y = (j * h - origin.y) / h;
370 Coord Dij = bilinear(dis, x, y, LerpMode::REPEAT);
373 v[0] = choppiness * Dij[0];
375 v[2] = choppiness * Dij[2];
381 DEFINE_CLASS(OceanPatch);