Description
Bevy version
0.14.0-rc.4
The following is a simple program which uses a custom vertex attribute to colour a shape.
use bevy::{
math::{vec3, vec4, VectorSpace},
prelude::*,
render::{
mesh::{MeshVertexAttribute, PrimitiveTopology},
render_asset::RenderAssetUsages,
render_resource::{AsBindGroup, VertexFormat},
},
sprite::{Material2d, Material2dPlugin, MaterialMesh2dBundle, Mesh2dHandle},
};
fn main() {
App::new()
.add_plugins((DefaultPlugins, MaterialPlugin::<CustomMaterial>::default()))
.add_systems(Startup, spawn)
.run();
}
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
struct CustomMaterial {
#[uniform(0)]
uniform_value: Vec4,
}
impl Material for CustomMaterial {
fn fragment_shader() -> bevy::render::render_resource::ShaderRef {
"custom_vertex_attr.wgsl".into()
}
fn vertex_shader() -> bevy::render::render_resource::ShaderRef {
"custom_vertex_attr.wgsl".into()
}
fn specialize(
_pipeline: &bevy::pbr::MaterialPipeline<Self>,
descriptor: &mut bevy::render::render_resource::RenderPipelineDescriptor,
layout: &bevy::render::mesh::MeshVertexBufferLayoutRef,
_key: bevy::pbr::MaterialPipelineKey<Self>,
) -> Result<(), bevy::render::render_resource::SpecializedMeshPipelineError> {
let vertex_layout = layout.0.get_layout(&[
Mesh::ATTRIBUTE_POSITION.at_shader_location(0),
CUSTOM_ATTR.at_shader_location(1),
])?;
descriptor.vertex.buffers = vec![vertex_layout];
Ok(())
}
}
const CUSTOM_ATTR: MeshVertexAttribute =
MeshVertexAttribute::new("CustomAttr", 83457934, VertexFormat::Float32x4);
fn spawn(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<CustomMaterial>>,
) {
let mut mesh = Mesh::from(Cuboid::default());
mesh.insert_attribute(CUSTOM_ATTR, vec![vec4(0.0, 0.0, 0.5, 1.0); 24]);
commands.spawn(MaterialMeshBundle {
mesh: meshes.add(mesh),
material: materials.add(CustomMaterial {
uniform_value: vec4(0.0, 0.5, 0.0, 1.0),
}),
..default()
});
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(0.0, 0.0, -5.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
}
However this equivalent in 2D does not work.
use bevy::{
math::{vec3, vec4},
prelude::*,
render::{
mesh::{MeshVertexAttribute, PrimitiveTopology},
render_asset::RenderAssetUsages,
render_resource::{AsBindGroup, VertexFormat},
},
sprite::{Material2d, Material2dPlugin, MaterialMesh2dBundle, Mesh2dHandle},
};
fn main() {
App::new()
.add_plugins((
DefaultPlugins,
Material2dPlugin::<CustomMaterial>::default(),
))
.add_systems(Startup, spawn)
.run();
}
#[derive(Asset, TypePath, AsBindGroup, Debug, Clone)]
struct CustomMaterial {
#[uniform(0)]
uniform_value: Vec4,
}
impl Material2d for CustomMaterial {
fn fragment_shader() -> bevy::render::render_resource::ShaderRef {
"custom_vertex_attr.wgsl".into()
}
fn vertex_shader() -> bevy::render::render_resource::ShaderRef {
"custom_vertex_attr.wgsl".into()
}
fn specialize(
descriptor: &mut bevy::render::render_resource::RenderPipelineDescriptor,
layout: &bevy::render::mesh::MeshVertexBufferLayoutRef,
_key: bevy::sprite::Material2dKey<Self>,
) -> Result<(), bevy::render::render_resource::SpecializedMeshPipelineError> {
let vertex_layout = layout.0.get_layout(&[
Mesh::ATTRIBUTE_POSITION.at_shader_location(0),
CUSTOM_ATTR.at_shader_location(1),
])?;
descriptor.vertex.buffers = vec![vertex_layout];
Ok(())
}
}
const CUSTOM_ATTR: MeshVertexAttribute =
MeshVertexAttribute::new("CustomAttr", 83457934, VertexFormat::Float32x4);
fn spawn(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<CustomMaterial>>,
) {
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList, RenderAssetUsages::all());
mesh.insert_attribute(
Mesh::ATTRIBUTE_POSITION,
vec![
vec3(0.0, 0.0, 0.0),
vec3(100.0, 0.0, 0.0),
vec3(0.0, 100.0, 0.0),
],
);
mesh.insert_attribute(CUSTOM_ATTR, vec![vec4(0.5, 0.0, 0.0, 1.0); 3]);
commands.spawn(MaterialMesh2dBundle {
mesh: Mesh2dHandle::from(meshes.add(mesh)),
material: materials.add(CustomMaterial {
uniform_value: vec4(0.0, 0.5, 0.0, 1.0),
}),
..default()
});
commands.spawn(Camera2dBundle { ..default() });
}
This error is shown, followed by a series of panics and the program crashing:
2024-06-30T15:15:49.531042Z ERROR wgpu_core::device::global: Device::create_render_pipeline error: Error matching ShaderStages(VERTEX) shader requirements against the pipeline
2024-06-30T15:15:49.531192Z ERROR wgpu::backend::wgpu_core: Handling wgpu errors as fatal by default
thread 'Async Compute Task Pool (0)' panicked at /home/.../.cargo/registry/src/index.crates.io-6f17d22bba15001f/wgpu-0.20.1/src/backend/wgpu_core.rs:2996:5:
wgpu error: Validation Error
Caused by:
In Device::create_render_pipeline
note: label = `transparent_mesh2d_pipeline`
Error matching ShaderStages(VERTEX) shader requirements against the pipeline
Shader global ResourceBinding { group: 1, binding: 0 } is not available in the pipeline layout
Buffer structure size 144, added to one element of an unbound array, if it's the last field, ended up greater than the given `min_binding_size`
The following shader is used in both examples:
#import bevy_pbr::mesh_functions::{get_world_from_local, mesh_position_local_to_clip}
struct CustomMaterial {
uniform_value: vec4<f32>,
}
@group(2) @binding(0)
var<uniform> material: CustomMaterial;
struct Vertex {
@builtin(instance_index) instance_index: u32,
@location(0) position: vec3<f32>,
@location(1) custom_attr: vec4<f32>,
};
struct VertexOutput {
@builtin(position) clip_position: vec4<f32>,
@location(0) custom_attr: vec4<f32>,
};
@vertex
fn vertex(vertex: Vertex) -> VertexOutput {
var out: VertexOutput;
out.clip_position = mesh_position_local_to_clip(
get_world_from_local(vertex.instance_index),
vec4<f32>(vertex.position, 1.0),
);
out.custom_attr = vertex.custom_attr;
return out;
}
struct FragmentInput {
@location(0) custom_attr: vec4<f32>,
};
@fragment
fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
return in.custom_attr;
}