hex-world
    Preparing search index...

    Variable SNOW_GLSLConst

    SNOW_GLSL: "\n uniform vec3 uSnowColor;\n uniform float uSnowSlope;\n uniform float uSnowNoise;\n\n float snHash(vec2 p) {\n return fract(sin(dot(p, vec2(269.5, 183.3))) * 43758.5453);\n }\n float snNoise(vec2 p) {\n vec2 i = floor(p);\n vec2 f = fract(p);\n f = f * f * (3.0 - 2.0 * f);\n return mix(mix(snHash(i), snHash(i + vec2(1,0)), f.x),\n mix(snHash(i + vec2(0,1)), snHash(i + vec2(1,1)), f.x), f.y);\n }\n\n /**\n * snow — the cell's snow depth, 0–1 (the climate texture's B channel)\n * upness — the surface normal's y, 1 on flat ground and 0 on a vertical face\n * worldXZ — world position, for breaking up the snowline\n */\n float snowCoverage(float snow, float upness, vec2 worldXZ) {\n if (snow <= 0.0) return 0.0;\n\n // Steep faces shed their snow, which is what keeps cliffs reading as rock\n // and stops the world going flat white the moment winter lands.\n float slope = mix(1.0, smoothstep(0.1, 0.55, upness), uSnowSlope);\n\n // Two octaves so the edge frays at both the hillside and the footprint\n // scale — a single frequency reads as a clean contour line either way.\n float n = snNoise(worldXZ * 0.35) * 0.65 + snNoise(worldXZ * 1.3) * 0.35;\n\n // Bias the threshold by noise rather than the value, so full snow stays\n // fully covered and only the transition band breaks up.\n float edge = (n - 0.5) * uSnowNoise;\n return smoothstep(0.15 + edge, 0.85 + edge, snow * slope);\n }\n" = ...

    Shared snow-coverage math. Terrain and scatter both call snowCoverage so a tree's cap appears at exactly the same moment as the ground it stands on — duplicating this curve is how those two drift apart by a frame of snowfall.

    Deliberately not included here: the snow color. Terrain samples the pack's snow slice triplanar from its texture array; a stock scatter material has no such array and takes a flat tint. Only the mask is common.