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::prepass_bindings

#import bevy_pbr::mesh_view_bindings::view
#import bevy_render::view::View
#import bevy_render::{
    globals::Globals,
}

#import bevy_eidolon::render::bindings::instance_uniforms
#import bevy_eidolon::render::utils
#import bevy_pbr::view_transformations::position_world_to_clip
#import bevy_eidolon::render::io_types::Vertex

#import bevy_pbr::utils::rand_f

#import bevy_feronia::wind::Wind
#import bevy_feronia::instancing::bindings::material_uniforms
#import bevy_feronia::types::{SampledNoise, DisplacedVertex, InstanceInfo}
#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;

struct PrepassVertexOutput {
    @builtin(position) clip_position: vec4<f32>,
    @location(0) world_position: vec4<f32>,
    @location(1) previous_world_position: vec4<f32>,

#ifdef NORMAL_PREPASS
    @location(2) world_normal: vec3<f32>,
    #ifdef VERTEX_TANGENTS
    @location(3) world_tangent: vec4<f32>,
    #endif
#endif

#ifdef VISIBILITY_RANGE_DITHER
    @location(4) @interpolate(flat) visibility_range_dither: i32,
#endif
};


@vertex
fn vertex(vertex: Vertex) -> PrepassVertexOutput {
    var out: PrepassVertexOutput;
    var scale = vertex.i_pos_scale.w;
    var translation = vertex.i_pos_scale.xyz;
    var world_from_local_matrix: mat4x4<f32>;

    let batch = instance_uniforms[vertex.i_batch_id];

#ifdef BILLBOARDING
    world_from_local_matrix = mat4x4<f32>(
        vec4<f32>(scale, 0.0, 0.0, 0.0),
        vec4<f32>(0.0, scale, 0.0, 0.0),
        vec4<f32>(0.0, 0.0, scale, 0.0),
        vec4<f32>(translation, 1.0)
    );
   var final_matrix = instance_uniforms.world_from_local * world_from_local_matrix;
#else
   let final_matrix = utils::calc_instance_world_matrix(
        vertex.i_pos_scale,
        vertex.i_rotation,
        batch.world_from_local
    );
#endif

#ifdef STATIC_BEND
    let static_bend = material_uniforms.static_bend_direction
                    * material_uniforms.static_bend_strength;
#endif

    // Current Frame
    {
        let wind = material_uniforms.current;

        var instance: InstanceInfo;
        instance.world_from_local = final_matrix;
        instance.instance_position = final_matrix[3];
        instance.wrapped_time = globals.time;
        instance.instance_index = vertex.i_index;
        instance.edge_correction_factor = material_uniforms.edge_correction_factor;
        instance.seed = vertex.i_seed;

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

#ifdef NORMAL_PREPASS
        let displaced = displace_vertex_and_calc_normal(
            wind,
            noise,
            vertex.position,
            instance,
    #ifdef STATIC_BEND
            static_bend,
            material_uniforms.static_bend_control_point,
            material_uniforms.static_bend_min_max,
    #endif
    #ifdef VERTEX_NORMALS
            vertex.normal,
    #endif
    #ifdef VERTEX_TANGENTS
            vertex.tangent,
    #endif
    #ifdef VERTEX_UVS_A
            vertex.uv
    #endif
        );

        out.world_position = displaced.world_position;
        out.clip_position = position_world_to_clip(out.world_position.xyz);
#else
        let world_pos = displace_vertex_position(
            wind, noise, vertex.position, instance,
            #ifdef STATIC_BEND
            static_bend,
            material_uniforms.static_bend_control_point,
            material_uniforms.static_bend_min_max,
            #endif
        );
        out.world_position = vec4<f32>(world_pos, 1.0);
#endif

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

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

    #ifdef VISIBILITY_RANGE_DITHER
        out.visibility_range_dither = utils::get_visibility_range_dither_level(
            batch.visibility_range,
            final_matrix[3]
        );
    #endif
    }

#ifdef MOTION_VECTOR_PREPASS
    // Previous Frame
    {
        let wind = material_uniforms.previous;
        let prev_final_matrix = utils::calc_instance_world_matrix(
            vertex.i_pos_scale,
            vertex.i_rotation,
            batch.previous_world_from_local
        );

        var instance_prev: InstanceInfo;
        instance_prev.world_from_local = prev_final_matrix;
        instance_prev.instance_position = prev_final_matrix[3];
        instance_prev.wrapped_time = globals.time - globals.delta_time;
        instance_prev.instance_index = vertex.i_index;
        instance_prev.edge_correction_factor = material_uniforms.edge_correction_factor;
        instance_prev.seed = vertex.i_seed;

        let noise_prev = sample_noise(instance_prev, wind, vertex.position);
        let world_pos_prev = displace_vertex_position(
            wind, noise_prev, vertex.position, instance_prev,
            #ifdef STATIC_BEND
            static_bend,
            material_uniforms.static_bend_control_point,
            material_uniforms.static_bend_min_max,
            #endif
        );

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

    return out;
}

#ifdef PREPASS_FRAGMENT

#import bevy_pbr::prepass_io::FragmentOutput

@fragment
fn fragment(in: PrepassVertexOutput) -> FragmentOutput {
    var out: FragmentOutput;
        
#ifdef VISIBILITY_RANGE_DITHER
    bevy_pbr::pbr_functions::visibility_range_dither(
        in.clip_position,
        in.visibility_range_dither
    );
#endif

#ifdef NORMAL_PREPASS
    out.normal = vec4(in.world_normal * 0.5 + vec3(0.5), 1.0);
#endif

#ifdef UNCLIPPED_DEPTH_ORTHO_EMULATION
    out.frag_depth = in.unclipped_depth;
#endif // UNCLIPPED_DEPTH_ORTHO_EMULATION

#ifdef MOTION_VECTOR_PREPASS
    let clip_position_t = view.unjittered_clip_from_world * in.world_position;
    let clip_position = clip_position_t.xy / clip_position_t.w;
    let previous_clip_position_t = prepass_bindings::previous_view_uniforms.clip_from_world * in.previous_world_position;
    let previous_clip_position = previous_clip_position_t.xy / previous_clip_position_t.w;

    out.motion_vector = (clip_position - previous_clip_position) * vec2(0.5, -0.5);
#endif // MOTION_VECTOR_PREPASS

    return out;
}
#endif // PREPASS_FRAGMENT