1use bevy_asset::Asset;
2use bevy_ecs::system::SystemParamItem;
3use bevy_material::{AlphaMode, OpaqueRendererMethod};
4use bevy_mesh::MeshVertexBufferLayoutRef;
5use bevy_reflect::{impl_type_path, Reflect};
6use bevy_render::{
7 combined_bind_group as cbg,
8 render_resource::{
9 AsBindGroup, AsBindGroupError, BindGroupBuilder, BindGroupLayout, BindGroupLayoutEntry,
10 BindlessDescriptor, BindlessSlabResourceLimit, RenderPipelineDescriptor,
11 SpecializedMeshPipelineError,
12 },
13 renderer::RenderDevice,
14};
15use bevy_shader::ShaderRef;
16
17use crate::{Material, MaterialPipeline, MaterialPipelineKey, MeshPipeline, MeshPipelineKey};
18
19pub struct MaterialExtensionPipeline {
20 pub mesh_pipeline: MeshPipeline,
21}
22
23pub struct MaterialExtensionKey<E: MaterialExtension> {
24 pub mesh_key: MeshPipelineKey,
25 pub bind_group_data: E::Data,
26}
27
28pub trait MaterialExtension: Asset + AsBindGroup + Clone + Sized {
32 fn vertex_shader() -> ShaderRef {
35 ShaderRef::Default
36 }
37
38 fn fragment_shader() -> ShaderRef {
41 ShaderRef::Default
42 }
43
44 fn alpha_mode() -> Option<AlphaMode> {
46 None
47 }
48
49 #[inline]
52 fn enable_prepass() -> bool {
53 true
54 }
55
56 #[inline]
58 fn enable_shadows() -> bool {
59 true
60 }
61
62 #[inline]
66 fn enable_oit() -> bool {
67 true
68 }
69
70 fn prepass_vertex_shader() -> ShaderRef {
73 ShaderRef::Default
74 }
75
76 fn prepass_fragment_shader() -> ShaderRef {
79 ShaderRef::Default
80 }
81
82 fn deferred_vertex_shader() -> ShaderRef {
85 ShaderRef::Default
86 }
87
88 fn deferred_fragment_shader() -> ShaderRef {
91 ShaderRef::Default
92 }
93
94 #[cfg(feature = "meshlet")]
97 fn meshlet_mesh_fragment_shader() -> ShaderRef {
98 ShaderRef::Default
99 }
100
101 #[cfg(feature = "meshlet")]
104 fn meshlet_mesh_prepass_fragment_shader() -> ShaderRef {
105 ShaderRef::Default
106 }
107
108 #[cfg(feature = "meshlet")]
111 fn meshlet_mesh_deferred_fragment_shader() -> ShaderRef {
112 ShaderRef::Default
113 }
114
115 #[expect(
119 unused_variables,
120 reason = "The parameters here are intentionally unused by the default implementation; however, putting underscores here will result in the underscores being copied by rust-analyzer's tab completion."
121 )]
122 #[inline]
123 fn specialize(
124 pipeline: &MaterialExtensionPipeline,
125 descriptor: &mut RenderPipelineDescriptor,
126 layout: &MeshVertexBufferLayoutRef,
127 key: MaterialExtensionKey<Self>,
128 ) -> Result<(), SpecializedMeshPipelineError> {
129 Ok(())
130 }
131}
132
133#[derive(impl<B: Material, E: MaterialExtension> bevy_asset::Asset for
ExtendedMaterial<B, E> {}
impl<B: Material, E: MaterialExtension> bevy_asset::VisitAssetDependencies for
ExtendedMaterial<B, E> {
fn visit_dependencies(&self,
visit: &mut impl ::core::ops::FnMut(bevy_asset::UntypedAssetId)) {}
}Asset, #[automatically_derived]
impl<B: ::core::clone::Clone + Material, E: ::core::clone::Clone +
MaterialExtension> ::core::clone::Clone for ExtendedMaterial<B, E> {
#[inline]
fn clone(&self) -> Self {
Self {
base: ::core::clone::Clone::clone(&self.base),
extension: ::core::clone::Clone::clone(&self.extension),
}
}
}Clone, #[automatically_derived]
impl<B: ::core::fmt::Debug + Material, E: ::core::fmt::Debug +
MaterialExtension> ::core::fmt::Debug for ExtendedMaterial<B, E> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
::core::fmt::Formatter::debug_struct_field2_finish(f,
"ExtendedMaterial", "base", &self.base, "extension",
&&self.extension)
}
}Debug, const _: () =
{
impl<B: Material, E: MaterialExtension>
bevy_reflect::GetTypeRegistration for ExtendedMaterial<B, E> where
ExtendedMaterial<B, E>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, B: bevy_reflect::FromReflect +
bevy_reflect::TypePath + bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection,
E: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
fn get_type_registration() -> bevy_reflect::TypeRegistration {
let mut registration =
bevy_reflect::TypeRegistration::of::<Self>();
registration.insert(<bevy_reflect::ReflectFromPtr as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration.insert(<bevy_reflect::ReflectFromReflect as
bevy_reflect::CreateTypeData<Self>>::create_type_data(()));
registration
}
#[inline(never)]
fn register_type_dependencies(registry:
&mut bevy_reflect::TypeRegistry) {
<B as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
<E as
bevy_reflect::__macro_exports::RegisterForReflection>::__register(registry);
}
}
impl<B: Material, E: MaterialExtension> bevy_reflect::Typed for
ExtendedMaterial<B, E> where
ExtendedMaterial<B, E>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, B: bevy_reflect::FromReflect +
bevy_reflect::TypePath + bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection,
E: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
#[inline(never)]
fn type_info() -> &'static bevy_reflect::TypeInfo {
static CELL: bevy_reflect::utility::GenericTypeInfoCell =
bevy_reflect::utility::GenericTypeInfoCell::new();
CELL.get_or_insert::<Self,
_>(#[inline(never)] ||
{
bevy_reflect::TypeInfo::Struct(bevy_reflect::structs::StructInfo::new::<Self>(&[bevy_reflect::NamedField::new::<B>("base"),
bevy_reflect::NamedField::new::<E>("extension")]))
})
}
}
impl<B: Material, E: MaterialExtension> bevy_reflect::Reflect for
ExtendedMaterial<B, E> where
ExtendedMaterial<B, E>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, B: bevy_reflect::FromReflect +
bevy_reflect::TypePath + bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection,
E: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
#[inline]
fn into_any(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn ::core::any::Any> {
self
}
#[inline]
fn as_any(&self) -> &dyn ::core::any::Any { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn ::core::any::Any { self }
#[inline]
fn into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect> {
self
}
#[inline]
fn as_reflect(&self) -> &dyn bevy_reflect::Reflect { self }
#[inline]
fn as_reflect_mut(&mut self) -> &mut dyn bevy_reflect::Reflect {
self
}
#[inline]
fn set(&mut self,
value:
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>)
->
::core::result::Result<(),
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>> {
*self = <dyn bevy_reflect::Reflect>::take(value)?;
::core::result::Result::Ok(())
}
}
impl<B: Material, E: MaterialExtension> bevy_reflect::structs::Struct
for ExtendedMaterial<B, E> where
ExtendedMaterial<B, E>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, B: bevy_reflect::FromReflect +
bevy_reflect::TypePath + bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection,
E: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
fn field(&self, name: &str)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match name {
"base" => ::core::option::Option::Some(&self.base),
"extension" =>
::core::option::Option::Some(&self.extension),
_ => ::core::option::Option::None,
}
}
fn field_mut(&mut self, name: &str)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match name {
"base" => ::core::option::Option::Some(&mut self.base),
"extension" =>
::core::option::Option::Some(&mut self.extension),
_ => ::core::option::Option::None,
}
}
fn field_at(&self, index: usize)
-> ::core::option::Option<&dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&self.base),
1usize => ::core::option::Option::Some(&self.extension),
_ => ::core::option::Option::None,
}
}
fn field_at_mut(&mut self, index: usize)
->
::core::option::Option<&mut dyn bevy_reflect::PartialReflect> {
match index {
0usize => ::core::option::Option::Some(&mut self.base),
1usize => ::core::option::Option::Some(&mut self.extension),
_ => ::core::option::Option::None,
}
}
fn name_at(&self, index: usize) -> ::core::option::Option<&str> {
match index {
0usize => ::core::option::Option::Some("base"),
1usize => ::core::option::Option::Some("extension"),
_ => ::core::option::Option::None,
}
}
fn index_of_name(&self, name: &str)
-> ::core::option::Option<usize> {
match name {
"base" => ::core::option::Option::Some(0usize),
"extension" => ::core::option::Option::Some(1usize),
_ => ::core::option::Option::None,
}
}
fn field_len(&self) -> usize { 2usize }
fn iter_fields(&self) -> bevy_reflect::structs::FieldIter {
bevy_reflect::structs::FieldIter::new(self)
}
fn to_dynamic_struct(&self)
->
::core::result::Result<bevy_reflect::structs::DynamicStruct,
bevy_reflect::ReflectCloneError> {
let mut dynamic: bevy_reflect::structs::DynamicStruct =
::core::default::Default::default();
dynamic.set_represented_type(bevy_reflect::PartialReflect::get_represented_type_info(self));
dynamic.insert_boxed("base",
bevy_reflect::PartialReflect::to_dynamic(&self.base)?);
dynamic.insert_boxed("extension",
bevy_reflect::PartialReflect::to_dynamic(&self.extension)?);
::core::result::Result::Ok(dynamic)
}
}
impl<B: Material, E: MaterialExtension> bevy_reflect::PartialReflect
for ExtendedMaterial<B, E> where
ExtendedMaterial<B, E>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, B: bevy_reflect::FromReflect +
bevy_reflect::TypePath + bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection,
E: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
#[inline]
fn get_represented_type_info(&self)
-> ::core::option::Option<&'static bevy_reflect::TypeInfo> {
::core::option::Option::Some(<Self as
bevy_reflect::Typed>::type_info())
}
#[inline]
fn try_apply(&mut self, value: &dyn bevy_reflect::PartialReflect)
-> ::core::result::Result<(), bevy_reflect::ApplyError> {
if let bevy_reflect::ReflectRef::Struct(struct_value) =
bevy_reflect::PartialReflect::reflect_ref(value) {
for (name, value) in
bevy_reflect::structs::Struct::iter_fields(struct_value) {
if let ::core::option::Option::Some(v) =
bevy_reflect::structs::Struct::field_mut(self, name) {
bevy_reflect::PartialReflect::try_apply(v, value)?;
}
}
} else {
return ::core::result::Result::Err(bevy_reflect::ApplyError::MismatchedKinds {
from_kind: bevy_reflect::PartialReflect::reflect_kind(value),
to_kind: bevy_reflect::ReflectKind::Struct,
});
}
::core::result::Result::Ok(())
}
#[inline]
fn reflect_kind(&self) -> bevy_reflect::ReflectKind {
bevy_reflect::ReflectKind::Struct
}
#[inline]
fn reflect_ref(&self) -> bevy_reflect::ReflectRef {
bevy_reflect::ReflectRef::Struct(self)
}
#[inline]
fn reflect_mut(&mut self) -> bevy_reflect::ReflectMut {
bevy_reflect::ReflectMut::Struct(self)
}
#[inline]
fn reflect_owned(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
-> bevy_reflect::ReflectOwned {
bevy_reflect::ReflectOwned::Struct(self)
}
#[inline]
fn try_into_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect>> {
::core::result::Result::Ok(self)
}
#[inline]
fn try_as_reflect(&self)
-> ::core::option::Option<&dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn try_as_reflect_mut(&mut self)
-> ::core::option::Option<&mut dyn bevy_reflect::Reflect> {
::core::option::Option::Some(self)
}
#[inline]
fn into_partial_reflect(self:
bevy_reflect::__macro_exports::alloc_utils::Box<Self>)
->
bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::PartialReflect> {
self
}
#[inline]
fn as_partial_reflect(&self)
-> &dyn bevy_reflect::PartialReflect {
self
}
#[inline]
fn as_partial_reflect_mut(&mut self)
-> &mut dyn bevy_reflect::PartialReflect {
self
}
fn reflect_partial_eq(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<bool> {
(bevy_reflect::structs::struct_partial_eq)(self, value)
}
fn reflect_partial_cmp(&self,
value: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<::core::cmp::Ordering> {
(bevy_reflect::structs::struct_partial_cmp)(self, value)
}
#[inline]
fn reflect_clone(&self)
->
::core::result::Result<bevy_reflect::__macro_exports::alloc_utils::Box<dyn bevy_reflect::Reflect>,
bevy_reflect::ReflectCloneError> {
::core::result::Result::Ok(bevy_reflect::__macro_exports::alloc_utils::Box::new(::core::clone::Clone::clone(self)))
}
}
impl<B: Material, E: MaterialExtension> bevy_reflect::FromReflect for
ExtendedMaterial<B, E> where
ExtendedMaterial<B, E>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, B: bevy_reflect::FromReflect +
bevy_reflect::TypePath + bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection,
E: bevy_reflect::FromReflect + bevy_reflect::TypePath +
bevy_reflect::MaybeTyped +
bevy_reflect::__macro_exports::RegisterForReflection {
fn from_reflect(reflect: &dyn bevy_reflect::PartialReflect)
-> ::core::option::Option<Self> {
if let bevy_reflect::ReflectRef::Struct(__ref_struct) =
bevy_reflect::PartialReflect::reflect_ref(reflect) {
let __this =
Self {
base: <B as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"base")?)?,
extension: <E as
bevy_reflect::FromReflect>::from_reflect(bevy_reflect::structs::Struct::field(__ref_struct,
"extension")?)?,
};
::core::option::Option::Some(__this)
} else { ::core::option::Option::None }
}
}
};Reflect)]
149#[reflect(type_path = false)]
150#[reflect(Clone)]
151pub struct ExtendedMaterial<B: Material, E: MaterialExtension> {
152 pub base: B,
153 pub extension: E,
154}
155
156impl<B, E> Default for ExtendedMaterial<B, E>
157where
158 B: Material + Default,
159 E: MaterialExtension + Default,
160{
161 fn default() -> Self {
162 Self {
163 base: B::default(),
164 extension: E::default(),
165 }
166 }
167}
168
169const _: () =
{
#[allow(deprecated, reason =
"derives on a deprecated type shouldn't be considered a usage")]
impl<B: Material, E: MaterialExtension> bevy_reflect::TypePath for
ExtendedMaterial<B, E> where
ExtendedMaterial<B, E>: ::core::any::Any + ::core::marker::Send +
::core::marker::Sync, B: bevy_reflect::TypePath,
E: bevy_reflect::TypePath {
fn type_path() -> &'static str {
static CELL: bevy_reflect::utility::GenericTypePathCell =
bevy_reflect::utility::GenericTypePathCell::new();
CELL.get_or_insert::<Self,
_>(#[inline(never)] ||
{
::core::ops::Add::<&str>::add(::core::ops::Add::<&str>::add(bevy_reflect::__macro_exports::alloc_utils::ToString::to_string("bevy_pbr::extended_material::ExtendedMaterial<"),
&::core::ops::Add::<&str>::add(::core::ops::Add::<&str>::add(bevy_reflect::__macro_exports::alloc_utils::ToString::to_string(<B
as bevy_reflect::TypePath>::type_path()), ", "),
<E as bevy_reflect::TypePath>::type_path())), ">")
})
}
fn short_type_path() -> &'static str {
static CELL: bevy_reflect::utility::GenericTypePathCell =
bevy_reflect::utility::GenericTypePathCell::new();
CELL.get_or_insert::<Self,
_>(#[inline(never)] ||
{
::core::ops::Add::<&str>::add(::core::ops::Add::<&str>::add(bevy_reflect::__macro_exports::alloc_utils::ToString::to_string("ExtendedMaterial<"),
&::core::ops::Add::<&str>::add(::core::ops::Add::<&str>::add(bevy_reflect::__macro_exports::alloc_utils::ToString::to_string(<B
as bevy_reflect::TypePath>::short_type_path()), ", "),
<E as bevy_reflect::TypePath>::short_type_path())), ">")
})
}
fn type_ident() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("ExtendedMaterial")
}
fn crate_name() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_pbr")
}
fn module_path() -> ::core::option::Option<&'static str> {
::core::option::Option::Some("bevy_pbr::extended_material")
}
}
};impl_type_path!((in bevy_pbr::extended_material) ExtendedMaterial<B: Material, E: MaterialExtension>);
172
173impl<B: Material, E: MaterialExtension> AsBindGroup for ExtendedMaterial<B, E> {
174 type Data = cbg::CombinedBindGroupData<B::Data, E::Data>;
175 type Param = (B::Param, E::Param);
176
177 fn bindless_slot_count() -> Option<BindlessSlabResourceLimit> {
178 cbg::bindless_slot_count::<B, E>()
179 }
180
181 fn bindless_supported(render_device: &RenderDevice) -> bool {
182 B::bindless_supported(render_device) && E::bindless_supported(render_device)
183 }
184
185 fn label() -> &'static str {
186 E::label()
187 }
188
189 fn bind_group_data(&self) -> Self::Data {
190 cbg::bind_group_data(&self.base, &self.extension)
191 }
192
193 fn build_bind_group(
194 &self,
195 layout: &BindGroupLayout,
196 render_device: &RenderDevice,
197 param: &mut SystemParamItem<'_, '_, Self::Param>,
198 force_no_bindless: bool,
199 output: &mut BindGroupBuilder,
200 ) -> Result<(), AsBindGroupError> {
201 cbg::build_bind_group(
202 &self.base,
203 &self.extension,
204 layout,
205 render_device,
206 param,
207 force_no_bindless,
208 output,
209 )
210 }
211
212 fn bind_group_layout_entries(
213 render_device: &RenderDevice,
214 force_no_bindless: bool,
215 ) -> Vec<BindGroupLayoutEntry>
216 where
217 Self: Sized,
218 {
219 cbg::bind_group_layout_entries::<B, E>(render_device, force_no_bindless)
220 }
221
222 fn bindless_descriptor() -> Option<BindlessDescriptor> {
223 cbg::bindless_descriptor::<B, E>()
224 }
225}
226
227impl<B: Material, E: MaterialExtension> Material for ExtendedMaterial<B, E> {
228 fn vertex_shader() -> ShaderRef {
229 match E::vertex_shader() {
230 ShaderRef::Default => B::vertex_shader(),
231 specified => specified,
232 }
233 }
234
235 fn fragment_shader() -> ShaderRef {
236 match E::fragment_shader() {
237 ShaderRef::Default => B::fragment_shader(),
238 specified => specified,
239 }
240 }
241
242 fn alpha_mode(&self) -> AlphaMode {
243 match E::alpha_mode() {
244 Some(specified) => specified,
245 None => B::alpha_mode(&self.base),
246 }
247 }
248
249 fn opaque_render_method(&self) -> OpaqueRendererMethod {
250 B::opaque_render_method(&self.base)
251 }
252
253 fn depth_bias(&self) -> f32 {
254 B::depth_bias(&self.base)
255 }
256
257 fn reads_view_transmission_texture(&self) -> bool {
258 B::reads_view_transmission_texture(&self.base)
259 }
260
261 fn enable_prepass() -> bool {
262 E::enable_prepass()
263 }
264
265 fn enable_shadows() -> bool {
266 E::enable_shadows()
267 }
268
269 fn enable_oit() -> bool {
270 E::enable_oit()
271 }
272
273 fn prepass_vertex_shader() -> ShaderRef {
274 match E::prepass_vertex_shader() {
275 ShaderRef::Default => B::prepass_vertex_shader(),
276 specified => specified,
277 }
278 }
279
280 fn prepass_fragment_shader() -> ShaderRef {
281 match E::prepass_fragment_shader() {
282 ShaderRef::Default => B::prepass_fragment_shader(),
283 specified => specified,
284 }
285 }
286
287 fn deferred_vertex_shader() -> ShaderRef {
288 match E::deferred_vertex_shader() {
289 ShaderRef::Default => B::deferred_vertex_shader(),
290 specified => specified,
291 }
292 }
293
294 fn deferred_fragment_shader() -> ShaderRef {
295 match E::deferred_fragment_shader() {
296 ShaderRef::Default => B::deferred_fragment_shader(),
297 specified => specified,
298 }
299 }
300
301 #[cfg(feature = "meshlet")]
302 fn meshlet_mesh_fragment_shader() -> ShaderRef {
303 match E::meshlet_mesh_fragment_shader() {
304 ShaderRef::Default => B::meshlet_mesh_fragment_shader(),
305 specified => specified,
306 }
307 }
308
309 #[cfg(feature = "meshlet")]
310 fn meshlet_mesh_prepass_fragment_shader() -> ShaderRef {
311 match E::meshlet_mesh_prepass_fragment_shader() {
312 ShaderRef::Default => B::meshlet_mesh_prepass_fragment_shader(),
313 specified => specified,
314 }
315 }
316
317 #[cfg(feature = "meshlet")]
318 fn meshlet_mesh_deferred_fragment_shader() -> ShaderRef {
319 match E::meshlet_mesh_deferred_fragment_shader() {
320 ShaderRef::Default => B::meshlet_mesh_deferred_fragment_shader(),
321 specified => specified,
322 }
323 }
324
325 fn specialize(
326 pipeline: &MaterialPipeline,
327 descriptor: &mut RenderPipelineDescriptor,
328 layout: &MeshVertexBufferLayoutRef,
329 key: MaterialPipelineKey<Self>,
330 ) -> Result<(), SpecializedMeshPipelineError> {
331 let base_key = MaterialPipelineKey::<B> {
333 mesh_key: key.mesh_key,
334 bind_group_data: key.bind_group_data.base,
335 };
336 B::specialize(pipeline, descriptor, layout, base_key)?;
337
338 E::specialize(
340 &MaterialExtensionPipeline {
341 mesh_pipeline: pipeline.mesh_pipeline.clone(),
342 },
343 descriptor,
344 layout,
345 MaterialExtensionKey {
346 mesh_key: key.mesh_key,
347 bind_group_data: key.bind_group_data.extension,
348 },
349 )
350 }
351}
352
353#[deprecated = "Use `bevy_render::combined_bind_group::CombinedBindGroupData` instead"]
354pub type MaterialExtensionBindGroupData<B, E> = cbg::CombinedBindGroupData<B, E>;