Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/assets/shaders/custom_clustered_decal.wgsl
6592 views
// This shader, a part of the `clustered_decals` example, shows how to use the
// decal `tag` field to apply arbitrary decal effects.

#import bevy_pbr::{
    clustered_forward,
    decal::clustered,
    forward_io::{VertexOutput, FragmentOutput},
    mesh_view_bindings,
    pbr_fragment::pbr_input_from_standard_material,
    pbr_functions::{alpha_discard, apply_pbr_lighting, main_pass_post_lighting_processing},
}

@fragment
fn fragment(
    in: VertexOutput,
    @builtin(front_facing) is_front: bool,
) -> FragmentOutput {
    // Generate a `PbrInput` struct from the `StandardMaterial` bindings.
    var pbr_input = pbr_input_from_standard_material(in, is_front);

    // Alpha discard.
    pbr_input.material.base_color = alpha_discard(pbr_input.material, pbr_input.material.base_color);

    // Apply the normal decals.
    pbr_input.material.base_color = clustered::apply_decal_base_color(
        in.world_position.xyz,
        in.position.xy,
        pbr_input.material.base_color
    );

    // Here we tint the color based on the tag of the decal.
    // We could optionally do other things, such as adjust the normal based on a normal map.
    let view_z = clustered::get_view_z(in.world_position.xyz);
    let is_orthographic = clustered::view_is_orthographic();
    let cluster_index =
        clustered_forward::fragment_cluster_index(in.position.xy, view_z, is_orthographic);
    var clusterable_object_index_ranges =
        clustered_forward::unpack_clusterable_object_index_ranges(cluster_index);
    var decal_iterator = clustered::clustered_decal_iterator_new(
        in.world_position.xyz,
        &clusterable_object_index_ranges
    );
    while (clustered::clustered_decal_iterator_next(&decal_iterator)) {
        var decal_base_color = textureSampleLevel(
            mesh_view_bindings::clustered_decal_textures[decal_iterator.texture_index],
            mesh_view_bindings::clustered_decal_sampler,
            decal_iterator.uv,
            0.0
        );

        switch (decal_iterator.tag) {
            case 1u: {
                // Tint with red.
                decal_base_color = vec4(
                    mix(pbr_input.material.base_color.rgb, vec3(1.0, 0.0, 0.0), 0.5),
                    decal_base_color.a,
                );
            }
            case 2u: {
                // Tint with blue.
                decal_base_color = vec4(
                    mix(pbr_input.material.base_color.rgb, vec3(0.0, 0.0, 1.0), 0.5),
                    decal_base_color.a,
                );
            }
            default: {}
        }

        pbr_input.material.base_color = vec4(
            mix(pbr_input.material.base_color.rgb, decal_base_color.rgb, decal_base_color.a),
            pbr_input.material.base_color.a + decal_base_color.a
        );
    }

    // Apply lighting.
    var out: FragmentOutput;
    out.color = apply_pbr_lighting(pbr_input);

    // Apply in-shader post processing (fog, alpha-premultiply, and also
    // tonemapping, debanding if the camera is non-HDR). Note this does not
    // include fullscreen postprocessing effects like bloom.
    out.color = main_pass_post_lighting_processing(pbr_input, out.color);

    return out;
}