bevy_procedural_grass/
lib.rs1use 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}