scena 1.7.2

A Rust-native scene-graph renderer with typed scene state, glTF assets, and explicit prepare/render lifecycles.
Documentation
struct LtcTableSample {
    inverse_matrix: vec4<f32>,
    fresnel_terms: vec4<f32>,
}

struct LtcSpecularProbe {
    irradiance: f32,
    fresnel_scale: vec3<f32>,
}

struct LtcClippedQuad {
    vertices: array<vec3<f32>, 5>,
    count: u32,
}

fn ltc_safe_normalize(value: vec3<f32>, fallback: vec3<f32>) -> vec3<f32> {
    let len_sq = dot(value, value);
    return select(fallback, value * inverseSqrt(len_sq), len_sq > 0.00000001);
}

fn ltc_lerp_vec4(left: vec4<f32>, right: vec4<f32>, t: f32) -> vec4<f32> {
    return left * (1.0 - t) + right * t;
}

fn ltc_bilinear_sample(
    table_00: vec4<f32>,
    table_10: vec4<f32>,
    table_01: vec4<f32>,
    table_11: vec4<f32>,
    tx: f32,
    ty: f32,
) -> vec4<f32> {
    return ltc_lerp_vec4(
        ltc_lerp_vec4(table_00, table_10, tx),
        ltc_lerp_vec4(table_01, table_11, tx),
        ty,
    );
}

fn ltc_lookup_tables(roughness_input: f32, n_dot_v_input: f32) -> LtcTableSample {
    let roughness = clamp(roughness_input, 0.0, 1.0);
    let view = sqrt(max(1.0 - clamp(n_dot_v_input, 0.0, 1.0), 0.0));
    let x = roughness * LTC_LUT_LAST_F;
    let y = view * LTC_LUT_LAST_F;
    let x0 = u32(floor(x));
    let y0 = u32(floor(y));
    let x1 = min(x0 + 1u, LTC_LUT_LAST_U);
    let y1 = min(y0 + 1u, LTC_LUT_LAST_U);
    let tx = x - f32(x0);
    let ty = y - f32(y0);
    return LtcTableSample(
        ltc_bilinear_sample(
            LTC_TABLE_1[y0 * LTC_LUT_STRIDE_U + x0],
            LTC_TABLE_1[y0 * LTC_LUT_STRIDE_U + x1],
            LTC_TABLE_1[y1 * LTC_LUT_STRIDE_U + x0],
            LTC_TABLE_1[y1 * LTC_LUT_STRIDE_U + x1],
            tx,
            ty,
        ),
        ltc_bilinear_sample(
            LTC_TABLE_2[y0 * LTC_LUT_STRIDE_U + x0],
            LTC_TABLE_2[y0 * LTC_LUT_STRIDE_U + x1],
            LTC_TABLE_2[y1 * LTC_LUT_STRIDE_U + x0],
            LTC_TABLE_2[y1 * LTC_LUT_STRIDE_U + x1],
            tx,
            ty,
        ),
    );
}

fn ltc_apply_inverse_matrix(matrix: vec4<f32>, value: vec3<f32>) -> vec3<f32> {
    return vec3<f32>(
        matrix.x * value.x + matrix.z * value.z,
        value.y,
        matrix.y * value.x + matrix.w * value.z,
    );
}

fn ltc_horizon_intersection(inside: vec3<f32>, outside: vec3<f32>) -> vec3<f32> {
    return -outside.z * inside + inside.z * outside;
}

