blob: 5420b73f214c7c18dc7ee2d11062005948daa784 [file] [log] [blame]
#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