bevy
bevy copied to clipboard
2d custom vertex attribute not working
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;
}
Do you know if this worked in 0.13?
Do you know if this worked in 0.13?
it did not. In 0.13.2, the same code with very minor changes gives the same output:
2024-07-01T21:18:02.604417Z ERROR log: Device::create_render_pipeline error: Error matching ShaderStages(VERTEX) shader requirements against the pipeline
2024-07-01T21:18:02.604511Z ERROR log: 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.19.4/src/backend/wgpu_core.rs:3006: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 160, added to one element of an unbound array, if it's the last field, ended up greater than the given `min_binding_size`
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_render::render_resource::pipeline_cache::PipelineCache::process_pipeline_queue_system`!
thread 'Compute Task Pool (0)' panicked at /home/.../.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_render-0.13.2/src/pipelined_rendering.rs:49:67:
called `Result::unwrap()` on an `Err` value: RecvError
This is the same as the 0.14 error, just with a bit less spam.