bevy_render::render_resource

Trait AsBindGroup

Source
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:

ArgumentsValuesDefault
dimension = “…”"1d", "2d", "2d_array", "3d", "cube", "cube_array""2d"
sample_type = “…”"float", "depth", "s_int" or "u_int""float"
filterable = …true, falsetrue
multisampled = …true, falsefalse
visibility(...)all, none, or a list-combination of vertex, fragment, computevertex, fragment
ArgumentsValuesDefault
dimension = “…”"1d", "2d", "2d_array", "3d", "cube", "cube_array""2d"
image_format = …any member of TextureFormatRgba8Unorm
access = …any member of StorageTextureAccessReadWrite
visibility(...)all, none, or a list-combination of vertex, fragment, computecompute
ArgumentsValuesDefault
sampler_type = “…”"filtering", "non_filtering", "comparison"."filtering"
visibility(...)all, none, or a list-combination of vertex, fragment, computevertex, fragment
  • storage(BINDING_INDEX, arguments)
    • The field’s Handle<Storage> will be used to look up the matching Buffer GPU resource, which will be bound as a storage buffer in shaders. If the storage 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.
ArgumentsValuesDefault
visibility(...)all, none, or a list-combination of vertex, fragment, computevertex, fragment
read_onlyif present then value is true, otherwise falsefalse
bufferif 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:

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§

Source

type Data: Send + Sync

Data that will be stored alongside the “prepared” bind group.

Source

type Param: SystemParam + 'static

Required Methods§

Source

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.

Source

fn bind_group_layout_entries( render_device: &RenderDevice, ) -> Vec<BindGroupLayoutEntry>
where Self: Sized,

Returns a vec of bind group layout entries

Provided Methods§

Source

fn label() -> Option<&'static str>

label

Source

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.

Source

fn bind_group_layout(render_device: &RenderDevice) -> BindGroupLayout
where 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.

Implementors§