monstertruck-render 0.2.0

Shape and polygon mesh visualization
Documentation
// Based on the microfacet theory
// cf: https://qiita.com/mebiusbox2/items/e7063c5dfe1424e0d01a

struct Light {
    position: vec4<f32>,
    color: vec4<f32>,
    light_type: vec4<u32>,
}

struct Material {
    albedo: vec4<f32>,
    roughness: f32,
    reflectance: f32,
    ambient_ratio: f32,
    background_ratio: f32,
}

fn light_direction(light: Light, position: vec3<f32>) -> vec3<f32> {
    var res: vec3<f32>;
    if (light.light_type[0] == 0u) {
        res = normalize(light.position.xyz - position);
    } else {
        res = light.position.xyz;
    }
    return res;
}

fn irradiance(light: Light, position: vec3<f32>, normal: vec3<f32>) -> vec3<f32> {
    let light_dir = light_direction(light, position);
    return light.color.xyz * clamp(dot(light_dir, normal), 0.0, 1.0);
}

fn diffuse_brdf(material: Material) -> vec3<f32> {
    return material.albedo.xyz * (1.0 - material.reflectance);
}

fn microfacet_distribution(middle: vec3<f32>, normal: vec3<f32>, alpha: f32) -> f32 {
    let dotNH = dot(normal, middle);
    let alpha2 = alpha * alpha;
    let sqrt_denom = 1.0 - dotNH * dotNH * (1.0 - alpha2);
    return alpha2 / (sqrt_denom * sqrt_denom);
}

fn schlick_approxy(v: vec3<f32>, normal: vec3<f32>, k: f32) -> f32 {
    let dotNV = dot(normal, v);
    return dotNV / (dotNV * (1.0 - k) + k);
}

fn geometric_decay(light_dir: vec3<f32>, camera_dir: vec3<f32>, normal: vec3<f32>, alpha: f32) -> f32 {
    let k = alpha / 2.0;
    return schlick_approxy(light_dir, normal, k) * schlick_approxy(camera_dir, normal, k);
}

fn fresnel(f0: vec3<f32>, middle: vec3<f32>, camera_dir: vec3<f32>) -> vec3<f32> {
    var c: f32 = 1.0 - dot(middle, camera_dir);
    c = c * c * c * c * c;
    return f0 + (1.0 - f0) * c;
}

fn specular_brdf(material: Material, camera_dir: vec3<f32>, light_dir: vec3<f32>, normal: vec3<f32>) -> vec3<f32> {
    let specular_color = material.albedo.xyz * material.reflectance;
    let middle = normalize(camera_dir + light_dir);
    let alpha = material.roughness * material.roughness;
    let distribution = microfacet_distribution(middle, normal, alpha);
    let decay = geometric_decay(light_dir, camera_dir, normal, alpha);
    let fresnel_color = fresnel(specular_color, middle, camera_dir);
    let dotCN = clamp(dot(camera_dir, normal), 0.0, 1.0);
    let dotLN = clamp(dot(light_dir, normal), 0.0, 1.0);
    let denom = 4.0 * dotCN * dotLN;
    if (denom < 1.0e-6) {
        return vec3<f32>(0.0, 0.0, 0.0);
    }
    return distribution * decay / denom * fresnel_color;
}

fn microfacet_color(position: vec3<f32>, normal: vec3<f32>, light: Light, camera_dir: vec3<f32>, material: Material) -> vec3<f32> {
    let light_dir = light_direction(light, position);
    let irr = irradiance(light, position, normal);
    let diffuse = diffuse_brdf(material);
    let specular = specular_brdf(material, camera_dir, light_dir, normal);
    return (diffuse + specular) * irr;
}

fn ambient_correction(pre_color: vec3<f32>, material: Material) -> vec3<f32> {
    return pre_color * (1.0 - material.ambient_ratio)
        + material.albedo.xyz * material.ambient_ratio;
}

fn background_correction(pre_color: vec3<f32>, bk_color: vec3<f32>, material: Material) -> vec3<f32> {
    return pre_color * (1.0 - material.background_ratio)
        + bk_color * material.background_ratio;
}