#include "ocean_alt.h" #include ocean_alt::ocean_alt() { // to be used for efficiency during fft std::cout << "hello" << std::endl; init_wave_index_constants(); } // initializes static constants (aka they are not time dependent) void ocean_alt::init_wave_index_constants(){ float tex_step = 1.f/num_rows; for (int i=0; i h_tildas = std::vector(); // std::vector ikh = std::vector(); // std::vector neg_ik_hat_h = std::vector(); std::vector ikhx = std::vector(); std::vector ikhz = std::vector(); std::vector neg_ik_hat_h_x = std::vector(); std::vector neg_ik_hat_h_z = std::vector(); // find each h_tilda at each index, to be used for next for loop for (int i=0; i tmp = fast_fft(h_tildas); // std::vector tmp2 = fast_fft(ikh); // std::vector tmp3 = fast_fft(neg_ik_hat_h); std::vector tmp4 = fast_fft(ikhx); std::vector tmp5 = fast_fft(ikhz); std::vector tmp6 = fast_fft(neg_ik_hat_h_x); std::vector tmp7 = fast_fft(neg_ik_hat_h_z); for (int i = 0; i < N; i++) { m_current_h[i] = tmp[i]; // m_slopes[i] = tmp2[i]; // m_displacements[i] = tmp3[i]; m_slopes_x[i] = tmp4[i]; m_slopes_z[i] = tmp5[i]; m_displacements_x[i] = tmp6[i]; m_displacements_z[i] = tmp7[i]; } return; } // for each position in grid, sum up amplitudes dependng on that position for (int i=0; i randoms = sample_complex_gaussian(); double random_r = randoms.first; double random_i = randoms.second; // seperate real and imag products double coeff = 0.707106781187 * sqrt(Ph_prime); double real_comp = coeff*random_r; double imag_comp = coeff*random_i; return Eigen::Vector2d(real_comp, imag_comp); } double ocean_alt::phillips_prime(Eigen::Vector2d k){ double k_mag = k.norm(); k.normalize(); double dot_prod = k.dot(omega_wind); double output = 0.0; // l = 1 if (k_mag < .0001) return 0.0; if (k_mag > 1.0){ output = A*exp(-(k_mag*k_mag))*dot_prod*dot_prod/(k_mag*k_mag*k_mag*k_mag); } else { output = A*exp(-1.0/(k_mag*L*k_mag*L))*dot_prod*dot_prod/(k_mag*k_mag*k_mag*k_mag); } return output; } Eigen::Vector2d ocean_alt::get_k_vector(int n_prime, int m_prime){ double n_ = (double)n_prime; double m_ = (double)m_prime; double N_ = (double)num_rows; double M_ = (double)num_cols; double k_x = (2*M_PI*n_ - M_PI*N_)/Lx; double k_z = (2*M_PI*m_ - M_PI*M_)/Lz; return Eigen::Vector2d(k_x, k_z); } Eigen::Vector2d ocean_alt::get_horiz_pos(int i){ Eigen::Vector2i m_n = index_1d_to_2d(i); double n_prime = (double)m_n[0]; double m_prime = (double)m_n[1]; double N_ = (double)num_rows; double M_ = (double)num_cols; double x = (n_prime-.5*N_)*Lx / N_; double z = (m_prime-.5*M_)*Lz / M_; return Eigen::Vector2d(x, z); } Eigen::Vector2i ocean_alt::index_1d_to_2d(int i){ int row = i/num_rows; // n' int col = i%num_rows; // m' return Eigen::Vector2i(row, col); } std::pair ocean_alt::sample_complex_gaussian(){ double uniform_1 = (double)rand() / (RAND_MAX); double uniform_2 = (double)rand() / (RAND_MAX); // set a lower bound on zero to avoid undefined log(0) if (uniform_1 == 0) { uniform_1 = 1e-10; } if (uniform_2 == 0) { uniform_2 = 1e-10; } // real and imaginary parts of the complex number double real = sqrt(-2*log(uniform_1)) * cos(2*M_PI*uniform_2); double imag = sqrt(-2*log(uniform_1)) * sin(2*M_PI*uniform_2); return std::make_pair(real, imag); } Eigen::Vector2d ocean_alt::complex_exp(double exponent){ double real = cos(exponent); double imag = sin(exponent); return Eigen::Vector2d(real, imag); } void ocean_alt::update_ocean() { std::vector vertices = std::vector(); if (iterations < 10){ for (int i = 0; i < N; i++){ Eigen::Vector2d amplitude = m_current_h[i]; float height = amplitude[0]; if (height < min) min = height; if (height > max) max = height; } iterations ++; } // reset normals & vertices arrays for the single tile m_vertices = std::vector(N); m_normals = std::vector(N); for (int i = 0; i < N; i++){ Eigen::Vector2d horiz_pos = spacing*m_waveIndexConstants[i].base_horiz_pos; Eigen::Vector2d amplitude = m_current_h[i]; float height = amplitude[0]; // Eigen::Vector2d slope = m_slopes[i] * .3f; // Eigen::Vector3f s = Eigen::Vector3f(-slope[0], 0.0, -slope[1]); // Eigen::Vector3f y = Eigen::Vector3f(0.0, 1.0, 0.0); // float xs = 1.f + s[0]*s[0]; // float ys = 1.f + s[1]*s[1]; // float zs = 1.f + s[2]*s[2]; // // Eigen::Vector3f diff = y - s; // Eigen::Vector3f Eigen::Vector3f(diff[0]/ sqrt(xs), diff[1]/ sqrt(ys), diff[2]/sqrt(zs)); // NEW Eigen::Vector3f norm = Eigen::Vector3f(-m_slopes_x[i][0], 1.0, -m_slopes_z[i][0]); norm = norm.normalized(); // FIXME: why do I have to be inverted? //if (i==6) std::cout << amplitude[0] << std::endl; // calculate displacement // Eigen::Vector2d disp = lambda*m_displacements[i]; Eigen::Vector2d disp = lambda*Eigen::Vector2d(m_displacements_x[i][0], m_displacements_z[i][0]) + Eigen::Vector2d(vertex_displacement, vertex_displacement); // set corner at 0,0 for retiling // for final vertex position, use the real number component of amplitude vector m_vertices[i] = {horiz_pos[0] + disp[0], height, horiz_pos[1] + disp[1]}; m_normals[i] = norm.normalized();//Eigen::Vector3f(-slope[0], 1.0, -slope[1]).normalized(); //std::cout << "normal: " << m_normals[i] << std::endl Eigen::Vector2i m_n = index_1d_to_2d(i); // m_foam_constants.wavelengths[i] = 2.f* M_PI * m_slopes[i].dot(m_slopes[i]) / Lx; float h_0 = m_waveIndexConstants[i].h0_prime[0]; // min*.2f; float h_max = max*.01f; // the smaller the constant, the more foam there is m_foam_constants.wavelengths[i] = (height - h_0 ) / (h_max - h_0); // if (i < 5){ // std::cout << h_0 << ", " << h_max << std::endl; // std::cout << m_foam_constants.wavelengths[i] << std::endl; // } } // populate foam constants m_foam_constants.positions = vertices; } std::vector ocean_alt::get_vertices(){ // extend the returned array based on the tilecount std::vector vertices = std::vector(); for (int i = 0; i < num_tiles_x; i++) { for (int j = 0; j < num_tiles_z; j++) { for (int k = 0; k < N; k++) { double c = Lx - 2 / (num_rows / Lx); Eigen::Vector3f vertex = m_vertices[k] + Eigen::Vector3f(i*(c), 0.0, (j)*(c)); vertices.push_back(vertex); } } } return vertices; } std::vector ocean_alt::getNormals(){ // based on the tile count, add more to the normals std::vector normals = std::vector(); // do the x 1D direction first for (int i = 0; i < num_tiles_x; i++) { for (int j = 0; j < num_tiles_z; j++) { for (int k = 0; k < N; k++) { normals.push_back(m_normals[k]); } } } return normals; } std::vector ocean_alt::get_faces() { // connect the vertices into faces std::vector faces = std::vector(); for (int i = 0; i < num_tiles_x; i++) { for (int j = 0; j < num_tiles_z; j++) { for (int k = 0; k < N; k++) { int x = k % num_rows; int z = k / num_rows; // connect the vertices into faces if (x < num_rows - 1 && z < num_cols - 1) { int tile_index_offset = (j + num_tiles_z * i) * N; int i1 = k + tile_index_offset; int i2 = k + 1 + tile_index_offset; int i3 = k + num_rows + tile_index_offset; int i4 = k + num_rows + 1 + tile_index_offset; faces.emplace_back(i2, i1, i3); faces.emplace_back(i2, i3, i4); } } } } return faces; // for (int i = 0; i < N; i++) // { // int x = i / num_rows; // int z = i % num_rows; // // // connect the vertices into faces // if (x < num_rows - 1 && z < num_cols - 1) // { // int i1 = i; // int i2 = i + 1; // int i3 = i + num_rows; // int i4 = i + num_rows + 1; // // faces.emplace_back(i2, i1, i3); // faces.emplace_back(i2, i3, i4); // faces.emplace_back(i1, i2, i3); // faces.emplace_back(i3, i2, i4); // } // } // return faces; } Eigen::Vector2d muliply_complex(Eigen::Vector2d a, Eigen::Vector2d b) { double real = a[0] * b[0] - a[1] * b[1]; double imag = a[0] * b[1] + a[1] * b[0]; return Eigen::Vector2d(real, imag); } std::vector ifft_1d ( std::vector frequencies, bool is_vertical ) { // one D case, assuming is a square int N = frequencies.size(); // make two buffers for intermediate butterfly values std::vector buffer1 = std::vector(N); std::vector buffer2 = std::vector(N); // fill buffer one with the frequencies in bit reverse order int log2_N = log2(N); for (int i = 0; i < N; i++) { int reversed = 0; for (int j = 0; j < log2_N; j++) { reversed |= ((i >> j) & 1) << (log2_N - 1 - j); } // std::cout << "reversed, i: " << reversed << ", " << i << std::endl; buffer1[i] = frequencies[reversed]; } bool reading_buffer1 = true; // go over the stages for (int stage = 1; stage <= log2_N; stage++) { // go over the groups for (int group = 0; group < N / pow(2, stage); group++) { // go over the butterflies for (int butterfly = 0; butterfly < pow(2, stage - 1); butterfly++) { // calculate the indices int index1 = group * pow(2, stage) + butterfly; int index2 = group * pow(2, stage) + pow(2, stage - 1) + butterfly; // calculate the twiddle factor int index = group * pow(2, stage) + butterfly; float w = index * 2 * M_PI / pow(2, stage); Eigen::Vector2d twiddle_factor = {cos(w), sin(w)}; if (reading_buffer1) { buffer2[index1] = buffer1[index1] + muliply_complex(twiddle_factor, buffer1[index2]); buffer2[index2] = buffer1[index1] - muliply_complex(twiddle_factor, buffer1[index2]); } else { buffer1[index1] = buffer2[index1] + muliply_complex(twiddle_factor, buffer2[index2]); buffer1[index2] = buffer2[index1] - muliply_complex(twiddle_factor, buffer2[index2]); } } } reading_buffer1 = !reading_buffer1; } // return the buffer that was read last if (reading_buffer1) { return buffer1; } else { return buffer2; } } std::vector ocean_alt::fast_fft ( std::vector h ) { // do a vertical fft on each column for (int i = 0; i < num_rows; i++) { std::vector col = std::vector(); for (int j = 0; j < num_cols; j++) { col.push_back(h[i + j * num_rows]); } std::vector col_fft = ifft_1d(col, true); for (int j = 0; j < num_cols; j++) { h[i + j * num_rows] = col_fft[j]; } } // do a horizontal fft on each row for (int i = 0; i < num_cols; i++) { std::vector row = std::vector(); for (int j = 0; j < num_rows; j++) { row.push_back(h[i * num_rows + j]); } std::vector row_fft = ifft_1d(row, false); for (int j = 0; j < num_rows; j++) { h[i * num_rows + j] = row_fft[j]; } } // divide by N*N and add the signs based on the indices double sign[] = {1.0, -1.0}; for (int i = 0; i < N; i++) { h[i] /= N; // h[i] /= sqrt(N); h[i] *= sign[(i / num_rows + i % num_cols) % 2]; } return h; }