Attempt to port eevee perlin noise implementation to wren. didn't really got the same result https://gist.github.com/eevee/26f547457522755cb1fb8739d0ea89a1#file-perlin-py-L71
seems like it's something related to the random.gauss function
Attempt to port eevee perlin noise implementation to wren. didn't really got the same result https://gist.github.com/eevee/26f547457522755cb1fb8739d0ea89a1#file-perlin-py-L71
seems like it's something related to the random.gauss function
import "random" for Random | |
class Perlin{ | |
construct new(seed, dimension, octaves, tile, unbias){ | |
_random = Random.new(seed) | |
_dimension = dimension | |
_octaves = octaves | |
_tile = tile | |
_unbias = unbias | |
_scale_factor = 2 * _dimension.pow(-0.5) | |
_gradient = {} | |
} | |
smoothstep(t){ | |
return t * t * (3.0 - 2.0 * t) | |
} | |
lerp(t, a, b){ | |
return a + t * (b - a) | |
} | |
generate_gradient(){ | |
if(_dimension == 1){ | |
return [_random.float(-1, 1), 0] | |
} | |
var random_point = [] | |
for(d in 0..._dimension){ | |
random_point.add(randn_bm(0, 1, 1)) | |
} | |
var scale = 0 | |
for(p in random_point){ | |
scale = scale + (p * p) | |
} | |
scale.pow(-0.5) | |
System.print(random_point) | |
for(i in 0...random_point.count){ | |
random_point[i] = random_point[i] * scale | |
} | |
return random_point | |
} | |
//https://stackoverflow.com/questions/25582882/javascript-math-random-normal-distribution-gaussian-bell-curve/39187274#39187274 | |
randn_bm(min, max, skew){ | |
var u = 0 | |
var v = 0 | |
while(u == 0) u = _random.float() //Converting [0,1) to (0,1) | |
while(v == 0) v = _random.float() | |
var num = ( -2.0 * u.log ).sqrt * ( 2.0 * Num.pi * v ).cos | |
num = num / 10.0 + 0.5 // Translate to 0 -> 1 | |
if (num > 1 || num < 0) num = randn_bm(min, max, skew) // resample between 0 and 1 if out of range | |
num = num.pow(skew) // Skew | |
num = num * (max - min) // Stretch to fill range | |
num = num + min // offset to min | |
return num | |
} | |
get_plain_noise(point){ | |
if(point.count != _dimension){ | |
System.print("expected %(_dimension) values, got %(point.count)") | |
} | |
var grid_coords = [] | |
for (coord in point){ | |
var min_coord = coord.floor | |
var max_coord = min_coord + 1 | |
grid_coords.add([min_coord, max_coord]) | |
} | |
var dots = [] | |
for(grid_point in cartesian_product(grid_coords)){ | |
var grid_point_hash = get_grid_point_hash(grid_point) | |
if(!_gradient[grid_point_hash]){ | |
_gradient[grid_point_hash] = generate_gradient() | |
} | |
var gradient = _gradient[grid_point_hash] | |
var dot = 0 | |
for(i in 0..._dimension){ | |
dot = dot + gradient[i] * (point[i] - grid_point[i]) | |
} | |
dots.add(dot) | |
} | |
var dim = _dimension | |
while(dots.count > 1){ | |
dim = dim - 1 | |
var s = smoothstep(point[dim] - grid_coords[dim][0]) | |
var next_dots = [] | |
while(dots.count > 0){ | |
next_dots.add(lerp(s, dots.removeAt(0), dots.removeAt(0))) | |
} | |
dots = next_dots | |
} | |
return dots[0] * _scale_factor | |
} | |
get_grid_point_hash(grid_point){ | |
var hash = "" | |
grid_point.each {|n| | |
hash = hash + "%(n)" | |
} | |
return hash | |
} | |
cartesian_product(list){ | |
var results = [[]] | |
for (i in 0...list.count) { | |
var currentSubArray = list[i] | |
var temp = [] | |
for ( j in 0...results.count) { | |
for (k in 0...currentSubArray.count) { | |
temp.add(results[j] + [currentSubArray[k]]) | |
} | |
} | |
results = temp | |
} | |
return results | |
} | |
noise(point){ | |
//return | |
var ret = 0 | |
for(oct in 0..._octaves){ | |
var oct_2 = 1 << oct | |
var new_point = [] | |
for(i in 0...point.count){ | |
var coord = point[i] | |
coord = coord * oct_2 | |
if(_tile[i]){ | |
coord = coord % _tile[i] * oct_2 | |
} | |
new_point.add(coord) | |
} | |
ret = ret + get_plain_noise(new_point) / oct_2 | |
} | |
ret = ret / (2 - 2.pow(1 - _octaves)) | |
if(_unbias){ | |
var r = (ret + 1) / 2 | |
for(i in 0...(_octaves / 2 + 0.5).floor){ | |
r = smoothstep(r) | |
} | |
ret = r * 2 - 1 | |
} | |
return ret | |
} | |
} |