#include "Perlin.hpp" #include "Grid.hpp" #include "Interpolation.hpp" namespace Math::Perlin { float ease(float t) { return t * t * t * ((6 * t - 15) * t + 10); } uint8_t hash(uint8_t x) { auto rot = x * 5 % 8; return x << rot | x >> (8 - rot); } Vector<2> gradient(Vector<2> pos) { Vector<2> gradients[] = { {1.0f, 1.0f}, {-1.0f, 1.0f}, {1.0f, -1.0f}, {-1.0f, -1.0f}, }; auto x = hash(hash(pos.x()) + pos.y()); return gradients[x % 4].normalize(); } float raw(Vector<2> pos) { auto cell = grid_cell_for_point(pos); auto uv = pos - cell.top_left(); auto unit = grid_cell_for_point({}); auto l11 = unit.top_left() - uv; auto l21 = unit.top_right() - uv; auto l12 = unit.bottom_left() - uv; auto l22 = unit.bottom_right() - uv; auto g11 = gradient(cell.top_left()); auto g21 = gradient(cell.top_right()); auto g12 = gradient(cell.bottom_left()); auto g22 = gradient(cell.bottom_right()); auto v = bilinear_interpolation( {l11 * g11, l21 * g21, l12 * g12, l22 * g22}, cell, uv.map(ease) + cell.top_left() ); return (v + 1.0f) / 2.0f; } Vector<3> gradient(Vector<3> pos) { constexpr float e = 0.5773502692; static Vector<3> gradients[] = { {e, e, e}, {-e, e, e}, {e, -e, e}, {-e, -e, e}, {e, e, -e}, {-e, e, -e}, {e, -e, -e}, {-e, -e, -e}, }; auto x = hash(hash(hash(pos.x()) + pos.y()) + pos.z()); return gradients[x % 8]; } float raw(Vector<3> pos) { auto cell = cube_cell_for_point(pos); auto uv = pos - cell.front_top_left(); auto unit = cube_cell_for_point({}); auto l111 = unit.front_top_left() - uv; auto l211 = unit.front_top_right() - uv; auto l121 = unit.front_bottom_left() - uv; auto l221 = unit.front_bottom_right() - uv; auto l112 = unit.back_top_left() - uv; auto l212 = unit.back_top_right() - uv; auto l122 = unit.back_bottom_left() - uv; auto l222 = unit.back_bottom_right() - uv; auto g111 = gradient(cell.front_top_left()); auto g211 = gradient(cell.front_top_right()); auto g121 = gradient(cell.front_bottom_left()); auto g221 = gradient(cell.front_bottom_right()); auto g112 = gradient(cell.back_top_left()); auto g212 = gradient(cell.back_top_right()); auto g122 = gradient(cell.back_bottom_left()); auto g222 = gradient(cell.back_bottom_right()); auto v = trilinear_interpolation( {l111 * g111, l211 * g211, l121 * g121, l221 * g221}, {l112 * g112, l212 * g212, l122 * g122, l222 * g222}, cell, uv.map(ease) + cell.front_top_left() ); return (v + 1.0f) / 2.0f; } }