#Render a mesh with a custom material?
1 messages · Page 1 of 1 (latest)
I saw that. I tried it out, and it had no effect.
#[derive(AsBindGroup, Debug, Clone, Asset, TypePath)]
struct VoxelMaterial {
}
impl Material for VoxelMaterial {
fn vertex_shader() -> bevy::render::render_resource::ShaderRef {
"shaders/voxel/voxel.wgsl".into()
}
fn fragment_shader() -> bevy::render::render_resource::ShaderRef {
"shaders/voxel/voxel.wgsl".into()
}
fn alpha_mode(&self) -> AlphaMode {
AlphaMode::Blend
}
}
commands.spawn((
MaterialMeshBundle {
mesh: meshes.add(mesh),
material: materials.add(VoxelMaterial { }),
transform: Transform::from_xyz(0.0, 0.0, 0.0),
..default()
},
cleanup::Menu
));
The same mesh will render if I put it into a PbrBundle.
Here's my shader code:
Vertex
struct VertexInput {
@location(0) position: vec3<f32>,
};
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) color: vec3<f32>,
};
@vertex
fn main(input: VertexInput) -> VertexOutput {
var output: VertexOutput;
output.position = vec4<f32>(input.position, 1.0);
output.color = vec3<f32>(1.0, 0.0, 0.0);
return output;
}
Fragment
struct FragmentInput {
@location(0) color: vec3<f32>,
};
@fragment
fn main(input: FragmentInput) -> @location(0) vec4<f32> {
return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}
Can you share a picture of the result?
There is no result. Nothing renders.
If I change it to a PbrBundle, it does render.
Like I said, nothing.
After doing some thinking, I've come to realize that I should probably transform the coordinates from world space to screenspace in the vertex shader, but I don't know WGSL so I'm not sure how to do that.
Ah, yea, that would be it. You'd want a vertex that had an instance_index and then transformed it to clipspace (a kind of screenspace) like this:
struct Vertex {
@builtin(instance_index) instance_index: u32,
@location(0) position: vec3<f32>,
};
@vertex
fn vertex(vertex: Vertex) -> VertexOutput {
var out: VertexOutput;
let model = mesh2d_functions::get_model_matrix(vertex.instance_index);
out.position = mesh2d_functions::mesh2d_position_local_to_clip(model, vec4<f32>(vertex.position, 1.0));
}
#import bevy_pbr::mesh_functions
?
yep.
Okay, here's the new code.
#import bevy_pbr::view_transformations::position_world_to_clip
#import bevy_pbr::mesh_functions
struct VertexInput {
@builtin(instance_index) instance_index: u32,
@location(0) position: vec3<f32>,
@location(1) uv: vec2<f32>,
};
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) uv: vec2<f32>,
};
@vertex
fn vertex(input: VertexInput) -> VertexOutput {
var model = mesh_functions::get_model_matrix(input.instance_index);
var output: VertexOutput;
var position = mesh_functions::mesh_position_local_to_world(
model,
vec4<f32>(input.position, 1.0)
);
output.position = position_world_to_clip(position.xyz);
output.uv = input.uv;
return output;
}
That's what I was able to figure out on my own, but it still doesn't work.
comment out this line: output.position = position_world_to_clip(position.xyz);
output.position = mesh_functions…
add that.
@vertex
fn vertex(input: VertexInput) -> VertexOutput {
var model = mesh_functions::get_model_matrix(input.instance_index);
var output: VertexOutput;
output.position = mesh_functions::mesh_position_local_to_world(
model,
vec4<f32>(input.position, 1.0)
);
// output.position = position_world_to_clip(position.xyz);
output.uv = input.uv;
return output;
}
Like that?
Oh, I see, that could maybe work. local_to_clip instead of local_to_world.
mesh_functions::local_to_clip?
mesh_position_local_to_clip
Where do I find documentation for these functions?
I don't even know if bevy is using my shader. I could literally mangle the path and bevy won't complain.
So I'm finding it hard to narrow down exactly what is going wrong.
Try running with cargo run --features bevy/file_watcher. that will reload your shader when it changes.
I don't even know if it's loading my shader in the first place.
Shouldn't bevy throw an error if the file isn't found?
Unlike the rust API, the shader API is harder to find documentation for. I'd suggest just cloning bevy's repo and searching for the wgsl files you're importing.
Yes. Where do you load your file?
impl Material for VoxelMaterial {
fn vertex_shader() -> bevy::render::render_resource::ShaderRef {
"shaders/voxel/voxel_vert.wgsl".into()
}
fn fragment_shader() -> bevy::render::render_resource::ShaderRef {
"shaders/voxel/voxel_frag.wgsl".into()
}
fn alpha_mode(&self) -> AlphaMode {
AlphaMode::Blend
}
}
Then I use
commands.spawn((
MaterialMeshBundle {
mesh: meshes.add(mesh),
material: materials.add(VoxelMaterial { }),
transform: Transform::from_xyz(0.0, 0.0, 0.0),
..default()
},
cleanup::Menu
));
To spawn the mesh.
mesh.insert_attribute(MeshVertexAttribute::new("position", 0, VertexFormat::Float32x3), vertices);
mesh.insert_attribute(MeshVertexAttribute::new("uv", 1, VertexFormat::Float32x2), uvs);
mesh.insert_indices(indices);
Building the mesh.
let mut mesh = bevy::prelude::Mesh::new(bevy::render::mesh::PrimitiveTopology::TriangleList, RenderAssetUsages::RENDER_WORLD);
let vertices: Vec<_> = [
vec3(0.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0),
vec3(0.0, 0.0, 1.0), vec3(1.0, 0.0, 1.0),
].into_iter().map(|v| v + vec3(-0.5, 0.0, -0.5)).collect();
let uvs = vec![
vec2(0.0, 0.0), vec2(0.0625, 0.0),
vec2(0.0, 0.0625), vec2(0.0625, 0.0625),
];
let indices = Indices::U32(vec![0, 2, 1, 1, 2, 3]);
Sorry for the weird order of the code.
No, it's fine. It's helpful.
Well, do this. Change your fragment_shader() file path to a file that isn't there. Confirm that bevy complains.
Write some garbage "XLKJLKSJD" into your shader; confirm that bevy complains.
I did change it to a file that wasn't there. As far as I could tell, bevy doesn't complain. I didn't see any errors in the terminal. Is there some sort of logging I should be enabling?
Are you adding DefaultPlugins first?
Yeah.
When you run it, it should spew a bunch of INFO logging. Do you see that?
2024-06-14T03:31:01.972069Z INFO bevy_render::renderer: AdapterInfo { name: "AMD Radeon Pro Vega 64", vendor: 0, device: 0, device_type: DiscreteGpu, driver: "", driver_info: "", backend: Metal }
2024-06-14T03:31:02.704866Z INFO bevy_winit::system: Creating new window "App" (0v1)
...
Copy and paste your main function, if you don't mind.
Yeah, I see that logging.
fn main() {
// TODO: Read from configuration file.
App::new()
.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(bevy::window::Window {
title: "Unvoga".into(),
resolution: (1280.0, 720.0).into(),
present_mode: PresentMode::AutoVsync,
prevent_default_event_handling: false,
..default()
}),
..default()
}))
.add_plugins(EguiPlugin)
.insert_resource(game::settings::UnvogaSettings::default())
.insert_state(GameState::MainMenu)
.add_systems(Update, main_menu.run_if(in_state(GameState::MainMenu)))
.add_systems(OnExit(GameState::LoadingScreen), cleanup_system::<cleanup::LoadingScreen>)
.add_systems(OnEnter(GameState::MainMenu), on_enter_main_menu)
.add_systems(OnExit(GameState::MainMenu), cleanup_system::<cleanup::Menu>)
.add_systems(OnEnter(GameState::SinglePlayer), on_enter_singleplayer)
.add_systems(OnExit(GameState::SinglePlayer), cleanup_system::<cleanup::SinglePlayer>)
.insert_resource(DebugFlag::<EnteredMainMenu>::new())
.insert_resource(Assets::<VoxelMaterial>::default())
.insert_resource(ClearColor(Color::rgb(0.2,0.2,0.2)))
.insert_resource(Msaa::Off)
.run();
}
When I fudge my shader path I get this: 2024-06-14T04:04:11.550166Z ERROR bevy_asset::server: Path not found: bevy_water/underwater2.wgsl
But it doesn't panic. It keeps going but doesn't render that object.
Oh, do you have this? .add_plugins(MaterialPlugin::<VoxelMaterial>::default())
No, I don't.
When I put garbage in my shader I get this:
2024-06-14T04:05:14.418854Z ERROR bevy_render::render_resource::pipeline_cache: failed to process shader:
error: expected global item ('struct', 'const', 'var', 'alias', ';', 'fn') or the end of the file, found 'laskjdflkjasd'
┌─ embedded://bevy_water/underwater.wgsl:36:1
│
36 │ laskjdflkjasd
│ ^^^^^^^^^^^^^ expected global item ('struct', 'const', 'var', 'alias', ';', 'fn') or the end of the file
│
= expected global item ('struct', 'const', 'var', 'alias', ';', 'fn') or the end of the file, found 'laskjdflkjasd'
Try that.
Woohoo! It's working now. Thanks!
I think your original shader code would have worked too.
I'm not sure how to mark this as resolved.
Not sure either. Saying it works is good enough for me. It’s good to leave here though. Good breadcrumbs for everybody else.
You’re welcome.
So if you're running with RUST_LOG=error ... you'll see the asset_server complaining about missing shaders.
you have to check the source unfortunately 😦 this project has a script that at least slaps all the functions into one markdown doc for you https://github.com/alphastrata/shadplay/blob/main/scripts/make-bevy-shaderdoc.py which maybe? makes it more searchable