codecraft 0.1.1

A minimalist 3D game engine built on parts of Bevy (ECS, color) with wgpu and winit: OpenPBR materials, clustered lighting, an immediate-mode UI, audio and gamepad haptics
Documentation
// Port of glsl/pathtracing/fuzz_brdf.glsl (Zeltner sheen via LTC).

struct BsdfEval {
    f: vec3<f32>,
    pdf: f32,
    /// dielectric lobes: Fresnel reflectance at the microfacet (used for joint R/T sampling)
    fresnel: f32,
};

struct BsdfSample {
    f: vec3<f32>,
    woutputL: vec3<f32>,
    pdf: f32,
    fresnel: f32,
};

fn zeltner_sheen_dir_albedo(x: f32, y: f32) -> f32 {
    let s = y * (0.0206607 + 1.58491 * y) / (0.0379424 + y * (1.32227 + y));
    let m = y * (-0.193854 + y * (-1.14885 + y * (1.7932 - 0.95943 * y * y))) / (0.046391 + y);
    let o = y * (0.000654023 + (-0.0207818 + 0.119681 * y) * y) / (1.26264 + y * (-1.92021 + y));
    return exp(-0.5 * sqr((x - m) / s)) / (s * sqrt(2.0 * PI)) + o;
}

fn zeltner_sheen_ltc_aInv(x: f32, y: f32) -> f32 {
    return (2.58126 * x + 0.813703 * y) * y / (1.0 + 0.310327 * x * x + 2.60994 * x * y);
}

fn zeltner_sheen_ltc_bInv(x: f32, y: f32) -> f32 {
    return sqrt(1.0 - x) * (y - 1.0) * y * y * y / (0.0000254053 + 1.71228 * x - 1.71506 * x * y + 1.34174 * y * y);
}

fn fuzz_brdf_evaluate(winputL: vec3<f32>, woutputL: vec3<f32>) -> BsdfEval {
    var out: BsdfEval;
    out.f = vec3<f32>(0.0);
    out.pdf = 0.0;
    if (winputL.z < DENOM_TOLERANCE || woutputL.z < DENOM_TOLERANCE) { return out; }

    let NdotV = min(winputL.z, 1.0);
    let roughness = clamp(fuzz_roughness, 0.01, 1.0);
    let toLTC = transpose(orthonormal_basis_ltc(winputL));
    let w = toLTC * woutputL;

    let aInv = zeltner_sheen_ltc_aInv(NdotV, roughness);
    let bInv = zeltner_sheen_ltc_bInv(NdotV, roughness);
    let wo = vec3<f32>(aInv * w.x + bInv * w.z, aInv * w.y, w.z);
    let lenSqr = dot(wo, wo);

    let jacobian = sqr(aInv / lenSqr);
    out.pdf = max(wo.z, 0.0) * RECIPROCAL_PI * jacobian;
    let albedo = zeltner_sheen_dir_albedo(NdotV, roughness);
    let NdotL = max(abs(woutputL.z), FLT_EPSILON);
    out.f = fuzz_color * albedo * out.pdf / NdotL;
    return out;
}

fn fuzz_brdf_sample(winputL: vec3<f32>) -> BsdfSample {
    var out: BsdfSample;
    out.f = vec3<f32>(0.0);
    out.woutputL = vec3<f32>(0.0, 0.0, 1.0);
    out.pdf = 0.0;
    if (winputL.z < DENOM_TOLERANCE) { return out; }
    let NdotV = min(winputL.z, 1.0);
    let roughness = clamp(fuzz_roughness, 0.01, 1.0);
    let wo = sampleHemisphereCosineWeighted().dir;

    let aInv = zeltner_sheen_ltc_aInv(NdotV, roughness);
    let bInv = zeltner_sheen_ltc_bInv(NdotV, roughness);
    var w = vec3<f32>(wo.x / aInv - wo.z * bInv / aInv, wo.y / aInv, wo.z);
    let lenSqr = dot(w, w);
    w *= inverseSqrt(lenSqr);

    let jacobian = sqr(aInv * lenSqr);
    out.pdf = max(w.z, 0.0) * RECIPROCAL_PI * jacobian;
    let fromLTC = orthonormal_basis_ltc(winputL);
    out.woutputL = fromLTC * w;
    let albedo = zeltner_sheen_dir_albedo(NdotV, roughness);
    out.f = fuzz_color * albedo * RECIPROCAL_PI * jacobian;
    return out;
}

fn fuzz_brdf_albedo(winputL: vec3<f32>) -> vec3<f32> {
    return vec3<f32>(zeltner_sheen_dir_albedo(winputL.z, fuzz_roughness));
}