mirror of
https://github.com/bevyengine/bevy
synced 2025-01-14 14:14:06 +00:00
11 commits
Author | SHA1 | Message | Date | |
---|---|---|---|---|
Gino Valente
|
aeeb20ec4c
|
bevy_reflect: FromReflect Ergonomics Implementation (#6056)
# Objective **This implementation is based on https://github.com/bevyengine/rfcs/pull/59.** --- Resolves #4597 Full details and motivation can be found in the RFC, but here's a brief summary. `FromReflect` is a very powerful and important trait within the reflection API. It allows Dynamic types (e.g., `DynamicList`, etc.) to be formed into Real ones (e.g., `Vec<i32>`, etc.). This mainly comes into play concerning deserialization, where the reflection deserializers both return a `Box<dyn Reflect>` that almost always contain one of these Dynamic representations of a Real type. To convert this to our Real type, we need to use `FromReflect`. It also sneaks up in other ways. For example, it's a required bound for `T` in `Vec<T>` so that `Vec<T>` as a whole can be made `FromReflect`. It's also required by all fields of an enum as it's used as part of the `Reflect::apply` implementation. So in other words, much like `GetTypeRegistration` and `Typed`, it is very much a core reflection trait. The problem is that it is not currently treated like a core trait and is not automatically derived alongside `Reflect`. This makes using it a bit cumbersome and easy to forget. ## Solution Automatically derive `FromReflect` when deriving `Reflect`. Users can then choose to opt-out if needed using the `#[reflect(from_reflect = false)]` attribute. ```rust #[derive(Reflect)] struct Foo; #[derive(Reflect)] #[reflect(from_reflect = false)] struct Bar; fn test<T: FromReflect>(value: T) {} test(Foo); // <-- OK test(Bar); // <-- Panic! Bar does not implement trait `FromReflect` ``` #### `ReflectFromReflect` This PR also automatically adds the `ReflectFromReflect` (introduced in #6245) registration to the derived `GetTypeRegistration` impl— if the type hasn't opted out of `FromReflect` of course. <details> <summary><h4>Improved Deserialization</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. And since we can do all the above, we might as well improve deserialization. We can now choose to deserialize into a Dynamic type or automatically convert it using `FromReflect` under the hood. `[Un]TypedReflectDeserializer::new` will now perform the conversion and return the `Box`'d Real type. `[Un]TypedReflectDeserializer::new_dynamic` will work like what we have now and simply return the `Box`'d Dynamic type. ```rust // Returns the Real type let reflect_deserializer = UntypedReflectDeserializer::new(®istry); let mut deserializer = ron:🇩🇪:Deserializer::from_str(input)?; let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // Returns the Dynamic type let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry); let mut deserializer = ron:🇩🇪:Deserializer::from_str(input)?; let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` </details> --- ## Changelog * `FromReflect` is now automatically derived within the `Reflect` derive macro * This includes auto-registering `ReflectFromReflect` in the derived `GetTypeRegistration` impl * ~~Renamed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic`, respectively~~ **Descoped** * ~~Changed `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` to automatically convert the deserialized output using `FromReflect`~~ **Descoped** ## Migration Guide * `FromReflect` is now automatically derived within the `Reflect` derive macro. Items with both derives will need to remove the `FromReflect` one. ```rust // OLD #[derive(Reflect, FromReflect)] struct Foo; // NEW #[derive(Reflect)] struct Foo; ``` If using a manual implementation of `FromReflect` and the `Reflect` derive, users will need to opt-out of the automatic implementation. ```rust // OLD #[derive(Reflect)] struct Foo; impl FromReflect for Foo {/* ... */} // NEW #[derive(Reflect)] #[reflect(from_reflect = false)] struct Foo; impl FromReflect for Foo {/* ... */} ``` <details> <summary><h4>Removed Migrations</h4></summary> > **Warning** > This section includes changes that have since been descoped from this PR. They will likely be implemented again in a followup PR. I am mainly leaving these details in for archival purposes, as well as for reference when implementing this logic again. * The reflect deserializers now perform a `FromReflect` conversion internally. The expected output of `TypedReflectDeserializer::new` and `UntypedReflectDeserializer::new` is no longer a Dynamic (e.g., `DynamicList`), but its Real counterpart (e.g., `Vec<i32>`). ```rust let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry); let mut deserializer = ron:🇩🇪:Deserializer::from_str(input)?; // OLD let output: DynamicStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; // NEW let output: SomeStruct = reflect_deserializer.deserialize(&mut deserializer)?.take()?; ``` Alternatively, if this behavior isn't desired, use the `TypedReflectDeserializer::new_dynamic` and `UntypedReflectDeserializer::new_dynamic` methods instead: ```rust // OLD let reflect_deserializer = UntypedReflectDeserializer::new(®istry); // NEW let reflect_deserializer = UntypedReflectDeserializer::new_dynamic(®istry); ``` </details> --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com> |
||
Raffaele Ragni
|
7fc6db32ce
|
Add FromReflect where Reflect is used (#8776)
# Objective Discovered that PointLight did not implement FromReflect. Adding FromReflect where Reflect is used. I overreached and applied this rule everywhere there was a Reflect without a FromReflect, except from where the compiler wouldn't allow me. Based from question: https://github.com/bevyengine/bevy/discussions/8774 ## Solution - Adding FromReflect where Reflect was already derived ## Notes First PR I do in this ecosystem, so not sure if this is the usual approach, that is, to touch many files at once. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
Daniel Chia
|
c3a46822e1 |
Cascaded shadow maps. (#7064)
Co-authored-by: Robert Swain <robert.swain@gmail.com> # Objective Implements cascaded shadow maps for directional lights, which produces better quality shadows without needing excessively large shadow maps. Fixes #3629 Before ![image](https://user-images.githubusercontent.com/1222141/210061203-bbd965a4-8d11-4cec-9a88-67fc59d0819f.png) After ![image](https://user-images.githubusercontent.com/1222141/210061334-2ff15334-e6d7-4a31-9314-f34a7805cac6.png) ## Solution Rather than rendering a single shadow map for directional light, the view frustum is divided into a series of cascades, each of which gets its own shadow map. The correct cascade is then sampled for shadow determination. --- ## Changelog Directional lights now use cascaded shadow maps for improved shadow quality. ## Migration Guide You no longer have to manually specify a `shadow_projection` for a directional light, and these settings should be removed. If customization of how cascaded shadow maps work is desired, modify the `CascadeShadowConfig` component instead. |
||
Carter Anderson
|
40d4992401 |
Visibilty Inheritance, universal ComputedVisibility and RenderLayers support (#5310)
# Objective Fixes #4907. Fixes #838. Fixes #5089. Supersedes #5146. Supersedes #2087. Supersedes #865. Supersedes #5114 Visibility is currently entirely local. Set a parent entity to be invisible, and the children are still visible. This makes it hard for users to hide entire hierarchies of entities. Additionally, the semantics of `Visibility` vs `ComputedVisibility` are inconsistent across entity types. 3D meshes use `ComputedVisibility` as the "definitive" visibility component, with `Visibility` being just one data source. Sprites just use `Visibility`, which means they can't feed off of `ComputedVisibility` data, such as culling information, RenderLayers, and (added in this pr) visibility inheritance information. ## Solution Splits `ComputedVisibilty::is_visible` into `ComputedVisibilty::is_visible_in_view` and `ComputedVisibilty::is_visible_in_hierarchy`. For each visible entity, `is_visible_in_hierarchy` is computed by propagating visibility down the hierarchy. The `ComputedVisibility::is_visible()` function combines these two booleans for the canonical "is this entity visible" function. Additionally, all entities that have `Visibility` now also have `ComputedVisibility`. Sprites, Lights, and UI entities now use `ComputedVisibility` when appropriate. This means that in addition to visibility inheritance, everything using Visibility now also supports RenderLayers. Notably, Sprites (and other 2d objects) now support `RenderLayers` and work properly across multiple views. Also note that this does increase the amount of work done per sprite. Bevymark with 100,000 sprites on `main` runs in `0.017612` seconds and this runs in `0.01902`. That is certainly a gap, but I believe the api consistency and extra functionality this buys us is worth it. See [this thread](https://github.com/bevyengine/bevy/pull/5146#issuecomment-1182783452) for more info. Note that #5146 in combination with #5114 _are_ a viable alternative to this PR and _would_ perform better, but that comes at the cost of api inconsistencies and doing visibility calculations in the "wrong" place. The current visibility system does have potential for performance improvements. I would prefer to evolve that one system as a whole rather than doing custom hacks / different behaviors for each feature slice. Here is a "split screen" example where the left camera uses RenderLayers to filter out the blue sprite. ![image](https://user-images.githubusercontent.com/2694663/178814868-2e9a2173-bf8c-4c79-8815-633899d492c3.png) Note that this builds directly on #5146 and that @james7132 deserves the credit for the baseline visibility inheritance work. This pr moves the inherited visibility field into `ComputedVisibility`, then does the additional work of porting everything to `ComputedVisibility`. See my [comments here](https://github.com/bevyengine/bevy/pull/5146#issuecomment-1182783452) for rationale. ## Follow up work * Now that lights use ComputedVisibility, VisibleEntities now includes "visible lights" in the entity list. Functionally not a problem as we use queries to filter the list down in the desired context. But we should consider splitting this out into a separate`VisibleLights` collection for both clarity and performance reasons. And _maybe_ even consider scoping `VisibleEntities` down to `VisibleMeshes`?. * Investigate alternative sprite rendering impls (in combination with visibility system tweaks) that avoid re-generating a per-view fixedbitset of visible entities every frame, then checking each ExtractedEntity. This is where most of the performance overhead lives. Ex: we could generate ExtractedEntities per-view using the VisibleEntities list, avoiding the need for the bitset. * Should ComputedVisibility use bitflags under the hood? This would cut down on the size of the component, potentially speed up the `is_visible()` function, and allow us to cheaply expand ComputedVisibility with more data (ex: split out local visibility and parent visibility, add more culling classes, etc). --- ## Changelog * ComputedVisibility now takes hierarchy visibility into account. * 2D, UI and Light entities now use the ComputedVisibility component. ## Migration Guide If you were previously reading `Visibility::is_visible` as the "actual visibility" for sprites or lights, use `ComputedVisibilty::is_visible()` instead: ```rust // before (0.7) fn system(query: Query<&Visibility>) { for visibility in query.iter() { if visibility.is_visible { log!("found visible entity"); } } } // after (0.8) fn system(query: Query<&ComputedVisibility>) { for visibility in query.iter() { if visibility.is_visible() { log!("found visible entity"); } } } ``` Co-authored-by: Carter Anderson <mcanders1@gmail.com> |
||
robtfm
|
132950cd55 |
Spotlights (#4715)
# Objective add spotlight support ## Solution / Changelog - add spotlight angles (inner, outer) to ``PointLight`` struct. emitted light is linearly attenuated from 100% to 0% as angle tends from inner to outer. Direction is taken from the existing transform rotation. - add spotlight direction (vec3) and angles (f32,f32) to ``GpuPointLight`` struct (60 bytes -> 80 bytes) in ``pbr/render/lights.rs`` and ``mesh_view_bind_group.wgsl`` - reduce no-buffer-support max point light count to 204 due to above - use spotlight data to attenuate light in ``pbr.wgsl`` - do additional cluster culling on spotlights to minimise cost in ``assign_lights_to_clusters`` - changed one of the lights in the lighting demo to a spotlight - also added a ``spotlight`` demo - probably not justified but so reviewers can see it more easily ## notes increasing the size of the GpuPointLight struct on my machine reduces the FPS of ``many_lights -- sphere`` from ~150fps to 140fps. i thought this was a reasonable tradeoff, and felt better than handling spotlights separately which is possible but would mean introducing a new bind group, refactoring light-assignment code and adding new spotlight-specific code in pbr.wgsl. the FPS impact for smaller numbers of lights should be very small. the cluster culling strategy reintroduces the cluster aabb code which was recently removed... sorry. the aabb is used to get a cluster bounding sphere, which can then be tested fairly efficiently using the strategy described at the end of https://bartwronski.com/2017/04/13/cull-that-cone/. this works well with roughly cubic clusters (where the cluster z size is close to the same as x/y size), less well for other cases like single Z slice / tiled forward rendering. In the worst case we will end up just keeping the culling of the equivalent point light. Co-authored-by: François <mockersf@gmail.com> |
||
Carter Anderson
|
747b0c69b0 |
Better Materials: AsBindGroup trait and derive, simpler Material trait (#5053)
# Objective This PR reworks Bevy's Material system, making the user experience of defining Materials _much_ nicer. Bevy's previous material system leaves a lot to be desired: * Materials require manually implementing the `RenderAsset` trait, which involves manually generating the bind group, handling gpu buffer data transfer, looking up image textures, etc. Even the simplest single-texture material involves writing ~80 unnecessary lines of code. This was never the long term plan. * There are two material traits, which is confusing, hard to document, and often redundant: `Material` and `SpecializedMaterial`. `Material` implicitly implements `SpecializedMaterial`, and `SpecializedMaterial` is used in most high level apis to support both use cases. Most users shouldn't need to think about specialization at all (I consider it a "power-user tool"), so the fact that `SpecializedMaterial` is front-and-center in our apis is a miss. * Implementing either material trait involves a lot of "type soup". The "prepared asset" parameter is particularly heinous: `&<Self as RenderAsset>::PreparedAsset`. Defining vertex and fragment shaders is also more verbose than it needs to be. ## Solution Say hello to the new `Material` system: ```rust #[derive(AsBindGroup, TypeUuid, Debug, Clone)] #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"] pub struct CoolMaterial { #[uniform(0)] color: Color, #[texture(1)] #[sampler(2)] color_texture: Handle<Image>, } impl Material for CoolMaterial { fn fragment_shader() -> ShaderRef { "cool_material.wgsl".into() } } ``` Thats it! This same material would have required [~80 lines of complicated "type heavy" code](https://github.com/bevyengine/bevy/blob/v0.7.0/examples/shader/shader_material.rs) in the old Material system. Now it is just 14 lines of simple, readable code. This is thanks to a new consolidated `Material` trait and the new `AsBindGroup` trait / derive. ### The new `Material` trait The old "split" `Material` and `SpecializedMaterial` traits have been removed in favor of a new consolidated `Material` trait. All of the functions on the trait are optional. The difficulty of implementing `Material` has been reduced by simplifying dataflow and removing type complexity: ```rust // Old impl Material for CustomMaterial { fn fragment_shader(asset_server: &AssetServer) -> Option<Handle<Shader>> { Some(asset_server.load("custom_material.wgsl")) } fn alpha_mode(render_asset: &<Self as RenderAsset>::PreparedAsset) -> AlphaMode { render_asset.alpha_mode } } // New impl Material for CustomMaterial { fn fragment_shader() -> ShaderRef { "custom_material.wgsl".into() } fn alpha_mode(&self) -> AlphaMode { self.alpha_mode } } ``` Specialization is still supported, but it is hidden by default under the `specialize()` function (more on this later). ### The `AsBindGroup` trait / derive The `Material` trait now requires the `AsBindGroup` derive. This can be implemented manually relatively easily, but deriving it will almost always be preferable. Field attributes like `uniform` and `texture` are used to define which fields should be bindings, what their binding type is, and what index they should be bound at: ```rust #[derive(AsBindGroup)] struct CoolMaterial { #[uniform(0)] color: Color, #[texture(1)] #[sampler(2)] color_texture: Handle<Image>, } ``` In WGSL shaders, the binding looks like this: ```wgsl struct CoolMaterial { color: vec4<f32>; }; [[group(1), binding(0)]] var<uniform> material: CoolMaterial; [[group(1), binding(1)]] var color_texture: texture_2d<f32>; [[group(1), binding(2)]] var color_sampler: sampler; ``` Note that the "group" index is determined by the usage context. It is not defined in `AsBindGroup`. Bevy material bind groups are bound to group 1. The following field-level attributes are supported: * `uniform(BINDING_INDEX)` * The field will be converted to a shader-compatible type using the `ShaderType` trait, written to a `Buffer`, and bound as a uniform. It can also be derived for custom structs. * `texture(BINDING_INDEX)` * This field's `Handle<Image>` will be used to look up the matching `Texture` gpu resource, which will be bound as a texture in shaders. The field will be assumed to implement `Into<Option<Handle<Image>>>`. In practice, most fields should be a `Handle<Image>` or `Option<Handle<Image>>`. If the value of an `Option<Handle<Image>>` is `None`, the new `FallbackImage` resource will be used instead. This attribute can be used in conjunction with a `sampler` binding attribute (with a different binding index). * `sampler(BINDING_INDEX)` * Behaves exactly like the `texture` attribute, but sets the Image's sampler binding instead of the texture. Note that fields without field-level binding attributes will be ignored. ```rust #[derive(AsBindGroup)] struct CoolMaterial { #[uniform(0)] color: Color, this_field_is_ignored: String, } ``` As mentioned above, `Option<Handle<Image>>` is also supported: ```rust #[derive(AsBindGroup)] struct CoolMaterial { #[uniform(0)] color: Color, #[texture(1)] #[sampler(2)] color_texture: Option<Handle<Image>>, } ``` This is useful if you want a texture to be optional. When the value is `None`, the `FallbackImage` will be used for the binding instead, which defaults to "pure white". Field uniforms with the same binding index will be combined into a single binding: ```rust #[derive(AsBindGroup)] struct CoolMaterial { #[uniform(0)] color: Color, #[uniform(0)] roughness: f32, } ``` In WGSL shaders, the binding would look like this: ```wgsl struct CoolMaterial { color: vec4<f32>; roughness: f32; }; [[group(1), binding(0)]] var<uniform> material: CoolMaterial; ``` Some less common scenarios will require "struct-level" attributes. These are the currently supported struct-level attributes: * `uniform(BINDING_INDEX, ConvertedShaderType)` * Similar to the field-level `uniform` attribute, but instead the entire `AsBindGroup` value is converted to `ConvertedShaderType`, which must implement `ShaderType`. This is useful if more complicated conversion logic is required. * `bind_group_data(DataType)` * The `AsBindGroup` type will be converted to some `DataType` using `Into<DataType>` and stored as `AsBindGroup::Data` as part of the `AsBindGroup::as_bind_group` call. This is useful if data needs to be stored alongside the generated bind group, such as a unique identifier for a material's bind group. The most common use case for this attribute is "shader pipeline specialization". The previous `CoolMaterial` example illustrating "combining multiple field-level uniform attributes with the same binding index" can also be equivalently represented with a single struct-level uniform attribute: ```rust #[derive(AsBindGroup)] #[uniform(0, CoolMaterialUniform)] struct CoolMaterial { color: Color, roughness: f32, } #[derive(ShaderType)] struct CoolMaterialUniform { color: Color, roughness: f32, } impl From<&CoolMaterial> for CoolMaterialUniform { fn from(material: &CoolMaterial) -> CoolMaterialUniform { CoolMaterialUniform { color: material.color, roughness: material.roughness, } } } ``` ### Material Specialization Material shader specialization is now _much_ simpler: ```rust #[derive(AsBindGroup, TypeUuid, Debug, Clone)] #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"] #[bind_group_data(CoolMaterialKey)] struct CoolMaterial { #[uniform(0)] color: Color, is_red: bool, } #[derive(Copy, Clone, Hash, Eq, PartialEq)] struct CoolMaterialKey { is_red: bool, } impl From<&CoolMaterial> for CoolMaterialKey { fn from(material: &CoolMaterial) -> CoolMaterialKey { CoolMaterialKey { is_red: material.is_red, } } } impl Material for CoolMaterial { fn fragment_shader() -> ShaderRef { "cool_material.wgsl".into() } fn specialize( pipeline: &MaterialPipeline<Self>, descriptor: &mut RenderPipelineDescriptor, layout: &MeshVertexBufferLayout, key: MaterialPipelineKey<Self>, ) -> Result<(), SpecializedMeshPipelineError> { if key.bind_group_data.is_red { let fragment = descriptor.fragment.as_mut().unwrap(); fragment.shader_defs.push("IS_RED".to_string()); } Ok(()) } } ``` Setting `bind_group_data` is not required for specialization (it defaults to `()`). Scenarios like "custom vertex attributes" also benefit from this system: ```rust impl Material for CustomMaterial { fn vertex_shader() -> ShaderRef { "custom_material.wgsl".into() } fn fragment_shader() -> ShaderRef { "custom_material.wgsl".into() } fn specialize( pipeline: &MaterialPipeline<Self>, descriptor: &mut RenderPipelineDescriptor, layout: &MeshVertexBufferLayout, key: MaterialPipelineKey<Self>, ) -> Result<(), SpecializedMeshPipelineError> { let vertex_layout = layout.get_layout(&[ Mesh::ATTRIBUTE_POSITION.at_shader_location(0), ATTRIBUTE_BLEND_COLOR.at_shader_location(1), ])?; descriptor.vertex.buffers = vec![vertex_layout]; Ok(()) } } ``` ### Ported `StandardMaterial` to the new `Material` system Bevy's built-in PBR material uses the new Material system (including the AsBindGroup derive): ```rust #[derive(AsBindGroup, Debug, Clone, TypeUuid)] #[uuid = "7494888b-c082-457b-aacf-517228cc0c22"] #[bind_group_data(StandardMaterialKey)] #[uniform(0, StandardMaterialUniform)] pub struct StandardMaterial { pub base_color: Color, #[texture(1)] #[sampler(2)] pub base_color_texture: Option<Handle<Image>>, /* other fields omitted for brevity */ ``` ### Ported Bevy examples to the new `Material` system The overall complexity of Bevy's "custom shader examples" has gone down significantly. Take a look at the diffs if you want a dopamine spike. Please note that while this PR has a net increase in "lines of code", most of those extra lines come from added documentation. There is a significant reduction in the overall complexity of the code (even accounting for the new derive logic). --- ## Changelog ### Added * `AsBindGroup` trait and derive, which make it much easier to transfer data to the gpu and generate bind groups for a given type. ### Changed * The old `Material` and `SpecializedMaterial` traits have been replaced by a consolidated (much simpler) `Material` trait. Materials no longer implement `RenderAsset`. * `StandardMaterial` was ported to the new material system. There are no user-facing api changes to the `StandardMaterial` struct api, but it now implements `AsBindGroup` and `Material` instead of `RenderAsset` and `SpecializedMaterial`. ## Migration Guide The Material system has been reworked to be much simpler. We've removed a lot of boilerplate with the new `AsBindGroup` derive and the `Material` trait is simpler as well! ### Bevy 0.7 (old) ```rust #[derive(Debug, Clone, TypeUuid)] #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"] pub struct CustomMaterial { color: Color, color_texture: Handle<Image>, } #[derive(Clone)] pub struct GpuCustomMaterial { _buffer: Buffer, bind_group: BindGroup, } impl RenderAsset for CustomMaterial { type ExtractedAsset = CustomMaterial; type PreparedAsset = GpuCustomMaterial; type Param = (SRes<RenderDevice>, SRes<MaterialPipeline<Self>>); fn extract_asset(&self) -> Self::ExtractedAsset { self.clone() } fn prepare_asset( extracted_asset: Self::ExtractedAsset, (render_device, material_pipeline): &mut SystemParamItem<Self::Param>, ) -> Result<Self::PreparedAsset, PrepareAssetError<Self::ExtractedAsset>> { let color = Vec4::from_slice(&extracted_asset.color.as_linear_rgba_f32()); let byte_buffer = [0u8; Vec4::SIZE.get() as usize]; let mut buffer = encase::UniformBuffer::new(byte_buffer); buffer.write(&color).unwrap(); let buffer = render_device.create_buffer_with_data(&BufferInitDescriptor { contents: buffer.as_ref(), label: None, usage: BufferUsages::UNIFORM | BufferUsages::COPY_DST, }); let (texture_view, texture_sampler) = if let Some(result) = material_pipeline .mesh_pipeline .get_image_texture(gpu_images, &Some(extracted_asset.color_texture.clone())) { result } else { return Err(PrepareAssetError::RetryNextUpdate(extracted_asset)); }; let bind_group = render_device.create_bind_group(&BindGroupDescriptor { entries: &[ BindGroupEntry { binding: 0, resource: buffer.as_entire_binding(), }, BindGroupEntry { binding: 0, resource: BindingResource::TextureView(texture_view), }, BindGroupEntry { binding: 1, resource: BindingResource::Sampler(texture_sampler), }, ], label: None, layout: &material_pipeline.material_layout, }); Ok(GpuCustomMaterial { _buffer: buffer, bind_group, }) } } impl Material for CustomMaterial { fn fragment_shader(asset_server: &AssetServer) -> Option<Handle<Shader>> { Some(asset_server.load("custom_material.wgsl")) } fn bind_group(render_asset: &<Self as RenderAsset>::PreparedAsset) -> &BindGroup { &render_asset.bind_group } fn bind_group_layout(render_device: &RenderDevice) -> BindGroupLayout { render_device.create_bind_group_layout(&BindGroupLayoutDescriptor { entries: &[ BindGroupLayoutEntry { binding: 0, visibility: ShaderStages::FRAGMENT, ty: BindingType::Buffer { ty: BufferBindingType::Uniform, has_dynamic_offset: false, min_binding_size: Some(Vec4::min_size()), }, count: None, }, BindGroupLayoutEntry { binding: 1, visibility: ShaderStages::FRAGMENT, ty: BindingType::Texture { multisampled: false, sample_type: TextureSampleType::Float { filterable: true }, view_dimension: TextureViewDimension::D2Array, }, count: None, }, BindGroupLayoutEntry { binding: 2, visibility: ShaderStages::FRAGMENT, ty: BindingType::Sampler(SamplerBindingType::Filtering), count: None, }, ], label: None, }) } } ``` ### Bevy 0.8 (new) ```rust impl Material for CustomMaterial { fn fragment_shader() -> ShaderRef { "custom_material.wgsl".into() } } #[derive(AsBindGroup, TypeUuid, Debug, Clone)] #[uuid = "f690fdae-d598-45ab-8225-97e2a3f056e0"] pub struct CustomMaterial { #[uniform(0)] color: Color, #[texture(1)] #[sampler(2)] color_texture: Handle<Image>, } ``` ## Future Work * Add support for more binding types (cubemaps, buffers, etc). This PR intentionally includes a bare minimum number of binding types to keep "reviewability" in check. * Consider optionally eliding binding indices using binding names. `AsBindGroup` could pass in (optional?) reflection info as a "hint". * This would make it possible for the derive to do this: ```rust #[derive(AsBindGroup)] pub struct CustomMaterial { #[uniform] color: Color, #[texture] #[sampler] color_texture: Option<Handle<Image>>, alpha_mode: AlphaMode, } ``` * Or this ```rust #[derive(AsBindGroup)] pub struct CustomMaterial { #[binding] color: Color, #[binding] color_texture: Option<Handle<Image>>, alpha_mode: AlphaMode, } ``` * Or even this (if we flip to "include bindings by default") ```rust #[derive(AsBindGroup)] pub struct CustomMaterial { color: Color, color_texture: Option<Handle<Image>>, #[binding(ignore)] alpha_mode: AlphaMode, } ``` * If we add the option to define custom draw functions for materials (which could be done in a type-erased way), I think that would be enough to support extra non-material bindings. Worth considering! |
||
robtfm
|
575ea81d7b |
add Visibility for lights (#3958)
# Objective Add Visibility for lights ## Solution - add Visibility to PointLightBundle and DirectionLightBundle - filter lights used by Visibility.is_visible note: includes changes from #3916 due to overlap, will be cleaner after that is merged |
||
Robert Swain
|
85b7589388 |
bevy_gltf: Add support for loading lights (#3506)
# Objective - Add support for loading lights from glTF 2.0 files ## Solution - This adds support for the KHR_punctual_lights extension which supports point, directional, and spot lights, though we don't yet support spot lights. - Inserting light bundles when creating scenes required registering some more light bundle component types. |
||
Carter Anderson
|
963e2f08a2 |
Materials and MaterialPlugin (#3428)
This adds "high level" `Material` and `SpecializedMaterial` traits, which can be used with a `MaterialPlugin<T: SpecializedMaterial>`. `MaterialPlugin` automatically registers the appropriate resources, draw functions, and queue systems. The `Material` trait is simpler, and should cover most use cases. `SpecializedMaterial` is like `Material`, but it also requires defining a "specialization key" (see #3031). `Material` has a trivial blanket impl of `SpecializedMaterial`, which allows us to use the same types + functions for both. This makes defining custom 3d materials much simpler (see the `shader_material` example diff) and ensures consistent behavior across all 3d materials (both built in and custom). I ported the built in `StandardMaterial` to `MaterialPlugin`. There is also a new `MaterialMeshBundle<T: SpecializedMaterial>`, which `PbrBundle` aliases to. |
||
François
|
c825fda74a |
add default standard material in PbrBundle (#3325)
# Objective - Fix #3323 ## Solution - Add a default standard material that is very visible. It is similar to the previous standard material that was used <img width="1392" alt="Screenshot 2021-12-14 at 15 39 01" src="https://user-images.githubusercontent.com/8672791/146019401-ed4b5fc1-7cce-4a8f-a511-a6f9665a51d7.png"> Co-authored-by: François <8672791+mockersf@users.noreply.github.com> |
||
Carter Anderson
|
ffecb05a0a |
Replace old renderer with new renderer (#3312)
This makes the [New Bevy Renderer](#2535) the default (and only) renderer. The new renderer isn't _quite_ ready for the final release yet, but I want as many people as possible to start testing it so we can identify bugs and address feedback prior to release. The examples are all ported over and operational with a few exceptions: * I removed a good portion of the examples in the `shader` folder. We still have some work to do in order to make these examples possible / ergonomic / worthwhile: #3120 and "high level shader material plugins" are the big ones. This is a temporary measure. * Temporarily removed the multiple_windows example: doing this properly in the new renderer will require the upcoming "render targets" changes. Same goes for the render_to_texture example. * Removed z_sort_debug: entity visibility sort info is no longer available in app logic. we could do this on the "render app" side, but i dont consider it a priority. |
Renamed from pipelined/bevy_pbr2/src/bundle.rs (Browse further)