perlin_noise 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|