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
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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
use crate::prelude::LightIntensity;

use bevy_color::Color;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::prelude::*;
use bevy_math::Vec2;
use bevy_reflect::Reflect;

/// Marker component to use Standard PBR shading instead of the simplified Blinn-Phong model.
///
/// Enables `#ifdef USE_STANDARD_PBR` in shaders.
///
/// Use [`Roughness`] and [`Metallic`] to control material properties.
/// [`SpecularPower`], [`SpecularStrength`], [`DiffuseScaling`] etc. might be ignored or behave differently.
///
/// TODO: might wanna make this default
#[derive(Component, Clone, Debug, Reflect, Default)]
#[reflect(Component, Clone, Debug)]
#[require(Roughness, Metallic, Reflectance)]
pub struct StandardPbr;

/// Controls the perceptual roughness of the material.
///
/// Only used if [`StandardPbr`] is enabled.
///
/// * `0.0`: Smooth (shiny).
/// * `1.0`: Rough (matte).
///
/// Defaults to `0.5`.
///
/// TODO: move to core/components and use in standard plugin.
#[derive(Component, Clone, Debug, Reflect, Deref, DerefMut)]
#[reflect(Component, Clone, Debug)]
pub struct Roughness(pub f32);

impl Default for Roughness {
    fn default() -> Self {
        Self(0.5)
    }
}

/// Controls the metallic factor of the material.
///
/// Only used if [`StandardPbr`] is enabled.
///
/// * `0.0`: Plastic, wood
/// * `1.0`: Metal.
///
///
/// Defaults to `0`.
///
/// TODO: move to core/components and use in standard plugin.
#[derive(Component, Clone, Default, Debug, Reflect, Deref, DerefMut)]
#[reflect(Component, Clone, Debug)]
pub struct Metallic(pub f32);

/// Controls the reflectance of the material.
///
/// Only used if [`StandardPbr`] is enabled.
///
/// Defaults to `0.1`.
///
/// TODO: move to core/components and use in standard plugin.
#[derive(Component, Clone, Debug, Reflect, Deref, DerefMut)]
#[reflect(Component, Clone, Debug)]
pub struct Reflectance(pub f32);

impl Default for Reflectance {
    fn default() -> Self {
        Self(0.1)
    }
}

/// Controls the exponent in the Blinn-Phong specular highlight model.
///
/// Determines the "shininess" of the surface.
/// * **Higher values** (e.g., 32.0, 64.0) result in smaller, tighter, sharper highlights (wet/glossy look).
/// * **Lower values** (e.g., 4.0, 8.0) result in broader, duller highlights (rough surface).
///
/// Maps to `material_uniforms.specular_power` in the shader.
///
/// Defaults to `32.0`.
///
/// **Note:** Ignored if [`StandardPbr`] is enabled.
///
/// Only supported with [`InstancedWindAffectedMaterial`].
#[derive(Component, Clone, Debug, Reflect, Deref, DerefMut)]
#[reflect(Component, Clone, Debug)]
pub struct SpecularPower(pub f32);

impl Default for SpecularPower {
    fn default() -> Self {
        Self(32.0)
    }
}

/// Enabled a fake Ambient Occlusion effect.
///
/// Enables `#ifdef AMBIENT_OCCLUSION` in shaders.
///
/// Only supported with [`InstancedWindAffectedMaterial`].
#[derive(Component, Clone, Debug, Reflect, Default)]
#[reflect(Component, Clone, Debug)]
pub struct AmbientOcclusion;

/// Controls the intensity of the specular highlight.
///
/// Acts as a multiplier for the specular light contribution.
/// * `0.0`: No specular highlights (purely diffuse).
/// * `1.0`: Full brightness specular highlights.
///
/// Maps to `specular_strength` in the shader.
///
/// Defaults to `0.1`.
///
/// **Note:** Ignored if [`StandardPbr`] is enabled.
///
/// Only supported with [`InstancedWindAffectedMaterial`].
#[derive(Component, Clone, Debug, Reflect, Deref, DerefMut)]
#[reflect(Component, Clone, Debug)]
pub struct SpecularStrength(pub f32);

