// Copyright (c) 2023 Lachlan McDonald // This work is licensed under the MIT License (MIT) // https://github.com/lachlanmcdonald/magicavoxel-shaders // // This script utilises or modifies code from other projects or publications. // Please see the attributions below for more information: // // 1. Copyright (c) 2011 Stefan Gustavson <https://github.com/ashima/webgl-noise> // MIT License (MIT) // https://github.com/ashima/webgl-noise/blob/master/LICENSE // // xs noise/cellular2D [Mode] [Scale] [Jitter] [Noise] [Power] [Steps] [Seed] [Tile X] [Tile Y] // // xs_begin // author : '@lmcdx.bsky.social' // arg : { name = 'Mode' var = 'm_mode' range = '0 5' value = '0' step = '1' precision = '0' } // arg : { name = 'Scale' var = 'm_scale' range = '1 100' value = '24' step = '1' precision = '0' } // arg : { name = 'Jitter' var = 'm_jitter' range = '-100 100' value = '100' step = '5' precision = '0' } // arg : { name = 'Noise' var = 'm_noise' range = '0 100' value = '0' step = '1' precision = '0' } // arg : { name = 'Power' var = 'm_power' range = '0 10' value = '1' step = '0.05' precision = '2' } // arg : { name = 'Steps' var = 'm_steps' range = '0 40' value = '0' step = '1' precision = '0' } // arg : { name = 'Seed' var = 'global_seed' range = '1 100' value = '1' step = '1' precision = '0' } // arg : { name = 'Tile X' var = 'tile_x' range = '0 40' value = '0' step = '1' precision = '0' } // arg : { name = 'Tile Y' var = 'tile_y' range = '0 40' value = '0' step = '1' precision = '0' } // xs_end int mode = int(m_mode); float noise = m_noise / 100.0; float jitter = m_jitter / 100.0; float steps = floor(m_steps); vec2 tile = vec2(tile_x, tile_y) * i_volume_size.xy; float pal(float p) { float f = floor(mix(0.0, float(i_num_color_sels), p)); return color_sel(f); } vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } vec3 mod7(vec3 x) { return x - floor(x * (1.0 / 7.0)) * 7.0; } vec3 permute(vec3 x) { return mod289((34.0 * x + 10.0) * x); } vec2 cellular(vec2 co, float jitter) { float K = 0.142857142857; float Ko = 0.428571428571; vec2 Pi = mod289(floor(co)); vec2 Pf = fract(co); vec3 oi = vec3(-1.0, 0.0, 1.0); vec3 of = vec3(-0.5, 0.5, 1.5); vec3 px = permute(Pi.x + oi); vec3 p = permute(px.x + Pi.y + oi); vec3 ox = fract(p * K) - Ko; vec3 oy = mod7(floor(p * K)) * K - Ko; vec3 dx = Pf.x + 0.5 + jitter * ox; vec3 dy = Pf.y - of + jitter * oy; vec3 d1 = dx * dx + dy * dy; p = permute(px.y + Pi.y + oi); ox = fract(p * K) - Ko; oy = mod7(floor(p * K)) * K - Ko; dx = Pf.x - 0.5 + jitter * ox; dy = Pf.y - of + jitter * oy; vec3 d2 = dx * dx + dy * dy; p = permute(px.z + Pi.y + oi); ox = fract(p * K) - Ko; oy = mod7(floor(p * K)) * K - Ko; dx = Pf.x - 1.5 + jitter * ox; dy = Pf.y - of + jitter * oy; vec3 d3 = dx * dx + dy * dy; vec3 d1a = min(d1, d2); d2 = max(d1, d2); d2 = min(d2, d3); d1 = min(d1a, d2); d2 = max(d1a, d2); d1.xy = (d1.x < d1.y) ? d1.xy : d1.yx; d1.xz = (d1.x < d1.z) ? d1.xz : d1.zx; d1.yz = min(d1.yz, d2.yz); d1.y = min(d1.y, d1.z); d1.y = min(d1.y, d2.x); return sqrt(d1.xy); } float roundf(float f) { return f > 0.5 ? ceil(f) : floor(f); } float map(vec3 v) { vec2 offset = global_seed * i_volume_size.xy + tile; vec3 k = floor(v) / i_volume_size; vec2 p = cellular((v.xy + offset) / m_scale, jitter); vec2 q = cellular((v.xy + offset), 1.0); float r; float z; if (mode == 0 || mode == 1 || mode == 4) { r = clamp(pow(p.x + q.x * noise, m_power), 0.0, 1.0); } else if (mode == 2 || mode == 3 || mode == 5) { r = clamp(pow(p.y + q.y * noise, m_power), 0.0, 1.0); } if (mode == 1 || mode == 3) { z = r; } else if (mode == 4 || mode == 5) { z = 1.0; } else { z = 1.0 - r; } if (steps > 0.0) { z = roundf(z * steps) / steps; } return (k.z <= z) ? pal(r) : 0.0; }