#[repr(C)]pub struct Vec3 {
pub x: f32,
pub y: f32,
pub z: f32,
}
Expand description
A 3-dimensional vector.
Fields§
§x: f32
§y: f32
§z: f32
Implementations§
Source§impl Vec3
impl Vec3
Sourcepub const NEG_INFINITY: Vec3
pub const NEG_INFINITY: Vec3
All f32::NEG_INFINITY
.
Sourcepub const fn new(x: f32, y: f32, z: f32) -> Vec3
pub const fn new(x: f32, y: f32, z: f32) -> Vec3
Creates a new vector.
Examples found in repository?
46const DISTANCE_BETWEEN_SHAPES: Vec3 = Vec3::new(2.0, 0.0, 0.0);
47
48/// Maximum amount of points allowed to be present.
49/// Should be set such that it does not cause large amounts of lag when reached.
50const MAX_POINTS: usize = 3000; // TODO: Test wasm and add a wasm-specific-bound
51
52/// How many points should be spawned each frame
53const POINTS_PER_FRAME: usize = 3;
54
55/// Color used for the inside points
56const INSIDE_POINT_COLOR: LinearRgba = LinearRgba::rgb(0.855, 1.1, 0.01);
57/// Color used for the points on the boundary
58const BOUNDARY_POINT_COLOR: LinearRgba = LinearRgba::rgb(0.08, 0.2, 0.90);
59
60/// Time (in seconds) for the spawning/despawning animation
61const ANIMATION_TIME: f32 = 1.0;
62
63/// Color for the sky and the sky-light
64const SKY_COLOR: Color = Color::srgb(0.02, 0.06, 0.15);
65
66const SMALL_3D: f32 = 0.5;
67const BIG_3D: f32 = 1.0;
68
69// primitives
70
71const CUBOID: Cuboid = Cuboid {
72 half_size: Vec3::new(SMALL_3D, BIG_3D, SMALL_3D),
73};
74
75const SPHERE: Sphere = Sphere {
76 radius: 1.5 * SMALL_3D,
77};
78
79const TRIANGLE_3D: Triangle3d = Triangle3d {
80 vertices: [
81 Vec3::new(BIG_3D, -BIG_3D * 0.5, 0.0),
82 Vec3::new(0.0, BIG_3D, 0.0),
83 Vec3::new(-BIG_3D, -BIG_3D * 0.5, 0.0),
84 ],
85};
86
87const CAPSULE_3D: Capsule3d = Capsule3d {
88 radius: SMALL_3D,
89 half_length: SMALL_3D,
90};
91
92const CYLINDER: Cylinder = Cylinder {
93 radius: SMALL_3D,
94 half_height: SMALL_3D,
95};
96
97const TETRAHEDRON: Tetrahedron = Tetrahedron {
98 vertices: [
99 Vec3::new(-BIG_3D, -BIG_3D * 0.67, BIG_3D * 0.5),
100 Vec3::new(BIG_3D, -BIG_3D * 0.67, BIG_3D * 0.5),
101 Vec3::new(0.0, -BIG_3D * 0.67, -BIG_3D * 1.17),
102 Vec3::new(0.0, BIG_3D, 0.0),
103 ],
104};
More examples
21const BALL_STARTING_POSITION: Vec3 = Vec3::new(0.0, -50.0, 1.0);
22const BALL_DIAMETER: f32 = 30.;
23const BALL_SPEED: f32 = 400.0;
24const INITIAL_BALL_DIRECTION: Vec2 = Vec2::new(0.5, -0.5);
25
26const WALL_THICKNESS: f32 = 10.0;
27// x coordinates
28const LEFT_WALL: f32 = -450.;
29const RIGHT_WALL: f32 = 450.;
30// y coordinates
31const BOTTOM_WALL: f32 = -300.;
32const TOP_WALL: f32 = 300.;
33
34const BRICK_SIZE: Vec2 = Vec2::new(100., 30.);
35// These values are exact
36const GAP_BETWEEN_PADDLE_AND_BRICKS: f32 = 270.0;
37const GAP_BETWEEN_BRICKS: f32 = 5.0;
38// These values are lower bounds, as the number of bricks is computed
39const GAP_BETWEEN_BRICKS_AND_CEILING: f32 = 20.0;
40const GAP_BETWEEN_BRICKS_AND_SIDES: f32 = 20.0;
41
42const SCOREBOARD_FONT_SIZE: f32 = 33.0;
43const SCOREBOARD_TEXT_PADDING: Val = Val::Px(5.0);
44
45const BACKGROUND_COLOR: Color = Color::srgb(0.9, 0.9, 0.9);
46const PADDLE_COLOR: Color = Color::srgb(0.3, 0.3, 0.7);
47const BALL_COLOR: Color = Color::srgb(1.0, 0.5, 0.5);
48const BRICK_COLOR: Color = Color::srgb(0.5, 0.5, 1.0);
49const WALL_COLOR: Color = Color::srgb(0.8, 0.8, 0.8);
50const TEXT_COLOR: Color = Color::srgb(0.5, 0.5, 1.0);
51const SCORE_COLOR: Color = Color::srgb(1.0, 0.5, 0.5);
52
53fn main() {
54 App::new()
55 .add_plugins(DefaultPlugins)
56 .add_plugins(
57 stepping::SteppingPlugin::default()
58 .add_schedule(Update)
59 .add_schedule(FixedUpdate)
60 .at(Val::Percent(35.0), Val::Percent(50.0)),
61 )
62 .insert_resource(Score(0))
63 .insert_resource(ClearColor(BACKGROUND_COLOR))
64 .add_event::<CollisionEvent>()
65 .add_systems(Startup, setup)
66 // Add our gameplay simulation systems to the fixed timestep schedule
67 // which runs at 64 Hz by default
68 .add_systems(
69 FixedUpdate,
70 (
71 apply_velocity,
72 move_paddle,
73 check_for_collisions,
74 play_collision_sound,
75 )
76 // `chain`ing systems together runs them in order
77 .chain(),
78 )
79 .add_systems(Update, update_scoreboard)
80 .run();
81}
82
83#[derive(Component)]
84struct Paddle;
85
86#[derive(Component)]
87struct Ball;
88
89#[derive(Component, Deref, DerefMut)]
90struct Velocity(Vec2);
91
92#[derive(Event, Default)]
93struct CollisionEvent;
94
95#[derive(Component)]
96struct Brick;
97
98#[derive(Resource, Deref)]
99struct CollisionSound(Handle<AudioSource>);
100
101// Default must be implemented to define this as a required component for the Wall component below
102#[derive(Component, Default)]
103struct Collider;
104
105// This is a collection of the components that define a "Wall" in our game
106#[derive(Component)]
107#[require(Sprite, Transform, Collider)]
108struct Wall;
109
110/// Which side of the arena is this wall located on?
111enum WallLocation {
112 Left,
113 Right,
114 Bottom,
115 Top,
116}
117
118impl WallLocation {
119 /// Location of the *center* of the wall, used in `transform.translation()`
120 fn position(&self) -> Vec2 {
121 match self {
122 WallLocation::Left => Vec2::new(LEFT_WALL, 0.),
123 WallLocation::Right => Vec2::new(RIGHT_WALL, 0.),
124 WallLocation::Bottom => Vec2::new(0., BOTTOM_WALL),
125 WallLocation::Top => Vec2::new(0., TOP_WALL),
126 }
127 }
128
129 /// (x, y) dimensions of the wall, used in `transform.scale()`
130 fn size(&self) -> Vec2 {
131 let arena_height = TOP_WALL - BOTTOM_WALL;
132 let arena_width = RIGHT_WALL - LEFT_WALL;
133 // Make sure we haven't messed up our constants
134 assert!(arena_height > 0.0);
135 assert!(arena_width > 0.0);
136
137 match self {
138 WallLocation::Left | WallLocation::Right => {
139 Vec2::new(WALL_THICKNESS, arena_height + WALL_THICKNESS)
140 }
141 WallLocation::Bottom | WallLocation::Top => {
142 Vec2::new(arena_width + WALL_THICKNESS, WALL_THICKNESS)
143 }
144 }
145 }
146}
147
148impl Wall {
149 // This "builder method" allows us to reuse logic across our wall entities,
150 // making our code easier to read and less prone to bugs when we change the logic
151 // Notice the use of Sprite and Transform alongside Wall, overwriting the default values defined for the required components
152 fn new(location: WallLocation) -> (Wall, Sprite, Transform) {
153 (
154 Wall,
155 Sprite::from_color(WALL_COLOR, Vec2::ONE),
156 Transform {
157 // We need to convert our Vec2 into a Vec3, by giving it a z-coordinate
158 // This is used to determine the order of our sprites
159 translation: location.position().extend(0.0),
160 // The z-scale of 2D objects must always be 1.0,
161 // or their ordering will be affected in surprising ways.
162 // See https://github.com/bevyengine/bevy/issues/4149
163 scale: location.size().extend(1.0),
164 ..default()
165 },
166 )
167 }
168}
169
170// This resource tracks the game's score
171#[derive(Resource, Deref, DerefMut)]
172struct Score(usize);
173
174#[derive(Component)]
175struct ScoreboardUi;
176
177// Add the game's entities to our world
178fn setup(
179 mut commands: Commands,
180 mut meshes: ResMut<Assets<Mesh>>,
181 mut materials: ResMut<Assets<ColorMaterial>>,
182 asset_server: Res<AssetServer>,
183) {
184 // Camera
185 commands.spawn(Camera2d);
186
187 // Sound
188 let ball_collision_sound = asset_server.load("sounds/breakout_collision.ogg");
189 commands.insert_resource(CollisionSound(ball_collision_sound));
190
191 // Paddle
192 let paddle_y = BOTTOM_WALL + GAP_BETWEEN_PADDLE_AND_FLOOR;
193
194 commands.spawn((
195 Sprite::from_color(PADDLE_COLOR, Vec2::ONE),
196 Transform {
197 translation: Vec3::new(0.0, paddle_y, 0.0),
198 scale: PADDLE_SIZE.extend(1.0),
199 ..default()
200 },
201 Paddle,
202 Collider,
203 ));
204
205 // Ball
206 commands.spawn((
207 Mesh2d(meshes.add(Circle::default())),
208 MeshMaterial2d(materials.add(BALL_COLOR)),
209 Transform::from_translation(BALL_STARTING_POSITION)
210 .with_scale(Vec2::splat(BALL_DIAMETER).extend(1.)),
211 Ball,
212 Velocity(INITIAL_BALL_DIRECTION.normalize() * BALL_SPEED),
213 ));
214
215 // Scoreboard
216 commands.spawn((
217 Text::new("Score: "),
218 TextFont {
219 font_size: SCOREBOARD_FONT_SIZE,
220 ..default()
221 },
222 TextColor(TEXT_COLOR),
223 ScoreboardUi,
224 Node {
225 position_type: PositionType::Absolute,
226 top: SCOREBOARD_TEXT_PADDING,
227 left: SCOREBOARD_TEXT_PADDING,
228 ..default()
229 },
230 children![(
231 TextSpan::default(),
232 TextFont {
233 font_size: SCOREBOARD_FONT_SIZE,
234 ..default()
235 },
236 TextColor(SCORE_COLOR),
237 )],
238 ));
239
240 // Walls
241 commands.spawn(Wall::new(WallLocation::Left));
242 commands.spawn(Wall::new(WallLocation::Right));
243 commands.spawn(Wall::new(WallLocation::Bottom));
244 commands.spawn(Wall::new(WallLocation::Top));
245
246 // Bricks
247 let total_width_of_bricks = (RIGHT_WALL - LEFT_WALL) - 2. * GAP_BETWEEN_BRICKS_AND_SIDES;
248 let bottom_edge_of_bricks = paddle_y + GAP_BETWEEN_PADDLE_AND_BRICKS;
249 let total_height_of_bricks = TOP_WALL - bottom_edge_of_bricks - GAP_BETWEEN_BRICKS_AND_CEILING;
250
251 assert!(total_width_of_bricks > 0.0);
252 assert!(total_height_of_bricks > 0.0);
253
254 // Given the space available, compute how many rows and columns of bricks we can fit
255 let n_columns = (total_width_of_bricks / (BRICK_SIZE.x + GAP_BETWEEN_BRICKS)).floor() as usize;
256 let n_rows = (total_height_of_bricks / (BRICK_SIZE.y + GAP_BETWEEN_BRICKS)).floor() as usize;
257 let n_vertical_gaps = n_columns - 1;
258
259 // Because we need to round the number of columns,
260 // the space on the top and sides of the bricks only captures a lower bound, not an exact value
261 let center_of_bricks = (LEFT_WALL + RIGHT_WALL) / 2.0;
262 let left_edge_of_bricks = center_of_bricks
263 // Space taken up by the bricks
264 - (n_columns as f32 / 2.0 * BRICK_SIZE.x)
265 // Space taken up by the gaps
266 - n_vertical_gaps as f32 / 2.0 * GAP_BETWEEN_BRICKS;
267
268 // In Bevy, the `translation` of an entity describes the center point,
269 // not its bottom-left corner
270 let offset_x = left_edge_of_bricks + BRICK_SIZE.x / 2.;
271 let offset_y = bottom_edge_of_bricks + BRICK_SIZE.y / 2.;
272
273 for row in 0..n_rows {
274 for column in 0..n_columns {
275 let brick_position = Vec2::new(
276 offset_x + column as f32 * (BRICK_SIZE.x + GAP_BETWEEN_BRICKS),
277 offset_y + row as f32 * (BRICK_SIZE.y + GAP_BETWEEN_BRICKS),
278 );
279
280 // brick
281 commands.spawn((
282 Sprite {
283 color: BRICK_COLOR,
284 ..default()
285 },
286 Transform {
287 translation: brick_position.extend(0.0),
288 scale: Vec3::new(BRICK_SIZE.x, BRICK_SIZE.y, 1.0),
289 ..default()
290 },
291 Brick,
292 Collider,
293 ));
294 }
295 }
296}
153const CUBOID: Cuboid = Cuboid {
154 half_size: Vec3::new(BIG_3D, SMALL_3D, BIG_3D),
155};
156
157const CIRCLE: Circle = Circle { radius: BIG_2D };
158const SPHERE: Sphere = Sphere { radius: BIG_3D };
159
160const ELLIPSE: Ellipse = Ellipse {
161 half_size: Vec2::new(BIG_2D, SMALL_2D),
162};
163
164const TRIANGLE_2D: Triangle2d = Triangle2d {
165 vertices: [
166 Vec2::new(BIG_2D, 0.0),
167 Vec2::new(0.0, BIG_2D),
168 Vec2::new(-BIG_2D, 0.0),
169 ],
170};
171
172const TRIANGLE_3D: Triangle3d = Triangle3d {
173 vertices: [
174 Vec3::new(BIG_3D, 0.0, 0.0),
175 Vec3::new(0.0, BIG_3D, 0.0),
176 Vec3::new(-BIG_3D, 0.0, 0.0),
177 ],
178};
179
180const PLANE_2D: Plane2d = Plane2d { normal: Dir2::Y };
181const PLANE_3D: Plane3d = Plane3d {
182 normal: Dir3::Y,
183 half_size: Vec2::new(BIG_3D, BIG_3D),
184};
185
186const LINE2D: Line2d = Line2d { direction: Dir2::X };
187const LINE3D: Line3d = Line3d { direction: Dir3::X };
188
189const SEGMENT_2D: Segment2d = Segment2d {
190 vertices: [Vec2::new(-BIG_2D / 2., 0.), Vec2::new(BIG_2D / 2., 0.)],
191};
192
193const SEGMENT_3D: Segment3d = Segment3d {
194 vertices: [
195 Vec3::new(-BIG_3D / 2., 0., 0.),
196 Vec3::new(BIG_3D / 2., 0., 0.),
197 ],
198};
199
200const POLYLINE_2D: Polyline2d<4> = Polyline2d {
201 vertices: [
202 Vec2::new(-BIG_2D, -SMALL_2D),
203 Vec2::new(-SMALL_2D, SMALL_2D),
204 Vec2::new(SMALL_2D, -SMALL_2D),
205 Vec2::new(BIG_2D, SMALL_2D),
206 ],
207};
208const POLYLINE_3D: Polyline3d<4> = Polyline3d {
209 vertices: [
210 Vec3::new(-BIG_3D, -SMALL_3D, -SMALL_3D),
211 Vec3::new(SMALL_3D, SMALL_3D, 0.0),
212 Vec3::new(-SMALL_3D, -SMALL_3D, 0.0),
213 Vec3::new(BIG_3D, SMALL_3D, SMALL_3D),
214 ],
215};
216
217const POLYGON_2D: Polygon<5> = Polygon {
218 vertices: [
219 Vec2::new(-BIG_2D, -SMALL_2D),
220 Vec2::new(BIG_2D, -SMALL_2D),
221 Vec2::new(BIG_2D, SMALL_2D),
222 Vec2::new(0.0, 0.0),
223 Vec2::new(-BIG_2D, SMALL_2D),
224 ],
225};
226
227const REGULAR_POLYGON: RegularPolygon = RegularPolygon {
228 circumcircle: Circle { radius: BIG_2D },
229 sides: 5,
230};
231
232const CAPSULE_2D: Capsule2d = Capsule2d {
233 radius: SMALL_2D,
234 half_length: SMALL_2D,
235};
236const CAPSULE_3D: Capsule3d = Capsule3d {
237 radius: SMALL_3D,
238 half_length: SMALL_3D,
239};
240
241const CYLINDER: Cylinder = Cylinder {
242 radius: SMALL_3D,
243 half_height: SMALL_3D,
244};
245
246const CONE: Cone = Cone {
247 radius: BIG_3D,
248 height: BIG_3D,
249};
250
251const CONICAL_FRUSTUM: ConicalFrustum = ConicalFrustum {
252 radius_top: BIG_3D,
253 radius_bottom: SMALL_3D,
254 height: BIG_3D,
255};
256
257const ANNULUS: Annulus = Annulus {
258 inner_circle: Circle { radius: SMALL_2D },
259 outer_circle: Circle { radius: BIG_2D },
260};
261
262const TORUS: Torus = Torus {
263 minor_radius: SMALL_3D / 2.0,
264 major_radius: SMALL_3D * 1.5,
265};
266
267const TETRAHEDRON: Tetrahedron = Tetrahedron {
268 vertices: [
269 Vec3::new(-BIG_3D, 0.0, 0.0),
270 Vec3::new(BIG_3D, 0.0, 0.0),
271 Vec3::new(0.0, 0.0, -BIG_3D * 1.67),
272 Vec3::new(0.0, BIG_3D * 1.67, -BIG_3D * 0.5),
273 ],
274};
275
276const ARC: Arc2d = Arc2d {
277 radius: BIG_2D,
278 half_angle: std::f32::consts::FRAC_PI_4,
279};
280
281const CIRCULAR_SECTOR: CircularSector = CircularSector {
282 arc: Arc2d {
283 radius: BIG_2D,
284 half_angle: std::f32::consts::FRAC_PI_4,
285 },
286};
287
288const CIRCULAR_SEGMENT: CircularSegment = CircularSegment {
289 arc: Arc2d {
290 radius: BIG_2D,
291 half_angle: std::f32::consts::FRAC_PI_4,
292 },
293};
294
295fn setup_cameras(mut commands: Commands) {
296 let start_in_2d = true;
297 let make_camera = |is_active| Camera {
298 is_active,
299 ..Default::default()
300 };
301
302 commands.spawn((Camera2d, make_camera(start_in_2d)));
303
304 commands.spawn((
305 Camera3d::default(),
306 make_camera(!start_in_2d),
307 Transform::from_xyz(0.0, 10.0, 0.0).looking_at(Vec3::ZERO, Vec3::Z),
308 ));
309}
310
311fn setup_ambient_light(mut ambient_light: ResMut<AmbientLight>) {
312 ambient_light.brightness = 50.0;
313}
314
315fn setup_lights(mut commands: Commands) {
316 commands.spawn((
317 PointLight {
318 intensity: 5000.0,
319 ..default()
320 },
321 Transform::from_translation(Vec3::new(-LEFT_RIGHT_OFFSET_3D, 2.0, 0.0))
322 .looking_at(Vec3::new(-LEFT_RIGHT_OFFSET_3D, 0.0, 0.0), Vec3::Y),
323 ));
324}
325
326/// Marker component for header text
327#[derive(Debug, Clone, Component, Default, Reflect)]
328pub struct HeaderText;
329
330/// Marker component for header node
331#[derive(Debug, Clone, Component, Default, Reflect)]
332pub struct HeaderNode;
333
334fn update_active_cameras(
335 state: Res<State<CameraActive>>,
336 camera_2d: Single<(Entity, &mut Camera), With<Camera2d>>,
337 camera_3d: Single<(Entity, &mut Camera), (With<Camera3d>, Without<Camera2d>)>,
338 mut text: Query<&mut UiTargetCamera, With<HeaderNode>>,
339) {
340 let (entity_2d, mut cam_2d) = camera_2d.into_inner();
341 let (entity_3d, mut cam_3d) = camera_3d.into_inner();
342 let is_camera_2d_active = matches!(*state.get(), CameraActive::Dim2);
343
344 cam_2d.is_active = is_camera_2d_active;
345 cam_3d.is_active = !is_camera_2d_active;
346
347 let active_camera = if is_camera_2d_active {
348 entity_2d
349 } else {
350 entity_3d
351 };
352
353 text.iter_mut().for_each(|mut target_camera| {
354 *target_camera = UiTargetCamera(active_camera);
355 });
356}
357
358fn switch_cameras(current: Res<State<CameraActive>>, mut next: ResMut<NextState<CameraActive>>) {
359 let next_state = match current.get() {
360 CameraActive::Dim2 => CameraActive::Dim3,
361 CameraActive::Dim3 => CameraActive::Dim2,
362 };
363 next.set(next_state);
364}
365
366fn setup_text(mut commands: Commands, cameras: Query<(Entity, &Camera)>) {
367 let active_camera = cameras
368 .iter()
369 .find_map(|(entity, camera)| camera.is_active.then_some(entity))
370 .expect("run condition ensures existence");
371 commands.spawn((
372 HeaderNode,
373 Node {
374 justify_self: JustifySelf::Center,
375 top: Val::Px(5.0),
376 ..Default::default()
377 },
378 UiTargetCamera(active_camera),
379 children![(
380 Text::default(),
381 HeaderText,
382 TextLayout::new_with_justify(JustifyText::Center),
383 children![
384 TextSpan::new("Primitive: "),
385 TextSpan(format!("{text}", text = PrimitiveSelected::default())),
386 TextSpan::new("\n\n"),
387 TextSpan::new(
388 "Press 'C' to switch between 2D and 3D mode\n\
389 Press 'Up' or 'Down' to switch to the next/previous primitive",
390 ),
391 TextSpan::new("\n\n"),
392 TextSpan::new("(If nothing is displayed, there's no rendering support yet)",),
393 ]
394 )],
395 ));
396}
397
398fn update_text(
399 primitive_state: Res<State<PrimitiveSelected>>,
400 header: Query<Entity, With<HeaderText>>,
401 mut writer: TextUiWriter,
402) {
403 let new_text = format!("{text}", text = primitive_state.get());
404 header.iter().for_each(|header_text| {
405 if let Some(mut text) = writer.get_text(header_text, 2) {
406 (*text).clone_from(&new_text);
407 };
408 });
409}
410
411fn switch_to_next_primitive(
412 current: Res<State<PrimitiveSelected>>,
413 mut next: ResMut<NextState<PrimitiveSelected>>,
414) {
415 let next_state = current.get().next();
416 next.set(next_state);
417}
418
419fn switch_to_previous_primitive(
420 current: Res<State<PrimitiveSelected>>,
421 mut next: ResMut<NextState<PrimitiveSelected>>,
422) {
423 let next_state = current.get().previous();
424 next.set(next_state);
425}
426
427fn in_mode(active: CameraActive) -> impl Fn(Res<State<CameraActive>>) -> bool {
428 move |state| *state.get() == active
429}
430
431fn draw_gizmos_2d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time: Res<Time>) {
432 const POSITION: Vec2 = Vec2::new(-LEFT_RIGHT_OFFSET_2D, 0.0);
433 let angle = time.elapsed_secs();
434 let isometry = Isometry2d::new(POSITION, Rot2::radians(angle));
435 let color = Color::WHITE;
436
437 #[expect(
438 clippy::match_same_arms,
439 reason = "Certain primitives don't have any 2D rendering support yet."
440 )]
441 match state.get() {
442 PrimitiveSelected::RectangleAndCuboid => {
443 gizmos.primitive_2d(&RECTANGLE, isometry, color);
444 }
445 PrimitiveSelected::CircleAndSphere => {
446 gizmos.primitive_2d(&CIRCLE, isometry, color);
447 }
448 PrimitiveSelected::Ellipse => drop(gizmos.primitive_2d(&ELLIPSE, isometry, color)),
449 PrimitiveSelected::Triangle => gizmos.primitive_2d(&TRIANGLE_2D, isometry, color),
450 PrimitiveSelected::Plane => gizmos.primitive_2d(&PLANE_2D, isometry, color),
451 PrimitiveSelected::Line => drop(gizmos.primitive_2d(&LINE2D, isometry, color)),
452 PrimitiveSelected::Segment => {
453 drop(gizmos.primitive_2d(&SEGMENT_2D, isometry, color));
454 }
455 PrimitiveSelected::Polyline => gizmos.primitive_2d(&POLYLINE_2D, isometry, color),
456 PrimitiveSelected::Polygon => gizmos.primitive_2d(&POLYGON_2D, isometry, color),
457 PrimitiveSelected::RegularPolygon => {
458 gizmos.primitive_2d(®ULAR_POLYGON, isometry, color);
459 }
460 PrimitiveSelected::Capsule => gizmos.primitive_2d(&CAPSULE_2D, isometry, color),
461 PrimitiveSelected::Cylinder => {}
462 PrimitiveSelected::Cone => {}
463 PrimitiveSelected::ConicalFrustum => {}
464 PrimitiveSelected::Torus => drop(gizmos.primitive_2d(&ANNULUS, isometry, color)),
465 PrimitiveSelected::Tetrahedron => {}
466 PrimitiveSelected::Arc => gizmos.primitive_2d(&ARC, isometry, color),
467 PrimitiveSelected::CircularSector => {
468 gizmos.primitive_2d(&CIRCULAR_SECTOR, isometry, color);
469 }
470 PrimitiveSelected::CircularSegment => {
471 gizmos.primitive_2d(&CIRCULAR_SEGMENT, isometry, color);
472 }
473 }
474}
475
476/// Marker for primitive meshes to record in which state they should be visible in
477#[derive(Debug, Clone, Component, Default, Reflect)]
478pub struct PrimitiveData {
479 camera_mode: CameraActive,
480 primitive_state: PrimitiveSelected,
481}
482
483/// Marker for meshes of 2D primitives
484#[derive(Debug, Clone, Component, Default)]
485pub struct MeshDim2;
486
487/// Marker for meshes of 3D primitives
488#[derive(Debug, Clone, Component, Default)]
489pub struct MeshDim3;
490
491fn spawn_primitive_2d(
492 mut commands: Commands,
493 mut materials: ResMut<Assets<ColorMaterial>>,
494 mut meshes: ResMut<Assets<Mesh>>,
495) {
496 const POSITION: Vec3 = Vec3::new(LEFT_RIGHT_OFFSET_2D, 0.0, 0.0);
497 let material: Handle<ColorMaterial> = materials.add(Color::WHITE);
498 let camera_mode = CameraActive::Dim2;
499 [
500 Some(RECTANGLE.mesh().build()),
501 Some(CIRCLE.mesh().build()),
502 Some(ELLIPSE.mesh().build()),
503 Some(TRIANGLE_2D.mesh().build()),
504 None, // plane
505 None, // line
506 None, // segment
507 None, // polyline
508 None, // polygon
509 Some(REGULAR_POLYGON.mesh().build()),
510 Some(CAPSULE_2D.mesh().build()),
511 None, // cylinder
512 None, // cone
513 None, // conical frustum
514 Some(ANNULUS.mesh().build()),
515 None, // tetrahedron
516 ]
517 .into_iter()
518 .zip(PrimitiveSelected::ALL)
519 .for_each(|(maybe_mesh, state)| {
520 if let Some(mesh) = maybe_mesh {
521 commands.spawn((
522 MeshDim2,
523 PrimitiveData {
524 camera_mode,
525 primitive_state: state,
526 },
527 Mesh2d(meshes.add(mesh)),
528 MeshMaterial2d(material.clone()),
529 Transform::from_translation(POSITION),
530 ));
531 }
532 });
533}
534
535fn spawn_primitive_3d(
536 mut commands: Commands,
537 mut materials: ResMut<Assets<StandardMaterial>>,
538 mut meshes: ResMut<Assets<Mesh>>,
539) {
540 const POSITION: Vec3 = Vec3::new(-LEFT_RIGHT_OFFSET_3D, 0.0, 0.0);
541 let material: Handle<StandardMaterial> = materials.add(Color::WHITE);
542 let camera_mode = CameraActive::Dim3;
543 [
544 Some(CUBOID.mesh().build()),
545 Some(SPHERE.mesh().build()),
546 None, // ellipse
547 Some(TRIANGLE_3D.mesh().build()),
548 Some(PLANE_3D.mesh().build()),
549 None, // line
550 None, // segment
551 None, // polyline
552 None, // polygon
553 None, // regular polygon
554 Some(CAPSULE_3D.mesh().build()),
555 Some(CYLINDER.mesh().build()),
556 None, // cone
557 None, // conical frustum
558 Some(TORUS.mesh().build()),
559 Some(TETRAHEDRON.mesh().build()),
560 ]
561 .into_iter()
562 .zip(PrimitiveSelected::ALL)
563 .for_each(|(maybe_mesh, state)| {
564 if let Some(mesh) = maybe_mesh {
565 commands.spawn((
566 MeshDim3,
567 PrimitiveData {
568 camera_mode,
569 primitive_state: state,
570 },
571 Mesh3d(meshes.add(mesh)),
572 MeshMaterial3d(material.clone()),
573 Transform::from_translation(POSITION),
574 ));
575 }
576 });
577}
578
579fn update_primitive_meshes(
580 camera_state: Res<State<CameraActive>>,
581 primitive_state: Res<State<PrimitiveSelected>>,
582 mut primitives: Query<(&mut Visibility, &PrimitiveData)>,
583) {
584 primitives.iter_mut().for_each(|(mut vis, primitive)| {
585 let visible = primitive.camera_mode == *camera_state.get()
586 && primitive.primitive_state == *primitive_state.get();
587 *vis = if visible {
588 Visibility::Inherited
589 } else {
590 Visibility::Hidden
591 };
592 });
593}
594
595fn rotate_primitive_2d_meshes(
596 mut primitives_2d: Query<
597 (&mut Transform, &ViewVisibility),
598 (With<PrimitiveData>, With<MeshDim2>),
599 >,
600 time: Res<Time>,
601) {
602 let rotation_2d = Quat::from_mat3(&Mat3::from_angle(time.elapsed_secs()));
603 primitives_2d
604 .iter_mut()
605 .filter(|(_, vis)| vis.get())
606 .for_each(|(mut transform, _)| {
607 transform.rotation = rotation_2d;
608 });
609}
610
611fn rotate_primitive_3d_meshes(
612 mut primitives_3d: Query<
613 (&mut Transform, &ViewVisibility),
614 (With<PrimitiveData>, With<MeshDim3>),
615 >,
616 time: Res<Time>,
617) {
618 let rotation_3d = Quat::from_rotation_arc(
619 Vec3::Z,
620 Vec3::new(
621 ops::sin(time.elapsed_secs()),
622 ops::cos(time.elapsed_secs()),
623 ops::sin(time.elapsed_secs()) * 0.5,
624 )
625 .try_normalize()
626 .unwrap_or(Vec3::Z),
627 );
628 primitives_3d
629 .iter_mut()
630 .filter(|(_, vis)| vis.get())
631 .for_each(|(mut transform, _)| {
632 transform.rotation = rotation_3d;
633 });
634}
635
636fn draw_gizmos_3d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time: Res<Time>) {
637 const POSITION: Vec3 = Vec3::new(LEFT_RIGHT_OFFSET_3D, 0.0, 0.0);
638 let rotation = Quat::from_rotation_arc(
639 Vec3::Z,
640 Vec3::new(
641 ops::sin(time.elapsed_secs()),
642 ops::cos(time.elapsed_secs()),
643 ops::sin(time.elapsed_secs()) * 0.5,
644 )
645 .try_normalize()
646 .unwrap_or(Vec3::Z),
647 );
648 let isometry = Isometry3d::new(POSITION, rotation);
649 let color = Color::WHITE;
650 let resolution = 10;
651
652 #[expect(
653 clippy::match_same_arms,
654 reason = "Certain primitives don't have any 3D rendering support yet."
655 )]
656 match state.get() {
657 PrimitiveSelected::RectangleAndCuboid => {
658 gizmos.primitive_3d(&CUBOID, isometry, color);
659 }
660 PrimitiveSelected::CircleAndSphere => drop(
661 gizmos
662 .primitive_3d(&SPHERE, isometry, color)
663 .resolution(resolution),
664 ),
665 PrimitiveSelected::Ellipse => {}
666 PrimitiveSelected::Triangle => gizmos.primitive_3d(&TRIANGLE_3D, isometry, color),
667 PrimitiveSelected::Plane => drop(gizmos.primitive_3d(&PLANE_3D, isometry, color)),
668 PrimitiveSelected::Line => gizmos.primitive_3d(&LINE3D, isometry, color),
669 PrimitiveSelected::Segment => gizmos.primitive_3d(&SEGMENT_3D, isometry, color),
670 PrimitiveSelected::Polyline => gizmos.primitive_3d(&POLYLINE_3D, isometry, color),
671 PrimitiveSelected::Polygon => {}
672 PrimitiveSelected::RegularPolygon => {}
673 PrimitiveSelected::Capsule => drop(
674 gizmos
675 .primitive_3d(&CAPSULE_3D, isometry, color)
676 .resolution(resolution),
677 ),
678 PrimitiveSelected::Cylinder => drop(
679 gizmos
680 .primitive_3d(&CYLINDER, isometry, color)
681 .resolution(resolution),
682 ),
683 PrimitiveSelected::Cone => drop(
684 gizmos
685 .primitive_3d(&CONE, isometry, color)
686 .resolution(resolution),
687 ),
688 PrimitiveSelected::ConicalFrustum => {
689 gizmos.primitive_3d(&CONICAL_FRUSTUM, isometry, color);
690 }
691
692 PrimitiveSelected::Torus => drop(
693 gizmos
694 .primitive_3d(&TORUS, isometry, color)
695 .minor_resolution(resolution)
696 .major_resolution(resolution),
697 ),
698 PrimitiveSelected::Tetrahedron => {
699 gizmos.primitive_3d(&TETRAHEDRON, isometry, color);
700 }
701
702 PrimitiveSelected::Arc => {}
703 PrimitiveSelected::CircularSector => {}
704 PrimitiveSelected::CircularSegment => {}
705 }
706}
63fn move_text(
64 mut commands: Commands,
65 mut texts: Query<(Entity, &mut Transform), With<Text2d>>,
66 time: Res<Time>,
67) {
68 for (entity, mut position) in &mut texts {
69 position.translation -= Vec3::new(0.0, 100.0 * time.delta_secs(), 0.0);
70 if position.translation.y < -300.0 {
71 commands.entity(entity).despawn();
72 }
73 }
74}
20fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
21 // Create a camera
22 commands.spawn((
23 Camera3d::default(),
24 Transform::from_xyz(-2.0, 2.5, 5.0).looking_at(Vec3::new(0.0, 1.0, 0.0), Vec3::Y),
25 ));
26
27 // Spawn the first scene in `models/SimpleSkin/SimpleSkin.gltf`
28 commands.spawn(SceneRoot(asset_server.load(
29 GltfAssetLabel::Scene(0).from_asset("models/SimpleSkin/SimpleSkin.gltf"),
30 )));
31}
121fn setup_env(mut commands: Commands) {
122 // Used to center camera on spawned cubes
123 let offset = if NUM_CUBES % 2 == 0 {
124 (NUM_CUBES / 2) as f32 - 0.5
125 } else {
126 (NUM_CUBES / 2) as f32
127 };
128
129 // lights
130 commands.spawn((PointLight::default(), Transform::from_xyz(4.0, 12.0, 15.0)));
131
132 // camera
133 commands.spawn((
134 Camera3d::default(),
135 Transform::from_xyz(offset, offset, 15.0)
136 .looking_at(Vec3::new(offset, offset, 0.0), Vec3::Y),
137 ));
138}
- examples/3d/query_gltf_primitives.rs
- examples/camera/2d_top_down_camera.rs
- examples/shader/array_texture.rs
- examples/shader/fallback_image.rs
- examples/3d/parallax_mapping.rs
- examples/shader/texture_binding_array.rs
- examples/2d/sprite_slice.rs
- examples/asset/multi_asset_sync.rs
- examples/stress_tests/bevymark.rs
- examples/3d/mesh_ray_cast.rs
- examples/3d/color_grading.rs
- examples/3d/atmospheric_fog.rs
- examples/3d/post_processing.rs
- examples/animation/animated_mesh.rs
- examples/games/loading_screen.rs
- examples/shader/custom_post_processing.rs
- examples/animation/animation_graph.rs
- examples/testbed/2d.rs
- examples/3d/tonemapping.rs
- examples/3d/edit_material_on_gltf.rs
- examples/animation/animation_masks.rs
- examples/3d/animated_material.rs
- examples/animation/animated_mesh_events.rs
- examples/3d/load_gltf.rs
- examples/3d/lines.rs
- examples/stress_tests/many_materials.rs
- examples/3d/update_gltf_scene.rs
- examples/2d/mesh2d_vertex_color_texture.rs
- examples/3d/order_independent_transparency.rs
- examples/audio/spatial_audio_2d.rs
- examples/shader/custom_shader_instancing.rs
- examples/games/contributors.rs
- examples/2d/2d_viewport_to_world.rs
- examples/gizmos/axes.rs
- examples/3d/motion_blur.rs
- examples/2d/bloom_2d.rs
- examples/animation/eased_motion.rs
- examples/3d/fog.rs
- examples/animation/easing_functions.rs
- examples/2d/sprite_animation.rs
- examples/testbed/3d.rs
- examples/animation/animated_mesh_control.rs
- examples/time/virtual_time.rs
- examples/3d/shadow_caster_receiver.rs
- examples/stress_tests/many_lights.rs
- examples/3d/anti_aliasing.rs
- examples/3d/scrolling_fog.rs
- examples/2d/mesh2d_arcs.rs
- examples/ecs/iter_combinations.rs
- examples/games/alien_cake_addict.rs
- examples/3d/3d_shapes.rs
- examples/3d/meshlet.rs
- examples/gizmos/3d_gizmos.rs
- examples/3d/render_to_texture.rs
- examples/3d/spotlight.rs
- examples/shader/shader_prepass.rs
- examples/picking/mesh_picking.rs
- examples/3d/shadow_biases.rs
- examples/stress_tests/many_foxes.rs
- examples/3d/split_screen.rs
- examples/games/desk_toy.rs
- examples/2d/text2d.rs
- examples/2d/texture_atlas.rs
- examples/2d/sprite_scale.rs
- examples/3d/deferred_rendering.rs
- examples/animation/custom_skinned_mesh.rs
- examples/stress_tests/many_cubes.rs
- examples/3d/lighting.rs
- examples/animation/animated_transform.rs
- examples/3d/transmission.rs
Sourcepub const fn splat(v: f32) -> Vec3
pub const fn splat(v: f32) -> Vec3
Creates a vector with all elements set to v
.
Examples found in repository?
More examples
269fn spawn_sphere(commands: &mut Commands, assets: &ExampleAssets) {
270 commands
271 .spawn((
272 Mesh3d(assets.main_sphere.clone()),
273 MeshMaterial3d(assets.main_sphere_material.clone()),
274 Transform::from_xyz(0.0, SPHERE_SCALE, 0.0).with_scale(Vec3::splat(SPHERE_SCALE)),
275 ))
276 .insert(MainObject);
277}
278
279fn spawn_voxel_cube_parent(commands: &mut Commands) {
280 commands.spawn((Visibility::Hidden, Transform::default(), VoxelCubeParent));
281}
282
283fn spawn_fox(commands: &mut Commands, assets: &ExampleAssets) {
284 commands.spawn((
285 SceneRoot(assets.fox.clone()),
286 Visibility::Hidden,
287 Transform::from_scale(Vec3::splat(FOX_SCALE)),
288 MainObject,
289 ));
290}
291
292fn spawn_text(commands: &mut Commands, app_status: &AppStatus) {
293 commands.spawn((
294 app_status.create_text(),
295 Node {
296 position_type: PositionType::Absolute,
297 bottom: Val::Px(12.0),
298 left: Val::Px(12.0),
299 ..default()
300 },
301 ));
302}
303
304// A system that updates the help text.
305fn update_text(mut text_query: Query<&mut Text>, app_status: Res<AppStatus>) {
306 for mut text in text_query.iter_mut() {
307 *text = app_status.create_text();
308 }
309}
310
311impl AppStatus {
312 // Constructs the help text at the bottom of the screen based on the
313 // application status.
314 fn create_text(&self) -> Text {
315 let irradiance_volume_help_text = if self.irradiance_volume_present {
316 DISABLE_IRRADIANCE_VOLUME_HELP_TEXT
317 } else {
318 ENABLE_IRRADIANCE_VOLUME_HELP_TEXT
319 };
320
321 let voxels_help_text = if self.voxels_visible {
322 HIDE_VOXELS_HELP_TEXT
323 } else {
324 SHOW_VOXELS_HELP_TEXT
325 };
326
327 let rotation_help_text = if self.rotating {
328 STOP_ROTATION_HELP_TEXT
329 } else {
330 START_ROTATION_HELP_TEXT
331 };
332
333 let switch_mesh_help_text = match self.model {
334 ExampleModel::Sphere => SWITCH_TO_FOX_HELP_TEXT,
335 ExampleModel::Fox => SWITCH_TO_SPHERE_HELP_TEXT,
336 };
337
338 format!(
339 "{CLICK_TO_MOVE_HELP_TEXT}\n\
340 {voxels_help_text}\n\
341 {irradiance_volume_help_text}\n\
342 {rotation_help_text}\n\
343 {switch_mesh_help_text}"
344 )
345 .into()
346 }
347}
348
349// Rotates the camera a bit every frame.
350fn rotate_camera(
351 mut camera_query: Query<&mut Transform, With<Camera3d>>,
352 time: Res<Time>,
353 app_status: Res<AppStatus>,
354) {
355 if !app_status.rotating {
356 return;
357 }
358
359 for mut transform in camera_query.iter_mut() {
360 transform.translation = Vec2::from_angle(ROTATION_SPEED * time.delta_secs())
361 .rotate(transform.translation.xz())
362 .extend(transform.translation.y)
363 .xzy();
364 transform.look_at(Vec3::ZERO, Vec3::Y);
365 }
366}
367
368// Toggles between the unskinned sphere model and the skinned fox model if the
369// user requests it.
370fn change_main_object(
371 keyboard: Res<ButtonInput<KeyCode>>,
372 mut app_status: ResMut<AppStatus>,
373 mut sphere_query: Query<&mut Visibility, (With<MainObject>, With<Mesh3d>, Without<SceneRoot>)>,
374 mut fox_query: Query<&mut Visibility, (With<MainObject>, With<SceneRoot>)>,
375) {
376 if !keyboard.just_pressed(KeyCode::Tab) {
377 return;
378 }
379 let Some(mut sphere_visibility) = sphere_query.iter_mut().next() else {
380 return;
381 };
382 let Some(mut fox_visibility) = fox_query.iter_mut().next() else {
383 return;
384 };
385
386 match app_status.model {
387 ExampleModel::Sphere => {
388 *sphere_visibility = Visibility::Hidden;
389 *fox_visibility = Visibility::Visible;
390 app_status.model = ExampleModel::Fox;
391 }
392 ExampleModel::Fox => {
393 *sphere_visibility = Visibility::Visible;
394 *fox_visibility = Visibility::Hidden;
395 app_status.model = ExampleModel::Sphere;
396 }
397 }
398}
399
400impl Default for AppStatus {
401 fn default() -> Self {
402 Self {
403 irradiance_volume_present: true,
404 rotating: true,
405 model: ExampleModel::Sphere,
406 voxels_visible: false,
407 }
408 }
409}
410
411// Turns on and off the irradiance volume as requested by the user.
412fn toggle_irradiance_volumes(
413 mut commands: Commands,
414 keyboard: Res<ButtonInput<KeyCode>>,
415 light_probe_query: Query<Entity, With<LightProbe>>,
416 mut app_status: ResMut<AppStatus>,
417 assets: Res<ExampleAssets>,
418 mut ambient_light: ResMut<AmbientLight>,
419) {
420 if !keyboard.just_pressed(KeyCode::Space) {
421 return;
422 };
423
424 let Some(light_probe) = light_probe_query.iter().next() else {
425 return;
426 };
427
428 if app_status.irradiance_volume_present {
429 commands.entity(light_probe).remove::<IrradianceVolume>();
430 ambient_light.brightness = AMBIENT_LIGHT_BRIGHTNESS * IRRADIANCE_VOLUME_INTENSITY;
431 app_status.irradiance_volume_present = false;
432 } else {
433 commands.entity(light_probe).insert(IrradianceVolume {
434 voxels: assets.irradiance_volume.clone(),
435 intensity: IRRADIANCE_VOLUME_INTENSITY,
436 ..default()
437 });
438 ambient_light.brightness = 0.0;
439 app_status.irradiance_volume_present = true;
440 }
441}
442
443fn toggle_rotation(keyboard: Res<ButtonInput<KeyCode>>, mut app_status: ResMut<AppStatus>) {
444 if keyboard.just_pressed(KeyCode::Enter) {
445 app_status.rotating = !app_status.rotating;
446 }
447}
448
449// Handles clicks on the plane that reposition the object.
450fn handle_mouse_clicks(
451 buttons: Res<ButtonInput<MouseButton>>,
452 windows: Query<&Window, With<PrimaryWindow>>,
453 cameras: Query<(&Camera, &GlobalTransform)>,
454 mut main_objects: Query<&mut Transform, With<MainObject>>,
455) {
456 if !buttons.pressed(MouseButton::Left) {
457 return;
458 }
459 let Some(mouse_position) = windows.iter().next().and_then(Window::cursor_position) else {
460 return;
461 };
462 let Some((camera, camera_transform)) = cameras.iter().next() else {
463 return;
464 };
465
466 // Figure out where the user clicked on the plane.
467 let Ok(ray) = camera.viewport_to_world(camera_transform, mouse_position) else {
468 return;
469 };
470 let Some(ray_distance) = ray.intersect_plane(Vec3::ZERO, InfinitePlane3d::new(Vec3::Y)) else {
471 return;
472 };
473 let plane_intersection = ray.origin + ray.direction.normalize() * ray_distance;
474
475 // Move all the main objects.
476 for mut transform in main_objects.iter_mut() {
477 transform.translation = vec3(
478 plane_intersection.x,
479 transform.translation.y,
480 plane_intersection.z,
481 );
482 }
483}
484
485impl FromWorld for ExampleAssets {
486 fn from_world(world: &mut World) -> Self {
487 let fox_animation =
488 world.load_asset(GltfAssetLabel::Animation(1).from_asset("models/animated/Fox.glb"));
489 let (fox_animation_graph, fox_animation_node) =
490 AnimationGraph::from_clip(fox_animation.clone());
491
492 ExampleAssets {
493 main_sphere: world.add_asset(Sphere::default().mesh().uv(32, 18)),
494 fox: world.load_asset(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb")),
495 main_sphere_material: world.add_asset(Color::from(SILVER)),
496 main_scene: world.load_asset(
497 GltfAssetLabel::Scene(0)
498 .from_asset("models/IrradianceVolumeExample/IrradianceVolumeExample.glb"),
499 ),
500 irradiance_volume: world.load_asset("irradiance_volumes/Example.vxgi.ktx2"),
501 fox_animation_graph: world.add_asset(fox_animation_graph),
502 fox_animation_node,
503 voxel_cube: world.add_asset(Cuboid::default()),
504 // Just use a specular map for the skybox since it's not too blurry.
505 // In reality you wouldn't do this--you'd use a real skybox texture--but
506 // reusing the textures like this saves space in the Bevy repository.
507 skybox: world.load_asset("environment_maps/pisa_specular_rgb9e5_zstd.ktx2"),
508 }
509 }
510}
511
512// Plays the animation on the fox.
513fn play_animations(
514 mut commands: Commands,
515 assets: Res<ExampleAssets>,
516 mut players: Query<(Entity, &mut AnimationPlayer), Without<AnimationGraphHandle>>,
517) {
518 for (entity, mut player) in players.iter_mut() {
519 commands
520 .entity(entity)
521 .insert(AnimationGraphHandle(assets.fox_animation_graph.clone()));
522 player.play(assets.fox_animation_node).repeat();
523 }
524}
525
526fn create_cubes(
527 image_assets: Res<Assets<Image>>,
528 mut commands: Commands,
529 irradiance_volumes: Query<(&IrradianceVolume, &GlobalTransform)>,
530 voxel_cube_parents: Query<Entity, With<VoxelCubeParent>>,
531 voxel_cubes: Query<Entity, With<VoxelCube>>,
532 example_assets: Res<ExampleAssets>,
533 mut voxel_visualization_material_assets: ResMut<Assets<VoxelVisualizationMaterial>>,
534) {
535 // If voxel cubes have already been spawned, don't do anything.
536 if !voxel_cubes.is_empty() {
537 return;
538 }
539
540 let Some(voxel_cube_parent) = voxel_cube_parents.iter().next() else {
541 return;
542 };
543
544 for (irradiance_volume, global_transform) in irradiance_volumes.iter() {
545 let Some(image) = image_assets.get(&irradiance_volume.voxels) else {
546 continue;
547 };
548
549 let resolution = image.texture_descriptor.size;
550
551 let voxel_cube_material = voxel_visualization_material_assets.add(ExtendedMaterial {
552 base: StandardMaterial::from(Color::from(RED)),
553 extension: VoxelVisualizationExtension {
554 irradiance_volume_info: VoxelVisualizationIrradianceVolumeInfo {
555 world_from_voxel: VOXEL_FROM_WORLD.inverse(),
556 voxel_from_world: VOXEL_FROM_WORLD,
557 resolution: uvec3(
558 resolution.width,
559 resolution.height,
560 resolution.depth_or_array_layers,
561 ),
562 intensity: IRRADIANCE_VOLUME_INTENSITY,
563 },
564 },
565 });
566
567 let scale = vec3(
568 1.0 / resolution.width as f32,
569 1.0 / resolution.height as f32,
570 1.0 / resolution.depth_or_array_layers as f32,
571 );
572
573 // Spawn a cube for each voxel.
574 for z in 0..resolution.depth_or_array_layers {
575 for y in 0..resolution.height {
576 for x in 0..resolution.width {
577 let uvw = (uvec3(x, y, z).as_vec3() + 0.5) * scale - 0.5;
578 let pos = global_transform.transform_point(uvw);
579 let voxel_cube = commands
580 .spawn((
581 Mesh3d(example_assets.voxel_cube.clone()),
582 MeshMaterial3d(voxel_cube_material.clone()),
583 Transform::from_scale(Vec3::splat(VOXEL_CUBE_SCALE))
584 .with_translation(pos),
585 ))
586 .insert(VoxelCube)
587 .insert(NotShadowCaster)
588 .id();
589
590 commands.entity(voxel_cube_parent).add_child(voxel_cube);
591 }
592 }
593 }
594 }
595}
12fn setup(
13 mut commands: Commands,
14 mut meshes: ResMut<Assets<Mesh>>,
15 mut materials: ResMut<Assets<ColorMaterial>>,
16) {
17 commands.spawn(Camera2d);
18
19 commands.spawn((
20 Mesh2d(meshes.add(Rectangle::default())),
21 MeshMaterial2d(materials.add(Color::from(PURPLE))),
22 Transform::default().with_scale(Vec3::splat(128.)),
23 ));
24}
162fn spawn_flight_helmet(commands: &mut Commands, asset_server: &AssetServer) {
163 commands.spawn((
164 SceneRoot(
165 asset_server
166 .load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
167 ),
168 Transform::from_scale(Vec3::splat(2.5)),
169 FlightHelmetModel,
170 Visibility::Hidden,
171 ));
172}
173
174// Spawns the water plane.
175fn spawn_water(
176 commands: &mut Commands,
177 asset_server: &AssetServer,
178 meshes: &mut Assets<Mesh>,
179 water_materials: &mut Assets<ExtendedMaterial<StandardMaterial, Water>>,
180) {
181 commands.spawn((
182 Mesh3d(meshes.add(Plane3d::new(Vec3::Y, Vec2::splat(1.0)))),
183 MeshMaterial3d(water_materials.add(ExtendedMaterial {
184 base: StandardMaterial {
185 base_color: BLACK.into(),
186 perceptual_roughness: 0.0,
187 ..default()
188 },
189 extension: Water {
190 normals: asset_server.load_with_settings::<Image, ImageLoaderSettings>(
191 "textures/water_normals.png",
192 |settings| {
193 settings.is_srgb = false;
194 settings.sampler = ImageSampler::Descriptor(ImageSamplerDescriptor {
195 address_mode_u: ImageAddressMode::Repeat,
196 address_mode_v: ImageAddressMode::Repeat,
197 mag_filter: ImageFilterMode::Linear,
198 min_filter: ImageFilterMode::Linear,
199 ..default()
200 });
201 },
202 ),
203 // These water settings are just random values to create some
204 // variety.
205 settings: WaterSettings {
206 octave_vectors: [
207 vec4(0.080, 0.059, 0.073, -0.062),
208 vec4(0.153, 0.138, -0.149, -0.195),
209 ],
210 octave_scales: vec4(1.0, 2.1, 7.9, 14.9) * 5.0,
211 octave_strengths: vec4(0.16, 0.18, 0.093, 0.044),
212 },
213 },
214 })),
215 Transform::from_scale(Vec3::splat(100.0)),
216 ));
217}
72fn setup_mesh(
73 mut commands: Commands,
74 mut meshes: ResMut<Assets<Mesh>>,
75 mut materials: ResMut<Assets<ColorMaterial>>,
76) {
77 commands.spawn((
78 Mesh2d(meshes.add(Capsule2d::default())),
79 MeshMaterial2d(materials.add(Color::BLACK)),
80 Transform::from_xyz(25., 0., 2.).with_scale(Vec3::splat(32.)),
81 Rotate,
82 PIXEL_PERFECT_LAYERS,
83 ));
84}
- examples/movement/physics_in_fixed_timestep.rs
- examples/math/sampling_primitives.rs
- examples/3d/reflection_probes.rs
- examples/shader/shader_material_2d.rs
- examples/ecs/parallel_query.rs
- examples/3d/rotate_environment_map.rs
- examples/stress_tests/bevymark.rs
- examples/3d/clearcoat.rs
- examples/2d/sprite_sheet.rs
- examples/animation/animation_graph.rs
- examples/shader/compute_shader_game_of_life.rs
- examples/animation/animation_masks.rs
- examples/movement/smooth_follow.rs
- examples/animation/animated_mesh_events.rs
- examples/3d/atmospheric_fog.rs
- examples/shader/storage_buffer.rs
- examples/2d/mesh2d_vertex_color_texture.rs
- examples/ecs/hierarchy.rs
- examples/transforms/transform.rs
- examples/stress_tests/many_sprites.rs
- examples/3d/spherical_area_lights.rs
- examples/stress_tests/many_animated_sprites.rs
- examples/stress_tests/many_text2d.rs
- examples/3d/motion_blur.rs
- examples/shader/automatic_instancing.rs
- examples/camera/projection_zoom.rs
- examples/3d/fog.rs
- examples/2d/sprite_animation.rs
- examples/3d/volumetric_fog.rs
- examples/3d/atmosphere.rs
- examples/stress_tests/many_lights.rs
- examples/3d/bloom_3d.rs
- examples/3d/decal.rs
- examples/picking/sprite_picking.rs
- examples/3d/scrolling_fog.rs
- examples/ecs/iter_combinations.rs
- examples/3d/meshlet.rs
- examples/gizmos/3d_gizmos.rs
- examples/stress_tests/many_foxes.rs
- examples/2d/texture_atlas.rs
- examples/3d/deferred_rendering.rs
- examples/stress_tests/many_cubes.rs
- examples/animation/animated_transform.rs
- examples/3d/transmission.rs
Sourcepub fn map<F>(self, f: F) -> Vec3
pub fn map<F>(self, f: F) -> Vec3
Returns a vector containing each element of self
modified by a mapping function f
.
Sourcepub fn select(mask: BVec3, if_true: Vec3, if_false: Vec3) -> Vec3
pub fn select(mask: BVec3, if_true: Vec3, if_false: Vec3) -> Vec3
Creates a vector from the elements in if_true
and if_false
, selecting which to use
for each element of self
.
A true element in the mask uses the corresponding element from if_true
, and false
uses the element from if_false
.
Sourcepub const fn from_array(a: [f32; 3]) -> Vec3
pub const fn from_array(a: [f32; 3]) -> Vec3
Creates a new vector from an array.
Sourcepub const fn from_slice(slice: &[f32]) -> Vec3
pub const fn from_slice(slice: &[f32]) -> Vec3
Creates a vector from the first 3 values in slice
.
§Panics
Panics if slice
is less than 3 elements long.
Examples found in repository?
284fn spawn_small_cubes(
285 commands: &mut Commands,
286 meshes: &mut Assets<Mesh>,
287 materials: &mut Assets<StandardMaterial>,
288) {
289 // Add the cube mesh.
290 let small_cube = meshes.add(Cuboid::new(
291 SMALL_CUBE_SIZE,
292 SMALL_CUBE_SIZE,
293 SMALL_CUBE_SIZE,
294 ));
295
296 // Add the cube material.
297 let small_cube_material = materials.add(StandardMaterial {
298 base_color: SILVER.into(),
299 ..default()
300 });
301
302 // Create the entity that the small cubes will be parented to. This is the
303 // entity that we rotate.
304 let sphere_parent = commands
305 .spawn(Transform::from_translation(Vec3::ZERO))
306 .insert(Visibility::default())
307 .insert(SphereParent)
308 .id();
309
310 // Now we have to figure out where to place the cubes. To do that, we create
311 // a sphere mesh, but we don't add it to the scene. Instead, we inspect the
312 // sphere mesh to find the positions of its vertices, and spawn a small cube
313 // at each one. That way, we end up with a bunch of cubes arranged in a
314 // spherical shape.
315
316 // Create the sphere mesh, and extract the positions of its vertices.
317 let sphere = Sphere::new(OUTER_RADIUS)
318 .mesh()
319 .ico(OUTER_SUBDIVISION_COUNT)
320 .unwrap();
321 let sphere_positions = sphere.attribute(Mesh::ATTRIBUTE_POSITION).unwrap();
322
323 // At each vertex, create a small cube.
324 for sphere_position in sphere_positions.as_float3().unwrap() {
325 let sphere_position = Vec3::from_slice(sphere_position);
326 let small_cube = commands
327 .spawn(Mesh3d(small_cube.clone()))
328 .insert(MeshMaterial3d(small_cube_material.clone()))
329 .insert(Transform::from_translation(sphere_position))
330 .id();
331 commands.entity(sphere_parent).add_child(small_cube);
332 }
333}
Sourcepub fn write_to_slice(self, slice: &mut [f32])
pub fn write_to_slice(self, slice: &mut [f32])
Writes the elements of self
to the first 3 elements in slice
.
§Panics
Panics if slice
is less than 3 elements long.
Sourcepub fn truncate(self) -> Vec2
pub fn truncate(self) -> Vec2
Creates a 2D vector from the x
and y
elements of self
, discarding z
.
Truncation may also be performed by using self.xy()
.
Examples found in repository?
172fn handle_click(
173 mouse_button_input: Res<ButtonInput<MouseButton>>,
174 camera: Single<(&Camera, &GlobalTransform)>,
175 windows: Query<&Window>,
176 mut commands: Commands,
177) {
178 let Ok(windows) = windows.single() else {
179 return;
180 };
181
182 let (camera, camera_transform) = *camera;
183 if let Some(pos) = windows
184 .cursor_position()
185 .and_then(|cursor| camera.viewport_to_world(camera_transform, cursor).ok())
186 .map(|ray| ray.origin.truncate())
187 {
188 if mouse_button_input.just_pressed(MouseButton::Left) {
189 commands.trigger(ExplodeMines { pos, radius: 1.0 });
190 }
191 }
192}
More examples
104fn draw_bounds<Shape: Bounded2d + Send + Sync + 'static>(
105 q: Query<(&DrawBounds<Shape>, &GlobalTransform)>,
106 mut gizmos: Gizmos,
107) {
108 for (shape, transform) in &q {
109 let (_, rotation, translation) = transform.to_scale_rotation_translation();
110 let translation = translation.truncate();
111 let rotation = rotation.to_euler(EulerRot::XYZ).2;
112 let isometry = Isometry2d::new(translation, Rot2::radians(rotation));
113
114 let aabb = shape.0.aabb_2d(isometry);
115 gizmos.rect_2d(aabb.center(), aabb.half_size() * 2.0, RED);
116
117 let bounding_circle = shape.0.bounding_circle(isometry);
118 gizmos.circle_2d(bounding_circle.center, bounding_circle.radius(), BLUE);
119 }
120}
220fn update_cursor_hit_test(
221 cursor_world_pos: Res<CursorWorldPos>,
222 mut primary_window: Single<&mut Window, With<PrimaryWindow>>,
223 bevy_logo_transform: Single<&Transform, With<BevyLogo>>,
224) {
225 // If the window has decorations (e.g. a border) then it should be clickable
226 if primary_window.decorations {
227 primary_window.cursor_options.hit_test = true;
228 return;
229 }
230
231 // If the cursor is not within the window we don't need to update whether the window is clickable or not
232 let Some(cursor_world_pos) = cursor_world_pos.0 else {
233 return;
234 };
235
236 // If the cursor is within the radius of the Bevy logo make the window clickable otherwise the window is not clickable
237 primary_window.cursor_options.hit_test = bevy_logo_transform
238 .translation
239 .truncate()
240 .distance(cursor_world_pos)
241 < BEVY_LOGO_RADIUS;
242}
243
244/// Start the drag operation and record the offset we started dragging from
245fn start_drag(
246 mut commands: Commands,
247 cursor_world_pos: Res<CursorWorldPos>,
248 bevy_logo_transform: Single<&Transform, With<BevyLogo>>,
249) {
250 // If the cursor is not within the primary window skip this system
251 let Some(cursor_world_pos) = cursor_world_pos.0 else {
252 return;
253 };
254
255 // Get the offset from the cursor to the Bevy logo sprite
256 let drag_offset = bevy_logo_transform.translation.truncate() - cursor_world_pos;
257
258 // If the cursor is within the Bevy logo radius start the drag operation and remember the offset of the cursor from the origin
259 if drag_offset.length() < BEVY_LOGO_RADIUS {
260 commands.insert_resource(DragOperation(drag_offset));
261 }
262}
263
264/// Stop the current drag operation
265fn end_drag(mut commands: Commands) {
266 commands.remove_resource::<DragOperation>();
267}
268
269/// Drag the Bevy logo
270fn drag(
271 drag_offset: Res<DragOperation>,
272 cursor_world_pos: Res<CursorWorldPos>,
273 time: Res<Time>,
274 mut bevy_transform: Single<&mut Transform, With<BevyLogo>>,
275 mut q_pupils: Query<&mut Pupil>,
276) {
277 // If the cursor is not within the primary window skip this system
278 let Some(cursor_world_pos) = cursor_world_pos.0 else {
279 return;
280 };
281
282 // Calculate the new translation of the Bevy logo based on cursor and drag offset
283 let new_translation = cursor_world_pos + drag_offset.0;
284
285 // Calculate how fast we are dragging the Bevy logo (unit/second)
286 let drag_velocity =
287 (new_translation - bevy_transform.translation.truncate()) / time.delta_secs();
288
289 // Update the translation of Bevy logo transform to new translation
290 bevy_transform.translation = new_translation.extend(bevy_transform.translation.z);
291
292 // Add the cursor drag velocity in the opposite direction to each pupil.
293 // Remember pupils are using local coordinates to move. So when the Bevy logo moves right they need to move left to
294 // simulate inertia, otherwise they will move fixed to the parent.
295 for mut pupil in &mut q_pupils {
296 pupil.velocity -= drag_velocity;
297 }
298}
299
300/// Quit when the user right clicks the Bevy logo
301fn quit(
302 cursor_world_pos: Res<CursorWorldPos>,
303 mut app_exit: EventWriter<AppExit>,
304 bevy_logo_transform: Single<&Transform, With<BevyLogo>>,
305) {
306 // If the cursor is not within the primary window skip this system
307 let Some(cursor_world_pos) = cursor_world_pos.0 else {
308 return;
309 };
310
311 // If the cursor is within the Bevy logo radius send the [`AppExit`] event to quit the app
312 if bevy_logo_transform
313 .translation
314 .truncate()
315 .distance(cursor_world_pos)
316 < BEVY_LOGO_RADIUS
317 {
318 app_exit.write(AppExit::Success);
319 }
320}
321
322/// Enable transparency for the window and make it on top
323fn toggle_transparency(
324 mut commands: Commands,
325 mut window_transparency: ResMut<WindowTransparency>,
326 mut q_instructions_text: Query<&mut Visibility, With<InstructionsText>>,
327 mut primary_window: Single<&mut Window, With<PrimaryWindow>>,
328) {
329 // Toggle the window transparency resource
330 window_transparency.0 = !window_transparency.0;
331
332 // Show or hide the instructions text
333 for mut visibility in &mut q_instructions_text {
334 *visibility = if window_transparency.0 {
335 Visibility::Hidden
336 } else {
337 Visibility::Visible
338 };
339 }
340
341 // Remove the primary window's decorations (e.g. borders), make it always on top of other desktop windows, and set the clear color to transparent
342 // only if window transparency is enabled
343 let clear_color;
344 (
345 primary_window.decorations,
346 primary_window.window_level,
347 clear_color,
348 ) = if window_transparency.0 {
349 (false, WindowLevel::AlwaysOnTop, Color::NONE)
350 } else {
351 (true, WindowLevel::Normal, WINDOW_CLEAR_COLOR)
352 };
353
354 // Set the clear color
355 commands.insert_resource(ClearColor(clear_color));
356}
357
358/// Move the pupils and bounce them around
359fn move_pupils(time: Res<Time>, mut q_pupils: Query<(&mut Pupil, &mut Transform)>) {
360 for (mut pupil, mut transform) in &mut q_pupils {
361 // The wiggle radius is how much the pupil can move within the eye
362 let wiggle_radius = pupil.eye_radius - pupil.pupil_radius;
363 // Store the Z component
364 let z = transform.translation.z;
365 // Truncate the Z component to make the calculations be on [`Vec2`]
366 let mut translation = transform.translation.truncate();
367 // Decay the pupil velocity
368 pupil.velocity *= ops::powf(0.04f32, time.delta_secs());
369 // Move the pupil
370 translation += pupil.velocity * time.delta_secs();
371 // If the pupil hit the outside border of the eye, limit the translation to be within the wiggle radius and invert the velocity.
372 // This is not physically accurate but it's good enough for the googly eyes effect.
373 if translation.length() > wiggle_radius {
374 translation = translation.normalize() * wiggle_radius;
375 // Invert and decrease the velocity of the pupil when it bounces
376 pupil.velocity *= -0.75;
377 }
378 // Update the entity transform with the new translation after reading the Z component
379 transform.translation = translation.extend(z);
380 }
381}
340fn check_for_collisions(
341 mut commands: Commands,
342 mut score: ResMut<Score>,
343 ball_query: Single<(&mut Velocity, &Transform), With<Ball>>,
344 collider_query: Query<(Entity, &Transform, Option<&Brick>), With<Collider>>,
345 mut collision_events: EventWriter<CollisionEvent>,
346) {
347 let (mut ball_velocity, ball_transform) = ball_query.into_inner();
348
349 for (collider_entity, collider_transform, maybe_brick) in &collider_query {
350 let collision = ball_collision(
351 BoundingCircle::new(ball_transform.translation.truncate(), BALL_DIAMETER / 2.),
352 Aabb2d::new(
353 collider_transform.translation.truncate(),
354 collider_transform.scale.truncate() / 2.,
355 ),
356 );
357
358 if let Some(collision) = collision {
359 // Writes a collision event so that other systems can react to the collision
360 collision_events.write_default();
361
362 // Bricks should be despawned and increment the scoreboard on collision
363 if maybe_brick.is_some() {
364 commands.entity(collider_entity).despawn();
365 **score += 1;
366 }
367
368 // Reflect the ball's velocity when it collides
369 let mut reflect_x = false;
370 let mut reflect_y = false;
371
372 // Reflect only if the velocity is in the opposite direction of the collision
373 // This prevents the ball from getting stuck inside the bar
374 match collision {
375 Collision::Left => reflect_x = ball_velocity.x > 0.0,
376 Collision::Right => reflect_x = ball_velocity.x < 0.0,
377 Collision::Top => reflect_y = ball_velocity.y < 0.0,
378 Collision::Bottom => reflect_y = ball_velocity.y > 0.0,
379 }
380
381 // Reflect velocity on the x-axis if we hit something on the x-axis
382 if reflect_x {
383 ball_velocity.x = -ball_velocity.x;
384 }
385
386 // Reflect velocity on the y-axis if we hit something on the y-axis
387 if reflect_y {
388 ball_velocity.y = -ball_velocity.y;
389 }
390 }
391 }
392}
Sourcepub fn dot_into_vec(self, rhs: Vec3) -> Vec3
pub fn dot_into_vec(self, rhs: Vec3) -> Vec3
Returns a vector where every component is the dot product of self
and rhs
.
Sourcepub fn cross(self, rhs: Vec3) -> Vec3
pub fn cross(self, rhs: Vec3) -> Vec3
Computes the cross product of self
and rhs
.
Examples found in repository?
137fn track_targets(
138 // `Single` ensures the system runs ONLY when exactly one matching entity exists.
139 mut player: Single<(&mut Transform, &Player)>,
140 // `Option<Single>` ensures that the system runs ONLY when zero or one matching entity exists.
141 enemy: Option<Single<&Transform, (With<Enemy>, Without<Player>)>>,
142 time: Res<Time>,
143) {
144 let (player_transform, player) = &mut *player;
145 if let Some(enemy_transform) = enemy {
146 // Enemy found, rotate and move towards it.
147 let delta = enemy_transform.translation - player_transform.translation;
148 let distance = delta.length();
149 let front = delta / distance;
150 let up = Vec3::Z;
151 let side = front.cross(up);
152 player_transform.rotation = Quat::from_mat3(&Mat3::from_cols(side, front, up));
153 let max_step = distance - player.min_follow_radius;
154 if 0.0 < max_step {
155 let velocity = (player.speed * time.delta_secs()).min(max_step);
156 player_transform.translation += front * velocity;
157 }
158 } else {
159 // 0 or multiple enemies found, keep searching.
160 player_transform.rotate_axis(Dir3::Z, player.rotation_speed * time.delta_secs());
161 }
162}
Sourcepub fn min(self, rhs: Vec3) -> Vec3
pub fn min(self, rhs: Vec3) -> Vec3
Returns a vector containing the minimum values for each element of self
and rhs
.
In other words this computes [self.x.min(rhs.x), self.y.min(rhs.y), ..]
.
Examples found in repository?
112fn player_movement_system(
113 time: Res<Time>,
114 keyboard_input: Res<ButtonInput<KeyCode>>,
115 query: Single<(&Player, &mut Transform)>,
116) {
117 let (ship, mut transform) = query.into_inner();
118
119 let mut rotation_factor = 0.0;
120 let mut movement_factor = 0.0;
121
122 if keyboard_input.pressed(KeyCode::ArrowLeft) {
123 rotation_factor += 1.0;
124 }
125
126 if keyboard_input.pressed(KeyCode::ArrowRight) {
127 rotation_factor -= 1.0;
128 }
129
130 if keyboard_input.pressed(KeyCode::ArrowUp) {
131 movement_factor += 1.0;
132 }
133
134 // Update the ship rotation around the Z axis (perpendicular to the 2D plane of the screen)
135 transform.rotate_z(rotation_factor * ship.rotation_speed * time.delta_secs());
136
137 // Get the ship's forward vector by applying the current rotation to the ships initial facing
138 // vector
139 let movement_direction = transform.rotation * Vec3::Y;
140 // Get the distance the ship will move based on direction, the ship's movement speed and delta
141 // time
142 let movement_distance = movement_factor * ship.movement_speed * time.delta_secs();
143 // Create the change in translation using the new movement direction and distance
144 let translation_delta = movement_direction * movement_distance;
145 // Update the ship translation with our new translation delta
146 transform.translation += translation_delta;
147
148 // Bound the ship within the invisible level bounds
149 let extents = Vec3::from((BOUNDS / 2.0, 0.0));
150 transform.translation = transform.translation.min(extents).max(-extents);
151}
Sourcepub fn max(self, rhs: Vec3) -> Vec3
pub fn max(self, rhs: Vec3) -> Vec3
Returns a vector containing the maximum values for each element of self
and rhs
.
In other words this computes [self.x.max(rhs.x), self.y.max(rhs.y), ..]
.
Examples found in repository?
112fn player_movement_system(
113 time: Res<Time>,
114 keyboard_input: Res<ButtonInput<KeyCode>>,
115 query: Single<(&Player, &mut Transform)>,
116) {
117 let (ship, mut transform) = query.into_inner();
118
119 let mut rotation_factor = 0.0;
120 let mut movement_factor = 0.0;
121
122 if keyboard_input.pressed(KeyCode::ArrowLeft) {
123 rotation_factor += 1.0;
124 }
125
126 if keyboard_input.pressed(KeyCode::ArrowRight) {
127 rotation_factor -= 1.0;
128 }
129
130 if keyboard_input.pressed(KeyCode::ArrowUp) {
131 movement_factor += 1.0;
132 }
133
134 // Update the ship rotation around the Z axis (perpendicular to the 2D plane of the screen)
135 transform.rotate_z(rotation_factor * ship.rotation_speed * time.delta_secs());
136
137 // Get the ship's forward vector by applying the current rotation to the ships initial facing
138 // vector
139 let movement_direction = transform.rotation * Vec3::Y;
140 // Get the distance the ship will move based on direction, the ship's movement speed and delta
141 // time
142 let movement_distance = movement_factor * ship.movement_speed * time.delta_secs();
143 // Create the change in translation using the new movement direction and distance
144 let translation_delta = movement_direction * movement_distance;
145 // Update the ship translation with our new translation delta
146 transform.translation += translation_delta;
147
148 // Bound the ship within the invisible level bounds
149 let extents = Vec3::from((BOUNDS / 2.0, 0.0));
150 transform.translation = transform.translation.min(extents).max(-extents);
151}
Sourcepub fn clamp(self, min: Vec3, max: Vec3) -> Vec3
pub fn clamp(self, min: Vec3, max: Vec3) -> Vec3
Component-wise clamping of values, similar to f32::clamp
.
Each element in min
must be less-or-equal to the corresponding element in max
.
§Panics
Will panic if min
is greater than max
when glam_assert
is enabled.
Sourcepub fn min_element(self) -> f32
pub fn min_element(self) -> f32
Returns the horizontal minimum of self
.
In other words this computes min(x, y, ..)
.
Examples found in repository?
65fn change_scale_direction(mut cubes: Query<(&mut Transform, &mut Scaling)>) {
66 for (mut transform, mut cube) in &mut cubes {
67 // If an entity scaled beyond the maximum of its size in any dimension
68 // the scaling vector is flipped so the scaling is gradually reverted.
69 // Additionally, to ensure the condition does not trigger again we floor the elements to
70 // their next full value, which should be max_element_size at max.
71 if transform.scale.max_element() > cube.max_element_size {
72 cube.scale_direction *= -1.0;
73 transform.scale = transform.scale.floor();
74 }
75 // If an entity scaled beyond the minimum of its size in any dimension
76 // the scaling vector is also flipped.
77 // Additionally the Values are ceiled to be min_element_size at least
78 // and the scale direction is flipped.
79 // This way the entity will change the dimension in which it is scaled any time it
80 // reaches its min_element_size.
81 if transform.scale.min_element() < cube.min_element_size {
82 cube.scale_direction *= -1.0;
83 transform.scale = transform.scale.ceil();
84 cube.scale_direction = cube.scale_direction.zxy();
85 }
86 }
87}
Sourcepub fn max_element(self) -> f32
pub fn max_element(self) -> f32
Returns the horizontal maximum of self
.
In other words this computes max(x, y, ..)
.
Examples found in repository?
65fn change_scale_direction(mut cubes: Query<(&mut Transform, &mut Scaling)>) {
66 for (mut transform, mut cube) in &mut cubes {
67 // If an entity scaled beyond the maximum of its size in any dimension
68 // the scaling vector is flipped so the scaling is gradually reverted.
69 // Additionally, to ensure the condition does not trigger again we floor the elements to
70 // their next full value, which should be max_element_size at max.
71 if transform.scale.max_element() > cube.max_element_size {
72 cube.scale_direction *= -1.0;
73 transform.scale = transform.scale.floor();
74 }
75 // If an entity scaled beyond the minimum of its size in any dimension
76 // the scaling vector is also flipped.
77 // Additionally the Values are ceiled to be min_element_size at least
78 // and the scale direction is flipped.
79 // This way the entity will change the dimension in which it is scaled any time it
80 // reaches its min_element_size.
81 if transform.scale.min_element() < cube.min_element_size {
82 cube.scale_direction *= -1.0;
83 transform.scale = transform.scale.ceil();
84 cube.scale_direction = cube.scale_direction.zxy();
85 }
86 }
87}
Sourcepub fn element_sum(self) -> f32
pub fn element_sum(self) -> f32
Returns the sum of all elements of self
.
In other words, this computes self.x + self.y + ..
.
Sourcepub fn element_product(self) -> f32
pub fn element_product(self) -> f32
Returns the product of all elements of self
.
In other words, this computes self.x * self.y * ..
.
Sourcepub fn cmpeq(self, rhs: Vec3) -> BVec3
pub fn cmpeq(self, rhs: Vec3) -> BVec3
Returns a vector mask containing the result of a ==
comparison for each element of
self
and rhs
.
In other words, this computes [self.x == rhs.x, self.y == rhs.y, ..]
for all
elements.
Sourcepub fn cmpne(self, rhs: Vec3) -> BVec3
pub fn cmpne(self, rhs: Vec3) -> BVec3
Returns a vector mask containing the result of a !=
comparison for each element of
self
and rhs
.
In other words this computes [self.x != rhs.x, self.y != rhs.y, ..]
for all
elements.
Sourcepub fn cmpge(self, rhs: Vec3) -> BVec3
pub fn cmpge(self, rhs: Vec3) -> BVec3
Returns a vector mask containing the result of a >=
comparison for each element of
self
and rhs
.
In other words this computes [self.x >= rhs.x, self.y >= rhs.y, ..]
for all
elements.
Sourcepub fn cmpgt(self, rhs: Vec3) -> BVec3
pub fn cmpgt(self, rhs: Vec3) -> BVec3
Returns a vector mask containing the result of a >
comparison for each element of
self
and rhs
.
In other words this computes [self.x > rhs.x, self.y > rhs.y, ..]
for all
elements.
Sourcepub fn cmple(self, rhs: Vec3) -> BVec3
pub fn cmple(self, rhs: Vec3) -> BVec3
Returns a vector mask containing the result of a <=
comparison for each element of
self
and rhs
.
In other words this computes [self.x <= rhs.x, self.y <= rhs.y, ..]
for all
elements.
Sourcepub fn cmplt(self, rhs: Vec3) -> BVec3
pub fn cmplt(self, rhs: Vec3) -> BVec3
Returns a vector mask containing the result of a <
comparison for each element of
self
and rhs
.
In other words this computes [self.x < rhs.x, self.y < rhs.y, ..]
for all
elements.
Sourcepub fn abs(self) -> Vec3
pub fn abs(self) -> Vec3
Returns a vector containing the absolute value of each element of self
.
Sourcepub fn signum(self) -> Vec3
pub fn signum(self) -> Vec3
Returns a vector with elements representing the sign of self
.
1.0
if the number is positive,+0.0
orINFINITY
-1.0
if the number is negative,-0.0
orNEG_INFINITY
NAN
if the number isNAN
Sourcepub fn copysign(self, rhs: Vec3) -> Vec3
pub fn copysign(self, rhs: Vec3) -> Vec3
Returns a vector with signs of rhs
and the magnitudes of self
.
Sourcepub fn is_negative_bitmask(self) -> u32
pub fn is_negative_bitmask(self) -> u32
Returns a bitmask with the lowest 3 bits set to the sign bits from the elements of self
.
A negative element results in a 1
bit and a positive element in a 0
bit. Element x
goes
into the first lowest bit, element y
into the second, etc.
Sourcepub fn is_finite(self) -> bool
pub fn is_finite(self) -> bool
Returns true
if, and only if, all elements are finite. If any element is either
NaN
, positive or negative infinity, this will return false
.
Sourcepub fn is_finite_mask(self) -> BVec3
pub fn is_finite_mask(self) -> BVec3
Performs is_finite
on each element of self, returning a vector mask of the results.
In other words, this computes [x.is_finite(), y.is_finite(), ...]
.
Sourcepub fn is_nan_mask(self) -> BVec3
pub fn is_nan_mask(self) -> BVec3
Performs is_nan
on each element of self, returning a vector mask of the results.
In other words, this computes [x.is_nan(), y.is_nan(), ...]
.
Sourcepub fn length(self) -> f32
pub fn length(self) -> f32
Computes the length of self
.
Examples found in repository?
346fn calculate_initial_decal_transform(start: Vec3, looking_at: Vec3, size: Vec2) -> Transform {
347 let direction = looking_at - start;
348 let center = start + direction * 0.5;
349 Transform::from_translation(center)
350 .with_scale((size * 0.5).extend(direction.length()))
351 .looking_to(direction, Vec3::Y)
352}
353
354/// Rotates the cube a bit every frame.
355fn rotate_cube(mut meshes: Query<&mut Transform, With<Mesh3d>>) {
356 for mut transform in &mut meshes {
357 transform.rotate_y(CUBE_ROTATION_SPEED);
358 }
359}
360
361/// Updates the state of the radio buttons when the user clicks on one.
362fn update_radio_buttons(
363 mut widgets: Query<(
364 Entity,
365 Option<&mut BackgroundColor>,
366 Has<Text>,
367 &WidgetClickSender<Selection>,
368 )>,
369 app_status: Res<AppStatus>,
370 mut writer: TextUiWriter,
371) {
372 for (entity, maybe_bg_color, has_text, sender) in &mut widgets {
373 let selected = app_status.selection == **sender;
374 if let Some(mut bg_color) = maybe_bg_color {
375 widgets::update_ui_radio_button(&mut bg_color, selected);
376 }
377 if has_text {
378 widgets::update_ui_radio_button_text(entity, &mut writer, selected);
379 }
380 }
381}
382
383/// Changes the selection when the user clicks a radio button.
384fn handle_selection_change(
385 mut events: EventReader<WidgetClickEvent<Selection>>,
386 mut app_status: ResMut<AppStatus>,
387) {
388 for event in events.read() {
389 app_status.selection = **event;
390 }
391}
392
393/// Process a drag event that moves the selected object.
394fn process_move_input(
395 mut selections: Query<(&mut Transform, &Selection)>,
396 mouse_buttons: Res<ButtonInput<MouseButton>>,
397 mouse_motion: Res<AccumulatedMouseMotion>,
398 app_status: Res<AppStatus>,
399) {
400 // Only process drags when movement is selected.
401 if !mouse_buttons.pressed(MouseButton::Left) || app_status.drag_mode != DragMode::Move {
402 return;
403 }
404
405 for (mut transform, selection) in &mut selections {
406 if app_status.selection != *selection {
407 continue;
408 }
409
410 let position = transform.translation;
411
412 // Convert to spherical coordinates.
413 let radius = position.length();
414 let mut theta = acos(position.y / radius);
415 let mut phi = position.z.signum() * acos(position.x * position.xz().length_recip());
416
417 // Camera movement is the inverse of object movement.
418 let (phi_factor, theta_factor) = match *selection {
419 Selection::Camera => (1.0, -1.0),
420 Selection::DecalA | Selection::DecalB => (-1.0, 1.0),
421 };
422
423 // Adjust the spherical coordinates. Clamp the inclination to (0, π).
424 phi += phi_factor * mouse_motion.delta.x * MOVE_SPEED;
425 theta = f32::clamp(
426 theta + theta_factor * mouse_motion.delta.y * MOVE_SPEED,
427 0.001,
428 PI - 0.001,
429 );
430
431 // Convert spherical coordinates back to Cartesian coordinates.
432 transform.translation =
433 radius * vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
434
435 // Look at the center, but preserve the previous roll angle.
436 let roll = transform.rotation.to_euler(EulerRot::YXZ).2;
437 transform.look_at(Vec3::ZERO, Vec3::Y);
438 let (yaw, pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
439 transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
440 }
441}
More examples
300fn move_cars(
301 time: Res<Time>,
302 mut movables: Query<(&mut Transform, &Moves, &Children)>,
303 mut spins: Query<&mut Transform, (Without<Moves>, With<Rotates>)>,
304) {
305 for (mut transform, moves, children) in &mut movables {
306 let time = time.elapsed_secs() * 0.25;
307 let t = time + 0.5 * moves.0;
308 let dx = ops::cos(t);
309 let dz = -ops::sin(3.0 * t);
310 let speed_variation = (dx * dx + dz * dz).sqrt() * 0.15;
311 let t = t + speed_variation;
312 let prev = transform.translation;
313 transform.translation.x = race_track_pos(0.0, t).x;
314 transform.translation.z = race_track_pos(0.0, t).y;
315 transform.translation.y = -0.59;
316 let delta = transform.translation - prev;
317 transform.look_to(delta, Vec3::Y);
318 for child in children.iter() {
319 let Ok(mut wheel) = spins.get_mut(child) else {
320 continue;
321 };
322 let radius = wheel.scale.x;
323 let circumference = 2.0 * std::f32::consts::PI * radius;
324 let angle = delta.length() / circumference * std::f32::consts::PI * 2.0;
325 wheel.rotate_local_y(angle);
326 }
327 }
328}
137fn track_targets(
138 // `Single` ensures the system runs ONLY when exactly one matching entity exists.
139 mut player: Single<(&mut Transform, &Player)>,
140 // `Option<Single>` ensures that the system runs ONLY when zero or one matching entity exists.
141 enemy: Option<Single<&Transform, (With<Enemy>, Without<Player>)>>,
142 time: Res<Time>,
143) {
144 let (player_transform, player) = &mut *player;
145 if let Some(enemy_transform) = enemy {
146 // Enemy found, rotate and move towards it.
147 let delta = enemy_transform.translation - player_transform.translation;
148 let distance = delta.length();
149 let front = delta / distance;
150 let up = Vec3::Z;
151 let side = front.cross(up);
152 player_transform.rotation = Quat::from_mat3(&Mat3::from_cols(side, front, up));
153 let max_step = distance - player.min_follow_radius;
154 if 0.0 < max_step {
155 let velocity = (player.speed * time.delta_secs()).min(max_step);
156 player_transform.translation += front * velocity;
157 }
158 } else {
159 // 0 or multiple enemies found, keep searching.
160 player_transform.rotate_axis(Dir3::Z, player.rotation_speed * time.delta_secs());
161 }
162}
126fn scale_down_sphere_proportional_to_cube_travel_distance(
127 cubes: Query<(&Transform, &CubeState), Without<Center>>,
128 mut centers: Query<(&mut Transform, &Center)>,
129) {
130 // First we need to calculate the length of between
131 // the current position of the orbiting cube and the spawn position.
132 let mut distances = 0.0;
133 for (cube_transform, cube_state) in &cubes {
134 distances += (cube_state.start_pos - cube_transform.translation).length();
135 }
136 // Now we use the calculated value to scale the sphere in the center accordingly.
137 for (mut transform, center) in &mut centers {
138 // Calculate the new size from the calculated distances and the centers scale_factor.
139 // Since we want to have the sphere at its max_size at the cubes spawn location we start by
140 // using the max_size as start value and subtract the distances scaled by a scaling factor.
141 let mut new_size: f32 = center.max_size - center.scale_factor * distances;
142
143 // The new size should also not be smaller than the centers min_size.
144 // Therefore the max value out of (new_size, center.min_size) is used.
145 new_size = new_size.max(center.min_size);
146
147 // Now scale the sphere uniformly in all directions using new_size.
148 // Here Vec3:splat is used to create a vector with new_size in x, y and z direction.
149 transform.scale = Vec3::splat(new_size);
150 }
151}
298fn move_camera(
299 keyboard_input: Res<ButtonInput<KeyCode>>,
300 mut mouse_wheel_input: EventReader<MouseWheel>,
301 mut cameras: Query<&mut Transform, With<Camera>>,
302) {
303 let (mut distance_delta, mut theta_delta) = (0.0, 0.0);
304
305 // Handle keyboard events.
306 if keyboard_input.pressed(KeyCode::KeyW) {
307 distance_delta -= CAMERA_KEYBOARD_ZOOM_SPEED;
308 }
309 if keyboard_input.pressed(KeyCode::KeyS) {
310 distance_delta += CAMERA_KEYBOARD_ZOOM_SPEED;
311 }
312 if keyboard_input.pressed(KeyCode::KeyA) {
313 theta_delta += CAMERA_KEYBOARD_ORBIT_SPEED;
314 }
315 if keyboard_input.pressed(KeyCode::KeyD) {
316 theta_delta -= CAMERA_KEYBOARD_ORBIT_SPEED;
317 }
318
319 // Handle mouse events.
320 for mouse_wheel_event in mouse_wheel_input.read() {
321 distance_delta -= mouse_wheel_event.y * CAMERA_MOUSE_WHEEL_ZOOM_SPEED;
322 }
323
324 // Update transforms.
325 for mut camera_transform in cameras.iter_mut() {
326 let local_z = camera_transform.local_z().as_vec3().normalize_or_zero();
327 if distance_delta != 0.0 {
328 camera_transform.translation = (camera_transform.translation.length() + distance_delta)
329 .clamp(CAMERA_ZOOM_RANGE.start, CAMERA_ZOOM_RANGE.end)
330 * local_z;
331 }
332 if theta_delta != 0.0 {
333 camera_transform
334 .translate_around(Vec3::ZERO, Quat::from_axis_angle(Vec3::Y, theta_delta));
335 camera_transform.look_at(Vec3::ZERO, Vec3::Y);
336 }
337 }
338}
Sourcepub fn length_squared(self) -> f32
pub fn length_squared(self) -> f32
Computes the squared length of self
.
This is faster than length()
as it avoids a square root operation.
Examples found in repository?
122fn interact_bodies(mut query: Query<(&Mass, &GlobalTransform, &mut Acceleration)>) {
123 let mut iter = query.iter_combinations_mut();
124 while let Some([(Mass(m1), transform1, mut acc1), (Mass(m2), transform2, mut acc2)]) =
125 iter.fetch_next()
126 {
127 let delta = transform2.translation() - transform1.translation();
128 let distance_sq: f32 = delta.length_squared();
129
130 let f = GRAVITY_CONSTANT / distance_sq;
131 let force_unit_mass = delta * f;
132 acc1.0 += force_unit_mass * *m2;
133 acc2.0 -= force_unit_mass * *m1;
134 }
135}
More examples
127fn run_camera_controller(
128 time: Res<Time>,
129 mut windows: Query<&mut Window>,
130 accumulated_mouse_motion: Res<AccumulatedMouseMotion>,
131 accumulated_mouse_scroll: Res<AccumulatedMouseScroll>,
132 mouse_button_input: Res<ButtonInput<MouseButton>>,
133 key_input: Res<ButtonInput<KeyCode>>,
134 mut toggle_cursor_grab: Local<bool>,
135 mut mouse_cursor_grab: Local<bool>,
136 mut query: Query<(&mut Transform, &mut CameraController), With<Camera>>,
137) {
138 let dt = time.delta_secs();
139
140 let Ok((mut transform, mut controller)) = query.single_mut() else {
141 return;
142 };
143
144 if !controller.initialized {
145 let (yaw, pitch, _roll) = transform.rotation.to_euler(EulerRot::YXZ);
146 controller.yaw = yaw;
147 controller.pitch = pitch;
148 controller.initialized = true;
149 info!("{}", *controller);
150 }
151 if !controller.enabled {
152 return;
153 }
154
155 let mut scroll = 0.0;
156
157 let amount = match accumulated_mouse_scroll.unit {
158 MouseScrollUnit::Line => accumulated_mouse_scroll.delta.y,
159 MouseScrollUnit::Pixel => accumulated_mouse_scroll.delta.y / 16.0,
160 };
161 scroll += amount;
162 controller.walk_speed += scroll * controller.scroll_factor * controller.walk_speed;
163 controller.run_speed = controller.walk_speed * 3.0;
164
165 // Handle key input
166 let mut axis_input = Vec3::ZERO;
167 if key_input.pressed(controller.key_forward) {
168 axis_input.z += 1.0;
169 }
170 if key_input.pressed(controller.key_back) {
171 axis_input.z -= 1.0;
172 }
173 if key_input.pressed(controller.key_right) {
174 axis_input.x += 1.0;
175 }
176 if key_input.pressed(controller.key_left) {
177 axis_input.x -= 1.0;
178 }
179 if key_input.pressed(controller.key_up) {
180 axis_input.y += 1.0;
181 }
182 if key_input.pressed(controller.key_down) {
183 axis_input.y -= 1.0;
184 }
185
186 let mut cursor_grab_change = false;
187 if key_input.just_pressed(controller.keyboard_key_toggle_cursor_grab) {
188 *toggle_cursor_grab = !*toggle_cursor_grab;
189 cursor_grab_change = true;
190 }
191 if mouse_button_input.just_pressed(controller.mouse_key_cursor_grab) {
192 *mouse_cursor_grab = true;
193 cursor_grab_change = true;
194 }
195 if mouse_button_input.just_released(controller.mouse_key_cursor_grab) {
196 *mouse_cursor_grab = false;
197 cursor_grab_change = true;
198 }
199 let cursor_grab = *mouse_cursor_grab || *toggle_cursor_grab;
200
201 // Apply movement update
202 if axis_input != Vec3::ZERO {
203 let max_speed = if key_input.pressed(controller.key_run) {
204 controller.run_speed
205 } else {
206 controller.walk_speed
207 };
208 controller.velocity = axis_input.normalize() * max_speed;
209 } else {
210 let friction = controller.friction.clamp(0.0, 1.0);
211 controller.velocity *= 1.0 - friction;
212 if controller.velocity.length_squared() < 1e-6 {
213 controller.velocity = Vec3::ZERO;
214 }
215 }
216 let forward = *transform.forward();
217 let right = *transform.right();
218 transform.translation += controller.velocity.x * dt * right
219 + controller.velocity.y * dt * Vec3::Y
220 + controller.velocity.z * dt * forward;
221
222 // Handle cursor grab
223 if cursor_grab_change {
224 if cursor_grab {
225 for mut window in &mut windows {
226 if !window.focused {
227 continue;
228 }
229
230 window.cursor_options.grab_mode = CursorGrabMode::Locked;
231 window.cursor_options.visible = false;
232 }
233 } else {
234 for mut window in &mut windows {
235 window.cursor_options.grab_mode = CursorGrabMode::None;
236 window.cursor_options.visible = true;
237 }
238 }
239 }
240
241 // Handle mouse input
242 if accumulated_mouse_motion.delta != Vec2::ZERO && cursor_grab {
243 // Apply look update
244 controller.pitch = (controller.pitch
245 - accumulated_mouse_motion.delta.y * RADIANS_PER_DOT * controller.sensitivity)
246 .clamp(-PI / 2., PI / 2.);
247 controller.yaw -=
248 accumulated_mouse_motion.delta.x * RADIANS_PER_DOT * controller.sensitivity;
249 transform.rotation = Quat::from_euler(EulerRot::ZYX, 0.0, controller.yaw, controller.pitch);
250 }
251}
Sourcepub fn length_recip(self) -> f32
pub fn length_recip(self) -> f32
Computes 1.0 / length()
.
For valid results, self
must not be of length zero.
Sourcepub fn distance(self, rhs: Vec3) -> f32
pub fn distance(self, rhs: Vec3) -> f32
Computes the Euclidean distance between two points in space.
Examples found in repository?
416fn handle_keypress(
417 mut commands: Commands,
418 keyboard: Res<ButtonInput<KeyCode>>,
419 mut mode: ResMut<SamplingMode>,
420 mut spawn_mode: ResMut<SpawningMode>,
421 samples: Query<Entity, With<SamplePoint>>,
422 shapes: Res<SampledShapes>,
423 mut spawn_queue: ResMut<SpawnQueue>,
424 mut counter: ResMut<PointCounter>,
425 mut text_menus: Query<&mut Visibility, With<Text>>,
426 mut camera_rig: Single<&mut CameraRig>,
427) {
428 // R => restart, deleting all samples
429 if keyboard.just_pressed(KeyCode::KeyR) {
430 // Don't forget to zero out the counter!
431 counter.0 = 0;
432 for entity in &samples {
433 commands.entity(entity).despawn();
434 }
435 }
436
437 // S => sample once
438 if keyboard.just_pressed(KeyCode::KeyS) {
439 spawn_queue.0 += 1;
440 }
441
442 // D => sample a hundred
443 if keyboard.just_pressed(KeyCode::KeyD) {
444 spawn_queue.0 += 100;
445 }
446
447 // M => toggle mode between interior and boundary.
448 if keyboard.just_pressed(KeyCode::KeyM) {
449 match *mode {
450 SamplingMode::Interior => *mode = SamplingMode::Boundary,
451 SamplingMode::Boundary => *mode = SamplingMode::Interior,
452 }
453 }
454
455 // A => toggle spawning mode between automatic and manual.
456 if keyboard.just_pressed(KeyCode::KeyA) {
457 match *spawn_mode {
458 SpawningMode::Manual => *spawn_mode = SpawningMode::Automatic,
459 SpawningMode::Automatic => *spawn_mode = SpawningMode::Manual,
460 }
461 }
462
463 // Tab => toggle help menu.
464 if keyboard.just_pressed(KeyCode::Tab) {
465 for mut visibility in text_menus.iter_mut() {
466 *visibility = match *visibility {
467 Visibility::Hidden => Visibility::Visible,
468 _ => Visibility::Hidden,
469 };
470 }
471 }
472
473 // +/- => zoom camera.
474 if keyboard.just_pressed(KeyCode::NumpadSubtract) || keyboard.just_pressed(KeyCode::Minus) {
475 camera_rig.distance += MAX_CAMERA_DISTANCE / 15.0;
476 camera_rig.distance = camera_rig
477 .distance
478 .clamp(MIN_CAMERA_DISTANCE, MAX_CAMERA_DISTANCE);
479 }
480
481 if keyboard.just_pressed(KeyCode::NumpadAdd) {
482 camera_rig.distance -= MAX_CAMERA_DISTANCE / 15.0;
483 camera_rig.distance = camera_rig
484 .distance
485 .clamp(MIN_CAMERA_DISTANCE, MAX_CAMERA_DISTANCE);
486 }
487
488 // Arrows => Move camera focus
489 let left = keyboard.just_pressed(KeyCode::ArrowLeft);
490 let right = keyboard.just_pressed(KeyCode::ArrowRight);
491
492 if left || right {
493 let mut closest = 0;
494 let mut closest_distance = f32::MAX;
495 for (i, (_, position)) in shapes.0.iter().enumerate() {
496 let distance = camera_rig.target.distance(*position);
497 if distance < closest_distance {
498 closest = i;
499 closest_distance = distance;
500 }
501 }
502 if closest > 0 && left {
503 camera_rig.target = shapes.0[closest - 1].1;
504 }
505 if closest < shapes.0.len() - 1 && right {
506 camera_rig.target = shapes.0[closest + 1].1;
507 }
508 }
509}
Sourcepub fn distance_squared(self, rhs: Vec3) -> f32
pub fn distance_squared(self, rhs: Vec3) -> f32
Compute the squared euclidean distance between two points in space.
Sourcepub fn div_euclid(self, rhs: Vec3) -> Vec3
pub fn div_euclid(self, rhs: Vec3) -> Vec3
Returns the element-wise quotient of [Euclidean division] of self
by rhs
.
Sourcepub fn rem_euclid(self, rhs: Vec3) -> Vec3
pub fn rem_euclid(self, rhs: Vec3) -> Vec3
Returns the element-wise remainder of Euclidean division of self
by rhs
.
Sourcepub fn normalize(self) -> Vec3
pub fn normalize(self) -> Vec3
Returns self
normalized to length 1.0.
For valid results, self
must be finite and not of length zero, nor very close to zero.
See also Self::try_normalize()
and Self::normalize_or_zero()
.
Panics
Will panic if the resulting normalized vector is not finite when glam_assert
is enabled.
Examples found in repository?
More examples
170fn movement(
171 time: Res<Time>,
172 input: Res<ButtonInput<KeyCode>>,
173 mut query: Query<&mut Transform, With<Sprite>>,
174) {
175 for mut transform in &mut query {
176 let mut direction = Vec3::ZERO;
177 if input.pressed(KeyCode::ArrowLeft) {
178 direction.x -= 1.0;
179 }
180 if input.pressed(KeyCode::ArrowRight) {
181 direction.x += 1.0;
182 }
183 if input.pressed(KeyCode::ArrowUp) {
184 direction.y += 1.0;
185 }
186 if input.pressed(KeyCode::ArrowDown) {
187 direction.y -= 1.0;
188 }
189
190 if direction != Vec3::ZERO {
191 transform.translation += direction.normalize() * SPEED * time.delta_secs();
192 }
193 }
194}
121fn movement(
122 time: Res<Time>,
123 input: Res<ButtonInput<KeyCode>>,
124 mut query: Query<&mut Transform, With<Sprite>>,
125) {
126 for mut transform in &mut query {
127 let mut direction = Vec3::ZERO;
128 if input.pressed(KeyCode::ArrowLeft) {
129 direction.x -= 1.0;
130 }
131 if input.pressed(KeyCode::ArrowRight) {
132 direction.x += 1.0;
133 }
134 if input.pressed(KeyCode::ArrowUp) {
135 direction.y += 1.0;
136 }
137 if input.pressed(KeyCode::ArrowDown) {
138 direction.y -= 1.0;
139 }
140
141 if direction != Vec3::ZERO {
142 transform.translation += direction.normalize() * SPEED * time.delta_secs();
143 }
144 }
145}
91fn movement(
92 time: Res<Time>,
93 input: Res<ButtonInput<KeyCode>>,
94 mut query: Query<&mut Transform, With<Sprite>>,
95) {
96 for mut transform in &mut query {
97 let mut direction = Vec3::ZERO;
98 if input.pressed(KeyCode::ArrowLeft) {
99 direction.x -= 1.0;
100 }
101 if input.pressed(KeyCode::ArrowRight) {
102 direction.x += 1.0;
103 }
104 if input.pressed(KeyCode::ArrowUp) {
105 direction.y += 1.0;
106 }
107 if input.pressed(KeyCode::ArrowDown) {
108 direction.y -= 1.0;
109 }
110
111 if direction != Vec3::ZERO {
112 transform.translation += direction.normalize() * SPEED * time.delta_secs();
113 }
114 }
115}
420 pub fn movement(
421 time: Res<Time>,
422 input: Res<ButtonInput<KeyCode>>,
423 turbo: Option<Res<State<TurboMode>>>,
424 mut query: Query<&mut Transform, With<Sprite>>,
425 ) {
426 for mut transform in &mut query {
427 let mut direction = Vec3::ZERO;
428 if input.pressed(KeyCode::ArrowLeft) {
429 direction.x -= 1.0;
430 }
431 if input.pressed(KeyCode::ArrowRight) {
432 direction.x += 1.0;
433 }
434 if input.pressed(KeyCode::ArrowUp) {
435 direction.y += 1.0;
436 }
437 if input.pressed(KeyCode::ArrowDown) {
438 direction.y -= 1.0;
439 }
440
441 if direction != Vec3::ZERO {
442 transform.translation += direction.normalize()
443 * if turbo.is_some() { TURBO_SPEED } else { SPEED }
444 * time.delta_secs();
445 }
446 }
447 }
450fn handle_mouse_clicks(
451 buttons: Res<ButtonInput<MouseButton>>,
452 windows: Query<&Window, With<PrimaryWindow>>,
453 cameras: Query<(&Camera, &GlobalTransform)>,
454 mut main_objects: Query<&mut Transform, With<MainObject>>,
455) {
456 if !buttons.pressed(MouseButton::Left) {
457 return;
458 }
459 let Some(mouse_position) = windows.iter().next().and_then(Window::cursor_position) else {
460 return;
461 };
462 let Some((camera, camera_transform)) = cameras.iter().next() else {
463 return;
464 };
465
466 // Figure out where the user clicked on the plane.
467 let Ok(ray) = camera.viewport_to_world(camera_transform, mouse_position) else {
468 return;
469 };
470 let Some(ray_distance) = ray.intersect_plane(Vec3::ZERO, InfinitePlane3d::new(Vec3::Y)) else {
471 return;
472 };
473 let plane_intersection = ray.origin + ray.direction.normalize() * ray_distance;
474
475 // Move all the main objects.
476 for mut transform in main_objects.iter_mut() {
477 transform.translation = vec3(
478 plane_intersection.x,
479 transform.translation.y,
480 plane_intersection.z,
481 );
482 }
483}
Sourcepub fn try_normalize(self) -> Option<Vec3>
pub fn try_normalize(self) -> Option<Vec3>
Returns self
normalized to length 1.0 if possible, else returns None
.
In particular, if the input is zero (or very close to zero), or non-finite,
the result of this operation will be None
.
See also Self::normalize_or_zero()
.
Examples found in repository?
611fn rotate_primitive_3d_meshes(
612 mut primitives_3d: Query<
613 (&mut Transform, &ViewVisibility),
614 (With<PrimitiveData>, With<MeshDim3>),
615 >,
616 time: Res<Time>,
617) {
618 let rotation_3d = Quat::from_rotation_arc(
619 Vec3::Z,
620 Vec3::new(
621 ops::sin(time.elapsed_secs()),
622 ops::cos(time.elapsed_secs()),
623 ops::sin(time.elapsed_secs()) * 0.5,
624 )
625 .try_normalize()
626 .unwrap_or(Vec3::Z),
627 );
628 primitives_3d
629 .iter_mut()
630 .filter(|(_, vis)| vis.get())
631 .for_each(|(mut transform, _)| {
632 transform.rotation = rotation_3d;
633 });
634}
635
636fn draw_gizmos_3d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time: Res<Time>) {
637 const POSITION: Vec3 = Vec3::new(LEFT_RIGHT_OFFSET_3D, 0.0, 0.0);
638 let rotation = Quat::from_rotation_arc(
639 Vec3::Z,
640 Vec3::new(
641 ops::sin(time.elapsed_secs()),
642 ops::cos(time.elapsed_secs()),
643 ops::sin(time.elapsed_secs()) * 0.5,
644 )
645 .try_normalize()
646 .unwrap_or(Vec3::Z),
647 );
648 let isometry = Isometry3d::new(POSITION, rotation);
649 let color = Color::WHITE;
650 let resolution = 10;
651
652 #[expect(
653 clippy::match_same_arms,
654 reason = "Certain primitives don't have any 3D rendering support yet."
655 )]
656 match state.get() {
657 PrimitiveSelected::RectangleAndCuboid => {
658 gizmos.primitive_3d(&CUBOID, isometry, color);
659 }
660 PrimitiveSelected::CircleAndSphere => drop(
661 gizmos
662 .primitive_3d(&SPHERE, isometry, color)
663 .resolution(resolution),
664 ),
665 PrimitiveSelected::Ellipse => {}
666 PrimitiveSelected::Triangle => gizmos.primitive_3d(&TRIANGLE_3D, isometry, color),
667 PrimitiveSelected::Plane => drop(gizmos.primitive_3d(&PLANE_3D, isometry, color)),
668 PrimitiveSelected::Line => gizmos.primitive_3d(&LINE3D, isometry, color),
669 PrimitiveSelected::Segment => gizmos.primitive_3d(&SEGMENT_3D, isometry, color),
670 PrimitiveSelected::Polyline => gizmos.primitive_3d(&POLYLINE_3D, isometry, color),
671 PrimitiveSelected::Polygon => {}
672 PrimitiveSelected::RegularPolygon => {}
673 PrimitiveSelected::Capsule => drop(
674 gizmos
675 .primitive_3d(&CAPSULE_3D, isometry, color)
676 .resolution(resolution),
677 ),
678 PrimitiveSelected::Cylinder => drop(
679 gizmos
680 .primitive_3d(&CYLINDER, isometry, color)
681 .resolution(resolution),
682 ),
683 PrimitiveSelected::Cone => drop(
684 gizmos
685 .primitive_3d(&CONE, isometry, color)
686 .resolution(resolution),
687 ),
688 PrimitiveSelected::ConicalFrustum => {
689 gizmos.primitive_3d(&CONICAL_FRUSTUM, isometry, color);
690 }
691
692 PrimitiveSelected::Torus => drop(
693 gizmos
694 .primitive_3d(&TORUS, isometry, color)
695 .minor_resolution(resolution)
696 .major_resolution(resolution),
697 ),
698 PrimitiveSelected::Tetrahedron => {
699 gizmos.primitive_3d(&TETRAHEDRON, isometry, color);
700 }
701
702 PrimitiveSelected::Arc => {}
703 PrimitiveSelected::CircularSector => {}
704 PrimitiveSelected::CircularSegment => {}
705 }
706}
Sourcepub fn normalize_or(self, fallback: Vec3) -> Vec3
pub fn normalize_or(self, fallback: Vec3) -> Vec3
Returns self
normalized to length 1.0 if possible, else returns a
fallback value.
In particular, if the input is zero (or very close to zero), or non-finite, the result of this operation will be the fallback value.
See also Self::try_normalize()
.
Sourcepub fn normalize_or_zero(self) -> Vec3
pub fn normalize_or_zero(self) -> Vec3
Returns self
normalized to length 1.0 if possible, else returns zero.
In particular, if the input is zero (or very close to zero), or non-finite, the result of this operation will be zero.
See also Self::try_normalize()
.
Examples found in repository?
167fn handle_input(
168 keyboard_input: Res<ButtonInput<KeyCode>>,
169 mut query: Query<(&mut AccumulatedInput, &mut Velocity)>,
170) {
171 /// Since Bevy's default 2D camera setup is scaled such that
172 /// one unit is one pixel, you can think of this as
173 /// "How many pixels per second should the player move?"
174 const SPEED: f32 = 210.0;
175 for (mut input, mut velocity) in query.iter_mut() {
176 if keyboard_input.pressed(KeyCode::KeyW) {
177 input.y += 1.0;
178 }
179 if keyboard_input.pressed(KeyCode::KeyS) {
180 input.y -= 1.0;
181 }
182 if keyboard_input.pressed(KeyCode::KeyA) {
183 input.x -= 1.0;
184 }
185 if keyboard_input.pressed(KeyCode::KeyD) {
186 input.x += 1.0;
187 }
188
189 // Need to normalize and scale because otherwise
190 // diagonal movement would be faster than horizontal or vertical movement.
191 // This effectively averages the accumulated input.
192 velocity.0 = input.extend(0.0).normalize_or_zero() * SPEED;
193 }
194}
More examples
298fn move_camera(
299 keyboard_input: Res<ButtonInput<KeyCode>>,
300 mut mouse_wheel_input: EventReader<MouseWheel>,
301 mut cameras: Query<&mut Transform, With<Camera>>,
302) {
303 let (mut distance_delta, mut theta_delta) = (0.0, 0.0);
304
305 // Handle keyboard events.
306 if keyboard_input.pressed(KeyCode::KeyW) {
307 distance_delta -= CAMERA_KEYBOARD_ZOOM_SPEED;
308 }
309 if keyboard_input.pressed(KeyCode::KeyS) {
310 distance_delta += CAMERA_KEYBOARD_ZOOM_SPEED;
311 }
312 if keyboard_input.pressed(KeyCode::KeyA) {
313 theta_delta += CAMERA_KEYBOARD_ORBIT_SPEED;
314 }
315 if keyboard_input.pressed(KeyCode::KeyD) {
316 theta_delta -= CAMERA_KEYBOARD_ORBIT_SPEED;
317 }
318
319 // Handle mouse events.
320 for mouse_wheel_event in mouse_wheel_input.read() {
321 distance_delta -= mouse_wheel_event.y * CAMERA_MOUSE_WHEEL_ZOOM_SPEED;
322 }
323
324 // Update transforms.
325 for mut camera_transform in cameras.iter_mut() {
326 let local_z = camera_transform.local_z().as_vec3().normalize_or_zero();
327 if distance_delta != 0.0 {
328 camera_transform.translation = (camera_transform.translation.length() + distance_delta)
329 .clamp(CAMERA_ZOOM_RANGE.start, CAMERA_ZOOM_RANGE.end)
330 * local_z;
331 }
332 if theta_delta != 0.0 {
333 camera_transform
334 .translate_around(Vec3::ZERO, Quat::from_axis_angle(Vec3::Y, theta_delta));
335 camera_transform.look_at(Vec3::ZERO, Vec3::Y);
336 }
337 }
338}
215fn move_camera(
216 keyboard_input: Res<ButtonInput<KeyCode>>,
217 mut mouse_wheel_events: EventReader<MouseWheel>,
218 mut cameras: Query<&mut Transform, With<Camera3d>>,
219) {
220 let (mut zoom_delta, mut theta_delta) = (0.0, 0.0);
221
222 // Process zoom in and out via the keyboard.
223 if keyboard_input.pressed(KeyCode::KeyW) || keyboard_input.pressed(KeyCode::ArrowUp) {
224 zoom_delta -= CAMERA_KEYBOARD_ZOOM_SPEED;
225 } else if keyboard_input.pressed(KeyCode::KeyS) || keyboard_input.pressed(KeyCode::ArrowDown) {
226 zoom_delta += CAMERA_KEYBOARD_ZOOM_SPEED;
227 }
228
229 // Process left and right pan via the keyboard.
230 if keyboard_input.pressed(KeyCode::KeyA) || keyboard_input.pressed(KeyCode::ArrowLeft) {
231 theta_delta -= CAMERA_KEYBOARD_PAN_SPEED;
232 } else if keyboard_input.pressed(KeyCode::KeyD) || keyboard_input.pressed(KeyCode::ArrowRight) {
233 theta_delta += CAMERA_KEYBOARD_PAN_SPEED;
234 }
235
236 // Process zoom in and out via the mouse wheel.
237 for event in mouse_wheel_events.read() {
238 zoom_delta -= event.y * CAMERA_MOUSE_MOVEMENT_SPEED;
239 }
240
241 // Update the camera transform.
242 for transform in cameras.iter_mut() {
243 let transform = transform.into_inner();
244
245 let direction = transform.translation.normalize_or_zero();
246 let magnitude = transform.translation.length();
247
248 let new_direction = Mat3::from_rotation_y(theta_delta) * direction;
249 let new_magnitude = (magnitude + zoom_delta).max(MIN_ZOOM_DISTANCE);
250
251 transform.translation = new_direction * new_magnitude;
252 transform.look_at(CAMERA_FOCAL_POINT, Vec3::Y);
253 }
254}
22fn setup(
23 mut commands: Commands,
24 mut meshes: ResMut<Assets<Mesh>>,
25 mut standard_materials: ResMut<Assets<StandardMaterial>>,
26 mut decal_standard_materials: ResMut<Assets<ForwardDecalMaterial<StandardMaterial>>>,
27 asset_server: Res<AssetServer>,
28) {
29 // Spawn the forward decal
30 commands.spawn((
31 Name::new("Decal"),
32 ForwardDecal,
33 MeshMaterial3d(decal_standard_materials.add(ForwardDecalMaterial {
34 base: StandardMaterial {
35 base_color_texture: Some(asset_server.load("textures/uv_checker_bw.png")),
36 ..default()
37 },
38 extension: ForwardDecalMaterialExt {
39 depth_fade_factor: 1.0,
40 },
41 })),
42 Transform::from_scale(Vec3::splat(4.0)),
43 ));
44
45 commands.spawn((
46 Name::new("Camera"),
47 Camera3d::default(),
48 CameraController::default(),
49 DepthPrepass, // Must enable the depth prepass to render forward decals
50 Transform::from_xyz(2.0, 9.5, 2.5).looking_at(Vec3::ZERO, Vec3::Y),
51 ));
52
53 let white_material = standard_materials.add(Color::WHITE);
54
55 commands.spawn((
56 Name::new("Floor"),
57 Mesh3d(meshes.add(Rectangle::from_length(10.0))),
58 MeshMaterial3d(white_material.clone()),
59 Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
60 ));
61
62 // Spawn a few cube with random rotations to showcase how the decals behave with non-flat geometry
63 let num_obs = 10;
64 let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
65 for i in 0..num_obs {
66 for j in 0..num_obs {
67 let rotation_axis: [f32; 3] = rng.r#gen();
68 let rotation_vec: Vec3 = rotation_axis.into();
69 let rotation: u32 = rng.gen_range(0..360);
70 let transform = Transform::from_xyz(
71 (-num_obs + 1) as f32 / 2.0 + i as f32,
72 -0.2,
73 (-num_obs + 1) as f32 / 2.0 + j as f32,
74 )
75 .with_rotation(Quat::from_axis_angle(
76 rotation_vec.normalize_or_zero(),
77 (rotation as f32).to_radians(),
78 ));
79
80 commands.spawn((
81 Mesh3d(meshes.add(Cuboid::from_length(0.6))),
82 MeshMaterial3d(white_material.clone()),
83 transform,
84 ));
85 }
86 }
87
88 commands.spawn((
89 Name::new("Light"),
90 PointLight {
91 shadows_enabled: true,
92 ..default()
93 },
94 Transform::from_xyz(4.0, 8.0, 4.0),
95 ));
96}
Sourcepub fn is_normalized(self) -> bool
pub fn is_normalized(self) -> bool
Returns whether self
is length 1.0
or not.
Uses a precision threshold of approximately 1e-4
.
Sourcepub fn project_onto(self, rhs: Vec3) -> Vec3
pub fn project_onto(self, rhs: Vec3) -> Vec3
Returns the vector projection of self
onto rhs
.
rhs
must be of non-zero length.
§Panics
Will panic if rhs
is zero length when glam_assert
is enabled.
Sourcepub fn reject_from(self, rhs: Vec3) -> Vec3
pub fn reject_from(self, rhs: Vec3) -> Vec3
Returns the vector rejection of self
from rhs
.
The vector rejection is the vector perpendicular to the projection of self
onto
rhs
, in rhs words the result of self - self.project_onto(rhs)
.
rhs
must be of non-zero length.
§Panics
Will panic if rhs
has a length of zero when glam_assert
is enabled.
Sourcepub fn project_onto_normalized(self, rhs: Vec3) -> Vec3
pub fn project_onto_normalized(self, rhs: Vec3) -> Vec3
Returns the vector projection of self
onto rhs
.
rhs
must be normalized.
§Panics
Will panic if rhs
is not normalized when glam_assert
is enabled.
Sourcepub fn reject_from_normalized(self, rhs: Vec3) -> Vec3
pub fn reject_from_normalized(self, rhs: Vec3) -> Vec3
Returns the vector rejection of self
from rhs
.
The vector rejection is the vector perpendicular to the projection of self
onto
rhs
, in rhs words the result of self - self.project_onto(rhs)
.
rhs
must be normalized.
§Panics
Will panic if rhs
is not normalized when glam_assert
is enabled.
Sourcepub fn round(self) -> Vec3
pub fn round(self) -> Vec3
Returns a vector containing the nearest integer to a number for each element of self
.
Round half-way cases away from 0.0.
Sourcepub fn floor(self) -> Vec3
pub fn floor(self) -> Vec3
Returns a vector containing the largest integer less than or equal to a number for each
element of self
.
Examples found in repository?
65fn change_scale_direction(mut cubes: Query<(&mut Transform, &mut Scaling)>) {
66 for (mut transform, mut cube) in &mut cubes {
67 // If an entity scaled beyond the maximum of its size in any dimension
68 // the scaling vector is flipped so the scaling is gradually reverted.
69 // Additionally, to ensure the condition does not trigger again we floor the elements to
70 // their next full value, which should be max_element_size at max.
71 if transform.scale.max_element() > cube.max_element_size {
72 cube.scale_direction *= -1.0;
73 transform.scale = transform.scale.floor();
74 }
75 // If an entity scaled beyond the minimum of its size in any dimension
76 // the scaling vector is also flipped.
77 // Additionally the Values are ceiled to be min_element_size at least
78 // and the scale direction is flipped.
79 // This way the entity will change the dimension in which it is scaled any time it
80 // reaches its min_element_size.
81 if transform.scale.min_element() < cube.min_element_size {
82 cube.scale_direction *= -1.0;
83 transform.scale = transform.scale.ceil();
84 cube.scale_direction = cube.scale_direction.zxy();
85 }
86 }
87}
Sourcepub fn ceil(self) -> Vec3
pub fn ceil(self) -> Vec3
Returns a vector containing the smallest integer greater than or equal to a number for
each element of self
.
Examples found in repository?
65fn change_scale_direction(mut cubes: Query<(&mut Transform, &mut Scaling)>) {
66 for (mut transform, mut cube) in &mut cubes {
67 // If an entity scaled beyond the maximum of its size in any dimension
68 // the scaling vector is flipped so the scaling is gradually reverted.
69 // Additionally, to ensure the condition does not trigger again we floor the elements to
70 // their next full value, which should be max_element_size at max.
71 if transform.scale.max_element() > cube.max_element_size {
72 cube.scale_direction *= -1.0;
73 transform.scale = transform.scale.floor();
74 }
75 // If an entity scaled beyond the minimum of its size in any dimension
76 // the scaling vector is also flipped.
77 // Additionally the Values are ceiled to be min_element_size at least
78 // and the scale direction is flipped.
79 // This way the entity will change the dimension in which it is scaled any time it
80 // reaches its min_element_size.
81 if transform.scale.min_element() < cube.min_element_size {
82 cube.scale_direction *= -1.0;
83 transform.scale = transform.scale.ceil();
84 cube.scale_direction = cube.scale_direction.zxy();
85 }
86 }
87}
Sourcepub fn trunc(self) -> Vec3
pub fn trunc(self) -> Vec3
Returns a vector containing the integer part each element of self
. This means numbers are
always truncated towards zero.
Sourcepub fn fract(self) -> Vec3
pub fn fract(self) -> Vec3
Returns a vector containing the fractional part of the vector as self - self.trunc()
.
Note that this differs from the GLSL implementation of fract
which returns
self - self.floor()
.
Note that this is fast but not precise for large numbers.
Sourcepub fn fract_gl(self) -> Vec3
pub fn fract_gl(self) -> Vec3
Returns a vector containing the fractional part of the vector as self - self.floor()
.
Note that this differs from the Rust implementation of fract
which returns
self - self.trunc()
.
Note that this is fast but not precise for large numbers.
Sourcepub fn exp(self) -> Vec3
pub fn exp(self) -> Vec3
Returns a vector containing e^self
(the exponential function) for each element of
self
.
Sourcepub fn powf(self, n: f32) -> Vec3
pub fn powf(self, n: f32) -> Vec3
Returns a vector containing each element of self
raised to the power of n
.
Sourcepub fn recip(self) -> Vec3
pub fn recip(self) -> Vec3
Returns a vector containing the reciprocal 1.0/n
of each element of self
.
Sourcepub fn lerp(self, rhs: Vec3, s: f32) -> Vec3
pub fn lerp(self, rhs: Vec3, s: f32) -> Vec3
Performs a linear interpolation between self
and rhs
based on the value s
.
When s
is 0.0
, the result will be equal to self
. When s
is 1.0
, the result
will be equal to rhs
. When s
is outside of range [0, 1]
, the result is linearly
extrapolated.
Examples found in repository?
More examples
185fn move_camera(
186 mut camera: Single<&mut Transform, With<CameraController>>,
187 mut current_view: Local<usize>,
188 button: Res<ButtonInput<MouseButton>>,
189) {
190 if button.just_pressed(MouseButton::Left) {
191 *current_view = (*current_view + 1) % CAMERA_POSITIONS.len();
192 }
193 let target = CAMERA_POSITIONS[*current_view];
194 camera.translation = camera.translation.lerp(target.translation, 0.2);
195 camera.rotation = camera.rotation.slerp(target.rotation, 0.2);
196}
224fn interpolate_rendered_transform(
225 fixed_time: Res<Time<Fixed>>,
226 mut query: Query<(
227 &mut Transform,
228 &PhysicalTranslation,
229 &PreviousPhysicalTranslation,
230 )>,
231) {
232 for (mut transform, current_physical_translation, previous_physical_translation) in
233 query.iter_mut()
234 {
235 let previous = previous_physical_translation.0;
236 let current = current_physical_translation.0;
237 // The overstep fraction is a value between 0 and 1 that tells us how far we are between two fixed timesteps.
238 let alpha = fixed_time.overstep_fraction();
239
240 let rendered_translation = previous.lerp(current, alpha);
241 transform.translation = rendered_translation;
242 }
243}
267fn focus_camera(
268 time: Res<Time>,
269 mut game: ResMut<Game>,
270 mut transforms: ParamSet<(Query<&mut Transform, With<Camera3d>>, Query<&Transform>)>,
271) {
272 const SPEED: f32 = 2.0;
273 // if there is both a player and a bonus, target the mid-point of them
274 if let (Some(player_entity), Some(bonus_entity)) = (game.player.entity, game.bonus.entity) {
275 let transform_query = transforms.p1();
276 if let (Ok(player_transform), Ok(bonus_transform)) = (
277 transform_query.get(player_entity),
278 transform_query.get(bonus_entity),
279 ) {
280 game.camera_should_focus = player_transform
281 .translation
282 .lerp(bonus_transform.translation, 0.5);
283 }
284 // otherwise, if there is only a player, target the player
285 } else if let Some(player_entity) = game.player.entity {
286 if let Ok(player_transform) = transforms.p1().get(player_entity) {
287 game.camera_should_focus = player_transform.translation;
288 }
289 // otherwise, target the middle
290 } else {
291 game.camera_should_focus = Vec3::from(RESET_FOCUS);
292 }
293 // calculate the camera motion based on the difference between where the camera is looking
294 // and where it should be looking; the greater the distance, the faster the motion;
295 // smooth out the camera movement using the frame time
296 let mut camera_motion = game.camera_should_focus - game.camera_is_focus;
297 if camera_motion.length() > 0.2 {
298 camera_motion *= SPEED * time.delta_secs();
299 // set the new camera's actual focus
300 game.camera_is_focus += camera_motion;
301 }
302 // look at that new camera's actual focus
303 for mut transform in transforms.p0().iter_mut() {
304 *transform = transform.looking_at(game.camera_is_focus, Vec3::Y);
305 }
306}
Sourcepub fn move_towards(&self, rhs: Vec3, d: f32) -> Vec3
pub fn move_towards(&self, rhs: Vec3, d: f32) -> Vec3
Moves towards rhs
based on the value d
.
When d
is 0.0
, the result will be equal to self
. When d
is equal to
self.distance(rhs)
, the result will be equal to rhs
. Will not go past rhs
.
Sourcepub fn midpoint(self, rhs: Vec3) -> Vec3
pub fn midpoint(self, rhs: Vec3) -> Vec3
Calculates the midpoint between self
and rhs
.
The midpoint is the average of, or halfway point between, two vectors.
a.midpoint(b)
should yield the same result as a.lerp(b, 0.5)
while being slightly cheaper to compute.
Sourcepub fn abs_diff_eq(self, rhs: Vec3, max_abs_diff: f32) -> bool
pub fn abs_diff_eq(self, rhs: Vec3, max_abs_diff: f32) -> bool
Returns true if the absolute difference of all elements between self
and rhs
is
less than or equal to max_abs_diff
.
This can be used to compare if two vectors contain similar elements. It works best when
comparing with a known value. The max_abs_diff
that should be used used depends on
the values being compared against.
For more see comparing floating point numbers.
Sourcepub fn clamp_length(self, min: f32, max: f32) -> Vec3
pub fn clamp_length(self, min: f32, max: f32) -> Vec3
Returns a vector with a length no less than min
and no more than max
.
§Panics
Will panic if min
is greater than max
, or if either min
or max
is negative, when glam_assert
is enabled.
Sourcepub fn clamp_length_max(self, max: f32) -> Vec3
pub fn clamp_length_max(self, max: f32) -> Vec3
Returns a vector with a length no more than max
.
§Panics
Will panic if max
is negative when glam_assert
is enabled.
Sourcepub fn clamp_length_min(self, min: f32) -> Vec3
pub fn clamp_length_min(self, min: f32) -> Vec3
Returns a vector with a length no less than min
.
§Panics
Will panic if min
is negative when glam_assert
is enabled.
Sourcepub fn mul_add(self, a: Vec3, b: Vec3) -> Vec3
pub fn mul_add(self, a: Vec3, b: Vec3) -> Vec3
Fused multiply-add. Computes (self * a) + b
element-wise with only one rounding
error, yielding a more accurate result than an unfused multiply-add.
Using mul_add
may be more performant than an unfused multiply-add if the target
architecture has a dedicated fma CPU instruction. However, this is not always true,
and will be heavily dependant on designing algorithms with specific target hardware in
mind.
Sourcepub fn reflect(self, normal: Vec3) -> Vec3
pub fn reflect(self, normal: Vec3) -> Vec3
Returns the reflection vector for a given incident vector self
and surface normal
normal
.
normal
must be normalized.
§Panics
Will panic if normal
is not normalized when glam_assert
is enabled.
Examples found in repository?
48fn bounce_ray(mut ray: Ray3d, ray_cast: &mut MeshRayCast, gizmos: &mut Gizmos, color: Color) {
49 let mut intersections = Vec::with_capacity(MAX_BOUNCES + 1);
50 intersections.push((ray.origin, Color::srgb(30.0, 0.0, 0.0)));
51
52 for i in 0..MAX_BOUNCES {
53 // Cast the ray and get the first hit
54 let Some((_, hit)) = ray_cast
55 .cast_ray(ray, &MeshRayCastSettings::default())
56 .first()
57 else {
58 break;
59 };
60
61 // Draw the point of intersection and add it to the list
62 let brightness = 1.0 + 10.0 * (1.0 - i as f32 / MAX_BOUNCES as f32);
63 intersections.push((hit.point, Color::BLACK.mix(&color, brightness)));
64 gizmos.sphere(hit.point, 0.005, Color::BLACK.mix(&color, brightness * 2.0));
65
66 // Reflect the ray off of the surface
67 ray.direction = Dir3::new(ray.direction.reflect(hit.normal)).unwrap();
68 ray.origin = hit.point + ray.direction * 1e-6;
69 }
70 gizmos.linestrip_gradient(intersections);
71}
Sourcepub fn refract(self, normal: Vec3, eta: f32) -> Vec3
pub fn refract(self, normal: Vec3, eta: f32) -> Vec3
Returns the refraction direction for a given incident vector self
, surface normal
normal
and ratio of indices of refraction, eta
. When total internal reflection occurs,
a zero vector will be returned.
self
and normal
must be normalized.
§Panics
Will panic if self
or normal
is not normalized when glam_assert
is enabled.
Sourcepub fn angle_between(self, rhs: Vec3) -> f32
pub fn angle_between(self, rhs: Vec3) -> f32
Returns the angle (in radians) between two vectors in the range [0, +π]
.
The inputs do not need to be unit vectors however they must be non-zero.
Sourcepub fn any_orthogonal_vector(&self) -> Vec3
pub fn any_orthogonal_vector(&self) -> Vec3
Returns some vector that is orthogonal to the given one.
The input vector must be finite and non-zero.
The output vector is not necessarily unit length. For that use
Self::any_orthonormal_vector()
instead.
Sourcepub fn any_orthonormal_vector(&self) -> Vec3
pub fn any_orthonormal_vector(&self) -> Vec3
Returns any unit vector that is orthogonal to the given one.
The input vector must be unit length.
§Panics
Will panic if self
is not normalized when glam_assert
is enabled.
Sourcepub fn any_orthonormal_pair(&self) -> (Vec3, Vec3)
pub fn any_orthonormal_pair(&self) -> (Vec3, Vec3)
Given a unit vector return two other vectors that together form an orthonormal basis. That is, all three vectors are orthogonal to each other and are normalized.
§Panics
Will panic if self
is not normalized when glam_assert
is enabled.
Sourcepub fn as_i16vec3(&self) -> I16Vec3
pub fn as_i16vec3(&self) -> I16Vec3
Casts all elements of self
to i16
.
Sourcepub fn as_u16vec3(&self) -> U16Vec3
pub fn as_u16vec3(&self) -> U16Vec3
Casts all elements of self
to u16
.
Sourcepub fn as_i64vec3(&self) -> I64Vec3
pub fn as_i64vec3(&self) -> I64Vec3
Casts all elements of self
to i64
.
Sourcepub fn as_u64vec3(&self) -> U64Vec3
pub fn as_u64vec3(&self) -> U64Vec3
Casts all elements of self
to u64
.
Trait Implementations§
Source§impl AddAssign<&Vec3> for Vec3
impl AddAssign<&Vec3> for Vec3
Source§fn add_assign(&mut self, rhs: &Vec3)
fn add_assign(&mut self, rhs: &Vec3)
+=
operation. Read moreSource§impl AddAssign<&f32> for Vec3
impl AddAssign<&f32> for Vec3
Source§fn add_assign(&mut self, rhs: &f32)
fn add_assign(&mut self, rhs: &f32)
+=
operation. Read moreSource§impl AddAssign<f32> for Vec3
impl AddAssign<f32> for Vec3
Source§fn add_assign(&mut self, rhs: f32)
fn add_assign(&mut self, rhs: f32)
+=
operation. Read moreSource§impl AddAssign for Vec3
impl AddAssign for Vec3
Source§fn add_assign(&mut self, rhs: Vec3)
fn add_assign(&mut self, rhs: Vec3)
+=
operation. Read moreSource§impl Animatable for Vec3
impl Animatable for Vec3
Source§impl AsMutVectorParts<f32, 3> for Vec3
impl AsMutVectorParts<f32, 3> for Vec3
fn as_mut_parts(&mut self) -> &mut [f32; 3]
Source§impl AsRefVectorParts<f32, 3> for Vec3
impl AsRefVectorParts<f32, 3> for Vec3
fn as_ref_parts(&self) -> &[f32; 3]
Source§impl CreateFrom for Vec3
impl CreateFrom for Vec3
Source§impl<'de> Deserialize<'de> for Vec3
Deserialize expects a sequence of 3 values.
impl<'de> Deserialize<'de> for Vec3
Deserialize expects a sequence of 3 values.
Source§fn deserialize<D>(
deserializer: D,
) -> Result<Vec3, <D as Deserializer<'de>>::Error>where
D: Deserializer<'de>,
fn deserialize<D>(
deserializer: D,
) -> Result<Vec3, <D as Deserializer<'de>>::Error>where
D: Deserializer<'de>,
Source§impl Distribution<Vec3> for UniformMeshSampler
impl Distribution<Vec3> for UniformMeshSampler
Source§impl DivAssign<&Vec3> for Vec3
impl DivAssign<&Vec3> for Vec3
Source§fn div_assign(&mut self, rhs: &Vec3)
fn div_assign(&mut self, rhs: &Vec3)
/=
operation. Read moreSource§impl DivAssign<&f32> for Vec3
impl DivAssign<&f32> for Vec3
Source§fn div_assign(&mut self, rhs: &f32)
fn div_assign(&mut self, rhs: &f32)
/=
operation. Read moreSource§impl DivAssign<f32> for Vec3
impl DivAssign<f32> for Vec3
Source§fn div_assign(&mut self, rhs: f32)
fn div_assign(&mut self, rhs: f32)
/=
operation. Read moreSource§impl DivAssign for Vec3
impl DivAssign for Vec3
Source§fn div_assign(&mut self, rhs: Vec3)
fn div_assign(&mut self, rhs: Vec3)
/=
operation. Read moreSource§impl From<Vec3> for Isometry3d
impl From<Vec3> for Isometry3d
Source§fn from(translation: Vec3) -> Isometry3d
fn from(translation: Vec3) -> Isometry3d
Source§impl FromIterator<Vec3> for BoxedPolyline3d
impl FromIterator<Vec3> for BoxedPolyline3d
Source§fn from_iter<I>(iter: I) -> BoxedPolyline3dwhere
I: IntoIterator<Item = Vec3>,
fn from_iter<I>(iter: I) -> BoxedPolyline3dwhere
I: IntoIterator<Item = Vec3>,
Source§impl<const N: usize> FromIterator<Vec3> for Polyline3d<N>
impl<const N: usize> FromIterator<Vec3> for Polyline3d<N>
Source§fn from_iter<I>(iter: I) -> Polyline3d<N>where
I: IntoIterator<Item = Vec3>,
fn from_iter<I>(iter: I) -> Polyline3d<N>where
I: IntoIterator<Item = Vec3>,
Source§impl FromReflect for Vec3
impl FromReflect for Vec3
Source§fn from_reflect(reflect: &(dyn PartialReflect + 'static)) -> Option<Vec3>
fn from_reflect(reflect: &(dyn PartialReflect + 'static)) -> Option<Vec3>
Self
from a reflected value.Source§fn take_from_reflect(
reflect: Box<dyn PartialReflect>,
) -> Result<Self, Box<dyn PartialReflect>>
fn take_from_reflect( reflect: Box<dyn PartialReflect>, ) -> Result<Self, Box<dyn PartialReflect>>
Self
using,
constructing the value using from_reflect
if that fails. Read moreSource§impl FromVectorParts<f32, 3> for Vec3
impl FromVectorParts<f32, 3> for Vec3
Source§impl GetOwnership for &Vec3
impl GetOwnership for &Vec3
Source§impl GetOwnership for &mut Vec3
impl GetOwnership for &mut Vec3
Source§impl GetOwnership for Vec3
impl GetOwnership for Vec3
Source§impl GetTypeRegistration for Vec3
impl GetTypeRegistration for Vec3
Source§fn get_type_registration() -> TypeRegistration
fn get_type_registration() -> TypeRegistration
TypeRegistration
for this type.Source§fn register_type_dependencies(registry: &mut TypeRegistry)
fn register_type_dependencies(registry: &mut TypeRegistry)
Source§impl IntoReturn for &Vec3
impl IntoReturn for &Vec3
Source§impl IntoReturn for &mut Vec3
impl IntoReturn for &mut Vec3
Source§impl IntoReturn for Vec3
impl IntoReturn for Vec3
Source§impl Mul<Vec3> for GlobalTransform
impl Mul<Vec3> for GlobalTransform
Source§impl Mul<Vec3> for Isometry3d
impl Mul<Vec3> for Isometry3d
Source§impl MulAssign<&Vec3> for Vec3
impl MulAssign<&Vec3> for Vec3
Source§fn mul_assign(&mut self, rhs: &Vec3)
fn mul_assign(&mut self, rhs: &Vec3)
*=
operation. Read moreSource§impl MulAssign<&f32> for Vec3
impl MulAssign<&f32> for Vec3
Source§fn mul_assign(&mut self, rhs: &f32)
fn mul_assign(&mut self, rhs: &f32)
*=
operation. Read moreSource§impl MulAssign<f32> for Vec3
impl MulAssign<f32> for Vec3
Source§fn mul_assign(&mut self, rhs: f32)
fn mul_assign(&mut self, rhs: f32)
*=
operation. Read moreSource§impl MulAssign for Vec3
impl MulAssign for Vec3
Source§fn mul_assign(&mut self, rhs: Vec3)
fn mul_assign(&mut self, rhs: Vec3)
*=
operation. Read moreSource§impl NormedVectorSpace for Vec3
impl NormedVectorSpace for Vec3
Source§fn norm_squared(self) -> f32
fn norm_squared(self) -> f32
NormedVectorSpace::norm
.Source§fn distance(self, rhs: Self) -> f32
fn distance(self, rhs: Self) -> f32
Source§fn distance_squared(self, rhs: Self) -> f32
fn distance_squared(self, rhs: Self) -> f32
NormedVectorSpace::distance
.Source§impl PartialReflect for Vec3
impl PartialReflect for Vec3
Source§fn get_represented_type_info(&self) -> Option<&'static TypeInfo>
fn get_represented_type_info(&self) -> Option<&'static TypeInfo>
Source§fn try_apply(
&mut self,
value: &(dyn PartialReflect + 'static),
) -> Result<(), ApplyError>
fn try_apply( &mut self, value: &(dyn PartialReflect + 'static), ) -> Result<(), ApplyError>
Source§fn reflect_kind(&self) -> ReflectKind
fn reflect_kind(&self) -> ReflectKind
Source§fn reflect_ref(&self) -> ReflectRef<'_>
fn reflect_ref(&self) -> ReflectRef<'_>
Source§fn reflect_mut(&mut self) -> ReflectMut<'_>
fn reflect_mut(&mut self) -> ReflectMut<'_>
Source§fn reflect_owned(self: Box<Vec3>) -> ReflectOwned
fn reflect_owned(self: Box<Vec3>) -> ReflectOwned
Source§fn try_into_reflect(
self: Box<Vec3>,
) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>>
fn try_into_reflect( self: Box<Vec3>, ) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>>
Source§fn try_as_reflect(&self) -> Option<&(dyn Reflect + 'static)>
fn try_as_reflect(&self) -> Option<&(dyn Reflect + 'static)>
Source§fn try_as_reflect_mut(&mut self) -> Option<&mut (dyn Reflect + 'static)>
fn try_as_reflect_mut(&mut self) -> Option<&mut (dyn Reflect + 'static)>
Source§fn into_partial_reflect(self: Box<Vec3>) -> Box<dyn PartialReflect>
fn into_partial_reflect(self: Box<Vec3>) -> Box<dyn PartialReflect>
Source§fn as_partial_reflect(&self) -> &(dyn PartialReflect + 'static)
fn as_partial_reflect(&self) -> &(dyn PartialReflect + 'static)
Source§fn as_partial_reflect_mut(&mut self) -> &mut (dyn PartialReflect + 'static)
fn as_partial_reflect_mut(&mut self) -> &mut (dyn PartialReflect + 'static)
Source§fn reflect_partial_eq(
&self,
value: &(dyn PartialReflect + 'static),
) -> Option<bool>
fn reflect_partial_eq( &self, value: &(dyn PartialReflect + 'static), ) -> Option<bool>
Source§fn debug(&self, f: &mut Formatter<'_>) -> Result<(), Error>
fn debug(&self, f: &mut Formatter<'_>) -> Result<(), Error>
Source§fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError>
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError>
Self
using reflection. Read moreSource§fn apply(&mut self, value: &(dyn PartialReflect + 'static))
fn apply(&mut self, value: &(dyn PartialReflect + 'static))
Source§fn clone_value(&self) -> Box<dyn PartialReflect>
fn clone_value(&self) -> Box<dyn PartialReflect>
reflect_clone
. To convert reflected values to dynamic ones, use to_dynamic
.Self
into its dynamic representation. Read moreSource§fn to_dynamic(&self) -> Box<dyn PartialReflect>
fn to_dynamic(&self) -> Box<dyn PartialReflect>
Source§fn reflect_hash(&self) -> Option<u64>
fn reflect_hash(&self) -> Option<u64>
Source§fn is_dynamic(&self) -> bool
fn is_dynamic(&self) -> bool
Source§impl Reflect for Vec3
impl Reflect for Vec3
Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut dyn Any
. Read moreSource§fn into_reflect(self: Box<Vec3>) -> Box<dyn Reflect>
fn into_reflect(self: Box<Vec3>) -> Box<dyn Reflect>
Source§fn as_reflect(&self) -> &(dyn Reflect + 'static)
fn as_reflect(&self) -> &(dyn Reflect + 'static)
Source§fn as_reflect_mut(&mut self) -> &mut (dyn Reflect + 'static)
fn as_reflect_mut(&mut self) -> &mut (dyn Reflect + 'static)
Source§impl RemAssign<&Vec3> for Vec3
impl RemAssign<&Vec3> for Vec3
Source§fn rem_assign(&mut self, rhs: &Vec3)
fn rem_assign(&mut self, rhs: &Vec3)
%=
operation. Read moreSource§impl RemAssign<&f32> for Vec3
impl RemAssign<&f32> for Vec3
Source§fn rem_assign(&mut self, rhs: &f32)
fn rem_assign(&mut self, rhs: &f32)
%=
operation. Read moreSource§impl RemAssign<f32> for Vec3
impl RemAssign<f32> for Vec3
Source§fn rem_assign(&mut self, rhs: f32)
fn rem_assign(&mut self, rhs: f32)
%=
operation. Read moreSource§impl RemAssign for Vec3
impl RemAssign for Vec3
Source§fn rem_assign(&mut self, rhs: Vec3)
fn rem_assign(&mut self, rhs: Vec3)
%=
operation. Read moreSource§impl Serialize for Vec3
Serialize as a sequence of 3 values.
impl Serialize for Vec3
Serialize as a sequence of 3 values.
Source§fn serialize<S>(
&self,
serializer: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where
S: Serializer,
fn serialize<S>(
&self,
serializer: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where
S: Serializer,
Source§impl ShaderSize for Vec3where
f32: ShaderSize,
impl ShaderSize for Vec3where
f32: ShaderSize,
Source§const SHADER_SIZE: NonZero<u64> = _
const SHADER_SIZE: NonZero<u64> = _
ShaderType::min_size
)Source§impl ShaderType for Vec3where
f32: ShaderSize,
impl ShaderType for Vec3where
f32: ShaderSize,
Source§fn assert_uniform_compat()
fn assert_uniform_compat()
Self
meets the requirements of the
uniform address space restrictions on stored values and the
uniform address space layout constraints Read moreSource§impl Struct for Vec3
impl Struct for Vec3
Source§fn field(&self, name: &str) -> Option<&(dyn PartialReflect + 'static)>
fn field(&self, name: &str) -> Option<&(dyn PartialReflect + 'static)>
name
as a &dyn PartialReflect
.Source§fn field_mut(
&mut self,
name: &str,
) -> Option<&mut (dyn PartialReflect + 'static)>
fn field_mut( &mut self, name: &str, ) -> Option<&mut (dyn PartialReflect + 'static)>
name
as a
&mut dyn PartialReflect
.Source§fn field_at(&self, index: usize) -> Option<&(dyn PartialReflect + 'static)>
fn field_at(&self, index: usize) -> Option<&(dyn PartialReflect + 'static)>
index
as a
&dyn PartialReflect
.Source§fn field_at_mut(
&mut self,
index: usize,
) -> Option<&mut (dyn PartialReflect + 'static)>
fn field_at_mut( &mut self, index: usize, ) -> Option<&mut (dyn PartialReflect + 'static)>
index
as a &mut dyn PartialReflect
.Source§fn name_at(&self, index: usize) -> Option<&str>
fn name_at(&self, index: usize) -> Option<&str>
index
.Source§fn iter_fields(&self) -> FieldIter<'_> ⓘ
fn iter_fields(&self) -> FieldIter<'_> ⓘ
fn to_dynamic_struct(&self) -> DynamicStruct
Source§fn clone_dynamic(&self) -> DynamicStruct
fn clone_dynamic(&self) -> DynamicStruct
to_dynamic_struct
insteadDynamicStruct
.Source§fn get_represented_struct_info(&self) -> Option<&'static StructInfo>
fn get_represented_struct_info(&self) -> Option<&'static StructInfo>
None
if TypeInfo
is not available.Source§impl SubAssign<&Vec3> for Vec3
impl SubAssign<&Vec3> for Vec3
Source§fn sub_assign(&mut self, rhs: &Vec3)
fn sub_assign(&mut self, rhs: &Vec3)
-=
operation. Read moreSource§impl SubAssign<&f32> for Vec3
impl SubAssign<&f32> for Vec3
Source§fn sub_assign(&mut self, rhs: &f32)
fn sub_assign(&mut self, rhs: &f32)
-=
operation. Read moreSource§impl SubAssign<f32> for Vec3
impl SubAssign<f32> for Vec3
Source§fn sub_assign(&mut self, rhs: f32)
fn sub_assign(&mut self, rhs: f32)
-=
operation. Read moreSource§impl SubAssign for Vec3
impl SubAssign for Vec3
Source§fn sub_assign(&mut self, rhs: Vec3)
fn sub_assign(&mut self, rhs: Vec3)
-=
operation. Read moreSource§impl TypePath for Vec3
impl TypePath for Vec3
Source§fn type_path() -> &'static str
fn type_path() -> &'static str
Source§fn short_type_path() -> &'static str
fn short_type_path() -> &'static str
Source§fn type_ident() -> Option<&'static str>
fn type_ident() -> Option<&'static str>
Source§fn crate_name() -> Option<&'static str>
fn crate_name() -> Option<&'static str>
Source§impl Vec3Swizzles for Vec3
impl Vec3Swizzles for Vec3
type Vec2 = Vec2
type Vec4 = Vec4
fn xx(self) -> Vec2
fn xy(self) -> Vec2
fn xz(self) -> Vec2
fn yx(self) -> Vec2
fn yy(self) -> Vec2
fn yz(self) -> Vec2
fn zx(self) -> Vec2
fn zy(self) -> Vec2
fn zz(self) -> Vec2
fn xxx(self) -> Vec3
fn xxy(self) -> Vec3
fn xxz(self) -> Vec3
fn xyx(self) -> Vec3
fn xyy(self) -> Vec3
fn xzx(self) -> Vec3
fn xzy(self) -> Vec3
fn xzz(self) -> Vec3
fn yxx(self) -> Vec3
fn yxy(self) -> Vec3
fn yxz(self) -> Vec3
fn yyx(self) -> Vec3
fn yyy(self) -> Vec3
fn yyz(self) -> Vec3
fn yzx(self) -> Vec3
fn yzy(self) -> Vec3
fn yzz(self) -> Vec3
fn zxx(self) -> Vec3
fn zxy(self) -> Vec3
fn zxz(self) -> Vec3
fn zyx(self) -> Vec3
fn zyy(self) -> Vec3
fn zyz(self) -> Vec3
fn zzx(self) -> Vec3
fn zzy(self) -> Vec3
fn zzz(self) -> Vec3
fn xxxx(self) -> Vec4
fn xxxy(self) -> Vec4
fn xxxz(self) -> Vec4
fn xxyx(self) -> Vec4
fn xxyy(self) -> Vec4
fn xxyz(self) -> Vec4
fn xxzx(self) -> Vec4
fn xxzy(self) -> Vec4
fn xxzz(self) -> Vec4
fn xyxx(self) -> Vec4
fn xyxy(self) -> Vec4
fn xyxz(self) -> Vec4
fn xyyx(self) -> Vec4
fn xyyy(self) -> Vec4
fn xyyz(self) -> Vec4
fn xyzx(self) -> Vec4
fn xyzy(self) -> Vec4
fn xyzz(self) -> Vec4
fn xzxx(self) -> Vec4
fn xzxy(self) -> Vec4
fn xzxz(self) -> Vec4
fn xzyx(self) -> Vec4
fn xzyy(self) -> Vec4
fn xzyz(self) -> Vec4
fn xzzx(self) -> Vec4
fn xzzy(self) -> Vec4
fn xzzz(self) -> Vec4
fn yxxx(self) -> Vec4
fn yxxy(self) -> Vec4
fn yxxz(self) -> Vec4
fn yxyx(self) -> Vec4
fn yxyy(self) -> Vec4
fn yxyz(self) -> Vec4
fn yxzx(self) -> Vec4
fn yxzy(self) -> Vec4
fn yxzz(self) -> Vec4
fn yyxx(self) -> Vec4
fn yyxy(self) -> Vec4
fn yyxz(self) -> Vec4
fn yyyx(self) -> Vec4
fn yyyy(self) -> Vec4
fn yyyz(self) -> Vec4
fn yyzx(self) -> Vec4
fn yyzy(self) -> Vec4
fn yyzz(self) -> Vec4
fn yzxx(self) -> Vec4
fn yzxy(self) -> Vec4
fn yzxz(self) -> Vec4
fn yzyx(self) -> Vec4
fn yzyy(self) -> Vec4
fn yzyz(self) -> Vec4
fn yzzx(self) -> Vec4
fn yzzy(self) -> Vec4
fn yzzz(self) -> Vec4
fn zxxx(self) -> Vec4
fn zxxy(self) -> Vec4
fn zxxz(self) -> Vec4
fn zxyx(self) -> Vec4
fn zxyy(self) -> Vec4
fn zxyz(self) -> Vec4
fn zxzx(self) -> Vec4
fn zxzy(self) -> Vec4
fn zxzz(self) -> Vec4
fn zyxx(self) -> Vec4
fn zyxy(self) -> Vec4
fn zyxz(self) -> Vec4
fn zyyx(self) -> Vec4
fn zyyy(self) -> Vec4
fn zyyz(self) -> Vec4
fn zyzx(self) -> Vec4
fn zyzy(self) -> Vec4
fn zyzz(self) -> Vec4
fn zzxx(self) -> Vec4
fn zzxy(self) -> Vec4
fn zzxz(self) -> Vec4
fn zzyx(self) -> Vec4
fn zzyy(self) -> Vec4
fn zzyz(self) -> Vec4
fn zzzx(self) -> Vec4
fn zzzy(self) -> Vec4
fn zzzz(self) -> Vec4
fn xyz(self) -> Self
Source§impl VectorSpace for Vec3
impl VectorSpace for Vec3
Source§impl WriteInto for Vec3
impl WriteInto for Vec3
fn write_into<B>(&self, writer: &mut Writer<B>)where
B: BufferMut,
impl Copy for Vec3
impl Pod for Vec3
impl StructuralPartialEq for Vec3
Auto Trait Implementations§
impl Freeze for Vec3
impl RefUnwindSafe for Vec3
impl Send for Vec3
impl Sync for Vec3
impl Unpin for Vec3
impl UnwindSafe for Vec3
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T
ShaderType
for self
. When used in AsBindGroup
derives, it is safe to assume that all images in self
exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CheckedBitPattern for Twhere
T: AnyBitPattern,
impl<T> CheckedBitPattern for Twhere
T: AnyBitPattern,
Source§type Bits = T
type Bits = T
Self
must have the same layout as the specified Bits
except for
the possible invalid bit patterns being checked during
is_valid_bit_pattern
.Source§fn is_valid_bit_pattern(_bits: &T) -> bool
fn is_valid_bit_pattern(_bits: &T) -> bool
bits
as &Self
.Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
, which can then be
downcast
into Box<dyn ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
, which can then be further
downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> DynamicTypePath for Twhere
T: TypePath,
impl<T> DynamicTypePath for Twhere
T: TypePath,
Source§fn reflect_type_path(&self) -> &str
fn reflect_type_path(&self) -> &str
TypePath::type_path
.Source§fn reflect_short_type_path(&self) -> &str
fn reflect_short_type_path(&self) -> &str
Source§fn reflect_type_ident(&self) -> Option<&str>
fn reflect_type_ident(&self) -> Option<&str>
TypePath::type_ident
.Source§fn reflect_crate_name(&self) -> Option<&str>
fn reflect_crate_name(&self) -> Option<&str>
TypePath::crate_name
.Source§fn reflect_module_path(&self) -> Option<&str>
fn reflect_module_path(&self) -> Option<&str>
Source§impl<T> DynamicTyped for Twhere
T: Typed,
impl<T> DynamicTyped for Twhere
T: Typed,
Source§fn reflect_type_info(&self) -> &'static TypeInfo
fn reflect_type_info(&self) -> &'static TypeInfo
Typed::type_info
.Source§impl<V> Ease for Vwhere
V: VectorSpace,
impl<V> Ease for Vwhere
V: VectorSpace,
Source§fn interpolating_curve_unbounded(start: V, end: V) -> impl Curve<V>
fn interpolating_curve_unbounded(start: V, end: V) -> impl Curve<V>
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> FromWorld for Twhere
T: Default,
impl<T> FromWorld for Twhere
T: Default,
Source§fn from_world(_world: &mut World) -> T
fn from_world(_world: &mut World) -> T
Creates Self
using default()
.
Source§impl<S> GetField for Swhere
S: Struct,
impl<S> GetField for Swhere
S: Struct,
Source§impl<T> GetPath for T
impl<T> GetPath for T
Source§fn reflect_path<'p>(
&self,
path: impl ReflectPath<'p>,
) -> Result<&(dyn PartialReflect + 'static), ReflectPathError<'p>>
fn reflect_path<'p>( &self, path: impl ReflectPath<'p>, ) -> Result<&(dyn PartialReflect + 'static), ReflectPathError<'p>>
path
. Read moreSource§fn reflect_path_mut<'p>(
&mut self,
path: impl ReflectPath<'p>,
) -> Result<&mut (dyn PartialReflect + 'static), ReflectPathError<'p>>
fn reflect_path_mut<'p>( &mut self, path: impl ReflectPath<'p>, ) -> Result<&mut (dyn PartialReflect + 'static), ReflectPathError<'p>>
path
. Read moreSource§fn path<'p, T>(
&self,
path: impl ReflectPath<'p>,
) -> Result<&T, ReflectPathError<'p>>where
T: Reflect,
fn path<'p, T>(
&self,
path: impl ReflectPath<'p>,
) -> Result<&T, ReflectPathError<'p>>where
T: Reflect,
path
. Read moreSource§fn path_mut<'p, T>(
&mut self,
path: impl ReflectPath<'p>,
) -> Result<&mut T, ReflectPathError<'p>>where
T: Reflect,
fn path_mut<'p, T>(
&mut self,
path: impl ReflectPath<'p>,
) -> Result<&mut T, ReflectPathError<'p>>where
T: Reflect,
path
. Read moreSource§impl<V> HasTangent for Vwhere
V: VectorSpace,
impl<V> HasTangent for Vwhere
V: VectorSpace,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<R, P> ReadPrimitive<R> for P
impl<R, P> ReadPrimitive<R> for P
Source§fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
ReadEndian::read_from_little_endian()
.Source§impl<T> Serialize for T
impl<T> Serialize for T
fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>
fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>
Source§impl<V> StableInterpolate for Vwhere
V: NormedVectorSpace,
impl<V> StableInterpolate for Vwhere
V: NormedVectorSpace,
Source§fn interpolate_stable(&self, other: &V, t: f32) -> V
fn interpolate_stable(&self, other: &V, t: f32) -> V
other
given value using the parameter t
. At
t = 0.0
, a value equivalent to self
is recovered, while t = 1.0
recovers a value
equivalent to other
, with intermediate values interpolating between the two.
See the trait-level documentation for details.Source§fn interpolate_stable_assign(&mut self, other: &Self, t: f32)
fn interpolate_stable_assign(&mut self, other: &Self, t: f32)
interpolate_stable
that assigns the result to self
for convenience.Source§fn smooth_nudge(&mut self, target: &Self, decay_rate: f32, delta: f32)
fn smooth_nudge(&mut self, target: &Self, decay_rate: f32, delta: f32)
target
at a given decay rate. The decay_rate
parameter controls how fast the distance between self
and target
decays relative to
the units of delta
; the intended usage is for decay_rate
to generally remain fixed,
while delta
is something like delta_time
from an updating system. This produces a
smooth following of the target that is independent of framerate. Read moreSource§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.