impl Default for SpecularStrength {
    fn default() -> Self {
        Self(0.1)
    }
}

/// Controls the diffuse scaling.
///
/// Maps to `diffuse_scaling` in the shader.
///
/// Defaults to `1.0`.
///
/// **Note:** Ignored if [`StandardPbr`] is enabled.
///
/// Only supported with [`InstancedWindAffectedMaterial`].
#[derive(Component, Clone, Debug, Reflect, Deref, DerefMut)]
#[reflect(Component, Clone, Debug)]
pub struct DiffuseScaling(pub f32);

impl Default for DiffuseScaling {
    fn default() -> Self {
        Self(1.0)
    }
}

/// Controls the ambient light intensity scale.
///
/// Defaults to `0.00001`.
///
/// **Note:** Ignored if [`StandardPbr`] is enabled.
///
/// Only supported with [`InstancedWindAffectedMaterial`].
///
/// **NOTE:** this might be removed in the future.
#[derive(Component, Clone, Debug, Reflect, Deref, DerefMut)]
#[reflect(Component, Clone, Debug)]
pub struct AmbientLightIntensity(pub f32);

impl Default for AmbientLightIntensity {
    fn default() -> Self {
        Self(0.0001)
    }
}

/// Controls the amount of light that is simulated passing through the object.
///
/// Used to simulate thin geometry like grass blades or leaves being lit from behind.
/// It scales the lighting contribution when the light direction is opposite the surface normal.
///
/// * `0.0`: Opaque (no light passes through).
/// * Higher values increase the brightness of backlit surfaces.
///
/// Corresponds to `material_uniforms.translucency` in the shader.
/// Defaults to `0.6`.
///
/// Only supported with [`InstancedWindAffectedMaterial`].
#[derive(Component, Clone, Debug, Reflect, Deref, DerefMut)]
#[reflect(Component, Clone, Debug)]
pub struct Translucency(pub f32);

impl Default for Translucency {
    fn default() -> Self {
        Self(0.6)
    }
}

/// Marker component to enable directional lights.
///
/// Enables `#ifdef DIRECTIONAL_LIGHTS` in shaders.
///
/// **Note:** Ignored if [`StandardPbr`] is enabled.
///
/// Only supported with [`InstancedWindAffectedMaterial`].
#[derive(Component, Clone, Debug, Reflect, Default)]
#[reflect(Component, Clone, Debug)]
#[require(
    Translucency,
    SpecularPower,
    SpecularStrength,
    DiffuseScaling,
    LightIntensity(0.0001),
    AmbientLightIntensity(0.0001)
)]
pub struct DirectionalLights;

/// Marker component to enable point lights.
///
/// Enables `#ifdef POINT_LIGHTS` in shaders.
///
/// **Note:** Ignored if [`StandardPbr`] is enabled.
///
/// Only supported with [`InstancedWindAffectedMaterial`].
#[derive(Component, Clone, Debug, Reflect, Default)]
#[reflect(Component, Clone, Debug)]
#[require(
    Translucency,
    SpecularPower,
    SpecularStrength,
    DiffuseScaling,
    LightIntensity(0.0001),
    AmbientLightIntensity(0.0001)
)]
pub struct PointLights;

/// Adds a normal curving effect (simulates curved blades).
///
/// See [`CurveFactor`].
#[derive(Component, Clone, Copy, Debug, Reflect, Default)]
#[reflect(Component, Clone, Debug)]
#[require(CurveFactor)]
pub struct CurveNormals;

