Skip to main content

MAPS_WGSL

Constant MAPS_WGSL 

Source
pub const MAPS_WGSL: &str = r#"
struct MapMaterial {
    indices: vec4i,
    factors: vec4f,
    age_a: vec4f,
    age_b: vec4f,
    seeds: vec4u,
    layer0: vec4f,
    layer1: vec4f,
    layer2: vec4f,
    layer3: vec4f,
    content: vec4f,
    content_extra: vec4f,
    packed: vec4f,
    atlas: vec4f,
    params: array<vec4f, 16>,
}
struct MapResult {
    base: vec3f,
    roughness: f32,
    metalness: f32,
    normal: vec3f,
    coat_roughness: f32,
    thin_film: f32,
}
@group(3) @binding(0) var map_base: texture_2d_array<f32>;
@group(3) @binding(1) var map_normal: texture_2d_array<f32>;
@group(3) @binding(2) var map_roughness: texture_2d_array<f32>;
@group(3) @binding(3) var map_metal: texture_2d_array<f32>;
@group(3) @binding(4) var map_sampler: sampler;
@group(3) @binding(5) var<storage, read> map_materials: array<MapMaterial>;
override use_maps: bool = true;
override use_detail: bool = true;
override use_ageing: bool = true;
override use_fine_noise: bool = false;
override use_uv1: bool = true;
override use_lacquer: bool = true;
override use_procedural_lacquer: bool = false;
override use_scratch: bool = true;
override use_grime: bool = true;
override use_wood: bool = true;
override use_wall: bool = true;
override use_fibre: bool = true;
override use_crinkle: bool = true;
override use_procedural_detail: bool = false;
var<private> map_ink_base: vec4f;
var<private> map_pixel: f32;
var<private> map_dx: vec3f;
var<private> map_dy: vec3f;
var<private> map_planes: vec3f = vec3f(0.0, 0.0, 1.0);
var<private> map_gain: f32 = 1.0;
const tile_cells: f32 = 64.0;
const lacquer_broad_range: f32 = 2.5;
const lacquer_fine_range: f32 = 1.5;
const lacquer_blend: f32 = 0.5;
const map_ring_mean: f32 = 0.25;
const map_line_mean: f32 = 0.0897;
const map_wear_mean: f32 = 0.3814;
const map_speck_mean: f32 = 0.0015;
fn map_footprint(position: vec3f) {
    let dx = dpdx(position);
    let dy = dpdy(position);
    map_pixel = max(length(dx), length(dy));
    if ((use_lacquer && !use_procedural_lacquer) || map_tiled()) {
        map_dx = dx;
        map_dy = dy;
        let face = cross(dx, dy);
        let size = length(face);
        var w = vec3f(0.0, 0.0, 1.0);
        if (size > 0.0) {
            w = max(abs(face) / size - vec3f(lacquer_blend), vec3f(0.0));
            w = w / (w.x + w.y + w.z);
        }
        map_planes = w;
        map_gain = inverseSqrt(dot(w, w));
    }
}
fn map_tiled() -> bool {
    return !use_procedural_detail && (use_scratch || use_wall || use_fibre || use_crinkle);
}
fn lacquer_plane(at: vec2f, dx: vec2f, dy: vec2f, layer: i32, fine_scale: f32) -> vec2f {
    let broad = textureSampleGrad(map_metal, map_sampler, at, layer, dx, dy).rg;
    let fine = textureSampleGrad(map_metal, map_sampler, at * fine_scale, layer, dx * fine_scale, dy * fine_scale).ba;
    return (broad * 2.0 - 1.0) * lacquer_broad_range + (fine * 2.0 - 1.0) * lacquer_fine_range;
}
fn map_lacquer(p: vec3f, amp: f32, tile: f32, a: vec4f, b: vec4f, d: vec4f) -> vec3f {
    if (use_procedural_lacquer || tile < 0.0 || d.w == 0.0) {
        return value_noise3_gradient(p, a.x) * amp + value_noise3_gradient(p, a.y) * (amp * a.w) + value_noise3_gradient(p, a.z) * (amp * b.x);
    }
    let layer = i32(tile);
    let w = map_planes;
    var g = vec3f(0.0);
    if (w.z > 0.0) {
        g += vec3f(lacquer_plane(p.xy, map_dx.xy, map_dy.xy, layer, d.z), 0.0) * w.z;
    }
    if (w.x > 0.0) {
        g += vec3f(0.0, lacquer_plane(p.yz + vec2f(0.31, 0.67), map_dx.yz, map_dy.yz, layer, d.z)) * w.x;
    }
    if (w.y > 0.0) {
        let t = lacquer_plane(p.zx + vec2f(0.53, 0.19), map_dx.zx, map_dy.zx, layer, d.z);
        g += vec3f(t.y, 0.0, t.x) * w.y;
    }
    return g * (amp * map_gain);
}
fn map_weight(rate: f32) -> f32 {
    if (use_fine_noise) {
        return 1.0;
    }
    return octave_weight(map_pixel * rate);
}
fn map_faded(mean: f32, value: f32, weight: f32) -> f32 {
    return select(mix(mean, value, weight), value, weight >= 1.0);
}
fn map_noise(q: vec3f, rate: f32) -> f32 {
    let weight = map_weight(rate);
    if (weight <= 0.0) {
        return 0.5;
    }
    return map_faded(0.5, value_noise3(q, false), weight);
}
fn tile_pair(at: vec2f, dx: vec2f, dy: vec2f, layer: i32, high: bool) -> vec2f {
    let s = 1.0 / tile_cells;
    let t = textureSampleGrad(map_metal, map_sampler, at * s, layer, dx * s, dy * s);
    return select(t.xy, t.zw, high);
}
fn tile_slice(pair: vec2f, depth: f32) -> f32 {
    let k = floor(depth);
    let w = fade_cubic(depth - k);
    let odd = k - 2.0 * floor(k * 0.5) > 0.5;
    return select(mix(pair.x, pair.y, w), mix(pair.y, pair.x, w), odd);
}
fn tile_flat(at: vec2f, dx: vec2f, dy: vec2f, depth: f32, tile: f32, octave: u32) -> f32 {
    return tile_slice(tile_pair(at, dx, dy, i32(tile) + 1 + i32(octave >> 1u), (octave & 1u) == 1u), depth);
}
fn tile_noise(q: vec3f, rate: vec3f, tile: f32, octave: u32) -> f32 {
    if (map_weight(max(rate.x, max(rate.y, rate.z))) <= 0.0) {
        return 0.5;
    }
    let dx = map_dx * rate;
    let dy = map_dy * rate;
    let w = map_planes;
    var sum = 0.0;
    if (w.z > 0.0) {
        sum += (tile_flat(q.xy, dx.xy, dy.xy, q.z, tile, octave) - 0.5) * w.z;
    }
    if (w.x > 0.0) {
        sum += (tile_flat(q.yz + vec2f(17.0, 41.0), dx.yz, dy.yz, q.x, tile, octave) - 0.5) * w.x;
    }
    if (w.y > 0.0) {
        sum += (tile_flat(q.zx + vec2f(29.0, 7.0), dx.zx, dy.zx, q.y, tile, octave) - 0.5) * w.y;
    }
    return 0.5 + sum * map_gain;
}
fn tile_gradient(at: vec2f, dx: vec2f, dy: vec2f, layer: i32) -> vec2f {
    let s = 1.0 / tile_cells;
    let t = textureSampleGrad(map_metal, map_sampler, at * s, layer, dx * s, dy * s).ba;
    return (t * 2.0 - 1.0) * lacquer_fine_range;
}
fn tile_wobble(p: vec3f, scale: f32, shift: vec2f, tile: f32) -> vec3f {
    if (map_weight(scale) <= 0.0) {
        return vec3f(0.0);
    }
    let q = p * scale;
    let dx = map_dx * scale;
    let dy = map_dy * scale;
    let layer = i32(tile);
    let w = map_planes;
    var g = vec3f(0.0);
    if (w.z > 0.0) {
        g += vec3f(tile_gradient(q.xy + shift, dx.xy, dy.xy, layer), 0.0) * w.z;
    }
    if (w.x > 0.0) {
        g += vec3f(0.0, tile_gradient(q.yz + shift.yx, dx.yz, dy.yz, layer)) * w.x;
    }
    if (w.y > 0.0) {
        let t = tile_gradient(q.zx + shift * 1.7, dx.zx, dy.zx, layer);
        g += vec3f(t.y, 0.0, t.x) * w.y;
    }
    return g * map_gain;
}
fn ink_sample(at: vec2f) -> vec4f {
    return map_ink_base;
}
fn map_perturb(n: vec3f, g: vec3f) -> vec3f {
    return normalize(n - (g - n * dot(g, n)));
}
fn map_scratch_coat(base: vec3f, roughness: f32, amount: f32, position: vec3f, seed: u32) -> vec4f {
    if (amount <= 0.0) {
        return vec4f(base, roughness);
    }
    let q = position * 900.0;
    let n = value_noise3(vec3f(q.x * 0.02 + f32(seed), q.y, q.z * 0.02), false);
    let line = 1.0 - smoothstep(0.0, 0.045, abs(n - 0.5));
    let smudge = smoothstep(0.52, 0.78, value_noise3(position * 22.0, false) * 0.65 + value_noise3(position * 61.0, false) * 0.35);
    let cell = vec3i(floor(position * 2600.0));
    let speck = select(0.0, 1.0, hash3_xor(vec3i(cell.x, cell.y, cell.z ^ i32(seed))) > 0.9985);
    let cover = min(amount, 1.0);
    let breakup = clamp(smudge * 0.55 + line * 0.35 + speck, 0.0, 1.0) * cover;
    let rough2 = roughness * roughness;
    let mixed = mix(rough2, min(rough2 * 4.0 + 0.02, 0.35), breakup);
    let albedo = mix(base, base * 0.9 + vec3f(0.06), speck * cover);
    return vec4f(albedo, sqrt(mixed));
}
fn map_scratch(base: vec3f, roughness: f32, amount: f32, position: vec3f, seed: u32, coated: bool, tile: f32, scales: vec4f, stretch: f32) -> vec4f {
    if (amount <= 0.0) {
        return vec4f(base, roughness);
    }
    let tiled = !use_procedural_detail && tile >= 0.0;
    var line = map_line_mean;
    let line_weight = map_weight(scales.x);
    if (line_weight > 0.0) {
        let at = vec3f(position.x * stretch + f32(seed), position.y * scales.x, position.z * stretch);
        var n: f32;
        if (tiled) {
            n = tile_noise(at, vec3f(stretch, scales.x, stretch), tile, 2u);
        } else {
            n = value_noise3(at, false);
        }
        line = map_faded(map_line_mean, 1.0 - smoothstep(0.0, 0.045, abs(n - 0.5)), line_weight);
    }
    var smudge: f32;
    if (tiled) {
        smudge = smoothstep(0.52, 0.78, tile_noise(position * scales.y, vec3f(scales.y), tile, 3u) * 0.65 + tile_noise(position * scales.z, vec3f(scales.z), tile, 1u) * 0.35);
    } else {
        smudge = smoothstep(0.52, 0.78, map_noise(position * scales.y, scales.y) * 0.65 + map_noise(position * scales.z, scales.z) * 0.35);
    }
    var speck = map_speck_mean;
    let speck_weight = map_weight(scales.w);
    if (speck_weight > 0.0) {
        let cell = vec3i(floor(position * scales.w));
        speck = map_faded(map_speck_mean, select(0.0, 1.0, hash3_xor(vec3i(cell.x, cell.y, cell.z ^ i32(seed))) > 0.9985), speck_weight);
    }
    let cover = min(amount, 1.0);
    let breakup = clamp(smudge * 0.55 + line * 0.35 + speck, 0.0, 1.0) * cover;
    let rough2 = roughness * roughness;
    var mixed = mix(rough2, min(rough2 * 3.0 + 0.03, 0.5), breakup);
    if (coated) {
        mixed = mix(rough2, min(rough2 * 4.0 + 0.02, 0.35), breakup);
    }
    let albedo = mix(base, base * 0.9 + vec3f(0.06), speck * cover);
    return vec4f(albedo, sqrt(mixed));
}
fn map_layer(result_in: MapResult, layer: vec4f, pa: vec4f, pb: vec4f, pc: vec4f, pd: vec4f, uv: vec2f, position: vec3f, time: f32, coated: bool, tile: f32) -> MapResult {
    var result = result_in;
    let kind = u32(round(layer.x));
    let amp = layer.z;
    if (kind == 0u || amp == 0.0) {
        return result;
    }
    let seed = bitcast<u32>(layer.w);
    let p = position + vec3f(f32(seed) * 0.001, f32(seed) * 0.001, 0.0);
    let tiled = !use_procedural_detail && tile >= 0.0;
    if (use_fibre && kind == 1u) {
        var fibre: f32;
        var mottle: f32;
        var g: vec3f;
        let streak = vec3f(pa.x, pa.y, pa.x);
        if (tiled) {
            fibre = tile_noise(p * streak, streak, tile, 0u) * 0.6 + tile_noise(p * pa.z, vec3f(pa.z), tile, 1u) * 0.4;
            mottle = tile_noise(p * pa.w, vec3f(pa.w), tile, 2u);
            g = tile_wobble(p, pb.x, vec2f(3.0, 5.0), tile) * (pc.x * amp) + tile_wobble(p, pb.y, vec2f(11.0, 23.0), tile) * (pc.y * amp);
        } else {
            fibre = map_noise(p * streak, max(pa.x, pa.y)) * 0.6 + map_noise(p * pa.z, pa.z) * 0.4;
            mottle = map_noise(p * pa.w, pa.w);
            g = value_noise3_gradient(p, pb.x) * (pc.x * amp) + value_noise3_gradient(p, pb.y) * (pc.y * amp);
        }
        result.base *= 1.0 + ((fibre - 0.5) * pb.z + (mottle - 0.5) * pb.w) * amp;
        result.normal = map_perturb(result.normal, g);
    } else if (use_crinkle && kind == 2u) {
        var g: vec3f;
        if (tiled) {
            g = tile_wobble(p, pa.x, vec2f(7.0, 19.0), tile) * (pa.z * amp) + tile_wobble(p, pa.y, vec2f(31.0, 2.0), tile) * (pa.w * amp);
        } else {
            g = value_noise3_gradient(p, pa.x) * (pa.z * amp) + value_noise3_gradient(p, pa.y) * (pa.w * amp);
        }
        result.normal = map_perturb(result.normal, g);
    } else if (use_wood && kind == 3u) {
        let plank = floor(p.z * pd.x);
        let tone = hash3_xor(vec3i(i32(plank), 7, 3));
        let across = fract(p.z * pd.x);
        let seam = smoothstep(0.0, 0.006, across) + smoothstep(0.0, 0.006, 1.0 - across) - 1.0;
        var grain = map_ring_mean;
        let ring_weight = map_weight(pd.z);
        if (ring_weight > 0.0) {
            let warp = map_noise(vec3f(p.x * 1.4, plank * 3.7, p.z * 6.0), 6.0) * 0.9 + map_noise(vec3f(p.x * 6.0, plank, p.z * 20.0), 20.0) * 0.25;
            let rings = fract(fma(fma(warp, pa.z, p.z), pa.y, map_noise(vec3f(p.x * 0.8, plank, 0.0), 0.8) * pc.y));
            grain = map_faded(map_ring_mean, smoothstep(0.55, 0.95, rings), ring_weight);
        }
        let figure = grain * 0.55 + map_noise(vec3f(p.x * pa.w, p.z * pb.x, plank), pb.x) * 0.25;
        let factor = (0.78 + tone * pb.y) * (1.08 - figure * pb.z) * (pb.w + clamp(seam, 0.0, 1.0) * pd.y);
        result.base *= mix(1.0, factor, clamp(amp, 0.0, 1.0));
        let alpha = result.roughness * result.roughness;
        result.roughness = mix(result.roughness, sqrt(min(alpha * (0.85 + figure * pc.x), 1.0)), clamp(amp, 0.0, 1.0));
    } else if (use_wall && kind == 4u) {
        let broad = map_noise(p * pa.x, pa.x) * 0.6 + map_noise(p * pa.y, pa.y) * 0.4;
        var fine: f32;
        var g: vec3f;
        if (tiled) {
            fine = tile_noise(p * pa.z, vec3f(pa.z), tile, 2u) * 0.6 + tile_noise(p * pa.w, vec3f(pa.w), tile, 3u) * 0.4;
            g = tile_wobble(p, pb.x, vec2f(5.0, 13.0), tile) * (pc.x * amp) + tile_wobble(p, pb.y, vec2f(29.0, 3.0), tile) * (pc.y * amp);
        } else {
            fine = map_noise(p * pa.z, pa.z) * 0.6 + map_noise(p * pa.w, pa.w) * 0.4;
            g = value_noise3_gradient(p, pb.x) * (pc.x * amp) + value_noise3_gradient(p, pb.y) * (pc.y * amp);
        }
        result.base *= mix(1.0, 1.0 + (broad - 0.5) * pb.z + (fine - 0.5) * pb.w, clamp(amp, 0.0, 1.0));
        result.normal = map_perturb(result.normal, g);
    } else if (use_grime && kind == 5u) {
        var wear = map_wear_mean;
        let grime_weight = map_weight(pa.x);
        if (grime_weight > 0.0) {
            let grime = value_noise3(p * pa.x, false) * 0.6 + map_noise(p * pa.y, pa.y) * 0.4;
            wear = map_faded(map_wear_mean, smoothstep(0.35, 0.75, grime), grime_weight);
        }
        let tint = mix(vec3f(pa.z, pa.w, pb.x), vec3f(pb.y, pb.z, pb.w), wear);
        result.base *= mix(vec3f(1.0), tint, clamp(amp, 0.0, 1.0));
        let alpha = result.roughness * result.roughness;
        result.roughness = mix(result.roughness, sqrt(min(alpha * mix(pc.x, pc.y, wear), 1.0)), clamp(amp, 0.0, 1.0));
    } else if (kind == 7u) {
        let spots = fbm3(vec3f(uv * 12.0, 2.0), 4, true);
        result.base *= mix(1.0, 0.7 + 0.6 * spots, clamp(amp, 0.0, 1.0));
    } else if (kind == 8u) {
        let value = fbm3(p * 300.0, 4, true);
        result.base *= mix(1.0, 0.75 + 0.5 * value, clamp(amp, 0.0, 1.0));
    } else if (use_scratch && kind == 17u) {
        if (coated) {
            let scratched = map_scratch(result.base, result.coat_roughness, amp, p, seed, true, tile, pa, pd.x);
            result.base = scratched.xyz;
            result.coat_roughness = scratched.w;
        } else {
            let scratched = map_scratch(result.base, result.roughness, amp, p, seed, false, tile, pa, pd.x);
            result.base = scratched.xyz;
            result.roughness = scratched.w;
        }
    } else if (use_lacquer && kind == 18u) {
        result.normal = map_perturb(result.normal, map_lacquer(p, amp, tile, pa, pb, pd));
    } else if (kind == 14u) {
        let value = flow(uv * layer.y, time);
        result.thin_film = max(result.thin_film + amp * (value - 0.5) * 2.0, 0.0);
    } else if (kind == 15u) {
        let value = map_noise(p * layer.y, abs(layer.y));
        result.base *= mix(1.0, 1.0 + (value - 0.5) * 2.0, clamp(amp, 0.0, 1.0));
    } else if (kind == 16u) {
        let value = fbm3(p * layer.y, 4, true);
        result.base *= mix(1.0, 1.0 + (value - 0.5) * 2.0, clamp(amp, 0.0, 1.0));
    }
    return result;
}
fn map_evaluate(base: vec3f, roughness: f32, metalness: f32, coat_roughness: f32, thin_film: f32, normal: vec3f, tangent: vec4f, uv: vec2f, object_position: vec3f, edge: f32, age_in: f32, time: f32, material_index: u32) -> MapResult {
    return map_evaluate_with(base, roughness, metalness, coat_roughness, thin_film, normal, tangent, uv, uv, object_position, edge, age_in, time, material_index);
}
fn map_evaluate_with(base: vec3f, roughness: f32, metalness: f32, coat_roughness: f32, thin_film: f32, normal: vec3f, tangent: vec4f, uv: vec2f, uv1: vec2f, object_position: vec3f, edge: f32, age_in: f32, time: f32, material_index: u32) -> MapResult {
    let material = map_materials[material_index];
    let baked = material.seeds.w != 0u;
    var atlas_uv = uv;
    if (use_uv1 && material.packed.y != 0.0) {
        atlas_uv = uv1;
    }
    let tiled_uv = select(uv * select(max(material.factors.x, 0.000001), 1.0, baked), atlas_uv * material.atlas.xy + material.atlas.zw, material.seeds.w >= 2u);
    var result = MapResult(base, roughness, metalness, normalize(normal), coat_roughness, thin_film);
    let tile_dx = dpdx(tiled_uv) * material.content_extra.z;
    let tile_dy = dpdy(tiled_uv) * material.content_extra.z;
    if (use_maps && material.indices.x >= 0) {
        let sample = textureSampleGrad(map_base, map_sampler, tiled_uv, material.indices.x, tile_dx, tile_dy);
        if (baked) {
            result.base = sample.rgb;
        } else {
            result.base *= mix(vec3f(1.0), sample.rgb, clamp(material.factors.y, 0.0, 1.0));
        }
    }
    if (use_maps && material.indices.z >= 0) {
        let sampled_roughness = textureSampleGrad(map_roughness, map_sampler, tiled_uv, material.indices.z, tile_dx, tile_dy).r;
        if (baked) {
            result.roughness = sampled_roughness;
        } else {
            result.roughness *= sampled_roughness;
        }
    }
    if (use_maps && material.indices.w >= 0) {
        result.metalness *= textureSampleGrad(map_metal, map_sampler, tiled_uv, material.indices.w, tile_dx, tile_dy).r;
    }
    if (use_maps && material.indices.y >= 0) {
        var mapped = textureSampleGrad(map_normal, map_sampler, tiled_uv, material.indices.y, tile_dx, tile_dy).xyz * 2.0 - vec3f(1.0);
        if (material.seeds.w == 3u) {
            mapped.z = sqrt(max(0.0, 1.0 - dot(mapped.xy, mapped.xy)));
        }
        let t = normalize(tangent.xyz - result.normal * dot(tangent.xyz, result.normal));
        let b = cross(result.normal, t) * tangent.w;
        let transformed = normalize(t * mapped.x + b * mapped.y + result.normal * mapped.z);
        result.normal = normalize(mix(result.normal, transformed, clamp(material.factors.z, 0.0, 1.0)));
    }
    let age = clamp(age_in, 0.0, 1.0);
    let seed = material.seeds.x;
    if (use_ageing && age > 0.0) {
        result.base = fade_colour(result.base, age * material.age_a.x, object_position, seed);
        result.base = yellow(result.base, age * material.age_a.y, uv, seed);
        if (material.age_a.z > 0.0) {
            map_ink_base = vec4f(result.base, 1.0);
            result.base = mix(result.base, ink_age(object_position.xy, 1.0, seed).xyz, clamp(age * material.age_a.z, 0.0, 1.0));
        }
        if (material.seeds.y != 0u) {
            let scratched = map_scratch_coat(result.base, result.coat_roughness, age * material.age_a.w, object_position, seed);
            result.base = scratched.xyz;
            result.coat_roughness = scratched.w;
        } else {
            let scratched = scratch(result.base, result.roughness, age * material.age_a.w, object_position, seed);
            result.base = scratched.xyz;
            result.roughness = scratched.w;
        }
        let worn = worn_edge(result.base, result.roughness, age * material.age_b.x, edge);
        result.base = worn.xyz;
        result.roughness = worn.w;
        let dusty = dust(result.base, result.roughness, age * material.age_b.y, object_position, seed);
        result.base = dusty.xyz;
        result.roughness = dusty.w;
        let patinated = patina(result.base, result.roughness, result.metalness, age * material.age_b.z, object_position, seed);
        result.base = patinated.xyz;
        result.roughness = patinated.w;
        if (material.age_b.z > 0.0) {
            let p = object_position + vec3f(f32(seed) * 0.001);
            let green = smoothstep(0.62, 0.9, fbm3(p * 1500.0 + vec3f(9.0), 3, true)) * clamp(age * material.age_b.z, 0.0, 1.0) * 0.45;
            result.metalness = mix(result.metalness, 0.5, green);
        }
    }
    if (use_detail && material.seeds.w == 0u) {
        result = map_layer(result, material.layer0, material.params[0], material.params[1], material.params[2], material.params[3], uv, object_position, time, material.seeds.y != 0u, material.packed.z);
        result = map_layer(result, material.layer1, material.params[4], material.params[5], material.params[6], material.params[7], uv, object_position, time, material.seeds.y != 0u, material.packed.z);
        result = map_layer(result, material.layer2, material.params[8], material.params[9], material.params[10], material.params[11], uv, object_position, time, material.seeds.y != 0u, material.packed.z);
        result = map_layer(result, material.layer3, material.params[12], material.params[13], material.params[14], material.params[15], uv, object_position, time, material.seeds.y != 0u, material.packed.z);
    }
    return result;
}
"#;