Add perlin noise library for use with genworld module.
parent
4cbe89aa12
commit
186f3718eb
|
@ -33,11 +33,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
import concurrent.futures
|
||||
import random
|
||||
import noise
|
||||
|
||||
from .blocks import *
|
||||
from .utilities import *
|
||||
from game import utilities
|
||||
from libs import perlin
|
||||
|
||||
|
||||
noise = perlin.SimplexNoise()
|
||||
|
||||
|
||||
class Chunk:
|
||||
|
@ -98,6 +101,7 @@ class WorldGenerator:
|
|||
"""Enclosure height, if generated"""
|
||||
|
||||
self.lookup_terrain = []
|
||||
|
||||
def add_terrain_map(height, terrains):
|
||||
"""Add a new entry to the height map lookup table.
|
||||
|
||||
|
@ -148,9 +152,11 @@ class WorldGenerator:
|
|||
"""Compute the content of a sector asynchronously and return the result to a
|
||||
callback already specified to this generator.
|
||||
"""
|
||||
|
||||
def send_result(future):
|
||||
chunk = future.result()
|
||||
self.callback(chunk)
|
||||
|
||||
future = self.executor.submit(self.generate, sector)
|
||||
future.add_done_callback(send_result)
|
||||
|
||||
|
@ -202,7 +208,7 @@ class WorldGenerator:
|
|||
|
||||
def _generate_floor(self, chunk):
|
||||
"""Generate a standard floor at a specific height"""
|
||||
y_pos= self.y - 2
|
||||
y_pos = self.y - 2
|
||||
n = self.enclosure_size
|
||||
for x, z in self._iter_xz(chunk.sector):
|
||||
if self.enclosure:
|
||||
|
@ -213,20 +219,19 @@ class WorldGenerator:
|
|||
def _generate_random_map(self, chunk):
|
||||
n = self.enclosure_size
|
||||
y_pos = self.y - 2
|
||||
octaves = 4
|
||||
freq = 38
|
||||
for x, z in self._iter_xz(chunk.sector):
|
||||
if self.enclosure:
|
||||
if x <= -n or x >= n - 1 or z <= -n or z >= n - 1:
|
||||
continue
|
||||
c = noise.snoise2(x/freq, z/freq, octaves=octaves)
|
||||
c = noise.noise2(x / freq, z / freq)
|
||||
c = int((c + 1) * 0.5 * len(self.lookup_terrain))
|
||||
if c < 0:
|
||||
c = 0
|
||||
nb_block, terrains = self.lookup_terrain[c]
|
||||
for i in range(nb_block):
|
||||
block = terrains[-1-i] if i < len(terrains) else terrains[0]
|
||||
chunk[(x, y_pos+nb_block-i, z)] = block
|
||||
chunk[(x, y_pos + nb_block - i, z)] = block
|
||||
|
||||
def _generate_trees(self, chunk):
|
||||
"""Generate trees in the map
|
||||
|
@ -234,6 +239,7 @@ class WorldGenerator:
|
|||
For now it do not generate trees between 2 sectors, and use rand
|
||||
instead of a procedural generation.
|
||||
"""
|
||||
|
||||
def get_biome(chunk, x, y, z):
|
||||
"""Return the biome at a location of the map plus the first empty place."""
|
||||
# This loop could be removed using procedural height map
|
||||
|
@ -249,8 +255,8 @@ class WorldGenerator:
|
|||
y_pos = self.y - 2
|
||||
|
||||
for _ in range(nb_trees):
|
||||
x = sector[0] * utilities.SECTOR_SIZE + 3 + random.randint(0, utilities.SECTOR_SIZE-7)
|
||||
z = sector[2] * utilities.SECTOR_SIZE + 3 + random.randint(0, utilities.SECTOR_SIZE-7)
|
||||
x = sector[0] * utilities.SECTOR_SIZE + 3 + random.randint(0, utilities.SECTOR_SIZE - 7)
|
||||
z = sector[2] * utilities.SECTOR_SIZE + 3 + random.randint(0, utilities.SECTOR_SIZE - 7)
|
||||
if self.enclosure:
|
||||
if x < -n + 2 or x > n - 2 or z < -n + 2 or z > n - 2:
|
||||
continue
|
||||
|
@ -353,9 +359,8 @@ class WorldGenerator:
|
|||
centered to 0.
|
||||
"""
|
||||
y_pos = self.y + 20
|
||||
octaves = 3
|
||||
freq = 20
|
||||
for x, z in self._iter_xz(chunk.sector):
|
||||
c = noise.snoise2(x/freq, z/freq, octaves=octaves)
|
||||
c = noise.noise2(x / freq, z / freq)
|
||||
if (c + 1) * 0.5 < self.cloudiness:
|
||||
chunk[(x, y_pos, z)] = CLOUD
|
||||
|
|
|
@ -226,7 +226,7 @@ class GameScene(Scene):
|
|||
|
||||
# Current (x, y, z) position in the world, specified with floats. Note
|
||||
# that, perhaps unlike in math class, the y-axis is the vertical axis.
|
||||
self.position = (utilities.SECTOR_SIZE // 2, 0, utilities.SECTOR_SIZE // 2)
|
||||
self.position = (SECTOR_SIZE // 2, 0, SECTOR_SIZE // 2)
|
||||
|
||||
# First element is rotation of the player in the x-z plane (ground
|
||||
# plane) measured from the z-axis down. The second is the rotation
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
Copyright (c) 2008 Casey Duncan
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
|
@ -0,0 +1,383 @@
|
|||
# Copyright (c) 2008, Casey Duncan (casey dot duncan at gmail dot com)
|
||||
# see LICENSE.txt for details
|
||||
|
||||
"""Perlin noise -- pure python implementation"""
|
||||
|
||||
__version__ = '$Id: perlin.py 521 2008-12-15 03:03:52Z casey.duncan $'
|
||||
|
||||
from math import floor, fmod, sqrt
|
||||
from random import randint
|
||||
|
||||
# 3D Gradient vectors
|
||||
_GRAD3 = ((1, 1, 0), (-1, 1, 0), (1, -1, 0), (-1, -1, 0),
|
||||
(1, 0, 1), (-1, 0, 1), (1, 0, -1), (-1, 0, -1),
|
||||
(0, 1, 1), (0, -1, 1), (0, 1, -1), (0, -1, -1),
|
||||
(1, 1, 0), (0, -1, 1), (-1, 1, 0), (0, -1, -1),
|
||||
)
|
||||
|
||||
# 4D Gradient vectors
|
||||
_GRAD4 = ((0, 1, 1, 1), (0, 1, 1, -1), (0, 1, -1, 1), (0, 1, -1, -1),
|
||||
(0, -1, 1, 1), (0, -1, 1, -1), (0, -1, -1, 1), (0, -1, -1, -1),
|
||||
(1, 0, 1, 1), (1, 0, 1, -1), (1, 0, -1, 1), (1, 0, -1, -1),
|
||||
(-1, 0, 1, 1), (-1, 0, 1, -1), (-1, 0, -1, 1), (-1, 0, -1, -1),
|
||||
(1, 1, 0, 1), (1, 1, 0, -1), (1, -1, 0, 1), (1, -1, 0, -1),
|
||||
(-1, 1, 0, 1), (-1, 1, 0, -1), (-1, -1, 0, 1), (-1, -1, 0, -1),
|
||||
(1, 1, 1, 0), (1, 1, -1, 0), (1, -1, 1, 0), (1, -1, -1, 0),
|
||||
(-1, 1, 1, 0), (-1, 1, -1, 0), (-1, -1, 1, 0), (-1, -1, -1, 0))
|
||||
|
||||
# A lookup table to traverse the simplex around a given point in 4D.
|
||||
# Details can be found where this table is used, in the 4D noise method.
|
||||
_SIMPLEX = (
|
||||
(0, 1, 2, 3), (0, 1, 3, 2), (0, 0, 0, 0), (0, 2, 3, 1), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (1, 2, 3, 0),
|
||||
(0, 2, 1, 3), (0, 0, 0, 0), (0, 3, 1, 2), (0, 3, 2, 1), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (1, 3, 2, 0),
|
||||
(0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0),
|
||||
(1, 2, 0, 3), (0, 0, 0, 0), (1, 3, 0, 2), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (2, 3, 0, 1), (2, 3, 1, 0),
|
||||
(1, 0, 2, 3), (1, 0, 3, 2), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (2, 0, 3, 1), (0, 0, 0, 0), (2, 1, 3, 0),
|
||||
(0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0),
|
||||
(2, 0, 1, 3), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (3, 0, 1, 2), (3, 0, 2, 1), (0, 0, 0, 0), (3, 1, 2, 0),
|
||||
(2, 1, 0, 3), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (3, 1, 0, 2), (0, 0, 0, 0), (3, 2, 0, 1), (3, 2, 1, 0))
|
||||
|
||||
# Simplex skew constants
|
||||
_F2 = 0.5 * (sqrt(3.0) - 1.0)
|
||||
_G2 = (3.0 - sqrt(3.0)) / 6.0
|
||||
_F3 = 1.0 / 3.0
|
||||
_G3 = 1.0 / 6.0
|
||||
|
||||
|
||||
class BaseNoise:
|
||||
"""Noise abstract base class"""
|
||||
|
||||
permutation = (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, 9, 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)
|
||||
|
||||
period = len(permutation)
|
||||
|
||||
# Double permutation array so we don't need to wrap
|
||||
permutation = permutation * 2
|
||||
|
||||
randint_function = randint
|
||||
|
||||
def __init__(self, period=None, permutation_table=None, randint_function=None):
|
||||
"""Initialize the noise generator. With no arguments, the default
|
||||
period and permutation table are used (256). The default permutation
|
||||
table generates the exact same noise pattern each time.
|
||||
|
||||
An integer period can be specified, to generate a random permutation
|
||||
table with period elements. The period determines the (integer)
|
||||
interval that the noise repeats, which is useful for creating tiled
|
||||
textures. period should be a power-of-two, though this is not
|
||||
enforced. Note that the speed of the noise algorithm is indpendent of
|
||||
the period size, though larger periods mean a larger table, which
|
||||
consume more memory.
|
||||
|
||||
A permutation table consisting of an iterable sequence of whole
|
||||
numbers can be specified directly. This should have a power-of-two
|
||||
length. Typical permutation tables are a sequnce of unique integers in
|
||||
the range [0,period) in random order, though other arrangements could
|
||||
prove useful, they will not be "pure" simplex noise. The largest
|
||||
element in the sequence must be no larger than period-1.
|
||||
|
||||
period and permutation_table may not be specified together.
|
||||
|
||||
A substitute for the method random.randint(a, b) can be chosen. The
|
||||
method must take two integer parameters a and b and return an integer N
|
||||
such that a <= N <= b.
|
||||
"""
|
||||
if randint_function is not None: # do this before calling randomize()
|
||||
if not hasattr(randint_function, '__call__'):
|
||||
raise TypeError(
|
||||
'randint_function has to be a function')
|
||||
self.randint_function = randint_function
|
||||
if period is None:
|
||||
period = self.period # enforce actually calling randomize()
|
||||
if period is not None and permutation_table is not None:
|
||||
raise ValueError(
|
||||
'Can specify either period or permutation_table, not both')
|
||||
if period is not None:
|
||||
self.randomize(period)
|
||||
elif permutation_table is not None:
|
||||
self.permutation = tuple(permutation_table) * 2
|
||||
self.period = len(permutation_table)
|
||||
|
||||
def randomize(self, period=None):
|
||||
"""Randomize the permutation table used by the noise functions. This
|
||||
makes them generate a different noise pattern for the same inputs.
|
||||
"""
|
||||
if period is not None:
|
||||
self.period = period
|
||||
perm = list(range(self.period))
|
||||
perm_right = self.period - 1
|
||||
for i in list(perm):
|
||||
j = self.randint_function(0, perm_right)
|
||||
perm[i], perm[j] = perm[j], perm[i]
|
||||
self.permutation = tuple(perm) * 2
|
||||
|
||||
|
||||
class SimplexNoise(BaseNoise):
|
||||
"""Perlin simplex noise generator
|
||||
|
||||
Adapted from Stefan Gustavson's Java implementation described here:
|
||||
|
||||
http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
|
||||
|
||||
To summarize:
|
||||
|
||||
"In 2001, Ken Perlin presented 'simplex noise', a replacement for his classic
|
||||
noise algorithm. Classic 'Perlin noise' won him an academy award and has
|
||||
become an ubiquitous procedural primitive for computer graphics over the
|
||||
years, but in hindsight it has quite a few limitations. Ken Perlin himself
|
||||
designed simplex noise specifically to overcome those limitations, and he
|
||||
spent a lot of good thinking on it. Therefore, it is a better idea than his
|
||||
original algorithm. A few of the more prominent advantages are:
|
||||
|
||||
* Simplex noise has a lower computational complexity and requires fewer
|
||||
multiplications.
|
||||
* Simplex noise scales to higher dimensions (4D, 5D and up) with much less
|
||||
computational cost, the complexity is O(N) for N dimensions instead of
|
||||
the O(2^N) of classic Noise.
|
||||
* Simplex noise has no noticeable directional artifacts. Simplex noise has
|
||||
a well-defined and continuous gradient everywhere that can be computed
|
||||
quite cheaply.
|
||||
* Simplex noise is easy to implement in hardware."
|
||||
"""
|
||||
|
||||
def noise2(self, x, y):
|
||||
"""2D Perlin simplex noise.
|
||||
|
||||
Return a floating point value from -1 to 1 for the given x, y coordinate.
|
||||
The same value is always returned for a given x, y pair unless the
|
||||
permutation table changes (see randomize above).
|
||||
"""
|
||||
# Skew input space to determine which simplex (triangle) we are in
|
||||
s = (x + y) * _F2
|
||||
i = floor(x + s)
|
||||
j = floor(y + s)
|
||||
t = (i + j) * _G2
|
||||
x0 = x - (i - t) # "Unskewed" distances from cell origin
|
||||
y0 = y - (j - t)
|
||||
|
||||
if x0 > y0:
|
||||
i1 = 1
|
||||
j1 = 0 # Lower triangle, XY order: (0,0)->(1,0)->(1,1)
|
||||
else:
|
||||
i1 = 0
|
||||
j1 = 1 # Upper triangle, YX order: (0,0)->(0,1)->(1,1)
|
||||
|
||||
x1 = x0 - i1 + _G2 # Offsets for middle corner in (x,y) unskewed coords
|
||||
y1 = y0 - j1 + _G2
|
||||
x2 = x0 + _G2 * 2.0 - 1.0 # Offsets for last corner in (x,y) unskewed coords
|
||||
y2 = y0 + _G2 * 2.0 - 1.0
|
||||
|
||||
# Determine hashed gradient indices of the three simplex corners
|
||||
perm = self.permutation
|
||||
ii = int(i) % self.period
|
||||
jj = int(j) % self.period
|
||||
gi0 = perm[ii + perm[jj]] % 12
|
||||
gi1 = perm[ii + i1 + perm[jj + j1]] % 12
|
||||
gi2 = perm[ii + 1 + perm[jj + 1]] % 12
|
||||
|
||||
# Calculate the contribution from the three corners
|
||||
tt = 0.5 - x0 ** 2 - y0 ** 2
|
||||
if tt > 0:
|
||||
g = _GRAD3[gi0]
|
||||
noise = tt ** 4 * (g[0] * x0 + g[1] * y0)
|
||||
else:
|
||||
noise = 0.0
|
||||
|
||||
tt = 0.5 - x1 ** 2 - y1 ** 2
|
||||
if tt > 0:
|
||||
g = _GRAD3[gi1]
|
||||
noise += tt ** 4 * (g[0] * x1 + g[1] * y1)
|
||||
|
||||
tt = 0.5 - x2 ** 2 - y2 ** 2
|
||||
if tt > 0:
|
||||
g = _GRAD3[gi2]
|
||||
noise += tt ** 4 * (g[0] * x2 + g[1] * y2)
|
||||
|
||||
return noise * 70.0 # scale noise to [-1, 1]
|
||||
|
||||
def noise3(self, x, y, z):
|
||||
"""3D Perlin simplex noise.
|
||||
|
||||
Return a floating point value from -1 to 1 for the given x, y, z coordinate.
|
||||
The same value is always returned for a given x, y, z pair unless the
|
||||
permutation table changes (see randomize above).
|
||||
"""
|
||||
# Skew the input space to determine which simplex cell we're in
|
||||
s = (x + y + z) * _F3
|
||||
i = floor(x + s)
|
||||
j = floor(y + s)
|
||||
k = floor(z + s)
|
||||
t = (i + j + k) * _G3
|
||||
x0 = x - (i - t) # "Unskewed" distances from cell origin
|
||||
y0 = y - (j - t)
|
||||
z0 = z - (k - t)
|
||||
|
||||
# For the 3D case, the simplex shape is a slightly irregular tetrahedron.
|
||||
# Determine which simplex we are in.
|
||||
if x0 >= y0:
|
||||
if y0 >= z0:
|
||||
i1 = 1
|
||||
j1 = 0
|
||||
k1 = 0
|
||||
i2 = 1
|
||||
j2 = 1
|
||||
k2 = 0
|
||||
elif x0 >= z0:
|
||||
i1 = 1
|
||||
j1 = 0
|
||||
k1 = 0
|
||||
i2 = 1
|
||||
j2 = 0
|
||||
k2 = 1
|
||||
else:
|
||||
i1 = 0
|
||||
j1 = 0
|
||||
k1 = 1
|
||||
i2 = 1
|
||||
j2 = 0
|
||||
k2 = 1
|
||||
else: # x0 < y0
|
||||
if y0 < z0:
|
||||
i1 = 0
|
||||
j1 = 0
|
||||
k1 = 1
|
||||
i2 = 0
|
||||
j2 = 1
|
||||
k2 = 1
|
||||
elif x0 < z0:
|
||||
i1 = 0
|
||||
j1 = 1
|
||||
k1 = 0
|
||||
i2 = 0
|
||||
j2 = 1
|
||||
k2 = 1
|
||||
else:
|
||||
i1 = 0
|
||||
j1 = 1
|
||||
k1 = 0
|
||||
i2 = 1
|
||||
j2 = 1
|
||||
k2 = 0
|
||||
|
||||
# Offsets for remaining corners
|
||||
x1 = x0 - i1 + _G3
|
||||
y1 = y0 - j1 + _G3
|
||||
z1 = z0 - k1 + _G3
|
||||
x2 = x0 - i2 + 2.0 * _G3
|
||||
y2 = y0 - j2 + 2.0 * _G3
|
||||
z2 = z0 - k2 + 2.0 * _G3
|
||||
x3 = x0 - 1.0 + 3.0 * _G3
|
||||
y3 = y0 - 1.0 + 3.0 * _G3
|
||||
z3 = z0 - 1.0 + 3.0 * _G3
|
||||
|
||||
# Calculate the hashed gradient indices of the four simplex corners
|
||||
perm = self.permutation
|
||||
ii = int(i) % self.period
|
||||
jj = int(j) % self.period
|
||||
kk = int(k) % self.period
|
||||
gi0 = perm[ii + perm[jj + perm[kk]]] % 12
|
||||
gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]] % 12
|
||||
gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]] % 12
|
||||
gi3 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]] % 12
|
||||
|
||||
# Calculate the contribution from the four corners
|
||||
noise = 0.0
|
||||
tt = 0.6 - x0 ** 2 - y0 ** 2 - z0 ** 2
|
||||
if tt > 0:
|
||||
g = _GRAD3[gi0]
|
||||
noise = tt ** 4 * (g[0] * x0 + g[1] * y0 + g[2] * z0)
|
||||
else:
|
||||
noise = 0.0
|
||||
|
||||
tt = 0.6 - x1 ** 2 - y1 ** 2 - z1 ** 2
|
||||
if tt > 0:
|
||||
g = _GRAD3[gi1]
|
||||
noise += tt ** 4 * (g[0] * x1 + g[1] * y1 + g[2] * z1)
|
||||
|
||||
tt = 0.6 - x2 ** 2 - y2 ** 2 - z2 ** 2
|
||||
if tt > 0:
|
||||
g = _GRAD3[gi2]
|
||||
noise += tt ** 4 * (g[0] * x2 + g[1] * y2 + g[2] * z2)
|
||||
|
||||
tt = 0.6 - x3 ** 2 - y3 ** 2 - z3 ** 2
|
||||
if tt > 0:
|
||||
g = _GRAD3[gi3]
|
||||
noise += tt ** 4 * (g[0] * x3 + g[1] * y3 + g[2] * z3)
|
||||
|
||||
return noise * 32.0
|
||||
|
||||
|
||||
def lerp(t, a, b):
|
||||
return a + t * (b - a)
|
||||
|
||||
|
||||
def grad3(hash, x, y, z):
|
||||
g = _GRAD3[hash % 16]
|
||||
return x * g[0] + y * g[1] + z * g[2]
|
||||
|
||||
|
||||
class TileableNoise(BaseNoise):
|
||||
"""Tileable implemention of Perlin "improved" noise. This
|
||||
is based on the reference implementation published here:
|
||||
|
||||
http://mrl.nyu.edu/~perlin/noise/
|
||||
"""
|
||||
|
||||
def noise3(self, x, y, z, repeat, base=0.0):
|
||||
"""Tileable 3D noise.
|
||||
|
||||
repeat specifies the integer interval in each dimension
|
||||
when the noise pattern repeats.
|
||||
|
||||
base allows a different texture to be generated for
|
||||
the same repeat interval.
|
||||
"""
|
||||
i = int(fmod(floor(x), repeat))
|
||||
j = int(fmod(floor(y), repeat))
|
||||
k = int(fmod(floor(z), repeat))
|
||||
ii = (i + 1) % repeat
|
||||
jj = (j + 1) % repeat
|
||||
kk = (k + 1) % repeat
|
||||
if base:
|
||||
i += base
|
||||
j += base
|
||||
k += base
|
||||
ii += base
|
||||
jj += base
|
||||
kk += base
|
||||
|
||||
x -= floor(x)
|
||||
y -= floor(y)
|
||||
z -= floor(z)
|
||||
fx = x ** 3 * (x * (x * 6 - 15) + 10)
|
||||
fy = y ** 3 * (y * (y * 6 - 15) + 10)
|
||||
fz = z ** 3 * (z * (z * 6 - 15) + 10)
|
||||
|
||||
perm = self.permutation
|
||||
A = perm[i]
|
||||
AA = perm[A + j]
|
||||
AB = perm[A + jj]
|
||||
B = perm[ii]
|
||||
BA = perm[B + j]
|
||||
BB = perm[B + jj]
|
||||
|
||||
return lerp(fz, lerp(fy, lerp(fx, grad3(perm[AA + k], x, y, z),
|
||||
grad3(perm[BA + k], x - 1, y, z)),
|
||||
lerp(fx, grad3(perm[AB + k], x, y - 1, z),
|
||||
grad3(perm[BB + k], x - 1, y - 1, z))),
|
||||
lerp(fy, lerp(fx, grad3(perm[AA + kk], x, y, z - 1),
|
||||
grad3(perm[BA + kk], x - 1, y, z - 1)),
|
||||
lerp(fx, grad3(perm[AB + kk], x, y - 1, z - 1),
|
||||
grad3(perm[BB + kk], x - 1, y - 1, z - 1))))
|
Loading…
Reference in New Issue