| #ifndef PERLIN_H |
| #define PERLIN_H |
| //============================================================================================== |
| // Originally written in 2016 by Peter Shirley <ptrshrl@gmail.com> |
| // |
| // To the extent possible under law, the author(s) have dedicated all copyright |
| // and related and neighboring rights to this software to the public domain |
| // worldwide. This software is distributed without any warranty. |
| // |
| // You should have received a copy (see file COPYING.txt) of the CC0 Public |
| // Domain Dedication along with this software. If not, see |
| // <http://creativecommons.org/publicdomain/zero/1.0/>. |
| // |
| // The original source code is from |
| // https://github.com/RayTracing/raytracing.github.io/tree/release/src/TheNextWeek |
| // |
| // Changes to the original code follow the following license. |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| //============================================================================================== |
| |
| #include "rtweekend.h" |
| |
| |
| class perlin { |
| public: |
| __host__ __device__ perlin(unsigned &rng) { |
| ranvec = new vec3[point_count]; |
| for (int i = 0; i < point_count; ++i) { |
| ranvec[i] = unit_vector(vec3::random(-1, 1, rng)); |
| } |
| |
| perm_x = perlin_generate_perm(rng); |
| perm_y = perlin_generate_perm(rng); |
| perm_z = perlin_generate_perm(rng); |
| } |
| |
| __host__ __device__ ~perlin() { |
| delete[] ranvec; |
| delete[] perm_x; |
| delete[] perm_y; |
| delete[] perm_z; |
| } |
| |
| __host__ __device__ double noise(const point3 &p) const { |
| auto u = p.x() - floor(p.x()); |
| auto v = p.y() - floor(p.y()); |
| auto w = p.z() - floor(p.z()); |
| auto i = static_cast<int>(floor(p.x())); |
| auto j = static_cast<int>(floor(p.y())); |
| auto k = static_cast<int>(floor(p.z())); |
| vec3 c[2][2][2]; |
| |
| for (int di = 0; di < 2; di++) |
| for (int dj = 0; dj < 2; dj++) |
| for (int dk = 0; dk < 2; dk++) |
| c[di][dj][dk] = |
| ranvec[perm_x[(i + di) & 255] ^ perm_y[(j + dj) & 255] ^ |
| perm_z[(k + dk) & 255]]; |
| |
| return perlin_interp(c, u, v, w); |
| } |
| |
| __host__ __device__ double turb(const point3 &p, int depth = 7) const { |
| auto accum = 0.0; |
| auto temp_p = p; |
| auto weight = 1.0; |
| |
| for (int i = 0; i < depth; i++) { |
| accum += weight * noise(temp_p); |
| weight *= 0.5; |
| temp_p *= 2; |
| } |
| |
| return fabs(accum); |
| } |
| |
| private: |
| static const int point_count = 256; |
| vec3* ranvec; |
| int* perm_x; |
| int* perm_y; |
| int* perm_z; |
| |
| __host__ __device__ static int *perlin_generate_perm(unsigned &rng) { |
| auto p = new int[point_count]; |
| |
| for (int i = 0; i < point_count; i++) |
| p[i] = i; |
| |
| permute(p, point_count, rng); |
| |
| return p; |
| } |
| |
| __host__ __device__ static void permute(int *p, int n, unsigned &rng) { |
| for (int i = n - 1; i > 0; i--) { |
| int target = random_int(0, i, rng); |
| int tmp = p[i]; |
| p[i] = p[target]; |
| p[target] = tmp; |
| } |
| } |
| |
| __host__ __device__ static double perlin_interp(vec3 c[2][2][2], double u, |
| double v, double w) { |
| auto uu = u * u * (3 - 2 * u); |
| auto vv = v * v * (3 - 2 * v); |
| auto ww = w * w * (3 - 2 * w); |
| auto accum = 0.0; |
| |
| for (int i = 0; i < 2; i++) |
| for (int j = 0; j < 2; j++) |
| for (int k = 0; k < 2; k++) { |
| vec3 weight_v(u - i, v - j, w - k); |
| accum += (i * uu + (1 - i) * (1 - uu)) * |
| (j * vv + (1 - j) * (1 - vv)) * |
| (k * ww + (1 - k) * (1 - ww)) * dot(c[i][j][k], weight_v); |
| } |
| |
| return accum; |
| } |
| }; |
| |
| |
| #endif |