// Controls the normal curving effect.
///
/// This is a multiplier that determines how strongly the blade curves from its
/// center (0.0) to its edges (1.0), using the **`uv.x`** coordinate of the mesh.
/// The final curve angle is hard-capped at **1.4 radians (~80°)**.
///
/// ### UV Requirements
/// **Important:** This feature relies on specific UV mapping:
///
/// **Horizontal (`uv.x`):** Must range from **0.0 to 1.0**.
///     * `0.0`: Left edge
///     * `0.5`: Center spine
///     * `1.0`: Right edge
///
/// If `uv.x` isn't mapped to this range, the curve math (`x * 2.0 - 1.0`) will produce
/// incorrect normal offsets and visual artifacts.
///
/// ### Behavior
///
/// The behavior changes significantly depending on the value:
///
/// - **`CurveFactor < 1.4`**: Creates a gentle, shallow curve. The blade will
///   never reach the 80° maximum, resulting in a softer look.
///
/// - **`CurveFactor = 1.4`**: Creates a full, linear curve. The blade
///   bends smoothly from 0° at the center to the 80° maximum exactly at the edge.
///
/// - **`CurveFactor > 1.4`**: The blade hits the 80° cap *before* reaching the edge.
///   This creates a sharp "crease" or "spine" down the center, with the rest
///   of the blade remaining flat at the maximum angle.
///
/// ### Notes
///
/// Corresponds to `material_uniforms.curve_factor` in shaders.
///
/// Defaults to `0.2`.
///
/// Enables `#ifdef CURVE_NORMALS` in shaders if larger than 0.
///
/// Currently only supported with [`InstancedWindAffectedMaterial`].
#[derive(Component, Deref, DerefMut, Clone, Copy, Debug, Reflect)]
#[reflect(Component, Clone, Debug)]
pub struct CurveFactor(pub f32);

impl Default for CurveFactor {
    fn default() -> Self {
        Self(0.2)
    }
}

/// Enables Bézier curve bending.
///
/// See [`StaticBendStrength`], [`StaticBendMinMax`], [`StaticBendDirection`] and [`StaticBendControlPoint`].
#[derive(Component, Clone, Copy, Debug, Reflect, Default)]
#[reflect(Component, Clone, Debug)]
#[require(StaticBendStrength)]
pub struct StaticBend;

/// Controls a persistent, non-wind bend.
///
/// A higher value will apply a stronger Bézier curve and will affect the instances more uniformly,
/// while a lower value will affect them more randomly and apply less curve.
///
/// Corresponds to `material_uniforms.static_bend_strength` in shaders.
///
/// Defaults to `0.5`.
///
/// Enables `#ifdef STATIC_BEND` in shaders if larger than 0.
///
/// Currently only supported with [`InstancedWindAffectedMaterial`].
#[derive(Component, Deref, DerefMut, Clone, Copy, Debug, Reflect)]
#[reflect(Component, Clone, Debug)]
#[require(StaticBendDirection, StaticBendControlPoint, StaticBendMinMax)]
pub struct StaticBendStrength(pub f32);

impl Default for StaticBendStrength {
    fn default() -> Self {
        Self(0.5)
    }
}

/// Controls the minimum and maximum values for the static bend.
///
/// Corresponds to `material_uniforms.static_bend_min_max` in shaders.
///
/// Defaults to:
///  - `min`:`0.3`
///  - `max`:`0.9`
///
/// Currently only supported with [`InstancedWindAffectedMaterial`].
#[derive(Component, Clone, Copy, Debug, Reflect)]
#[reflect(Component, Clone, Debug)]
pub struct StaticBendMinMax {
    min: f32,
    max: f32,
}

impl StaticBendMinMax {
    pub fn new(min: f32, max: f32) -> Self {
        Self { min, max }
    }
}

impl From<StaticBendMinMax> for Vec2 {
    fn from(val: StaticBendMinMax) -> Self {
        Vec2::new(val.min, val.max)
    }
}

impl From<Vec2> for StaticBendMinMax {
    fn from(vec: Vec2) -> Self {
        Self {
            min: vec.x,
            max: vec.y,
        }
    }
}

impl Default for StaticBendMinMax {
    fn default() -> Self {
        Self { min: 0.2, max: 0.7 }
    }
}

