bevy_procedural_grass/
lib.rs

1use bevy::{prelude::*, render::{render_asset::RenderAssetPlugin, extract_component::ExtractComponentPlugin, RenderApp, render_resource::SpecializedMeshPipelines, Render, render_phase::AddRenderCommand, RenderSet, extract_resource::ExtractResourcePlugin}, core_pipeline::core_3d::Opaque3d, asset::load_internal_asset};
2
3use grass::{chunk::GrassChunks, grass::{Grass, GrassLODMesh}, wind::GrassWind, config::GrassConfig};
4use render::{instance::GrassInstanceData, pipeline::GrassPipeline, draw::DrawGrass};
5
6pub mod grass;
7mod render;
8
9pub mod prelude {
10    pub use crate::ProceduralGrassPlugin;
11    pub use crate::grass::{
12        grass::{GrassBundle, Grass, GrassLODMesh}, 
13        mesh::GrassMesh, 
14        wind::{GrassWind, Wind}
15    };
16}
17
18pub(crate) const GRASS_SHADER_HANDLE: Handle<Shader> =
19    Handle::weak_from_u128(195_094_223_228_228_028_086_047_086_167_255_040_126);
20
21#[derive(Default, Clone)]
22pub struct ProceduralGrassPlugin {
23    pub config: GrassConfig,
24    pub wind: GrassWind,
25}
26
27impl Plugin for ProceduralGrassPlugin {
28    fn build(&self, app: &mut App) {
29        load_internal_asset!(
30            app,
31            GRASS_SHADER_HANDLE,
32            "assets/shaders/grass.wgsl",
33            Shader::from_wgsl
34        );
35
36        #[cfg(feature = "bevy-inspector-egui")]
37        {
38            app
39                .register_type::<Grass>()
40                .register_type::<GrassWind>()
41                .register_type::<GrassConfig>();
42        }
43        app
44            .insert_resource(self.wind.clone())
45            .insert_resource(self.config)
46            .add_systems(Startup, grass::wind::create_wind_map)
47            .add_systems(PostStartup, grass::grass::generate_grass)
48            .add_systems(Update, grass::chunk::grass_culling)
49            .init_asset::<GrassInstanceData>()
50            .add_plugins(RenderAssetPlugin::<GrassInstanceData>::default())
51            .add_plugins((
52                ExtractComponentPlugin::<Grass>::default(),
53                ExtractComponentPlugin::<GrassChunks>::default(),
54                ExtractComponentPlugin::<GrassLODMesh>::default(),
55                ExtractComponentPlugin::<GrassWind>::default(),
56                ExtractResourcePlugin::<GrassWind>::default(),
57            ));
58
59        let render_app = app.sub_app_mut(RenderApp);
60        render_app.add_render_command::<Opaque3d, DrawGrass>()
61        .init_resource::<SpecializedMeshPipelines<GrassPipeline>>()
62        .add_systems(
63            Render,
64            (
65                render::queue::grass_queue.in_set(RenderSet::QueueMeshes),
66                render::prepare::prepare_grass_buffers.in_set(RenderSet::PrepareResources),
67                render::prepare::prepare_global_wind_buffers.in_set(RenderSet::PrepareResources),
68                render::prepare::prepare_local_wind_buffers.in_set(RenderSet::PrepareResources),
69                render::prepare::prepare_grass_bind_group.in_set(RenderSet::PrepareBindGroups),
70                render::prepare::prepare_global_wind_bind_group.in_set(RenderSet::PrepareBindGroups),
71                render::prepare::prepare_local_wind_bind_group.in_set(RenderSet::PrepareBindGroups),
72            ),
73        );
74    }
75
76    fn finish(&self, app: &mut App) {
77        app.sub_app_mut(RenderApp)
78            .init_resource::<GrassPipeline>();
79    }
80}