Implement Ken Perlin's 'Improved Noise' algorithm and add example

This commit is contained in:
Brendan Zabarauskas 2013-07-23 15:07:39 +10:00
parent c206d7dc3c
commit f68c488163
2 changed files with 161 additions and 9 deletions

50
examples/perlin.rs Normal file
View file

@ -0,0 +1,50 @@
// Copyright 2013 The Lmath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! An example of using perlin noise
// Noise rendering based off rust/src/test/bench/noise.rs
extern mod lmath;
use std::uint::range;
use lmath::noise::perlin::Perlin;
use lmath::math::Point2;
static WIDTH: uint = 100;
static HEIGHT: uint = 100;
fn main() {
let symbols = [" ", "", "", "", "", ""];
let mut pixels = [[0f32, ..WIDTH], ..HEIGHT];
let perlin = Perlin::new::<f32>();
for range(0, HEIGHT) |y| {
for range(0, WIDTH) |x| {
pixels[y][x] = perlin.noise2(
Point2::new(x as f32 * 0.1f32,
y as f32 * 0.1f32)
) * 0.5f32 + 0.5f32;
};
};
for range(0, HEIGHT) |y| {
for range(0, WIDTH) |x| {
print(symbols[pixels[y][x] / 0.2f32 as int]);
}
println("");
}
}

View file

@ -13,24 +13,126 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! An implementation of Ken Perlin's [Improved Noise]
//! (http://mrl.nyu.edu/~perlin/noise/) algorithm.
use std::num::cast;
use math::{Point2, Point3};
pub struct Perlin<T>;
pub struct Perlin<T> {
// permutation table
priv ptable: [uint, ..512],
}
impl<T> Perlin<T> {
impl<T:Clone + Float> Perlin<T> {
pub fn new() -> Perlin<T> {
fail!("Not yet implemented!")
// TODO: generate random permutation table
Perlin { ptable: P }
}
pub fn noise1(&self, _x: T) -> T {
fail!("Not yet implemented!")
pub fn noise1(&self, t: T) -> T {
self.noise3(Point3::new(t, zero!(T), zero!(T)))
}
pub fn noise2(&self, _pos: Point2<T>) -> T {
fail!("Not yet implemented!")
pub fn noise2(&self, pos: Point2<T>) -> T {
self.noise3(Point3::new(pos.x.clone(), pos.y.clone(), zero!(T)))
}
pub fn noise3(&self, _pos: Point3<T>) -> T {
fail!("Not yet implemented!")
pub fn noise3(&self, pos: Point3<T>) -> T {
// Find the unit cube that contains the point
let X = pos.x.floor().to_uint() & 255;
let Y = pos.y.floor().to_uint() & 255;
let Z = pos.z.floor().to_uint() & 255;
// Find the relative X, Y, Z of point in the cube
let x = pos.x - pos.x.floor();
let y = pos.y - pos.y.floor();
let z = pos.z - pos.z.floor();
// Compute the fade curves for X, Y, Z
let u = fade(x.clone());
let v = fade(y.clone());
let w = fade(z.clone());
// Hash coordinates of the 8 cube corners
let A = self.ptable[X ] + Y;
let AA = self.ptable[A ] + Z;
let AB = self.ptable[A + 1] + Z;
let B = self.ptable[X + 1] + Y;
let BA = self.ptable[B ] + Z;
let BB = self.ptable[B + 1] + Z;
// Add the blended results from the 8 corners of the cube
lerp(w, lerp(v.clone(), lerp(u.clone(), grad(self.ptable[AA ], x.clone(), y.clone(), z.clone()),
grad(self.ptable[BA ], x-one!(T), y.clone(), z.clone())),
lerp(u.clone(), grad(self.ptable[AB ], x.clone(), y-one!(T), z.clone()),
grad(self.ptable[BB ], x-one!(T), y-one!(T), z.clone()))),
lerp(v.clone(), lerp(u.clone(), grad(self.ptable[AA + 1], x.clone(), y.clone(), z-one!(T)),
grad(self.ptable[BA + 1], x-one!(T), y.clone(), z-one!(T))),
lerp(u.clone(), grad(self.ptable[AB + 1], x.clone(), y-one!(T), z-one!(T)),
grad(self.ptable[BB + 1], x-one!(T), y-one!(T), z-one!(T)))))
}
}
fn fade<T:Num + NumCast>(t: T) -> T {
t * t * t * (t * (t * cast(6) - cast(15)) + cast(10))
}
fn lerp<T:Num + NumCast>(t: T, a: T, b: T) -> T {
a + t * (b - a)
}
fn grad<T:Clone + Num + NumCast>(hash: uint, x: T, y: T, z: T) -> T {
let h = hash & 15;
let u = match h {
0..7 => x.clone(),
_ => y.clone(),
};
let v = match h {
0..3 => y.clone(),
12 | 14 => x.clone(),
_ => z.clone(),
};
(if (h & 1) == 0 { u } else { -u }) +
(if (h & 2) == 0 { v } else { -v })
}
/// Permutation table
static P: [uint, ..512] = [
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225,
140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148,
247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32,
57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122,
60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169,
200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64,
52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212,
207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213,
119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104,
218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241,
81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157,
184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93,
222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180,
151, 160, 137, 91, 90, 15, 131, 13, 201, 95, 96, 53, 194, 233, 7, 225,
140, 36, 103, 30, 69, 142, 8, 99, 37, 240, 21, 10, 23, 190, 6, 148,
247, 120, 234, 75, 0, 26, 197, 62, 94, 252, 219, 203, 117, 35, 11, 32,
57, 177, 33, 88, 237, 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175,
74, 165, 71, 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122,
60, 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, 54,
65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, 18, 169,
200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, 173, 186, 3, 64,
52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, 126, 255, 82, 85, 212,
207, 206, 59, 227, 47, 16, 58, 17, 182, 189, 28, 42, 223, 183, 170, 213,
119, 248, 152, 2, 44, 154, 163, 70, 221, 153, 101, 155, 167, 43, 172, 9,
129, 22, 39, 253, 19, 98, 108, 110, 79, 113, 224, 232, 178, 185, 112, 104,
218, 246, 97, 228, 251, 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241,
81, 51, 145, 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157,
184, 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, 93,
222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, 156, 180,
];