1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
//! # bevy_feronia
//! [](https://github.com/NicoZweifel/bevy_feronia?tab=readme-ov-file#licensecreditsinspirationsreferences)
//! [](https://crates.io/crates/bevy_feronia)
//! [](https://crates.io/crates/bevy_feronia)
//! [](https://docs.rs/bevy_feronia/)
//! [](https://github.com/NicoZweifel/bevy_feronia/actions)
//!
//! Environment scattering tools and shaders/materials that prioritize visual
//! fidelity/artistic freedom, a declarative API, and modularity.
//!
//! ## Who is this for?
//!
//! In the current stage, this is mostly for tinkerers and learners within the
//! [bevy](https://github.com/bevyengine/bevy) ecosystem, but the plan is to use this
//! for actual game dev eventually.
//!
//! **Warning: Early Development**
//! > This package is in early development and in an experimentation stage.
//! > I wouldn't personally use this in production quite yet, but it's getting closer
//! > to that state incrementally.
//!
//! 
//!
//! ## Getting started
//!
//! The possible use-cases are demonstrated in the `examples` directory.
//!
//! ### Setup
//!
//! The setup depends on the use-case, but a typical setup would look like this:
//!
//! ```rust,no_run
//! # use bevy::prelude::*;
//! # // Mocking plugins for documentation purposes
//! # struct MeshMaterialAssetBackendPlugin; impl Plugin for MeshMaterialAssetBackendPlugin { fn build(&self, app: &mut App) {} }
//! # struct SceneAssetBackendPlugin; impl Plugin for SceneAssetBackendPlugin { fn build(&self, app: &mut App) {} }
//! # struct ExtendedWindAffectedScatterPlugin; impl Plugin for ExtendedWindAffectedScatterPlugin { fn build(&self, app: &mut App) {} }
//! # let mut app = App::new();
//! app.add_plugins((
//! MeshMaterialAssetBackendPlugin,
//! // Or
//! SceneAssetBackendPlugin,
//! // ...
//! ExtendedWindAffectedScatterPlugin
//! ));
//! ```
//!
//! The Scatter system needs to know when it can set up since it can depend on height mapping.
//! You need to insert the setup state at some point.
//!
//! **Note:** In complex setups that load assets and bake a height map, this can be
//! done after `Startup`.
//!
//! ```rust,ignore
//! app.insert_state(ScatterState::Setup)
//! ```
//!
//! Or:
//!
//! ```rust,ignore
//! ns_height_map.set(HeightMapState::Setup);
//! ns_scatter.set(ScatterState::Setup);
//! ```
//!
//! For chunking or GPU driven culling to work, `Center` and `CullComputeCamera` need to be inserted on the Camera:
//! ```rust
//! cmd.spawn((
//! (Camera::default(), Camera3d::default()),
//! (Center, CullComputeCamera),
//! // etc...
//! ```
//!
//! ### Defining layers
//!
//! A `ScatterItem`'s `LOD`s are grouped by `Name`. If the names end in `LOD_1` or `lod1` etc.,
//! the LOD suffix will be stripped from the name to match it to the other LODs of the asset.
//!
//! **Caution:** When defining multiple `ScatterItems` per `ScatterLayer` without names,
//! a different asset will render when `LODs` are changing, leading to visual bugs.
//!
//! ```rust,ignore
//! // Landscape
//! cmd.spawn((
//! MeshMaterial3d(materials.add(StandardMaterial {
//! base_color: GRAY_500.into(),
//! ..default()
//! })),
//! Mesh3d(meshes.add(PlaneMeshBuilder::from_length(80.).build())),
//! ScatterRoot::default(),
//! // Scatter layers
//! children![(
//! // Make sure you use the correct `ScatterLayer` with the desired `ScatterLayerType`, e.g.,
//! // Standard, Extended or Instanced Material/Layer.
//! extension::scatter_layer("Wind Affected Layer"),
//! // Scatter Options
//! DistributionDensity(50.),
//! InstanceJitter::default(),
//! // You can define material options on the full layer here
//! WindAffected,
//! children![
//! (
//! // Or overwrite on the item, e.g.,
//! // WindAffected,
//! //
//! // CAUTION: If you have multiple assets, all lods that belong to each other need to have the same name!
//! //
//! // You can have multiple assets in each layer; as long as all LODs have the same name, they will be matched correctly.
//! Name::new("Wind Affected Example Item"),
//! MeshMaterial3d(materials.add(StandardMaterial::default())),
//! Mesh3d(mesh.clone()),
//! ),
//! (
//! Name::new("Wind Affected Example Item"),
//! // We need to specify the LOD Level if it is not 0 (Highest level)
//! LevelOfDetail(1),
//! MeshMaterial3d(materials.add(StandardMaterial {
//! base_color: RED_500.into(),
//! ..default()
//! })),
//! Mesh3d(mesh.clone()),
//! ),
//! ]
//! )]
//! ));
//! ```
//!
//! ### Scattering
//!
//! Now you can start scattering! π± π πΏ π π³ π² π΄ πΊ
//!
//! ```rust,ignore
//! cmd.trigger(Scatter::<ExtendedWindAffectedMaterial>::new(*root));
//! ```
//!
//! **Note:** `ScatterLayers` and their `ScatterItems` of the same `ScatterType` are always
//! scattered in order, but layers of different `ScatterTypes` can be scattered at the same time.
//!
//! #### Ordered Scattering
//!
//! In complex scenes it is often required to scatter a complete hierarchy in order
//! (rocks β trees/foliage β grass).
//!
//! **Tip:** If an ordered scatter is still required, and you can't or don't want to scatter
//! in parallel, observers need to be used to chain the scattering of `ScatterTypes` in order.
//!
//! ```rust,ignore
//! fn scatter_on_keypress(
//! mut cmd: Commands,
//! keyboard_input: Res<ButtonInput<KeyCode>>,
//! root: Single<Entity, With<ScatterRoot>>
//! ) {
//! if !keyboard_input.just_pressed(KeyCode::Space) {
//! return;
//! };
//!
//! // Scatter the rocks.
//! cmd.trigger(Scatter::<StandardMaterial>::new(*root));
//! }
//!
//! fn scatter_extended(
//! _: On<ScatterFinished<StandardMaterial>>,
//! mut cmd: Commands,
//! root: Single<Entity, With<ScatterRoot>>,
//! ) {
//! // Scatter the foliage after the rocks.
//! cmd.trigger(Scatter::<ExtendedWindAffectedMaterial>::new(*root));
//! }
//!
//! fn scatter_instanced(
//! _: On<ScatterFinished<ExtendedWindAffectedMaterial>>,
//! mut cmd: Commands,
//! root: Single<Entity, With<ScatterRoot>>,
//! ) {
//! // Scatter the grass last so it doesn't grow on occupied areas.
//! cmd.trigger(Scatter::<InstancedWindAffectedMaterial>::new(*root));
//! }
//! ```
//!
//! ## Compatibility
//!
//! There are very experimental releases before 0.5.0, but I wouldn't use them.
//!
//! | bevy | bevy_feronia |
//! |------|--------------|
//! | 0.18 | 0.8+ |
//! | 0.17 | 0.7 |
//!
//! ## License/Credits/Inspirations/References
//!
//! The code is dual-licensed:
//!
//! - MIT License ([LICENSE-MIT](LICENSE-MIT) or [http://opensource.org/licenses/MIT](http://opensource.org/licenses/MIT))
//! - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0))
//!
//! Feel free to copy the grass assets. All the other assets used in the examples are licensed assets.
//!
//! **Important:** If you intend to use them, make sure you comply with the license.
//!
//! - [Graswald](https://gscatter.com/gallery) for their amazing assets and [`GScatter`](https://gscatter.com/gscatter), which served as inspiration for the scatter tools.
//! - Sucker Punch Productions for their Procedural Grass and Wind simulation in 'Ghost of Tsushima' and [GDC Talks](https://www.youtube.com/watch?v=Ibe1JBF5i5Y).
//! - [bevy_procedural_grass](https://github.com/jadedbay/bevy_procedural_grass) by jadedbay
//! - [warbler_grass](https://github.com/EmiOnGit/warbler_grass) by EmiOnGit
//! - [GDC 2011 "Approximating Translucency"](https://www.gdcvault.com/play/1014538/Approximating-Translucency-for-a-Fast)
//! - [BlinnβPhong reflection model](https://en.wikipedia.org/wiki/Blinn%E2%80%93Phong_reflection_model)
//! - [All the other assets](https://github.com/villor/bevy_feronia/blob/main/assets/LICENSE)
//!
//! ## Alternatives
//!
//! - If you want a lower level scattering API, just for scattering and sampling there is also [`bevy_map_scatter`](https://github.com/morgenthum/map_scatter),
//! which I might use eventually as well but for now I want this crate to achieve a vision.
//!
//! ## Roadmap
//!
//! A bunch of issues are already open, but some of the larger milestones could be:
//!
//! - Allow physics-based and other entities to impact the displacement/wind.
//! - Make use of compute shaders (Allow scattering on CPU and GPU, improve culling).
//! - Allow for multiple `ScatterRoots` when baking height maps.