/// Controls the direction of the static bend.
///
/// Corresponds to `material_uniforms.bend_direction` in the shader.
///
/// Defaults to: `(0.309017, -0.951056)`.
#[derive(Component, Deref, DerefMut, Clone, Copy, Debug, Reflect)]
#[reflect(Component, Clone, Debug)]
pub struct StaticBendDirection(pub Vec2);

impl Default for StaticBendDirection {
    fn default() -> Self {
        Self(Vec2::new(0.309017, -0.951056))
    }
}

impl StaticBendDirection {
    pub fn new(x: f32, y: f32) -> Self {
        Self(Vec2::new(x, y))
    }
}

/// Controls the Bézier control points.
///
/// * **Stiffness**: Controls how far out the control point is. Lower values make the curve "tighter" at the base. Defaults to `0.33`.
/// * **Height**: Controls the vertical height of the control point relative to the mesh height. Defaults to `0.55`.
///
/// Corresponds to `material_uniforms.bend_control_point` in the shader.
#[derive(Component, Clone, Copy, Debug, Reflect)]
#[reflect(Component, Clone, Debug)]
pub struct StaticBendControlPoint {
    pub stiffness: f32,
    pub height: f32,
}

impl Default for StaticBendControlPoint {
    fn default() -> Self {
        Self::new(0.33, 0.55)
    }
}

impl StaticBendControlPoint {
    pub fn new(stiffness: f32, height: f32) -> Self {
        Self { stiffness, height }
    }
}

impl From<Vec2> for StaticBendControlPoint {
    fn from(value: Vec2) -> Self {
        Self::new(value.x, value.y)
    }
}

impl From<StaticBendControlPoint> for Vec2 {
    fn from(val: StaticBendControlPoint) -> Self {
        Vec2::new(val.stiffness, val.height)
    }
}

/// Sets a material color gradient.
///
/// ### UV Requirements
///
/// **Important:** This feature relies on specific UV mapping:
///
/// **Vertical (`uv.y`):** Must range from **0.0 to 1.0**.
///    - `0.0`: **Tip / Top** of the mesh.
///    - `1.0`: **Root / Base** of the mesh.
///
/// #### Troubleshooting:
///   - If you have black spots or other artifacts on your mesh, `uv.y` might not be ranging from `0.0` to `1.0`.
///
///   - If your colors appear upside down (Top Color at the bottom), your mesh likely uses
///     UVs where `0.0` is at the bottom. You should flip the UVs vertically (so the root is at `1.0`).
///
/// ### Notes
///
/// Corresponds to the following uniforms in shaders.
///   - `material.bottom_color`
///   - `material.top_color`
///   - `material.tint_factor`
///   - `material.gradient_start`
///   - `material.gradient_end`
///
/// Currently only supported with [`InstancedWindAffectedMaterial`].
#[derive(Component, Clone, Copy, Debug, Reflect, Default)]
#[reflect(Component, Clone, Debug)]
pub struct InstanceColorGradient {
    /// The top color if the gradient.
    pub top: Color,
    /// The bottom color of the gradient.
    pub bottom: Color,
    /// The tint factor of the gradient.
    ///
    /// Controls how much the gradient overrides the base instance color.
    /// - `0.0`: The gradient is invisible.
    /// - `1.0`: The gradient is fully opaque.
    /// - `0.5`: A 50/50 blend.
    ///
    /// Defaults to `0.5`.
    pub tint: f32,
    /// The height (0.0 to 1.0) where the bottom color stops being solid
    /// and the gradient begins transitioning to be top-colored.
    ///
    /// Defaults to `0.2`.
    pub start: f32,
    /// The height (0.0 to 1.0) where the gradient finishes, becoming fully top-colored.
    ///
    /// Defaults to `0.6`.
    pub end: f32,
}

impl InstanceColorGradient {
    pub fn new(top: impl Into<Color>, bottom: impl Into<Color>) -> Self {
        Self {
            top: top.into(),
            bottom: bottom.into(),
            tint: 0.5,
            start: 0.2,
            end: 0.8,
        }
    }
}