shader_type spatial; // The imported AB/BB/QG surfaces are double-sided, including thin foliage. render_mode diffuse_burley, specular_schlick_ggx, cull_disabled; uniform float roughness_value : hint_range(0, 1) = 0.75; uniform float metallic_value : hint_range(0, 1) = 0.0; uniform float grain_amount = 0.08; uniform float grain_scale = 90.0; uniform float relief_depth = 0.00045; // 0 mineral, 1 leather, 2 fabric, 3 bark, 4 leaf, 5 metal. uniform int surface_kind = 0; float hash21(vec2 p) { p = fract(p * vec2(123.34, 456.21)); p += dot(p, p + 45.32); return fract(p.x * p.y); } float grain_noise(vec2 p) { vec2 cell = floor(p); vec2 f = fract(p); vec2 blend = f * f * (3.0 - 2.0 * f); return mix(mix(hash21(cell), hash21(cell + vec2(1.0, 0.0)), blend.x), mix(hash21(cell + vec2(0.0, 1.0)), hash21(cell + vec2(1.0)), blend.x), blend.y); } void fragment() { if (!FRONT_FACING) { NORMAL = -NORMAL; } vec2 p = UV * grain_scale; float footprint = max(length(dFdx(p)), length(dFdy(p))); float detail = 1.0 - smoothstep(0.5, 2.0, footprint); float coarse = grain_noise(p * 0.37); float fine = grain_noise(p) * 0.65 + grain_noise(p * 2.03 + 19.7) * 0.35; float grain = mix(0.0, fine - 0.5, detail); float relief = grain; if (surface_kind == 2) { // Subpixel weave fades out instead of producing a moving checkerboard. float weave = sin(p.x * 6.28318) * sin(p.y * 6.28318); relief += weave * detail * 0.1; } else if (surface_kind == 3) { relief = (grain_noise(vec2(p.x, p.y * 0.12)) - 0.5) * detail; } else if (surface_kind == 4) { relief *= 0.2; BACKLIGHT = COLOR.rgb * 0.12; } else if (surface_kind == 5) { relief = (grain_noise(vec2(p.x * 0.1, p.y)) - 0.5) * detail * 0.2; } ALBEDO = COLOR.rgb * (1.0 + grain * grain_amount + (coarse - 0.5) * grain_amount * 0.35); ROUGHNESS = clamp(roughness_value + grain * 0.07, 0.08, 1.0); METALLIC = metallic_value; // Surface gradient in view space; preserves authored UVs while joints deform. vec3 dx = dFdx(VERTEX), dy = dFdy(VERTEX); vec3 rx = cross(dy, NORMAL), ry = cross(NORMAL, dx); float determinant = dot(dx, rx); if (abs(determinant) > 0.00000001) { NORMAL = normalize(abs(determinant) * NORMAL - sign(determinant) * (dFdx(relief) * rx + dFdy(relief) * ry) * relief_depth); } }