Constant PROBE_WGSL
Source pub const PROBE_WGSL: &str = "\nfn ssr_encode_normal(n: vec3f) -> vec2f {\n let p = n.xy / (abs(n.x) + abs(n.y) + abs(n.z));\n if (n.z >= 0.0) { return p; }\n return (vec2f(1.0) - abs(p.yx)) * select(vec2f(-1.0), vec2f(1.0), p >= vec2f(0.0));\n}\nfn ssr_decode_normal(e: vec2f) -> vec3f {\n var n = vec3f(e, 1.0 - abs(e.x) - abs(e.y));\n let t = max(-n.z, 0.0);\n n.x += select(t, -t, n.x >= 0.0);\n n.y += select(t, -t, n.y >= 0.0);\n return normalize(n);\n}\nfn ssr_similarity(depth: f32, normal: vec3f, other_depth: f32, other_normal: vec3f, tolerance: f32) -> f32 {\n if (depth <= 0.0 || other_depth <= 0.0) { return 0.0; }\n let near = clamp(1.0 - abs(depth - other_depth) / max(tolerance, 0.000001), 0.0, 1.0);\n let facing = smoothstep(0.6, 0.85, dot(normal, other_normal));\n return near * facing;\n}\nconst SSR_DEPTH_TOLERANCE: f32 = 0.03;\n\noverride use_local_reflections: bool = true;\nconst LOCAL_DEPTH_LEVELS: f32 = 6.0;\nconst LOCAL_DEPTH_START: f32 = 0.02;\nconst LOCAL_DEPTH_GROWTH: f32 = 2.5;\nconst LOCAL_DEPTH_STEPS: u32 = 9u;\nconst LOCAL_DEPTH_REFINE: u32 = 4u;\nconst LOCAL_DEPTH_TOLERANCE: f32 = 0.02;\nconst LOCAL_DEPTH_THICKNESS: f32 = 0.03;\nstruct ReflectionProbe {\n center: vec3f,\n layer: i32,\n box_min: vec3f,\n priority: f32,\n box_max: vec3f,\n fade: f32,\n}\nfn local_probe_direction(probe: ReflectionProbe, world: vec3f, direction: vec3f) -> vec3f {\n let safe = select(vec3f(-1.0), vec3f(1.0), direction >= vec3f(0.0)) * max(abs(direction), vec3f(0.00001));\n let a = (probe.box_min - world) / safe;\n let b = (probe.box_max - world) / safe;\n let reach = min(max(a.x, b.x), min(max(a.y, b.y), max(a.z, b.z)));\n return normalize(world + direction * max(reach, 0.0) - probe.center);\n}\nfn ssr_resolve(colour: texture_2d<f32>, guide: texture_2d<f32>, samp: sampler, uv: vec2f, written: vec2f, depth: f32, normal: vec3f) -> vec4f {\n let dimensions = vec2i(textureDimensions(colour));\n if (any(dimensions != vec2i(textureDimensions(guide)))) { return vec4f(0.0); }\n let size = min(dimensions, vec2i(written));\n let f = uv * vec2f(size) - vec2f(0.5);\n let base = vec2i(floor(f));\n let t = f - floor(f);\n let tolerance = depth * SSR_DEPTH_TOLERANCE;\n let first = textureLoad(guide, clamp(base, vec2i(0), size - vec2i(1)), 0);\n if (first.w >= 0.0 && ssr_similarity(depth, normal, first.x, ssr_decode_normal(first.yz), tolerance) > 0.8) {\n let inner = any(size < dimensions);\n let texel = select(uv * vec2f(size), min(uv * vec2f(size), vec2f(size) - vec2f(0.5)), inner);\n return textureSampleLevel(colour, samp, select(uv, texel / vec2f(dimensions), inner), 0.0);\n }\n var sum = vec4f(0.0);\n var total = 0.0;\n for (var i = 0; i < 4; i++) {\n let offset = vec2i(i & 1, i >> 1u);\n let at = clamp(base + offset, vec2i(0), size - vec2i(1));\n let bilinear = select(1.0 - t.x, t.x, offset.x == 1) * select(1.0 - t.y, t.y, offset.y == 1);\n let g = textureLoad(guide, at, 0);\n let weight = (bilinear + 0.01) * ssr_similarity(depth, normal, g.x, ssr_decode_normal(g.yz), tolerance);\n sum += textureLoad(colour, at, 0) * weight;\n total += weight;\n }\n if (total < 0.001) { return vec4f(0.0); }\n return sum / total;\n}\nfn local_probe_weight(probe: ReflectionProbe, world: vec3f) -> vec2f {\n if (any(world < probe.box_min) || any(world > probe.box_max)) {\n return vec2f(0.0);\n }\n let low = world - probe.box_min;\n let high = probe.box_max - world;\n let edge = min(min(min(low.x, low.y), low.z), min(min(high.x, high.y), high.z));\n let seam = select(clamp(edge / probe.fade, 0.0, 1.0), 1.0, probe.fade == 0.0);\n return vec2f(seam * (1.0 + max(probe.priority, 0.0)) / (length(world - probe.center) + 0.001), seam);\n}\nfn local_probe_weights(probe_a: ReflectionProbe, probe_b: ReflectionProbe, present: vec2f, world: vec3f) -> vec2f {\n let a = local_probe_weight(probe_a, world) * present.x;\n let b = local_probe_weight(probe_b, world) * present.y;\n let total = a.x + b.x;\n if (total <= 0.0) {\n return vec2f(0.0);\n }\n let coverage = max(a.y, b.y);\n return vec2f(a.x, b.x) * coverage / total;\n}\nfn local_probe_gap(probe: ReflectionProbe, reached: vec3f, local: texture_cube_array<f32>, samp: sampler, level: f32) -> f32 {\n let distance = max(length(reached), 0.000001);\n let stored = 1.0 / max(-1.0 - textureSampleLevel(local, samp, reached / distance, probe.layer, level).a, 0.00001);\n return (distance - stored) / distance;\n}\nfn local_probe_lookup(probe: ReflectionProbe, world: vec3f, direction: vec3f, local: texture_cube_array<f32>, samp: sampler, local_mip: f32) -> vec3f {\n let level = max(local_mip - LOCAL_DEPTH_LEVELS, 0.0);\n if (textureSampleLevel(local, samp, direction, probe.layer, level).a >= 0.0) {\n return local_probe_direction(probe, world, direction);\n }\n let offset = world - probe.center;\n var ahead = local_probe_gap(probe, offset, local, samp, level) < LOCAL_DEPTH_THICKNESS;\n var near = 0.0;\n var t = LOCAL_DEPTH_START;\n for (var step = 0u; step < LOCAL_DEPTH_STEPS; step++) {\n let outer = local_probe_gap(probe, offset + direction * t, local, samp, level);\n if (outer <= LOCAL_DEPTH_TOLERANCE) {\n ahead = true;\n } else {\n if (ahead) {\n var low = near;\n var high = t;\n var gap = outer;\n for (var refine = 0u; refine < LOCAL_DEPTH_REFINE; refine++) {\n let middle = (low + high) * 0.5;\n let found = local_probe_gap(probe, offset + direction * middle, local, samp, level);\n if (found > LOCAL_DEPTH_TOLERANCE) {\n high = middle;\n gap = found;\n } else {\n low = middle;\n }\n }\n let reached = offset + direction * high;\n if (gap < LOCAL_DEPTH_THICKNESS + (high - low) / max(length(reached), 0.000001)) {\n return select(direction, normalize(reached), dot(reached, reached) > 0.0000001);\n }\n }\n ahead = false;\n }\n near = t;\n t *= LOCAL_DEPTH_GROWTH;\n }\n return direction;\n}\nfn local_probe_reference(probe: ReflectionProbe, world: vec3f, n: vec3f, local: texture_cube_array<f32>, samp: sampler, local_mip: f32) -> vec3f {\n let along = textureSampleLevel(local, samp, n, probe.layer, local_mip);\n if (along.a < 0.0) {\n return along.rgb;\n }\n return textureSampleLevel(local, samp, local_probe_direction(probe, world, n), probe.layer, local_mip).rgb;\n}\nstruct LocalLookup {\n weights: vec2f,\n first: vec3f,\n second: vec3f,\n}\nfn local_lookup(probe_a: ReflectionProbe, probe_b: ReflectionProbe, present: vec2f, world: vec3f, direction: vec3f, local: texture_cube_array<f32>, samp: sampler, local_mip: f32) -> LocalLookup {\n var lookup = LocalLookup(vec2f(0.0), direction, direction);\n if (!use_local_reflections) {\n return lookup;\n }\n let weights = local_probe_weights(probe_a, probe_b, present, world);\n let a = clamp(weights.x, 0.0, 1.0);\n lookup.weights = vec2f(a, clamp(weights.y, 0.0, 1.0 - a));\n if (lookup.weights.x > 0.0) {\n lookup.first = local_probe_lookup(probe_a, world, direction, local, samp, local_mip);\n }\n if (lookup.weights.y > 0.0) {\n lookup.second = local_probe_lookup(probe_b, world, direction, local, samp, local_mip);\n }\n return lookup;\n}\nfn reflection_dfg(roughness: f32, ndv: f32) -> vec2f {\n let u = 2.0 * clamp(roughness, 0.05, 1.0) - 1.0;\n let n = clamp(ndv, 0.02, 1.0);\n let s = 2.0 * sqrt(n) - 1.0;\n let p = vec3f(1.0, s, s * s);\n let f5 = pow(1.0 - n, 5.0);\n var dfg = vec2f(0.0);\n dfg = dfg * u + vec2f(dot(p, vec3f(-0.4534661, 0.6691472, -0.1939928) + f5 * vec3f(2.698063, 3.846977, 1.655182)), dot(p, vec3f(0.1391939, -0.3242128, 0.1875587) + f5 * vec3f(-0.3898746, -2.342672, -3.369676)));\n dfg = dfg * u + vec2f(dot(p, vec3f(0.02489464, 0.1060682, 0.07428504) + f5 * vec3f(-0.6803499, -2.683833, -1.808813)), dot(p, vec3f(0.2148219, -0.494718, 0.2827545) + f5 * vec3f(-1.484991, -0.5113827, 0.5854544)));\n dfg = dfg * u + vec2f(dot(p, vec3f(0.462142, -0.411372, -0.06177693) + f5 * vec3f(-2.763494, -3.524146, -0.6253516)), dot(p, vec3f(-0.3198297, 0.7459178, -0.4316107) + f5 * vec3f(1.550273, 4.079052, 4.483775)));\n dfg = dfg * u + vec2f(dot(p, vec3f(-0.02032731, -0.4825735, 0.04973246) + f5 * vec3f(0.2092212, 2.050402, 1.003509)), dot(p, vec3f(-0.1640982, 0.3660604, -0.2035734) + f5 * vec3f(1.369269, -0.2278983, -0.9679774)));\n dfg = dfg * u + vec2f(dot(p, vec3f(-0.3511763, -0.1810853, 0.1673936) + f5 * vec3f(0.5484627, 0.5771128, -0.3130064)), dot(p, vec3f(0.1204449, -0.2777732, 0.1592967) + f5 * vec3f(-1.316489, -1.468577, -1.091297)));\n dfg = dfg * u + vec2f(dot(p, vec3f(0.8148172, 0.1125372, -0.01374308) + f5 * vec3f(0.05596158, -0.1952609, -0.01097813)), dot(p, vec3f(0.03557167, -0.07356264, 0.03812399) + f5 * vec3f(0.1873088, 0.3210023, 0.1747016)));\n return clamp(dfg, vec2f(0.0), vec2f(1.0));\n}\nfn reflection_environment(surface: Shaded, ndv: f32, film: vec3f, film_normal: vec3f) -> vec3f {\n let f0 = reflection_filmed(surface, 1.0, film_normal);\n if (all(f0 <= vec3f(0.0)) && surface.thin_film_amount <= 0.0) {\n return vec3f(0.0);\n }\n let dfg = reflection_dfg(surface.roughness, ndv);\n let fitted = clamp(f0 * (dfg.x - dfg.y) + vec3f(dfg.y), vec3f(0.0), vec3f(1.0));\n let filmed = reflection_filmed(surface, ndv, film) - (f0 + (vec3f(1.0) - f0) * pow(1.0 - ndv, 5.0));\n return clamp(fitted + select(vec3f(0.0), filmed, surface.thin_film_amount > 0.0), vec3f(0.0), vec3f(1.0));\n}\nfn reflection_diffuse_weight(surface: Shaded, view: vec3f, normal: vec3f, film: vec3f, film_normal: vec3f) -> vec3f {\n let ndv = clamp(dot(normal, view), 0.0, 1.0);\n let fresnel = reflection_environment(surface, ndv, film, film_normal);\n let coat = clamp(surface.clearcoat, 0.0, 1.0);\n let coat_f = schlick(vec3f(0.04), ndv, 5.0).r;\n return (vec3f(1.0) - fresnel) * (1.0 - clamp(surface.metalness, 0.0, 1.0)) * (1.0 - clamp(surface.transmission, 0.0, 1.0)) * (1.0 - coat * coat_f);\n}\nfn reflection_fallback(\n direction: vec3f,\n lookup: LocalLookup,\n rough: f32,\n open: f32,\n sky: texture_cube<f32>,\n local: texture_cube_array<f32>,\n probe_a: ReflectionProbe,\n probe_b: ReflectionProbe,\n samp: sampler,\n local_mip: f32,\n sky_mip: f32,\n) -> vec3f {\n var fallback = vec3f(0.0);\n if (open != 0.0) {\n fallback = textureSampleLevel(sky, samp, direction, rough * sky_mip).rgb * open;\n }\n if (lookup.weights.x != 0.0) {\n fallback += textureSampleLevel(local, samp, lookup.first, probe_a.layer, rough * local_mip).rgb * lookup.weights.x;\n }\n if (lookup.weights.y != 0.0) {\n fallback += textureSampleLevel(local, samp, lookup.second, probe_b.layer, rough * local_mip).rgb * lookup.weights.y;\n }\n return fallback;\n}\nfn reflection_radiance(\n surface: Shaded,\n view: vec3f,\n normal: vec3f,\n hit: vec4f,\n sky: texture_cube<f32>,\n local: texture_cube_array<f32>,\n probe_a: ReflectionProbe,\n probe_b: ReflectionProbe,\n lookup: LocalLookup,\n samp: sampler,\n local_mip: f32,\n sky_mip: f32,\n film: vec3f,\n film_normal: vec3f,\n sky_visible: f32,\n) -> vec3f {\n let ndv = clamp(dot(normal, view), 0.0, 1.0);\n let direction = reflect(-view, normal);\n let rough = clamp(surface.roughness, 0.0, 1.0);\n let open = (1.0 - lookup.weights.x - lookup.weights.y) * sky_visible;\n let confidence = clamp(hit.a, 0.0, 1.0);\n let caught = max(hit.rgb, vec3f(0.0));\n let radiance = reflection_fallback(direction, lookup, rough, open, sky, local, probe_a, probe_b, samp, local_mip, sky_mip) * (1.0 - confidence) + caught;\n let fresnel = reflection_environment(surface, ndv, film, film_normal);\n let coat = clamp(surface.clearcoat, 0.0, 1.0);\n let coat_f = schlick(vec3f(0.04), ndv, 5.0).r;\n let coat_spec = coat * coat_f;\n let substrate = min(fresnel * (1.0 - coat_spec), vec3f(1.0 - coat_spec));\n if (coat_spec <= 0.0) {\n return radiance * substrate;\n }\n let coat_rough = clamp(surface.clearcoat_roughness, 0.0, 1.0);\n var coated = radiance;\n if (coat_rough != rough) {\n coated = reflection_fallback(direction, lookup, coat_rough, open, sky, local, probe_a, probe_b, samp, local_mip, sky_mip) * (1.0 - confidence) + caught;\n }\n return radiance * substrate + coated * coat_spec;\n}\n";