forked from bevyengine/bevy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lines.rs
141 lines (125 loc) · 4.34 KB
/
lines.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
//! Create a custom material to draw basic lines in 3D
use bevy::{
pbr::{MaterialPipeline, MaterialPipelineKey},
prelude::*,
reflect::TypeUuid,
render::{
mesh::{MeshVertexBufferLayout, PrimitiveTopology},
render_resource::{
AsBindGroup, PolygonMode, RenderPipelineDescriptor, ShaderRef,
SpecializedMeshPipelineError,
},
},
};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugin(MaterialPlugin::<LineMaterial>::default())
.add_startup_system(setup)
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<LineMaterial>>,
) {
// Spawn a list of lines with start and end points for each lines
commands.spawn().insert_bundle(MaterialMeshBundle {
mesh: meshes.add(Mesh::from(LineList {
lines: vec![
(Vec3::ZERO, Vec3::new(1.0, 1.0, 0.0)),
(Vec3::new(1.0, 1.0, 0.0), Vec3::new(1.0, 0.0, 0.0)),
],
})),
transform: Transform::from_xyz(-1.5, 0.0, 0.0),
material: materials.add(LineMaterial {
color: Color::GREEN,
}),
..default()
});
// Spawn a line strip that goes from point to point
commands.spawn().insert_bundle(MaterialMeshBundle {
mesh: meshes.add(Mesh::from(LineStrip {
points: vec![
Vec3::ZERO,
Vec3::new(1.0, 1.0, 0.0),
Vec3::new(1.0, 0.0, 0.0),
],
})),
transform: Transform::from_xyz(0.5, 0.0, 0.0),
material: materials.add(LineMaterial { color: Color::BLUE }),
..default()
});
// camera
commands.spawn_bundle(Camera3dBundle {
transform: Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
..default()
});
}
#[derive(Default, AsBindGroup, TypeUuid, Debug, Clone)]
#[uuid = "050ce6ac-080a-4d8c-b6b5-b5bab7560d8f"]
struct LineMaterial {
#[uniform(0)]
color: Color,
}
impl Material for LineMaterial {
fn fragment_shader() -> ShaderRef {
"shaders/line_material.wgsl".into()
}
fn specialize(
_pipeline: &MaterialPipeline<Self>,
descriptor: &mut RenderPipelineDescriptor,
_layout: &MeshVertexBufferLayout,
_key: MaterialPipelineKey<Self>,
) -> Result<(), SpecializedMeshPipelineError> {
// This is the important part to tell bevy to render this material as a line between vertices
descriptor.primitive.polygon_mode = PolygonMode::Line;
Ok(())
}
}
/// A list of lines with a start and end position
#[derive(Debug, Clone)]
pub struct LineList {
pub lines: Vec<(Vec3, Vec3)>,
}
impl From<LineList> for Mesh {
fn from(line: LineList) -> Self {
let mut vertices = vec![];
let mut normals = vec![];
for (start, end) in line.lines {
vertices.push(start.to_array());
vertices.push(end.to_array());
normals.push(Vec3::ZERO.to_array());
normals.push(Vec3::ZERO.to_array());
}
// This tells wgpu that the positions are list of lines
// where every pair is a start and end point
let mut mesh = Mesh::new(PrimitiveTopology::LineList);
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertices);
// Normals are currently required by bevy, but they aren't used by the [`LineMaterial`]
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
mesh
}
}
/// A list of points that will have a line drawn between each consecutive points
#[derive(Debug, Clone)]
pub struct LineStrip {
pub points: Vec<Vec3>,
}
impl From<LineStrip> for Mesh {
fn from(line: LineStrip) -> Self {
let mut vertices = vec![];
let mut normals = vec![];
for pos in line.points {
vertices.push(pos.to_array());
normals.push(Vec3::ZERO.to_array());
}
// This tells wgpu that the positions are a list of points
// where a line will be drawn between each consecutive point
let mut mesh = Mesh::new(PrimitiveTopology::LineStrip);
mesh.insert_attribute(Mesh::ATTRIBUTE_POSITION, vertices);
// Normals are currently required by bevy, but they aren't used by the [`LineMaterial`]
mesh.insert_attribute(Mesh::ATTRIBUTE_NORMAL, normals);
mesh
}
}