fn ltc_clip_quad_to_horizon(vertices: array<vec3<f32>, 4>) -> LtcClippedQuad {
    var clipped: array<vec3<f32>, 5>;
    clipped[0] = vertices[0];
    clipped[1] = vertices[1];
    clipped[2] = vertices[2];
    clipped[3] = vertices[3];
    clipped[4] = vec3<f32>(0.0);
    var config = 0u;
    if vertices[0].z > 0.0 { config = config + 1u; }
    if vertices[1].z > 0.0 { config = config + 2u; }
    if vertices[2].z > 0.0 { config = config + 4u; }
    if vertices[3].z > 0.0 { config = config + 8u; }
    var count = 0u;

    if config == 1u {
        count = 3u;
        clipped[1] = ltc_horizon_intersection(clipped[0], clipped[1]);
        clipped[2] = ltc_horizon_intersection(clipped[0], clipped[3]);
    } else if config == 2u {
        count = 3u;
        clipped[0] = ltc_horizon_intersection(clipped[1], clipped[0]);
        clipped[2] = ltc_horizon_intersection(clipped[1], clipped[2]);
    } else if config == 3u {
        count = 4u;
        clipped[2] = ltc_horizon_intersection(clipped[1], clipped[2]);
        clipped[3] = ltc_horizon_intersection(clipped[0], clipped[3]);
    } else if config == 4u {
        count = 3u;
        clipped[0] = ltc_horizon_intersection(clipped[2], clipped[3]);
        clipped[1] = ltc_horizon_intersection(clipped[2], clipped[1]);
    } else if config == 6u {
        count = 4u;
        clipped[0] = ltc_horizon_intersection(clipped[1], clipped[0]);
        clipped[3] = ltc_horizon_intersection(clipped[2], clipped[3]);
    } else if config == 7u {
        count = 5u;
        clipped[4] = ltc_horizon_intersection(clipped[0], clipped[3]);
        clipped[3] = ltc_horizon_intersection(clipped[2], clipped[3]);
    } else if config == 8u {
        count = 3u;
        clipped[0] = ltc_horizon_intersection(clipped[3], clipped[0]);
        clipped[1] = ltc_horizon_intersection(clipped[3], clipped[2]);
        clipped[2] = clipped[3];
    } else if config == 9u {
        count = 4u;
        clipped[1] = ltc_horizon_intersection(clipped[0], clipped[1]);
        clipped[2] = ltc_horizon_intersection(clipped[3], clipped[2]);
    } else if config == 11u {
        count = 5u;
        clipped[4] = clipped[3];
        clipped[3] = ltc_horizon_intersection(clipped[3], clipped[2]);
        clipped[2] = ltc_horizon_intersection(clipped[1], clipped[2]);
    } else if config == 12u {
        count = 4u;
        clipped[1] = ltc_horizon_intersection(clipped[2], clipped[1]);
        clipped[0] = ltc_horizon_intersection(clipped[3], clipped[0]);
    } else if config == 13u {
        count = 5u;
        clipped[4] = clipped[3];
        clipped[3] = clipped[2];
        clipped[2] = ltc_horizon_intersection(clipped[2], clipped[1]);
        clipped[1] = ltc_horizon_intersection(clipped[0], clipped[1]);
    } else if config == 14u {
        count = 5u;
        clipped[4] = ltc_horizon_intersection(clipped[3], clipped[0]);
        clipped[0] = ltc_horizon_intersection(clipped[1], clipped[0]);
    } else if config == 15u {
        count = 4u;
    }

    if count == 3u {
        clipped[3] = clipped[0];
    }
    if count == 4u {
        clipped[4] = clipped[0];
    }
    return LtcClippedQuad(clipped, count);
}

fn ltc_integrate_edge(left: vec3<f32>, right: vec3<f32>) -> f32 {
    let cosine = clamp(dot(left, right), -0.9999, 0.9999);
    let y = abs(cosine);
    let numerator = 0.8543985 + (0.4965155 + 0.0145206 * y) * y;
    let denominator = max(3.417594 + (4.1616724 + y) * y, 0.0001);
    let approximation = numerator / denominator;
    let theta_sin_theta = select(
        0.5 / sqrt(max(1.0 - cosine * cosine, 0.0000001)) - approximation,
        approximation,
        cosine > 0.0,
    );
    return cross(left, right).z * theta_sin_theta;
}

fn ltc_integrate_transformed_quad(vertices: array<vec3<f32>, 4>, two_sided: bool) -> f32 {
    var clipped = ltc_clip_quad_to_horizon(vertices);
    if clipped.count == 0u {
        return 0.0;
    }
    let vertex_count = min(clipped.count + 1u, 5u);
    for (var i = 0u; i < vertex_count; i = i + 1u) {
        clipped.vertices[i] = ltc_safe_normalize(clipped.vertices[i], vec3<f32>(0.0, 0.0, 1.0));
    }
    var sum = ltc_integrate_edge(clipped.vertices[0], clipped.vertices[1]) +
        ltc_integrate_edge(clipped.vertices[1], clipped.vertices[2]) +
        ltc_integrate_edge(clipped.vertices[2], clipped.vertices[3]);
    if clipped.count >= 4u {
        sum += ltc_integrate_edge(clipped.vertices[3], clipped.vertices[4]);
    }
    if clipped.count == 5u {
        sum += ltc_integrate_edge(clipped.vertices[4], clipped.vertices[0]);
    }
    return select(max(sum, 0.0), abs(sum), two_sided);
}

