1use bevy::{
4 asset::RenderAssetUsages,
5 mesh::{MeshVertexBufferLayoutRef, PrimitiveTopology},
6 pbr::{MaterialPipeline, MaterialPipelineKey},
7 prelude::*,
8 reflect::TypePath,
9 render::render_resource::{
10 AsBindGroup, PolygonMode, RenderPipelineDescriptor, SpecializedMeshPipelineError,
11 },
12 shader::ShaderRef,
13};
14
15const SHADER_ASSET_PATH: &str = "shaders/line_material.wgsl";
17
18fn main() {
19 App::new()
20 .add_plugins((DefaultPlugins, MaterialPlugin::<LineMaterial>::default()))
21 .add_systems(Startup, setup)
22 .run();
23}
24
25fn setup(
26 mut commands: Commands,
27 mut meshes: ResMut<Assets<Mesh>>,
28 mut materials: ResMut<Assets<LineMaterial>>,
29) {
30 commands.spawn((
32 Mesh3d(meshes.add(LineList {
33 lines: vec![
34 (Vec3::ZERO, Vec3::new(1.0, 1.0, 0.0)),
35 (Vec3::new(1.0, 1.0, 0.0), Vec3::new(1.0, 0.0, 0.0)),
36 ],
37 })),
38 MeshMaterial3d(materials.add(LineMaterial {
39 color: LinearRgba::GREEN,
40 })),
41 Transform::from_xyz(-1.5, 0.0, 0.0),
42 ));
43
44 commands.spawn((
46 Mesh3d(meshes.add(LineStrip {
47 points: vec![
48 Vec3::ZERO,
49 Vec3::new(1.0, 1.0, 0.0),
50 Vec3::new(1.0, 0.0, 0.0),
51 ],
52 })),
53 MeshMaterial3d(materials.add(LineMaterial {
54 color: LinearRgba::BLUE,
55 })),
56 Transform::from_xyz(0.5, 0.0, 0.0),
57 ));
58
59 commands.spawn((
61 Camera3d::default(),
62 Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
63 ));
64}
65
66#[derive(Asset, TypePath, Default, AsBindGroup, Debug, Clone)]
67struct LineMaterial {
68 #[uniform(0)]
69 color: LinearRgba,
70}
71
72impl Material for LineMaterial {
73 fn fragment_shader() -> ShaderRef {
74 SHADER_ASSET_PATH.into()
75 }
76
77 fn specialize(
78 _pipeline: &MaterialPipeline,
79 descriptor: &mut RenderPipelineDescriptor,
80 _layout: &MeshVertexBufferLayoutRef,
81 _key: MaterialPipelineKey<Self>,
82 ) -> Result<(), SpecializedMeshPipelineError> {
83 descriptor.primitive.polygon_mode = PolygonMode::Line;
85 Ok(())
86 }
87}
88
89#[derive(Debug, Clone)]
91struct LineList {
92 lines: Vec<(Vec3, Vec3)>,
93}
94
95impl From<LineList> for Mesh {
96 fn from(line: LineList) -> Self {
97 let vertices: Vec<_> = line.lines.into_iter().flat_map(|(a, b)| [a, b]).collect();
98
99 Mesh::new(
100 PrimitiveTopology::LineList,
103 RenderAssetUsages::RENDER_WORLD,
104 )
105 .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vertices)
107 }
108}
109
110#[derive(Debug, Clone)]
112struct LineStrip {
113 points: Vec<Vec3>,
114}
115
116impl From<LineStrip> for Mesh {
117 fn from(line: LineStrip) -> Self {
118 Mesh::new(
119 PrimitiveTopology::LineStrip,
122 RenderAssetUsages::RENDER_WORLD,
123 )
124 .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, line.points)
126 }
127}