2D Perlin noise generator using layered InterpolatedNoise

Get values at any coordinates with []. The behavior of this generator can be customized using its attributes min, max, period and seed.

This noise is more realistic and less smooth than the InterpolatedNoise.

Due to implementation logic, the full amplitude cannot be reached. In practice, only amplitude * (1.0 - 1.0 / n_levels) is covered.

This implementation uses a custom deterministic pseudo random number generator to set InterpolatedNoise::seed of the layers. It is seeded with the local seed and can be further customized by redefining pseudo_random. This process do not require any state, so this class only holds the attributes of the generator and does not keep any generated data.

Usage example

var map = new PerlinNoise
map.min = 0.0
map.max = 16.0
map.period = 20.0
map.seed = 0

var max = 0.0
var min = 100.0
for y in 30.times do
    for x in 70.times do
        # Get a value at x, y
        var val = map[x.to_f, y.to_f]
        printn val.to_i.to_hex

        max = max.max(val)
        min = min.min(val)
    end
    print ""
end
assert max <= map.max
assert min >= map.min

Result at seed == 0

76666555444322234567789abbcbbaabbaa98777766665665566667888987655444444
776665554443322234567789abbbbbbbbba98777766666665556666788998654444444
777766544443322234566789abbbbbbbbaa99877777776665556666788888655444444
777776444443322244556679abbbccbbbaa99877777776655556666688888655444444
777766444444332244555678abbbccbbbaa99887787877655556666678888654444444
8887654344443333444456789abcccbbaa999877888886555555666688777654444455
8887654344443333444456789abbcdcbaa999887889887655555566677777654444456
7876654434444444444456778abbcccaaa999888899888655555566677777654444556
78765544344445544444567789bbccca99999888899988765555566666667654445566
77765444344455554445567889bbccba99999998999988765555566555666654445667
7765444334555665445556788abbbba988998999999988765555566545556554456677
87654444334556655455567899bbbba998888899999887766555566544556555456777
87655444334566665555567899bbbbba98888899988888776555566544556555556777
97655544334566665555567899abbbba98888899988888776555655544456555667777
97655544444566665556667899aaaaba98888999877777776555555444456666667777
866555444456666666566789999aaaaa98889998877777766556544443456667777777
976555445556776666666789aa99aaaa98889998876777666555544444456677887777
9765554556667777776667899999aaaa98889988876676666555443444446678888888
87655555666777788766678999899aaa99889988776666666554433344446789998888
876555566777788888766889998899a999889987776666666543333334456899a99899
766556677877889998877888888889a99998888777666666653222233345799aaa999a
6665556777777899998878988888899999999887777656666543222233446899aa999a
6655456777777899999888988888889999a988887776566666532222233457899a999a
665555677777789999998998888878899aa9888887765666655322222234578899aa9a
665555677777789999a98888888877899aa9888887766666655322222234467899aa9a
65666677667778999aaa988878877789aaa9888887776676654322222344467889aa9a
55566677767788899aaa987777777789aaa9888887776666654322222344567889aaa9
5566767777788889aaaa987777777789aaaa988887777666555432122344556899aaa9
5567777777788889aaaa977777777789aaaa99888777766555543212234555689aaaaa
5667877777889989aaa9876677777889aaaa99888777765554443212334555689aaaaa

Introduced properties

fun layers: Array[InterpolatedNoise]

noise :: PerlinNoise :: layers

Layers of InterpolatedNoise composing self
protected fun layers=(layers: Array[InterpolatedNoise])

noise :: PerlinNoise :: layers=

Layers of InterpolatedNoise composing self
fun n_layers: Int

noise :: PerlinNoise :: n_layers

Desired number of layers
fun n_layers=(n_layers: Int)

noise :: PerlinNoise :: n_layers=

Desired number of layers
protected fun pseudo_random(value: Int): Int

noise :: PerlinNoise :: pseudo_random

Deterministic pseudo random number generator

Redefined properties

redef type SELF: PerlinNoise

noise $ PerlinNoise :: SELF

Type of this instance, automatically specialized in every class
redef fun [](x: Float, y: Float): Float

noise $ PerlinNoise :: []

Get the noise value at x, y
redef fun core_serialize_to(v: Serializer)

noise $ PerlinNoise :: core_serialize_to

Actual serialization of self to serializer
redef init from_deserializer(v: Deserializer)

noise $ PerlinNoise :: from_deserializer

Create an instance of this class from the deserializer

All properties

fun !=(other: nullable Object): Bool

core :: Object :: !=

Have self and other different values?
fun ==(other: nullable Object): Bool

core :: Object :: ==

Have self and other the same value?
type CLASS: Class[SELF]

core :: Object :: CLASS

The type of the class of self.
type SELF: Object

core :: Object :: SELF

Type of this instance, automatically specialized in every class
abstract fun [](x: Float, y: Float): Float

noise :: Noise :: []

Get the noise value at x, y
protected fun accept_json_serializer(v: JsonSerializer)

serialization :: Serializable :: accept_json_serializer

Refinable service to customize the serialization of this class to JSON
protected fun accept_msgpack_attribute_counter(v: AttributeCounter)

serialization :: Serializable :: accept_msgpack_attribute_counter

Hook to customize the behavior of the AttributeCounter
protected fun accept_msgpack_serializer(v: MsgPackSerializer)

serialization :: Serializable :: accept_msgpack_serializer

Hook to customize the serialization of this class to MessagePack
protected fun add_to_bundle(bundle: NativeBundle, key: JavaString)

serialization :: Serializable :: add_to_bundle

Called by []= to dynamically choose the appropriate method according
fun amplitude: Float

noise :: Noise :: amplitude

Amplitude of the values returned by []
fun amplitude=(value: Float)

noise :: Noise :: amplitude=

Set the desired amplitude of the values returned by []
protected fun class_factory(name: String): CLASS

core :: Object :: class_factory

Implementation used by get_class to create the specific class.
fun class_name: String

core :: Object :: class_name

The class name of the object.
fun core_serialize_to(serializer: Serializer)

serialization :: Serializable :: core_serialize_to

Actual serialization of self to serializer
fun frequency: Float

noise :: Noise :: frequency

Frequency of this noise
fun frequency=(value: Float)

noise :: Noise :: frequency=

Set the frequency if this noise
init from_deserializer(deserializer: Deserializer)

serialization :: Serializable :: from_deserializer

Create an instance of this class from the deserializer
fun get_class: CLASS

core :: Object :: get_class

The meta-object representing the dynamic type of self.
fun hash: Int

core :: Object :: hash

The hash code of the object.
init init

core :: Object :: init

fun inspect: String

core :: Object :: inspect

Developer readable representation of self.
protected fun inspect_head: String

core :: Object :: inspect_head

Return "CLASSNAME:#OBJECTID".
intern fun is_same_instance(other: nullable Object): Bool

core :: Object :: is_same_instance

Return true if self and other are the same instance (i.e. same identity).
fun is_same_serialized(other: nullable Object): Bool

core :: Object :: is_same_serialized

Is self the same as other in a serialization context?
intern fun is_same_type(other: Object): Bool

core :: Object :: is_same_type

Return true if self and other have the same dynamic type.
fun layers: Array[InterpolatedNoise]

noise :: PerlinNoise :: layers

Layers of InterpolatedNoise composing self
protected fun layers=(layers: Array[InterpolatedNoise])

noise :: PerlinNoise :: layers=

Layers of InterpolatedNoise composing self
fun max: Float

noise :: Noise :: max

Highest possible value returned by []
fun max=(max: Float)

noise :: Noise :: max=

Highest possible value returned by []
fun min: Float

noise :: Noise :: min

Lowest possible value returned by []
fun min=(min: Float)

noise :: Noise :: min=

Lowest possible value returned by []
protected fun msgpack_extra_array_items: Int

serialization :: Serializable :: msgpack_extra_array_items

Hook to request a larger than usual metadata array
fun n_layers: Int

noise :: PerlinNoise :: n_layers

Desired number of layers
fun n_layers=(n_layers: Int)

noise :: PerlinNoise :: n_layers=

Desired number of layers
intern fun object_id: Int

core :: Object :: object_id

An internal hash code for the object based on its identity.
fun output

core :: Object :: output

Display self on stdout (debug only).
intern fun output_class_name

core :: Object :: output_class_name

Display class name on stdout (debug only).
fun period: Float

noise :: Noise :: period

Distance between reference points of the noise
fun period=(period: Float)

noise :: Noise :: period=

Distance between reference points of the noise
protected fun pseudo_random(value: Int): Int

noise :: PerlinNoise :: pseudo_random

Deterministic pseudo random number generator
fun seed: Int

noise :: Noise :: seed

Seed to the random number generator gradient_vector
fun seed=(seed: Int)

noise :: Noise :: seed=

Seed to the random number generator gradient_vector
fun serialization_hash: Int

core :: Object :: serialization_hash

Hash value use for serialization
fun serialize_msgpack(plain: nullable Bool): Bytes

serialization :: Serializable :: serialize_msgpack

Serialize self to MessagePack bytes
fun serialize_to(serializer: Serializer)

serialization :: Serializable :: serialize_to

Serialize self to serializer
fun serialize_to_json(plain: nullable Bool, pretty: nullable Bool): String

serialization :: Serializable :: serialize_to_json

Serialize self to JSON
intern fun sys: Sys

core :: Object :: sys

Return the global sys object, the only instance of the Sys class.
fun to_json: String

serialization :: Serializable :: to_json

Serialize self to plain JSON
abstract fun to_jvalue(env: JniEnv): JValue

core :: Object :: to_jvalue

fun to_pretty_json: String

serialization :: Serializable :: to_pretty_json

Serialize self to plain pretty JSON
fun to_s: String

core :: Object :: to_s

User readable representation of self.
package_diagram noise::PerlinNoise PerlinNoise noise::Noise Noise noise::PerlinNoise->noise::Noise serialization::Serializable Serializable noise::Noise->serialization::Serializable ...serialization::Serializable ... ...serialization::Serializable->serialization::Serializable

Ancestors

interface Object

core :: Object

The root of the class hierarchy.
interface Serializable

serialization :: Serializable

Instances of this class can be passed to Serializer::serialize

Parents

abstract class Noise

noise :: Noise

2D noise generator

Class definitions

noise $ PerlinNoise
# 2D Perlin noise generator using layered `InterpolatedNoise`
#
# Get values at any coordinates with `[]`.
# The behavior of this generator can be customized using its attributes `min`,
# `max`, `period` and `seed`.
#
# This noise is more realistic and less smooth than the `InterpolatedNoise`.
#
# Due to implementation logic, the full amplitude cannot be reached.
# In practice, only `amplitude * (1.0 - 1.0 / n_levels)` is covered.
#
# This implementation uses a custom deterministic pseudo random number
# generator to set `InterpolatedNoise::seed` of the `layers`.
# It is seeded with the local `seed` and can be further customized by
# redefining `pseudo_random`.
# This process do not require any state, so this class only holds the
# attributes of the generator and does not keep any generated data.
#
# ## Usage example
#
# ~~~
# var map = new PerlinNoise
# map.min = 0.0
# map.max = 16.0
# map.period = 20.0
# map.seed = 0
#
# var max = 0.0
# var min = 100.0
# for y in 30.times do
#     for x in 70.times do
#         # Get a value at x, y
#         var val = map[x.to_f, y.to_f]
#         printn val.to_i.to_hex
#
#         max = max.max(val)
#         min = min.min(val)
#     end
#     print ""
# end
# assert max <= map.max
# assert min >= map.min
# ~~~
#
# ## Result at seed == 0
#
# ~~~raw
# 76666555444322234567789abbcbbaabbaa98777766665665566667888987655444444
# 776665554443322234567789abbbbbbbbba98777766666665556666788998654444444
# 777766544443322234566789abbbbbbbbaa99877777776665556666788888655444444
# 777776444443322244556679abbbccbbbaa99877777776655556666688888655444444
# 777766444444332244555678abbbccbbbaa99887787877655556666678888654444444
# 8887654344443333444456789abcccbbaa999877888886555555666688777654444455
# 8887654344443333444456789abbcdcbaa999887889887655555566677777654444456
# 7876654434444444444456778abbcccaaa999888899888655555566677777654444556
# 78765544344445544444567789bbccca99999888899988765555566666667654445566
# 77765444344455554445567889bbccba99999998999988765555566555666654445667
# 7765444334555665445556788abbbba988998999999988765555566545556554456677
# 87654444334556655455567899bbbba998888899999887766555566544556555456777
# 87655444334566665555567899bbbbba98888899988888776555566544556555556777
# 97655544334566665555567899abbbba98888899988888776555655544456555667777
# 97655544444566665556667899aaaaba98888999877777776555555444456666667777
# 866555444456666666566789999aaaaa98889998877777766556544443456667777777
# 976555445556776666666789aa99aaaa98889998876777666555544444456677887777
# 9765554556667777776667899999aaaa98889988876676666555443444446678888888
# 87655555666777788766678999899aaa99889988776666666554433344446789998888
# 876555566777788888766889998899a999889987776666666543333334456899a99899
# 766556677877889998877888888889a99998888777666666653222233345799aaa999a
# 6665556777777899998878988888899999999887777656666543222233446899aa999a
# 6655456777777899999888988888889999a988887776566666532222233457899a999a
# 665555677777789999998998888878899aa9888887765666655322222234578899aa9a
# 665555677777789999a98888888877899aa9888887766666655322222234467899aa9a
# 65666677667778999aaa988878877789aaa9888887776676654322222344467889aa9a
# 55566677767788899aaa987777777789aaa9888887776666654322222344567889aaa9
# 5566767777788889aaaa987777777789aaaa988887777666555432122344556899aaa9
# 5567777777788889aaaa977777777789aaaa99888777766555543212234555689aaaaa
# 5667877777889989aaa9876677777889aaaa99888777765554443212334555689aaaaa
# ~~~
class PerlinNoise
	super Noise

	# Desired number of `layers`
	#
	# This attribute must be assigned before any call to `layers` or `[]`.
	#
	# By default, it is the highest integer under the logarithm base 2
	# of `amplitude`, or 4, whichever is the highest.
	var n_layers: Int = 4.max(amplitude.abs.log_base(2.0).to_i) is lazy, writable

	# Layers of `InterpolatedNoise` composing `self`
	var layers: Array[InterpolatedNoise] is lazy do
		var layers = new Array[InterpolatedNoise]

		var max = max
		var min = min
		var period = period
		var seed = seed
		for l in n_layers.times do
			min = min / 2.0
			max = max / 2.0
			seed = pseudo_random(seed)

			var layer = new InterpolatedNoise
			layer.min = min
			layer.max = max
			layer.period = period
			layer.seed = seed
			layers.add layer

			period = period / 2.0
		end
		return layers
	end

	redef fun [](x, y)
	do
		var val = 0.0
		for layer in layers do
			val += layer[x, y]
		end
		return val
	end

	# Deterministic pseudo random number generator
	#
	# Used to get seeds for layers from the previous layers or `seed`.
	protected fun pseudo_random(value: Int): Int
	do
		return (value * 3537391).mask % 1291377
	end
end
lib/noise/noise.nit:72,1--202,3