bevy_feronia 0.8.2

Foliage/grass scattering tools and wind simulation shaders/materials that prioritize visual fidelity/artistic freedom, a declarative api and modularity.
Documentation
#import bevy_pbr::mesh_view_bindings::view
#import bevy_pbr::mesh_functions::{
    get_world_from_local,
    get_visibility_range_dither_level,
    get_model_matrix,
    mesh_tangent_local_to_world,
    get_previous_world_from_local,
    mesh_normal_local_to_world
}
#import bevy_pbr::view_transformations::position_world_to_clip
#import bevy_pbr::pbr_fragment::pbr_input_from_standard_material
#import bevy_pbr::pbr_fragment::pbr_material_from_standard_material
#import bevy_pbr::pbr_functions::alpha_discard
#import bevy_pbr::pbr_functions::apply_pbr_lighting
#import bevy_pbr::pbr_functions::main_pass_post_lighting_processing
#import bevy_pbr::prepass_io::Vertex
#import bevy_pbr::prepass_io::VertexOutput
#import bevy_render::{
    globals::Globals,
}
#import bevy_pbr::mesh_bindings::mesh

#import bevy_feronia::wind::Wind
#import bevy_feronia::types::{SampledNoise, DisplacedVertex, InstanceInfo}

#ifdef BINDLESS
#import bevy_feronia::extension::bindings::material_uniforms_array
#else
#import bevy_feronia::extension::bindings::material_uniforms
#endif

#ifdef BINDLESS
#import bevy_feronia::wind::bindings::wind_affected_material_indices
#else
#import bevy_feronia::bindings::{noise_texture, noise_texture_sampler}
#endif

#import bevy_feronia::displace::{displace_vertex_and_calc_normal, displace_vertex_position}
#import bevy_feronia::noise::sample_noise

@group(0) @binding(1) var<uniform> globals: Globals;

@vertex
fn vertex(vertex: Vertex) -> VertexOutput {
    var out: VertexOutput;

#ifdef BINDLESS
    let slot = mesh[vertex.instance_index].material_and_lightmap_bind_group_slot & 0xffffu;
    let material_uniforms = material_uniforms_array[wind_affected_material_indices[slot].material];
#endif


    // Current Frame
    {
        let wind = material_uniforms.current;
        let world_from_local = get_world_from_local(vertex.instance_index);

        // Instance
        var instance: InstanceInfo;
        let camera_world_pos = view.world_position.xyz;
        instance.world_from_local = world_from_local;
        instance.instance_position = instance.world_from_local[3];
        instance.wrapped_time = globals.time;
        instance.instance_index = vertex.instance_index;

        let noise = sample_noise(instance, wind, vertex.position);

        var static_shadows = false;

        #ifdef STATIC_SHADOW
        #ifndef MOTION_VECTOR_PREPASS
        static_shadows = true;
        #endif
        #endif

        // Displacement
       var displaced: DisplacedVertex;
        if static_shadows {
            displaced.world_position = (instance.world_from_local * vec4<f32>(vertex.position, 1.0));

            #ifdef VERTEX_NORMALS
                displaced.world_normal = mesh_normal_local_to_world(vertex.normal, instance.instance_index);
            #else
                displaced.world_normal = vec3<f32>(0.0, 0.0, 1.0);
            #endif

            #ifdef VERTEX_TANGENTS
                displaced.world_tangent = mesh_tangent_local_to_world(instance.world_from_local, vertex.tangent, instance.instance_index);
            #else
                const local_fallback_tangent: vec4<f32> = vec4<f32>(1.0, 0.0, 0.0, 1.0);
                let world_tangent_xyz = (instance.world_from_local * vec4<f32>(local_fallback_tangent.xyz, 0.0)).xyz;

                displaced.world_tangent = vec4<f32>(normalize(world_tangent_xyz), local_fallback_tangent.w);
            #endif
        } else {
            displaced = displace_vertex_and_calc_normal(
                wind,
                noise,
                vertex.position,
                instance,
                #ifdef VERTEX_NORMALS
                vertex.normal,
                #endif
                #ifdef VERTEX_TANGENTS
                vertex.tangent,
                #endif
                #ifdef VERTEX_UVS_A
                vertex.uv
                #endif
            );
        }

#ifdef VERTEX_POSITIONS
        out.position = position_world_to_clip(displaced.world_position.xyz);
        out.world_position = displaced.world_position;
#endif

#ifdef VERTEX_NORMALS
        out.world_normal = displaced.world_normal;
#endif

#ifdef VERTEX_UVS_A
        out.uv = vertex.uv;
#endif
#ifdef VERTEX_UVS_B
        out.uv_b = vertex.uv_b;
#endif

#ifdef VERTEX_TANGENTS
        out.world_tangent = displaced.world_tangent;
#endif

#ifdef VERTEX_OUTPUT_INSTANCE_INDEX
        out.instance_index = vertex.instance_index;
#endif

#ifdef VISIBILITY_RANGE_DITHER
        out.visibility_range_dither = get_visibility_range_dither_level(
            vertex.instance_index, world_from_local[3]);
#endif

#ifdef UNCLIPPED_DEPTH_ORTHO_EMULATION
        out.unclipped_depth = view.projection[2][2] * out.world_position.z + view.projection[3][2];
#endif
}

#ifdef MOTION_VECTOR_PREPASS
    // Previous Frame
    {
        let wind = material_uniforms.previous;

        var instance_prev: InstanceInfo;
        instance_prev.world_from_local = get_previous_world_from_local(vertex.instance_index);
        instance_prev.instance_position = instance_prev.world_from_local[3];
        instance_prev.wrapped_time = globals.time - globals.delta_time;
        instance_prev.instance_index = vertex.instance_index;

        let noise_prev = sample_noise(instance_prev, wind, vertex.position);

        /// Displacement
        let world_pos_prev = displace_vertex_position(
            wind,
            noise_prev,
            vertex.position,
            instance_prev,
        );

        out.previous_world_position = vec4<f32>(world_pos_prev, 1.0);
    }
#endif // MOTION_VECTOR_PREPASS

    return out;
}