bevy/crates/bevy_pbr/src/environment_map/mod.rs
Edgar Geier f18f28874a
Allow tuples and single plugins in add_plugins, deprecate add_plugin (#8097)
# Objective

- Better consistency with `add_systems`.
- Deprecating `add_plugin` in favor of a more powerful `add_plugins`.
- Allow passing `Plugin` to `add_plugins`.
- Allow passing tuples to `add_plugins`.

## Solution

- `App::add_plugins` now takes an `impl Plugins` parameter.
- `App::add_plugin` is deprecated.
- `Plugins` is a new sealed trait that is only implemented for `Plugin`,
`PluginGroup` and tuples over `Plugins`.
- All examples, benchmarks and tests are changed to use `add_plugins`,
using tuples where appropriate.

---

## Changelog

### Changed

- `App::add_plugins` now accepts all types that implement `Plugins`,
which is implemented for:
  - Types that implement `Plugin`.
  - Types that implement `PluginGroup`.
  - Tuples (up to 16 elements) over types that implement `Plugins`.
- Deprecated `App::add_plugin` in favor of `App::add_plugins`.

## Migration Guide

- Replace `app.add_plugin(plugin)` calls with `app.add_plugins(plugin)`.

---------

Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2023-06-21 20:51:03 +00:00

138 lines
5.0 KiB
Rust

use bevy_app::{App, Plugin};
use bevy_asset::{load_internal_asset, Handle, HandleUntyped};
use bevy_core_pipeline::prelude::Camera3d;
use bevy_ecs::{prelude::Component, query::With};
use bevy_reflect::{Reflect, TypeUuid};
use bevy_render::{
extract_component::{ExtractComponent, ExtractComponentPlugin},
render_asset::RenderAssets,
render_resource::{
BindGroupEntry, BindGroupLayoutEntry, BindingResource, BindingType, SamplerBindingType,
Shader, ShaderStages, TextureSampleType, TextureViewDimension,
},
texture::{FallbackImageCubemap, Image},
};
pub const ENVIRONMENT_MAP_SHADER_HANDLE: HandleUntyped =
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 154476556247605696);
pub struct EnvironmentMapPlugin;
impl Plugin for EnvironmentMapPlugin {
fn build(&self, app: &mut App) {
load_internal_asset!(
app,
ENVIRONMENT_MAP_SHADER_HANDLE,
"environment_map.wgsl",
Shader::from_wgsl
);
app.register_type::<EnvironmentMapLight>()
.add_plugins(ExtractComponentPlugin::<EnvironmentMapLight>::default());
}
}
/// Environment map based ambient lighting representing light from distant scenery.
///
/// When added to a 3D camera, this component adds indirect light
/// to every point of the scene (including inside, enclosed areas) based on
/// an environment cubemap texture. This is similar to [`crate::AmbientLight`], but
/// higher quality, and is intended for outdoor scenes.
///
/// The environment map must be prefiltered into a diffuse and specular cubemap based on the
/// [split-sum approximation](https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf).
///
/// To prefilter your environment map, you can use `KhronosGroup`'s [glTF-IBL-Sampler](https://github.com/KhronosGroup/glTF-IBL-Sampler).
/// The diffuse map uses the Lambertian distribution, and the specular map uses the GGX distribution.
///
/// `KhronosGroup` also has several prefiltered environment maps that can be found [here](https://github.com/KhronosGroup/glTF-Sample-Environments).
#[derive(Component, Reflect, Clone)]
pub struct EnvironmentMapLight {
pub diffuse_map: Handle<Image>,
pub specular_map: Handle<Image>,
}
impl EnvironmentMapLight {
/// Whether or not all textures necessary to use the environment map
/// have been loaded by the asset server.
pub fn is_loaded(&self, images: &RenderAssets<Image>) -> bool {
images.get(&self.diffuse_map).is_some() && images.get(&self.specular_map).is_some()
}
}
impl ExtractComponent for EnvironmentMapLight {
type Query = &'static Self;
type Filter = With<Camera3d>;
type Out = Self;
fn extract_component(item: bevy_ecs::query::QueryItem<'_, Self::Query>) -> Option<Self::Out> {
Some(item.clone())
}
}
pub fn get_bindings<'a>(
environment_map_light: Option<&EnvironmentMapLight>,
images: &'a RenderAssets<Image>,
fallback_image_cubemap: &'a FallbackImageCubemap,
bindings: [u32; 3],
) -> [BindGroupEntry<'a>; 3] {
let (diffuse_map, specular_map) = match (
environment_map_light.and_then(|env_map| images.get(&env_map.diffuse_map)),
environment_map_light.and_then(|env_map| images.get(&env_map.specular_map)),
) {
(Some(diffuse_map), Some(specular_map)) => {
(&diffuse_map.texture_view, &specular_map.texture_view)
}
_ => (
&fallback_image_cubemap.texture_view,
&fallback_image_cubemap.texture_view,
),
};
[
BindGroupEntry {
binding: bindings[0],
resource: BindingResource::TextureView(diffuse_map),
},
BindGroupEntry {
binding: bindings[1],
resource: BindingResource::TextureView(specular_map),
},
BindGroupEntry {
binding: bindings[2],
resource: BindingResource::Sampler(&fallback_image_cubemap.sampler),
},
]
}
pub fn get_bind_group_layout_entries(bindings: [u32; 3]) -> [BindGroupLayoutEntry; 3] {
[
BindGroupLayoutEntry {
binding: bindings[0],
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Texture {
sample_type: TextureSampleType::Float { filterable: true },
view_dimension: TextureViewDimension::Cube,
multisampled: false,
},
count: None,
},
BindGroupLayoutEntry {
binding: bindings[1],
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Texture {
sample_type: TextureSampleType::Float { filterable: true },
view_dimension: TextureViewDimension::Cube,
multisampled: false,
},
count: None,
},
BindGroupLayoutEntry {
binding: bindings[2],
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Sampler(SamplerBindingType::Filtering),
count: None,
},
]
}