fn ltc_area_light_polygon(index: u32, world_position: vec3<f32>, normal: vec3<f32>) -> array<vec3<f32>, 4> {
    let center = camera.lighting.area_light_position_flux[index].xyz;
    let axis_x_shape = camera.lighting.area_light_axis_x_shape[index];
    let axis_x = axis_x_shape.xyz;
    let axis_y = camera.lighting.area_light_axis_y_range[index].xyz;
    var polygon: array<vec3<f32>, 4>;
    if axis_x_shape.w < 0.5 {
        polygon[0] = center - axis_x - axis_y;
        polygon[1] = center + axis_x - axis_y;
        polygon[2] = center + axis_x + axis_y;
        polygon[3] = center - axis_x + axis_y;
        return polygon;
    }
    if axis_x_shape.w < 1.5 {
        polygon[0] = center - axis_x;
        polygon[1] = center - axis_y;
        polygon[2] = center + axis_x;
        polygon[3] = center + axis_y;
        return polygon;
    }
    let radius = max(max(length(axis_x), length(axis_y)), 0.001);
    let to_surface = ltc_safe_normalize(world_position - center, -normal);
    let tangent = ltc_safe_normalize(cross(normal, to_surface), vec3<f32>(1.0, 0.0, 0.0)) * radius;
    let bitangent = ltc_safe_normalize(cross(to_surface, tangent), vec3<f32>(0.0, 0.0, 1.0)) * radius;
    polygon[0] = center - tangent - bitangent;
    polygon[1] = center + tangent - bitangent;
    polygon[2] = center + tangent + bitangent;
    polygon[3] = center - tangent + bitangent;
    return polygon;
}

fn ltc_evaluate_specular_polygon(
    polygon: array<vec3<f32>, 4>,
    world_position: vec3<f32>,
    normal_input: vec3<f32>,
    view_input: vec3<f32>,
    roughness: f32,
    f0: vec3<f32>,
) -> LtcSpecularProbe {
    let normal = ltc_safe_normalize(normal_input, vec3<f32>(0.0, 1.0, 0.0));
    let view = ltc_safe_normalize(view_input, normal);
    let n_dot_v = clamp(dot(normal, view), 0.0, 1.0);
    if n_dot_v <= 0.000001 {
        return LtcSpecularProbe(0.0, vec3<f32>(0.0));
    }
    let sample = ltc_lookup_tables(roughness, n_dot_v);
    let fallback_axis = select(vec3<f32>(0.0, 1.0, 0.0), vec3<f32>(0.0, 0.0, 1.0), abs(normal.z) < 0.9);
    let fallback_tangent = ltc_safe_normalize(cross(fallback_axis, normal), vec3<f32>(1.0, 0.0, 0.0));
    let tangent = ltc_safe_normalize(view - normal * dot(view, normal), fallback_tangent);
    let bitangent = ltc_safe_normalize(cross(normal, tangent), vec3<f32>(0.0, 0.0, 1.0));
    var transformed: array<vec3<f32>, 4>;
    for (var i = 0u; i < 4u; i = i + 1u) {
        let local = polygon[i] - world_position;
        let basis = vec3<f32>(dot(local, tangent), dot(local, bitangent), dot(local, normal));
        transformed[i] = ltc_apply_inverse_matrix(sample.inverse_matrix, basis);
    }
    let irradiance = ltc_integrate_transformed_quad(transformed, true);
    let fresnel_scale = f0 * sample.fresnel_terms.x +
        (vec3<f32>(1.0) - f0) * sample.fresnel_terms.y;
    return LtcSpecularProbe(irradiance, fresnel_scale);
}

fn ltc_area_light_specular_contribution(
    index: u32,
    base: vec3<f32>,
    metallic: f32,
    roughness: f32,
    normal: vec3<f32>,
    view: vec3<f32>,
    world_position: vec3<f32>,
    shadow_visibility: f32,
) -> vec3<f32> {
    let visibility = clamp(shadow_visibility, 0.0, 1.0);
    if visibility <= 0.000001 {
        return vec3<f32>(0.0);
    }
    let polygon = ltc_area_light_polygon(index, world_position, normal);
    let f0 = vec3<f32>(0.04) * (1.0 - metallic) + base * metallic;
    let probe = ltc_evaluate_specular_polygon(
        polygon,
        world_position,
        normal,
        view,
        roughness,
        f0,
    );
    if probe.irradiance <= 0.000001 {
        return vec3<f32>(0.0);
    }
    let center = camera.lighting.area_light_position_flux[index].xyz;
    let to_light = center - world_position;
    let range = camera.lighting.area_light_axis_y_range[index].w;
    let radiance = camera.lighting.area_light_color[index].rgb *
        camera.lighting.area_light_position_flux[index].w /
        (4.0 * PI) *
        distance_attenuation(to_light, range);
    return probe.fresnel_scale * radiance * probe.irradiance * visibility;
}