pub trait AsBindGroup {
type Data: Send + Sync;
type Param: SystemParam + 'static;
// Required methods
fn unprepared_bind_group(
&self,
layout: &BindGroupLayout,
render_device: &RenderDevice,
param: &mut SystemParamItem<'_, '_, Self::Param>,
) -> Result<UnpreparedBindGroup<Self::Data>, AsBindGroupError>;
fn bind_group_layout_entries(
render_device: &RenderDevice,
) -> Vec<BindGroupLayoutEntry>
where Self: Sized;
// Provided methods
fn label() -> Option<&'static str> { ... }
fn as_bind_group(
&self,
layout: &BindGroupLayout,
render_device: &RenderDevice,
param: &mut SystemParamItem<'_, '_, Self::Param>,
) -> Result<PreparedBindGroup<Self::Data>, AsBindGroupError> { ... }
fn bind_group_layout(render_device: &RenderDevice) -> BindGroupLayout
where Self: Sized { ... }
}
Expand description
Converts a value to a BindGroup
with a given BindGroupLayout
, which can then be used in Bevy shaders.
This trait can be derived (and generally should be). Read on for details and examples.
This is an opinionated trait that is intended to make it easy to generically
convert a type into a BindGroup
. It provides access to specific render resources,
such as RenderAssets<GpuImage>
and crate::texture::FallbackImage
. If a type has a Handle<Image>
,
these can be used to retrieve the corresponding Texture
resource.
AsBindGroup::as_bind_group
is intended to be called once, then the result cached somewhere. It is generally
ok to do “expensive” work here, such as creating a Buffer
for a uniform.
If for some reason a BindGroup
cannot be created yet (for example, the Texture
for an Image
hasn’t loaded yet), just return AsBindGroupError::RetryNextUpdate
, which signals that the caller
should retry again later.
§Deriving
This trait can be derived. 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:
#[derive(AsBindGroup)]
struct CoolMaterial {
#[uniform(0)]
color: LinearRgba,
#[texture(1)]
#[sampler(2)]
color_texture: Handle<Image>,
#[storage(3, read_only)]
storage_buffer: Handle<ShaderStorageBuffer>,
#[storage(4, read_only, buffer)]
raw_buffer: Buffer,
#[storage_texture(5)]
storage_texture: Handle<Image>,
}
In WGSL shaders, the binding would look like this:
@group(2) @binding(0) var<uniform> color: vec4<f32>;
@group(2) @binding(1) var color_texture: texture_2d<f32>;
@group(2) @binding(2) var color_sampler: sampler;
@group(2) @binding(3) var<storage> storage_buffer: array<f32>;
@group(2) @binding(4) var<storage> raw_buffer: array<f32>;
@group(2) @binding(5) var storage_texture: texture_storage_2d<rgba8unorm, read_write>;
Note that the “group” index is determined by the usage context. It is not defined in AsBindGroup
. For example, in Bevy material bind groups
are generally bound to group 2.
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 aBuffer
, and bound as a uniform.ShaderType
is implemented for most math types already, such asf32
,Vec4
, andLinearRgba
. It can also be derived for custom structs.
- The field will be converted to a shader-compatible type using the
-
texture(BINDING_INDEX, arguments)
- This field’s
Handle<Image>
will be used to look up the matchingTexture
GPU resource, which will be bound as a texture in shaders. The field will be assumed to implementInto<Option<Handle<Image>>>
. In practice, most fields should be aHandle<Image>
orOption<Handle<Image>>
. If the value of anOption<Handle<Image>>
isNone
, thecrate::texture::FallbackImage
resource will be used instead. This attribute can be used in conjunction with asampler
binding attribute (with a different binding index) if a binding of the sampler for theImage
is also required.
- This field’s
Arguments | Values | Default |
---|---|---|
dimension = “…” | "1d" , "2d" , "2d_array" , "3d" , "cube" , "cube_array" | "2d" |
sample_type = “…” | "float" , "depth" , "s_int" or "u_int" | "float" |
filterable = … | true , false | true |
multisampled = … | true , false | false |
visibility(...) | all , none , or a list-combination of vertex , fragment , compute | vertex , fragment |
storage_texture(BINDING_INDEX, arguments)
- This field’s
Handle<Image>
will be used to look up the matchingTexture
GPU resource, which will be bound as a storage texture in shaders. The field will be assumed to implementInto<Option<Handle<Image>>>
. In practice, most fields should be aHandle<Image>
orOption<Handle<Image>>
. If the value of anOption<Handle<Image>>
isNone
, thecrate::texture::FallbackImage
resource will be used instead.
- This field’s
Arguments | Values | Default |
---|---|---|
dimension = “…” | "1d" , "2d" , "2d_array" , "3d" , "cube" , "cube_array" | "2d" |
image_format = … | any member of TextureFormat | Rgba8Unorm |
access = … | any member of StorageTextureAccess | ReadWrite |
visibility(...) | all , none , or a list-combination of vertex , fragment , compute | compute |
sampler(BINDING_INDEX, arguments)
- This field’s
Handle<Image>
will be used to look up the matchingSampler
GPU resource, which will be bound as a sampler in shaders. The field will be assumed to implementInto<Option<Handle<Image>>>
. In practice, most fields should be aHandle<Image>
orOption<Handle<Image>>
. If the value of anOption<Handle<Image>>
isNone
, thecrate::texture::FallbackImage
resource will be used instead. This attribute can be used in conjunction with atexture
binding attribute (with a different binding index) if a binding of the texture for theImage
is also required.
- This field’s
Arguments | Values | Default |
---|---|---|
sampler_type = “…” | "filtering" , "non_filtering" , "comparison" . | "filtering" |
visibility(...) | all , none , or a list-combination of vertex , fragment , compute | vertex , fragment |
storage(BINDING_INDEX, arguments)
- The field’s
Handle<Storage>
will be used to look up the matchingBuffer
GPU resource, which will be bound as a storage buffer in shaders. If thestorage
attribute is used, the field is expected a raw buffer, and the buffer will be bound as a storage buffer in shaders. - It supports and optional
read_only
parameter. Defaults to false if not present.
- The field’s
Arguments | Values | Default |
---|---|---|
visibility(...) | all , none , or a list-combination of vertex , fragment , compute | vertex , fragment |
read_only | if present then value is true, otherwise false | false |
buffer | if present then the field will be assumed to be a raw wgpu buffer |
Note that fields without field-level binding attributes will be ignored.
#[derive(AsBindGroup)]
struct CoolMaterial {
#[uniform(0)]
color: LinearRgba,
this_field_is_ignored: String,
}
As mentioned above, Option<Handle<Image>>
is also supported:
#[derive(AsBindGroup)]
struct CoolMaterial {
#[uniform(0)]
color: LinearRgba,
#[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 crate::texture::FallbackImage
will be used for the binding instead, which defaults
to “pure white”.
Field uniforms with the same index will be combined into a single binding:
#[derive(AsBindGroup)]
struct CoolMaterial {
#[uniform(0)]
color: LinearRgba,
#[uniform(0)]
roughness: f32,
}
In WGSL shaders, the binding would look like this:
struct CoolMaterial {
color: vec4<f32>,
roughness: f32,
};
@group(2) @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)
- This also creates a
Buffer
usingShaderType
and binds it as a uniform, much like the field-leveluniform
attribute. The difference is that the entireAsBindGroup
value is converted toConvertedShaderType
, which must implementShaderType
, instead of a specific field implementingShaderType
. This is useful if more complicated conversion logic is required. The conversion is done using theAsBindGroupShaderType<ConvertedShaderType>
trait, which is automatically implemented if&Self
implementsInto<ConvertedShaderType>
. Only useAsBindGroupShaderType
if access to resources likeRenderAssets<GpuImage>
is required.
- This also creates a
bind_group_data(DataType)
- The
AsBindGroup
type will be converted to someDataType
usingInto<DataType>
and stored asAsBindGroup::Data
as part of theAsBindGroup::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”. SeeSpecializedRenderPipeline
.
- The
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:
#[derive(AsBindGroup)]
#[uniform(0, CoolMaterialUniform)]
struct CoolMaterial {
color: LinearRgba,
roughness: f32,
}
#[derive(ShaderType)]
struct CoolMaterialUniform {
color: LinearRgba,
roughness: f32,
}
impl From<&CoolMaterial> for CoolMaterialUniform {
fn from(material: &CoolMaterial) -> CoolMaterialUniform {
CoolMaterialUniform {
color: material.color,
roughness: material.roughness,
}
}
}
Setting bind_group_data
looks like this:
#[derive(AsBindGroup)]
#[bind_group_data(CoolMaterialKey)]
struct CoolMaterial {
#[uniform(0)]
color: LinearRgba,
is_shaded: bool,
}
#[derive(Copy, Clone, Hash, Eq, PartialEq)]
struct CoolMaterialKey {
is_shaded: bool,
}
impl From<&CoolMaterial> for CoolMaterialKey {
fn from(material: &CoolMaterial) -> CoolMaterialKey {
CoolMaterialKey {
is_shaded: material.is_shaded,
}
}
}
Required Associated Types§
type Param: SystemParam + 'static
Required Methods§
Sourcefn unprepared_bind_group(
&self,
layout: &BindGroupLayout,
render_device: &RenderDevice,
param: &mut SystemParamItem<'_, '_, Self::Param>,
) -> Result<UnpreparedBindGroup<Self::Data>, AsBindGroupError>
fn unprepared_bind_group( &self, layout: &BindGroupLayout, render_device: &RenderDevice, param: &mut SystemParamItem<'_, '_, Self::Param>, ) -> Result<UnpreparedBindGroup<Self::Data>, AsBindGroupError>
Returns a vec of (binding index, OwnedBindingResource
).
In cases where OwnedBindingResource
is not available (as for bindless texture arrays currently),
an implementor may define as_bind_group
directly. This may prevent certain features
from working correctly.
Sourcefn bind_group_layout_entries(
render_device: &RenderDevice,
) -> Vec<BindGroupLayoutEntry>where
Self: Sized,
fn bind_group_layout_entries(
render_device: &RenderDevice,
) -> Vec<BindGroupLayoutEntry>where
Self: Sized,
Returns a vec of bind group layout entries
Provided Methods§
Sourcefn as_bind_group(
&self,
layout: &BindGroupLayout,
render_device: &RenderDevice,
param: &mut SystemParamItem<'_, '_, Self::Param>,
) -> Result<PreparedBindGroup<Self::Data>, AsBindGroupError>
fn as_bind_group( &self, layout: &BindGroupLayout, render_device: &RenderDevice, param: &mut SystemParamItem<'_, '_, Self::Param>, ) -> Result<PreparedBindGroup<Self::Data>, AsBindGroupError>
Creates a bind group for self
matching the layout defined in AsBindGroup::bind_group_layout
.
Sourcefn bind_group_layout(render_device: &RenderDevice) -> BindGroupLayoutwhere
Self: Sized,
fn bind_group_layout(render_device: &RenderDevice) -> BindGroupLayoutwhere
Self: Sized,
Creates the bind group layout matching all bind groups returned by AsBindGroup::as_bind_group
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.