|
| 1 | +use bevy::{ |
| 2 | + prelude::*, |
| 3 | + render::{ |
| 4 | + mesh::{shape, VertexAttributeValues}, |
| 5 | + pipeline::{DynamicBinding, PipelineDescriptor, PipelineSpecialization, RenderPipeline}, |
| 6 | + render_graph::{base, AssetRenderResourcesNode, RenderGraph}, |
| 7 | + renderer::RenderResources, |
| 8 | + shader::{ShaderStage, ShaderStages}, |
| 9 | + }, |
| 10 | + type_registry::TypeUuid, |
| 11 | +}; |
| 12 | + |
| 13 | +/// This example illustrates how to add a custom attribute to a mesh and use it in a custom shader. |
| 14 | +fn main() { |
| 15 | + App::build() |
| 16 | + .add_default_plugins() |
| 17 | + .add_asset::<MyMaterialWithVertexColorSupport>() |
| 18 | + .add_startup_system(setup.system()) |
| 19 | + .run(); |
| 20 | +} |
| 21 | + |
| 22 | +#[derive(RenderResources, Default, TypeUuid)] |
| 23 | +#[uuid = "0320b9b8-b3a3-4baa-8bfa-c94008177b17"] |
| 24 | +struct MyMaterialWithVertexColorSupport {} |
| 25 | + |
| 26 | +const VERTEX_SHADER: &str = r#" |
| 27 | +#version 450 |
| 28 | +layout(location = 0) in vec3 Vertex_Position; |
| 29 | +layout(location = 1) in vec3 Vertex_Color; |
| 30 | +layout(location = 0) out vec3 v_color; |
| 31 | +
|
| 32 | +layout(set = 0, binding = 0) uniform Camera { |
| 33 | + mat4 ViewProj; |
| 34 | +}; |
| 35 | +layout(set = 1, binding = 0) uniform Transform { |
| 36 | + mat4 Model; |
| 37 | +}; |
| 38 | +void main() { |
| 39 | + gl_Position = ViewProj * Model * vec4(Vertex_Position, 1.0); |
| 40 | + v_color = Vertex_Color; |
| 41 | +} |
| 42 | +"#; |
| 43 | + |
| 44 | +const FRAGMENT_SHADER: &str = r#" |
| 45 | +#version 450 |
| 46 | +layout(location = 0) out vec4 o_Target; |
| 47 | +layout(location = 0) in vec3 v_color; |
| 48 | +
|
| 49 | +void main() { |
| 50 | + o_Target = vec4(v_color, 1.0); |
| 51 | +} |
| 52 | +"#; |
| 53 | + |
| 54 | +fn setup( |
| 55 | + mut commands: Commands, |
| 56 | + mut pipelines: ResMut<Assets<PipelineDescriptor>>, |
| 57 | + mut shaders: ResMut<Assets<Shader>>, |
| 58 | + mut meshes: ResMut<Assets<Mesh>>, |
| 59 | + mut materials: ResMut<Assets<MyMaterialWithVertexColorSupport>>, |
| 60 | + mut render_graph: ResMut<RenderGraph>, |
| 61 | +) { |
| 62 | + // Create a new shader pipeline |
| 63 | + let pipeline_handle = pipelines.add(PipelineDescriptor::default_config(ShaderStages { |
| 64 | + vertex: shaders.add(Shader::from_glsl(ShaderStage::Vertex, VERTEX_SHADER)), |
| 65 | + fragment: Some(shaders.add(Shader::from_glsl(ShaderStage::Fragment, FRAGMENT_SHADER))), |
| 66 | + })); |
| 67 | + |
| 68 | + // Add an AssetRenderResourcesNode to our Render Graph. This will bind MyMaterialWithVertexColorSupport resources to our shader |
| 69 | + render_graph.add_system_node( |
| 70 | + "my_material_with_vertex_color_support", |
| 71 | + AssetRenderResourcesNode::<MyMaterialWithVertexColorSupport>::new(true), |
| 72 | + ); |
| 73 | + |
| 74 | + // Add a Render Graph edge connecting our new "my_material" node to the main pass node. This ensures "my_material" runs before the main pass |
| 75 | + render_graph |
| 76 | + .add_node_edge( |
| 77 | + "my_material_with_vertex_color_support", |
| 78 | + base::node::MAIN_PASS, |
| 79 | + ) |
| 80 | + .unwrap(); |
| 81 | + |
| 82 | + // Create a new material |
| 83 | + let material = materials.add(MyMaterialWithVertexColorSupport {}); |
| 84 | + |
| 85 | + // create a generic cube |
| 86 | + let mut cube_with_vertex_colors = Mesh::from(shape::Cube { size: 1.0 }); |
| 87 | + |
| 88 | + // insert our custom color attribute with some nice colors! |
| 89 | + cube_with_vertex_colors.set_attribute( |
| 90 | + // name of the attribute |
| 91 | + "Vertex_Color", |
| 92 | + // the vertex attributes, represented by `VertexAttributeValues` |
| 93 | + // NOTE: the attribute count has to be consistent across all attributes, otherwise bevy will panic. |
| 94 | + VertexAttributeValues::from(vec![ |
| 95 | + // top |
| 96 | + [0.79, 0.73, 0.07], |
| 97 | + [0.74, 0.14, 0.29], |
| 98 | + [0.08, 0.55, 0.74], |
| 99 | + [0.20, 0.27, 0.29], |
| 100 | + // bottom |
| 101 | + [0.79, 0.73, 0.07], |
| 102 | + [0.74, 0.14, 0.29], |
| 103 | + [0.08, 0.55, 0.74], |
| 104 | + [0.20, 0.27, 0.29], |
| 105 | + // right |
| 106 | + [0.79, 0.73, 0.07], |
| 107 | + [0.74, 0.14, 0.29], |
| 108 | + [0.08, 0.55, 0.74], |
| 109 | + [0.20, 0.27, 0.29], |
| 110 | + // left |
| 111 | + [0.79, 0.73, 0.07], |
| 112 | + [0.74, 0.14, 0.29], |
| 113 | + [0.08, 0.55, 0.74], |
| 114 | + [0.20, 0.27, 0.29], |
| 115 | + // front |
| 116 | + [0.79, 0.73, 0.07], |
| 117 | + [0.74, 0.14, 0.29], |
| 118 | + [0.08, 0.55, 0.74], |
| 119 | + [0.20, 0.27, 0.29], |
| 120 | + // back |
| 121 | + [0.79, 0.73, 0.07], |
| 122 | + [0.74, 0.14, 0.29], |
| 123 | + [0.08, 0.55, 0.74], |
| 124 | + [0.20, 0.27, 0.29], |
| 125 | + ]), |
| 126 | + ); |
| 127 | + // Setup our world |
| 128 | + commands |
| 129 | + // cube |
| 130 | + .spawn(MeshComponents { |
| 131 | + mesh: meshes.add(cube_with_vertex_colors), // use our cube with vertex colors |
| 132 | + render_pipelines: RenderPipelines::from_pipelines(vec![RenderPipeline::specialized( |
| 133 | + pipeline_handle, |
| 134 | + // NOTE: in the future you wont need to manually declare dynamic bindings |
| 135 | + PipelineSpecialization { |
| 136 | + dynamic_bindings: vec![ |
| 137 | + // Transform |
| 138 | + DynamicBinding { |
| 139 | + bind_group: 1, |
| 140 | + binding: 0, |
| 141 | + }, |
| 142 | + ], |
| 143 | + ..Default::default() |
| 144 | + }, |
| 145 | + )]), |
| 146 | + transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)), |
| 147 | + ..Default::default() |
| 148 | + }) |
| 149 | + .with(material) |
| 150 | + // camera |
| 151 | + .spawn(Camera3dComponents { |
| 152 | + transform: Transform::from_translation(Vec3::new(3.0, 5.0, -8.0)) |
| 153 | + .looking_at(Vec3::default(), Vec3::unit_y()), |
| 154 | + ..Default::default() |
| 155 | + }); |
| 156 | +} |
0 commit comments