Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/3d/lines.rs
6592 views
1
//! Create a custom material to draw basic lines in 3D
2
3
use 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
15
/// This example uses a shader source file from the assets subdirectory
16
const SHADER_ASSET_PATH: &str = "shaders/line_material.wgsl";
17
18
fn main() {
19
App::new()
20
.add_plugins((DefaultPlugins, MaterialPlugin::<LineMaterial>::default()))
21
.add_systems(Startup, setup)
22
.run();
23
}
24
25
fn setup(
26
mut commands: Commands,
27
mut meshes: ResMut<Assets<Mesh>>,
28
mut materials: ResMut<Assets<LineMaterial>>,
29
) {
30
// Spawn a list of lines with start and end points for each lines
31
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
// Spawn a line strip that goes from point to point
45
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
// camera
60
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)]
67
struct LineMaterial {
68
#[uniform(0)]
69
color: LinearRgba,
70
}
71
72
impl 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
// This is the important part to tell bevy to render this material as a line between vertices
84
descriptor.primitive.polygon_mode = PolygonMode::Line;
85
Ok(())
86
}
87
}
88
89
/// A list of lines with a start and end position
90
#[derive(Debug, Clone)]
91
struct LineList {
92
lines: Vec<(Vec3, Vec3)>,
93
}
94
95
impl 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
// This tells wgpu that the positions are list of lines
101
// where every pair is a start and end point
102
PrimitiveTopology::LineList,
103
RenderAssetUsages::RENDER_WORLD,
104
)
105
// Add the vertices positions as an attribute
106
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, vertices)
107
}
108
}
109
110
/// A list of points that will have a line drawn between each consecutive points
111
#[derive(Debug, Clone)]
112
struct LineStrip {
113
points: Vec<Vec3>,
114
}
115
116
impl From<LineStrip> for Mesh {
117
fn from(line: LineStrip) -> Self {
118
Mesh::new(
119
// This tells wgpu that the positions are a list of points
120
// where a line will be drawn between each consecutive point
121
PrimitiveTopology::LineStrip,
122
RenderAssetUsages::RENDER_WORLD,
123
)
124
// Add the point positions as an attribute
125
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, line.points)
126
}
127
}
128
129