Skip to content

Instantly share code, notes, and snippets.

@malleusinferni
Created January 24, 2019 06:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save malleusinferni/8a9c3b16e7e3632bc12e2f0dd0f974da to your computer and use it in GitHub Desktop.
Save malleusinferni/8a9c3b16e7e3632bc12e2f0dd0f974da to your computer and use it in GitHub Desktop.
use cgmath::{Vector2, Vector3, Vector4};
#[derive(Copy, Clone, Debug)]
pub struct Params {
pub offset: f32,
pub lacunarity: f32,
pub highest_dim: f32,
pub octaves: f32,
pub gain: f32,
}
impl Params {
/// Sample the Cartesian coordinates of a point on the surface of a
/// sphere. Returns the altitude at that point.
pub fn sample(&self, mut point: Vector3<f32>) -> f32 {
let Params {
offset,
lacunarity,
highest_dim,
octaves,
gain,
} = *self;
let mut result = noise(point) + offset;
let attenuation = lacunarity.powf(-highest_dim);
let mut power = attenuation;
let mut weight = gain * result;
point *= lacunarity;
let max_octaves = octaves.floor() as usize;
for _ in 0 .. max_octaves {
if weight > 1.0 { weight = 1.0; }
let signal = (noise(point) + offset) * power;
power *= attenuation;
result += weight * signal;
weight *= gain * signal;
point *= lacunarity;
}
let remainder = max_octaves as f32 - octaves;
if remainder != 0.0 {
result += remainder * ((noise(point) + offset) * power);
}
result
}
}
fn mod289(f: f32) -> f32 {
f - (f * (1.0 / 289.0)).floor() * 289.0
}
fn permutate(p: Vector4<f32>) -> Vector4<f32> {
p.map(|n| mod289((n * 34.0 + 1.0) * n))
}
fn noise(p: Vector3<f32>) -> f32 {
let a = p.map(|n| n.floor());
let mut d = p - a;
d = d.map(|n| n * n * (3.0 - 2.0 * n));
let b = Vector4::from([a.x, a.x + 1.0, a.y, a.y + 1.0]);
let k1 = permutate([b.x, b.y, b.x, b.y].into());
let k2 = permutate([k1.x + b.z, k1.y + b.z, k1.x + b.w, k1.y + b.w].into());
let c = k2 + Vector4::from([a.z; 4]);
let k3 = permutate(c);
let k4 = permutate(c + Vector4::from([1.0; 4]));
let o1 = k3.map(|n| (n * 1.0 / 41.0).fract());
let o2 = k4.map(|n| (n * 1.0 / 41.0).fract());
let o3 = o2 * d.z + o1 * (1.0 - d.z);
let o4 = Vector2::from([o3.y, o3.w]) * d.x + Vector2::from([o3.x, o3.z]) * (1.0 - d.x);
o4.y * d.y + o4.x * (1.0 - d.y)
}
impl Default for Params {
fn default() -> Self {
Self {
highest_dim: 0.0,
lacunarity: 1.75,
octaves: 13.5,
offset: -0.75,
gain: 6.25,
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment