perlin_noise 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +22 -9
- data/lib/perlin/gradient_table.rb +19 -3
- data/lib/perlin/noise.rb +6 -4
- data/lib/perlin/version.rb +1 -1
- data/test/test_perlin.rb +20 -3
- metadata +3 -4
data/README.markdown
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# perlin_noise
|
2
2
|
Ruby-implementation of N-dimension Perlin noise.
|
3
3
|
|
4
4
|
## Installation
|
@@ -37,7 +37,7 @@ n5d[rand, rand, rand, rand, rand]
|
|
37
37
|
```
|
38
38
|
|
39
39
|
## Options
|
40
|
-
###
|
40
|
+
### `:interval`
|
41
41
|
A gradient noise repeats itself at certain interval. (Default interval is 256)
|
42
42
|
You can change the interval of the noise generator but keep in mind that
|
43
43
|
longer interval requires more pseudo-random gradient vectors to be maintained in memory.
|
@@ -48,6 +48,15 @@ n3d[0.1, 0.2, 0.3]
|
|
48
48
|
n3d[0.1, 0.2, 100.3]
|
49
49
|
```
|
50
50
|
|
51
|
+
### `:seed`
|
52
|
+
|
53
|
+
You can optionally specify a seed value for the random number generator.
|
54
|
+
(Caveat: seed value is set globally in Ruby 1.8)
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
noises = Perlin::Noise.new 1, :seed => 12345
|
58
|
+
```
|
59
|
+
|
51
60
|
## Range of noise function
|
52
61
|
While the original algorithm outputs a number between -1.0 and 1.0,
|
53
62
|
Perlin::Noise#[] manipulates this output and returns a number between 0.0 and 1.0 for ease of use.
|
@@ -58,7 +67,8 @@ Even though the range of the noise function is from 0 to 1,
|
|
58
67
|
you'll rarely see a noise value close to either end,
|
59
68
|
as most of the values are distributed around the center.
|
60
69
|
You might want to apply S-shaped curve functions defined in Perlin::Curve module
|
61
|
-
one or more times to push away those
|
70
|
+
one or more times to push away those "grey" values to either end,
|
71
|
+
achiving more contrasted output.
|
62
72
|
|
63
73
|
```ruby
|
64
74
|
noise = Perlin::Noise.new 1
|
@@ -70,7 +80,8 @@ n = noise[0.1]
|
|
70
80
|
end
|
71
81
|
```
|
72
82
|
|
73
|
-
There's a shortcut for this process.
|
83
|
+
There's a shortcut for this specific process.
|
84
|
+
|
74
85
|
```ruby
|
75
86
|
contrast = Perlin::Curve.contrast(Perlin::Curve::CUBIC, 3)
|
76
87
|
n = contrast.call n
|
@@ -83,9 +94,7 @@ n = contrast.call n
|
|
83
94
|
```ruby
|
84
95
|
noise = Perlin::Noise.new 1, :interval => 200
|
85
96
|
0.step(300, 0.1).each do |x|
|
86
|
-
|
87
|
-
len = (n * 60).to_i
|
88
|
-
puts '#' * len
|
97
|
+
puts '#' * (noise[x] * 60).floor
|
89
98
|
end
|
90
99
|
```
|
91
100
|
|
@@ -237,7 +246,7 @@ bar = lambda { |n|
|
|
237
246
|
bars[ (bars.length * n).floor ]
|
238
247
|
}
|
239
248
|
|
240
|
-
|
249
|
+
100.times do |i|
|
241
250
|
70.times do |y|
|
242
251
|
n = noises[i * 0.1, y * 0.1]
|
243
252
|
n = contrast.call n
|
@@ -359,7 +368,7 @@ Noise looks much more interesting when combined.
|
|
359
368
|
noises = Perlin::Noise.new(2)
|
360
369
|
contrast = Perlin::Curve.contrast(Perlin::Curve::QUINTIC, 3)
|
361
370
|
|
362
|
-
|
371
|
+
100.times do |x|
|
363
372
|
n = 0
|
364
373
|
[[0.02, 10], [0.04, 10], [0.1, 20], [0.2, 15]].each_with_index do |step_scale, idx|
|
365
374
|
step, scale = step_scale
|
@@ -474,6 +483,10 @@ end
|
|
474
483
|
```
|
475
484
|
|
476
485
|
|
486
|
+
## Contributors
|
487
|
+
|
488
|
+
- [Matthew Johnston](https://github.com/warmwaffles)
|
489
|
+
|
477
490
|
## References
|
478
491
|
- Texturing & modeling: a procedural approach by David S. Ebert et al.
|
479
492
|
- Improving Noise by Ken Perlin (http://mrl.nyu.edu/~perlin/paper445.pdf)
|
@@ -1,12 +1,28 @@
|
|
1
1
|
module Perlin
|
2
|
+
if RUBY_VERSION =~ /^1\.8\./
|
3
|
+
class Random
|
4
|
+
def initialize *seed
|
5
|
+
# FIXME: Sets the global seed value; this is misleading
|
6
|
+
srand *seed
|
7
|
+
end
|
8
|
+
|
9
|
+
def rand *interval
|
10
|
+
Kernel.rand *interval
|
11
|
+
end
|
12
|
+
end
|
13
|
+
else
|
14
|
+
Random = ::Random
|
15
|
+
end
|
16
|
+
|
2
17
|
class GradientTable
|
3
18
|
# Bit-wise AND operation is not any faster than MOD in Ruby
|
4
19
|
# MOD operation returns positive number for negative input
|
5
|
-
def initialize dim, interval = 256
|
20
|
+
def initialize dim, interval = 256, seed = nil
|
6
21
|
@dim = dim
|
7
22
|
@interval = interval
|
23
|
+
@random = Random.new(*[seed].compact)
|
8
24
|
|
9
|
-
@table = Array.new(interval) { rand @interval }
|
25
|
+
@table = Array.new(interval) { @random.rand @interval }
|
10
26
|
@vectors = Array.new(interval) { random_unit_vector }
|
11
27
|
end
|
12
28
|
|
@@ -30,7 +46,7 @@ module Perlin
|
|
30
46
|
|
31
47
|
def random_unit_vector
|
32
48
|
while true
|
33
|
-
v = Vector[*Array.new(@dim) { rand * 2 - 1 }]
|
49
|
+
v = Vector[*Array.new(@dim) { @random.rand * 2 - 1 }]
|
34
50
|
# Discards vectors whose length greater than 1 to avoid bias in distribution
|
35
51
|
break if v.r > 0 && v.r <= 1
|
36
52
|
end
|
data/lib/perlin/noise.rb
CHANGED
@@ -3,7 +3,7 @@ module Perlin
|
|
3
3
|
DEFAULT_OPTIONS = {
|
4
4
|
:interval => 256,
|
5
5
|
:curve => Perlin::Curve::QUINTIC,
|
6
|
-
:
|
6
|
+
:seed => nil
|
7
7
|
}
|
8
8
|
|
9
9
|
def initialize dim, options = {}
|
@@ -12,13 +12,15 @@ module Perlin
|
|
12
12
|
@dim = dim
|
13
13
|
@interval = options.fetch(:interval)
|
14
14
|
@curve = options.fetch(:curve)
|
15
|
+
@seed = options.fetch(:seed)
|
15
16
|
|
16
17
|
raise ArgumentError.new("Invalid dimension: must be a positive integer") unless @dim.is_a?(Fixnum) && @dim > 0
|
17
18
|
raise ArgumentError.new("Invalid interval: must be a positive integer") unless @interval.is_a?(Fixnum) && @interval > 0
|
18
19
|
raise ArgumentError.new("Invalid curve specified: must be a Proc object") unless @curve.is_a?(Proc)
|
20
|
+
raise ArgumentError.new("Invalid seed: must be a number") unless @seed.nil? || @seed.is_a?(Numeric)
|
19
21
|
|
20
22
|
# Generate pseudo-random gradient vector for each grid point
|
21
|
-
@gradient_table = Perlin::GradientTable.new @dim, @interval
|
23
|
+
@gradient_table = Perlin::GradientTable.new @dim, @interval, @seed
|
22
24
|
end
|
23
25
|
|
24
26
|
# @param [*coords] Coordinates
|
@@ -30,7 +32,7 @@ module Perlin
|
|
30
32
|
cell = Vector[*coords.map(&:to_i)]
|
31
33
|
diff = coords - cell
|
32
34
|
|
33
|
-
|
35
|
+
# Calculate noise factor at each surrouning vertex
|
34
36
|
nf = {}
|
35
37
|
iterate @dim, 2 do |idx|
|
36
38
|
idx = Vector[*idx]
|
@@ -39,7 +41,7 @@ module Perlin
|
|
39
41
|
# product (dot product) between the gradient vectors of each grid point
|
40
42
|
# and the vectors from the grid points."
|
41
43
|
gv = @gradient_table[ * (cell + idx).to_a ]
|
42
|
-
|
44
|
+
nf[idx.to_a] = gv.inner_product(diff - idx)
|
43
45
|
end
|
44
46
|
|
45
47
|
dim = @dim
|
data/lib/perlin/version.rb
CHANGED
data/test/test_perlin.rb
CHANGED
@@ -79,6 +79,12 @@ class PerlinTest < Test::Unit::TestCase
|
|
79
79
|
assert_raise(ArgumentError) { Perlin::Noise.new 1, :interval => 0.5 }
|
80
80
|
assert_raise(ArgumentError) { Perlin::Noise.new 1, :interval => -1 }
|
81
81
|
|
82
|
+
# Seed
|
83
|
+
Perlin::Noise.new 1, :seed => 1
|
84
|
+
Perlin::Noise.new 1, :seed => 0.1
|
85
|
+
Perlin::Noise.new 1, :seed => -0.1
|
86
|
+
assert_raise(ArgumentError) { Perlin::Noise.new 1, :seed => "seed" }
|
87
|
+
|
82
88
|
# Curve
|
83
89
|
Perlin::Noise.new 2, :curve => Perlin::Curve::CUBIC
|
84
90
|
assert_raise(ArgumentError) { Perlin::Noise.new 2, :curve => nil }
|
@@ -128,7 +134,7 @@ class PerlinTest < Test::Unit::TestCase
|
|
128
134
|
bars[ (bars.length * n).floor ]
|
129
135
|
}
|
130
136
|
|
131
|
-
|
137
|
+
100.times do |i|
|
132
138
|
70.times do |y|
|
133
139
|
n = noises[i * 0.1, y * 0.1]
|
134
140
|
n = contrast.call n
|
@@ -139,11 +145,22 @@ class PerlinTest < Test::Unit::TestCase
|
|
139
145
|
end
|
140
146
|
end
|
141
147
|
|
148
|
+
def test_seed
|
149
|
+
noise1 = Perlin::Noise.new(1, :seed => 12345)
|
150
|
+
noise2 = Perlin::Noise.new(1, :seed => 12345)
|
151
|
+
assert_equal 0.step(1, 0.01).map { |v| noise1[v] },
|
152
|
+
0.step(1, 0.01).map { |v| noise2[v] }
|
153
|
+
|
154
|
+
noise3 = Perlin::Noise.new(1, :seed => 54321)
|
155
|
+
assert_not_equal 0.step(1, 0.01).map { |v| noise1[v] },
|
156
|
+
0.step(1, 0.01).map { |v| noise3[v] }
|
157
|
+
end
|
158
|
+
|
142
159
|
def test_synthesis
|
143
|
-
noises = Perlin::Noise.new(2)
|
160
|
+
noises = Perlin::Noise.new(2, :seed => 0.12345)
|
144
161
|
contrast = Perlin::Curve.contrast(Perlin::Curve::QUINTIC, 3)
|
145
162
|
|
146
|
-
|
163
|
+
100.times do |x|
|
147
164
|
n = 0
|
148
165
|
[[0.02, 10], [0.04, 10], [0.1, 30], [0.2, 15]].each_with_index do |step_scale, idx|
|
149
166
|
step, scale = step_scale
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perlin_noise
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2012-07-22 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Perlin noise implemented in Ruby
|
15
15
|
email:
|
@@ -49,10 +49,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
49
|
version: '0'
|
50
50
|
requirements: []
|
51
51
|
rubyforge_project: perlin
|
52
|
-
rubygems_version: 1.8.
|
52
|
+
rubygems_version: 1.8.24
|
53
53
|
signing_key:
|
54
54
|
specification_version: 3
|
55
55
|
summary: Perlin noise generator
|
56
56
|
test_files:
|
57
57
|
- test/test_perlin.rb
|
58
|
-
has_rdoc:
|