# SPDX-License-Identifier: GPL-2.0-or-later # Another Noise Tool - Noise and Effects # Jimmy Hazevoet import bpy from mathutils.noise import ( seed_set, noise, turbulence, turbulence_vector, fractal, hybrid_multi_fractal, multi_fractal, ridged_multi_fractal, hetero_terrain, random_unit_vector, variable_lacunarity, voronoi, ) from math import ( floor, sqrt, sin, cos, pi, ) noise_basis_default = "BLENDER" noise_basis = [ ("BLENDER", "Blender", "Blender default noise", 0), ("PERLIN_ORIGINAL", "Perlin", "Perlin noise", 1), ("PERLIN_NEW", "New Perlin", "New Perlin noise", 2), ("VORONOI_F1", "Voronoi F1", "Voronoi F1", 3), ("VORONOI_F2", "Voronoi F2", "Voronoi F2", 4), ("VORONOI_F3", "Voronoi F3", "Voronoi F3", 5), ("VORONOI_F4", "Voronoi F4", "Voronoi F4", 6), ("VORONOI_F2F1", "Voronoi F2-F1", "Voronoi F2-F1", 7), ("VORONOI_CRACKLE", "Voronoi Crackle", "Voronoi Crackle", 8), ("CELLNOISE", "Cell Noise", "Cell noise", 9) ] # ------------------------------------------------------------ # Height scale: def Height_Scale(input, iscale, offset, invert): if invert != 0: return (1.0 - input) * iscale + offset else: return input * iscale + offset # Functions for marble_noise and effects: def Dist(x, y): return sqrt((x * x) + (y * y)) def sin_bias(a): return 0.5 + 0.5 * sin(a) def cos_bias(a): return 0.5 + 0.5 * cos(a) def tri_bias(a): b = 2 * pi a = 1 - 2 * abs(floor((a * (1 / b)) + 0.5) - (a * (1 / b))) return a def saw_bias(a): b = 2 * pi n = int(a / b) a -= n * b if a < 0: a += b return a / b def soft(a): return a def sharp(a): return a**0.5 def sharper(a): return sharp(sharp(a)) def no_bias(a): return a def shapes(x, y, z, shape=0): p = pi if shape == 1: # ring x = x * p y = y * p s = cos(x**2 + y**2) / (x**2 + y**2 + 0.5) elif shape == 2: # swirl x = x * p y = y * p s = ((x * sin(x * x + y * y) + y * cos(x * x + y * y)) / (x**2 + y**2 + 0.5)) elif shape == 3: # bumps x = x * p y = y * p z = z * p s = 1 - ((cos(x * p) + cos(y * p) + cos(z * p)) - 0.5) elif shape == 4: # wave x = x * p * 2 y = y * p * 2 s = sin(x + sin(y)) elif shape == 5: # z grad. s = (z * p) elif shape == 6: # y grad. s = (y * p) elif shape == 7: # x grad. s = (x * p) else: # marble default s = ((x + y + z) * 5) return s # marble_noise def marble_noise(x, y, z, origin, size, shape, bias, sharpnes, turb, depth, hard, basis, amp, freq): s = shapes(x, y, z, shape) x += origin[0] y += origin[1] z += origin[2] value = s + turb * turbulence_vector((x, y, z), depth, hard, noise_basis=basis)[1] if bias == 1: value = cos_bias(value) elif bias == 2: value = tri_bias(value) elif bias == 3: value = saw_bias(value) else: value = sin_bias(value) if sharpnes == 1: value = 1.0 - sharp(value) elif sharpnes == 2: value = 1.0 - sharper(value) elif sharpnes == 3: value = soft(value) elif sharpnes == 4: value = sharp(value) elif sharpnes == 5: value = sharper(value) else: value = 1.0 - soft(value) return value # vl_noise_turbulence: def vlnTurbMode(coords, distort, basis, vlbasis, hardnoise): # hard noise if hardnoise: return (abs(-variable_lacunarity(coords, distort, noise_type1=basis, noise_type2=vlbasis))) # soft noise else: return variable_lacunarity(coords, distort, noise_type1=basis, noise_type2=vlbasis) def vl_noise_turbulence(coords, distort, depth, basis, vlbasis, hardnoise, amp, freq): x, y, z = coords value = vlnTurbMode(coords, distort, basis, vlbasis, hardnoise) i=0 for i in range(depth): i+=1 value += vlnTurbMode((x * (freq * i), y * (freq * i), z * (freq * i)), distort, basis, vlbasis, hardnoise) * (amp * 0.5 / i) return value ## duo_multiFractal: def double_multiFractal(coords, H, lacunarity, octaves, offset, gain, basis, vlbasis): x, y, z = coords n1 = multi_fractal((x * 1.5 + 1, y * 1.5 + 1, z * 1.5 + 1), 1.0, 1.0, 1.0, noise_basis=basis) * (offset * 0.5) n2 = multi_fractal((x - 1, y - 1, z - 1), H, lacunarity, octaves, noise_basis=vlbasis) * (gain * 0.5) return (n1 * n1 + n2 * n2) * 0.5 ## distorted_heteroTerrain: def distorted_heteroTerrain(coords, H, lacunarity, octaves, offset, distort, basis, vlbasis): x, y, z = coords h1 = (hetero_terrain((x, y, z), 1.0, 2.0, 1.0, 1.0, noise_basis=basis) * 0.5) d = h1 * distort h2 = (hetero_terrain((x + d, y + d, z + d), H, lacunarity, octaves, offset, noise_basis=vlbasis) * 0.25) return (h1 * h1 + h2 * h2) * 0.5 ## SlickRock: def slick_rock(coords, H, lacunarity, octaves, offset, gain, distort, basis, vlbasis): x, y, z = coords n = multi_fractal((x,y,z), 1.0, 2.0, 2.0, noise_basis=basis) * distort * 0.25 r = ridged_multi_fractal((x + n, y + n, z + n), H, lacunarity, octaves, offset + 0.1, gain * 2, noise_basis=vlbasis) return (n + (n * r)) * 0.5 ## vlhTerrain def vl_hTerrain(coords, H, lacunarity, octaves, offset, basis, vlbasis, distort): x, y, z = coords ht = hetero_terrain((x, y, z), H, lacunarity, octaves, offset, noise_basis=basis ) * 0.25 vl = ht * variable_lacunarity((x, y, z), distort, noise_type1=basis, noise_type2=vlbasis) * 0.5 + 0.5 return vl * ht # another turbulence def ant_turbulence(coords, depth, hardnoise, nbasis, amp, freq, distortion): x, y, z = coords t = turbulence_vector((x/2, y/2, z/2), depth, 0, noise_basis=nbasis, amplitude_scale=amp, frequency_scale=freq) * 0.5 * distortion return turbulence((t[0], t[1], t[2]), 2, hardnoise, noise_basis="VORONOI_F1") * 0.5 + 0.5 # rocks noise def rocks_noise(coords, depth, hardnoise, nbasis, distortion): x,y,z = coords p = turbulence((x, y, z), 4, 0, noise_basis='BLENDER') * 0.125 * distortion xx, yy, zz = x, y, z a = turbulence((xx + p, yy + p, zz), 2, 0, noise_basis='VORONOI_F2F1') pa = a * 0.1875 * distortion b = turbulence((x, y, z + pa), depth, hardnoise, noise_basis=nbasis) return ((a + 0.5 * (b - a)) * 0.5 + 0.5) # shattered_hterrain: def shattered_hterrain(coords, H, lacunarity, octaves, offset, distort, basis): x, y, z = coords d = (turbulence_vector(coords, 6, 0)[0] * 0.5 + 0.5) * distort * 0.5 t1 = (turbulence_vector((x + d, y + d, z + d), 0, 0, noise_basis='VORONOI_F2F1')[0] + 0.5) t2 = (hetero_terrain((x * 2, y * 2, z * 2), H, lacunarity, octaves, offset, noise_basis=basis) * 0.5) return ((t1 * t2) + t2 * 0.5) * 0.5 # strata_hterrain def strata_hterrain(coords, H, lacunarity, octaves, offset, distort, basis): x, y, z = coords value = hetero_terrain((x, y, z), H, lacunarity, octaves, offset, noise_basis=basis) * 0.5 steps = (sin(value * (distort * 5) * pi) * (0.1 / (distort * 5) * pi)) return (value * (1.0 - 0.5) + steps * 0.5) # Planet Noise by: Farsthary # https://farsthary.com/2010/11/24/new-planet-procedural-texture/ def planet_noise(coords, oct=6, hard=0, noisebasis='PERLIN_ORIGINAL', nabla=0.001): x, y, z = coords d = 0.001 offset = nabla * 1000 x = turbulence((x, y, z), oct, hard, noise_basis=noisebasis) y = turbulence((x + offset, y, z), oct, hard, noise_basis=noisebasis) z = turbulence((x, y + offset, z), oct, hard, noise_basis=noisebasis) xdy = x - turbulence((x, y + d, z), oct, hard, noise_basis=noisebasis) xdz = x - turbulence((x, y, z + d), oct, hard, noise_basis=noisebasis) ydx = y - turbulence((x + d, y, z), oct, hard, noise_basis=noisebasis) ydz = y - turbulence((x, y, z + d), oct, hard, noise_basis=noisebasis) zdx = z - turbulence((x + d, y, z), oct, hard, noise_basis=noisebasis) zdy = z - turbulence((x, y + d, z), oct, hard, noise_basis=noisebasis) return (zdy - ydz), (zdx - xdz), (ydx - xdy) ###---------------------------------------------------------------------- # v.1.04 Effect functions: def maximum(a, b): if (a > b): b = a return b def minimum(a, b): if (a < b): b = a return b def Mix_Modes(a, b, mixfactor, mode): mode = int(mode) a = a * (1.0 - mixfactor) b = b * (1.0 + mixfactor) #1 mix if mode == 0: return (a * (1.0 - 0.5) + b * 0.5) #2 add elif mode == 1: return (a + b) #3 sub. elif mode == 2: return (a - b) #4 mult. elif mode == 3: return (a * b) #5 abs diff. elif mode == 4: return (abs(a - b)) #6 screen elif mode == 5: return 1.0 - ((1.0 - a) * (1.0 - b) / 1.0) #7 addmodulo elif mode == 6: return (a + b) % 1.0 #8 min. elif mode == 7: return minimum(a, b) #9 max. elif mode == 8: return maximum(a, b) else: return 0 Bias_Types = [sin_bias, cos_bias, tri_bias, saw_bias, no_bias] Sharp_Types = [soft, sharp, sharper] # Transpose effect coords: def Trans_Effect(coords, size, loc): x, y, z = coords x = (x * 2.0 / size + loc[0]) y = (y * 2.0 / size + loc[1]) return x, y, z # Effect_Basis_Function: def Effect_Basis_Function(coords, type, bias): bias = int(bias) type = int(type) x, y, z = coords iscale = 1.0 offset = 0.0 ## gradient: if type == 1: effect = offset + iscale * (Bias_Types[bias](x + y)) ## waves / bumps: elif type == 2: effect = offset + iscale * 0.5 * (Bias_Types[bias](x * pi) + Bias_Types[bias](y * pi)) ## zigzag: elif type == 3: effect = offset + iscale * Bias_Types[bias](offset + iscale * sin(x * pi + sin(y * pi))) ## wavy: elif type == 4: effect = offset + iscale * (Bias_Types[bias](cos(x) + sin(y) + cos(x * 2 + y * 2) - sin(-x * 4 + y * 4))) ## sine bump: elif type == 5: effect = offset + iscale * 1 - Bias_Types[bias]((sin(x * pi) + sin(y * pi))) ## dots: elif type == 6: effect = offset + iscale * (Bias_Types[bias](x * pi * 2) * Bias_Types[bias](y * pi * 2)) - 0.5 ## rings: elif type == 7: effect = offset + iscale * (Bias_Types[bias ](1.0 - (x * x + y * y))) ## spiral: elif type == 8: effect = offset + iscale * Bias_Types[bias]( (x * sin(x * x + y * y) + y * cos(x * x + y * y)) / (x**2 + y**2 + 0.5)) * 2 ## square / piramide: elif type == 9: effect = offset + iscale * Bias_Types[bias](1.0 - sqrt((x * x)**10 + (y * y)**10)**0.1) ## blocks: elif type == 10: effect = (0.5 - max(Bias_Types[bias](x * pi) , Bias_Types[bias](y * pi))) if effect > 0.0: effect = 1.0 effect = offset + iscale * effect ## grid: elif type == 11: effect = (0.025 - min(Bias_Types[bias](x * pi), Bias_Types[bias](y * pi))) if effect > 0.0: effect = 1.0 effect = offset + iscale * effect ## tech: elif type == 12: a = max(Bias_Types[bias](x * pi), Bias_Types[bias](y * pi)) b = max(Bias_Types[bias](x * pi * 2 + 2), Bias_Types[bias](y * pi * 2 + 2)) effect = min(Bias_Types[bias](a), Bias_Types[bias](b)) * 3.0 - 2.0 if effect > 0.5: effect = 1.0 effect = offset + iscale * effect ## crackle: elif type == 13: t = turbulence((x, y, 0), 6, 0, noise_basis="BLENDER") * 0.25 effect = variable_lacunarity((x, y, t), 0.25, noise_type2='VORONOI_CRACKLE') if effect > 0.5: effect = 0.5 effect = offset + iscale * effect ## sparse cracks noise: elif type == 14: effect = 2.5 * abs(noise((x, y, 0), noise_basis="PERLIN_ORIGINAL")) - 0.1 if effect > 0.25: effect = 0.25 effect = offset + iscale * (effect * 2.5) ## shattered rock noise: elif type == 15: effect = 0.5 + noise((x, y, 0), noise_basis="VORONOI_F2F1") if effect > 0.75: effect = 0.75 effect = offset + iscale * effect ## lunar noise: elif type == 16: effect = 0.25 + 1.5 * voronoi((x, y, 0), distance_metric='DISTANCE_SQUARED')[0][0] if effect > 0.5: effect = 0.5 effect = offset + iscale * effect * 2 ## cosine noise: elif type == 17: effect = cos(5 * noise((x, y, 0), noise_basis="BLENDER")) effect = offset + iscale * (effect * 0.5) ## spikey noise: elif type == 18: n = 0.5 + 0.5 * turbulence((x * 5, y * 5, 0), 8, 0, noise_basis="BLENDER") effect = ((n * n)**5) effect = offset + iscale * effect ## stone noise: elif type == 19: effect = offset + iscale * (noise((x * 2, y * 2, 0), noise_basis="BLENDER") * 1.5 - 0.75) ## Flat Turb: elif type == 20: t = turbulence((x, y, 0), 6, 0, noise_basis="BLENDER") effect = t * 2.0 if effect > 0.25: effect = 0.25 effect = offset + iscale * effect ## Flat Voronoi: elif type == 21: t = 1 - voronoi((x, y, 0), distance_metric='DISTANCE_SQUARED')[0][0] effect = t * 2 - 1.5 if effect > 0.25: effect = 0.25 effect = offset + iscale * effect else: effect = 0.0 if effect < 0.0: effect = 0.0 return effect # fractalize Effect_Basis_Function: ------------------------------ def Effect_Function(coords, type, bias, turb, depth, frequency, amplitude): x, y, z = coords ## turbulence: if turb > 0.0: t = turb * ( 0.5 + 0.5 * turbulence(coords, 6, 0, noise_basis="BLENDER")) x = x + t y = y + t z = z + t result = Effect_Basis_Function((x, y, z), type, bias) * amplitude ## fractalize: if depth != 0: i=0 for i in range(depth): i+=1 x *= frequency y *= frequency result += Effect_Basis_Function((x, y, z), type, bias) * amplitude / i return result # ------------------------------------------------------------ # landscape_gen def noise_gen(coords, props): terrain_name = props[0] cursor = props[1] smooth = props[2] triface = props[3] sphere = props[4] land_mat = props[5] water_mat = props[6] texture_name = props[7] subd_x = props[8] subd_y = props[9] meshsize_x = props[10] meshsize_y = props[11] meshsize = props[12] rseed = props[13] x_offset = props[14] y_offset = props[15] z_offset = props[16] size_x = props[17] size_y = props[18] size_z = props[19] nsize = props[20] ntype = props[21] nbasis = props[22] vlbasis = props[23] distortion = props[24] hardnoise = int(props[25]) depth = props[26] amp = props[27] freq = props[28] dimension = props[29] lacunarity = props[30] offset = props[31] gain = props[32] marblebias = int(props[33]) marblesharpnes = int(props[34]) marbleshape = int(props[35]) height = props[36] height_invert = props[37] height_offset = props[38] maximum = props[39] minimum = props[40] falloff = int(props[41]) edge_level = props[42] falloffsize_x = props[43] falloffsize_y = props[44] stratatype = props[45] strata = props[46] addwater = props[47] waterlevel = props[48] vert_group = props[49] remove_double = props[50] fx_mixfactor = props[51] fx_mix_mode = props[52] fx_type = props[53] fx_bias = props[54] fx_turb = props[55] fx_depth = props[56] fx_frequency = props[57] fx_amplitude = props[58] fx_size = props[59] fx_loc_x = props[60] fx_loc_y = props[61] fx_height = props[62] fx_offset = props[63] fx_invert = props[64] x, y, z = coords # Origin if rseed == 0: origin = x_offset, y_offset, z_offset origin_x = x_offset origin_y = y_offset origin_z = z_offset o_range = 1.0 else: # Randomise origin o_range = 100 seed_set(rseed) origin = random_unit_vector() ox = (origin[0] * o_range) oy = (origin[1] * o_range) oz = 0 origin_x = (ox - (ox * 0.5)) + x_offset origin_y = (oy - (oy * 0.5)) + y_offset origin_z = oz + z_offset ncoords = (x / (nsize * size_x) + origin_x, y / (nsize * size_y) + origin_y, z / (nsize * size_z) + origin_z) # Noise type's if ntype in [0, 'multi_fractal']: value = multi_fractal(ncoords, dimension, lacunarity, depth, noise_basis=nbasis) * 0.5 elif ntype in [1, 'ridged_multi_fractal']: value = ridged_multi_fractal(ncoords, dimension, lacunarity, depth, offset, gain, noise_basis=nbasis) * 0.5 elif ntype in [2, 'hybrid_multi_fractal']: value = hybrid_multi_fractal(ncoords, dimension, lacunarity, depth, offset, gain, noise_basis=nbasis) * 0.5 elif ntype in [3, 'hetero_terrain']: value = hetero_terrain(ncoords, dimension, lacunarity, depth, offset, noise_basis=nbasis) * 0.25 elif ntype in [4, 'fractal']: value = fractal(ncoords, dimension, lacunarity, depth, noise_basis=nbasis) elif ntype in [5, 'turbulence_vector']: value = turbulence_vector(ncoords, depth, hardnoise, noise_basis=nbasis, amplitude_scale=amp, frequency_scale=freq)[0] elif ntype in [6, 'variable_lacunarity']: value = variable_lacunarity(ncoords, distortion, noise_type1=nbasis, noise_type2=vlbasis) elif ntype in [7, 'marble_noise']: value = marble_noise( (ncoords[0] - origin_x + x_offset), (ncoords[1] - origin_y + y_offset), (ncoords[2] - origin_z + z_offset), (origin[0] + x_offset, origin[1] + y_offset, origin[2] + z_offset), nsize, marbleshape, marblebias, marblesharpnes, distortion, depth, hardnoise, nbasis, amp, freq ) elif ntype in [8, 'shattered_hterrain']: value = shattered_hterrain(ncoords, dimension, lacunarity, depth, offset, distortion, nbasis) elif ntype in [9, 'strata_hterrain']: value = strata_hterrain(ncoords, dimension, lacunarity, depth, offset, distortion, nbasis) elif ntype in [10, 'ant_turbulence']: value = ant_turbulence(ncoords, depth, hardnoise, nbasis, amp, freq, distortion) elif ntype in [11, 'vl_noise_turbulence']: value = vl_noise_turbulence(ncoords, distortion, depth, nbasis, vlbasis, hardnoise, amp, freq) elif ntype in [12, 'vl_hTerrain']: value = vl_hTerrain(ncoords, dimension, lacunarity, depth, offset, nbasis, vlbasis, distortion) elif ntype in [13, 'distorted_heteroTerrain']: value = distorted_heteroTerrain(ncoords, dimension, lacunarity, depth, offset, distortion, nbasis, vlbasis) elif ntype in [14, 'double_multiFractal']: value = double_multiFractal(ncoords, dimension, lacunarity, depth, offset, gain, nbasis, vlbasis) elif ntype in [15, 'rocks_noise']: value = rocks_noise(ncoords, depth, hardnoise, nbasis, distortion) elif ntype in [16, 'slick_rock']: value = slick_rock(ncoords,dimension, lacunarity, depth, offset, gain, distortion, nbasis, vlbasis) elif ntype in [17, 'planet_noise']: value = planet_noise(ncoords, depth, hardnoise, nbasis)[2] * 0.5 + 0.5 elif ntype in [18, 'blender_texture']: if texture_name != "" and texture_name in bpy.data.textures: value = bpy.data.textures[texture_name].evaluate(ncoords)[3] else: value = 0.0 else: value = 0.5 # Effect mix val = value if fx_type in [0,"0"]: fx_mixfactor = -1.0 fxval = val else: fxcoords = Trans_Effect((x, y, z), fx_size, (fx_loc_x, fx_loc_y)) effect = Effect_Function(fxcoords, fx_type, fx_bias, fx_turb, fx_depth, fx_frequency, fx_amplitude) effect = Height_Scale(effect, fx_height, fx_offset, fx_invert) fxval = Mix_Modes(val, effect, fx_mixfactor, fx_mix_mode) value = fxval # Adjust height value = Height_Scale(value, height, height_offset, height_invert) # Edge falloff: if not sphere: if falloff: ratio_x, ratio_y = abs(x) * 2 / meshsize_x, abs(y) * 2 / meshsize_y fallofftypes = [0, sqrt(ratio_y**falloffsize_y), sqrt(ratio_x**falloffsize_x), sqrt(ratio_x**falloffsize_x + ratio_y**falloffsize_y) ] dist = fallofftypes[falloff] value -= edge_level if(dist < 1.0): dist = (dist * dist * (3 - 2 * dist)) value = (value - value * dist) + edge_level else: value = edge_level # Strata / terrace / layers if stratatype not in [0, "0"]: if stratatype in [1, "1"]: strata = strata / height strata *= 2 steps = (sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * 0.5 + steps * 0.5) * 2.0 elif stratatype in [2, "2"]: strata = strata / height steps = -abs(sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * 0.5 + steps * 0.5) * 2.0 elif stratatype in [3, "3"]: strata = strata / height steps = abs(sin(value * strata * pi) * (0.1 / strata * pi)) value = (value * 0.5 + steps * 0.5) * 2.0 elif stratatype in [4, "4"]: strata = strata / height value = int( value * strata ) * 1.0 / strata elif stratatype in [5, "5"]: strata = strata / height steps = (int( value * strata ) * 1.0 / strata) value = (value * (1.0 - 0.5) + steps * 0.5) # Clamp height min max if (value < minimum): value = minimum if (value > maximum): value = maximum return value