docs/bevy/examples/2d/mesh2d_repeated_texture.rs 3.8 K · 107 lines · raw · history

1 //! By default Bevy loads images to textures that clamps the image to the edges
2 //! This example shows how to configure it to repeat the image instead.
3
4 use bevy::{
5 audio::AudioPlugin,
6 image::{ImageAddressMode, ImageLoaderSettings, ImageSampler, ImageSamplerDescriptor},
7 math::Affine2,
8 prelude::*,
9 };
10
11 /// How much to move some rectangles away from the center
12 const RECTANGLE_OFFSET: f32 = 250.0;
13 /// Length of the sides of the rectangle
14 const RECTANGLE_SIDE: f32 = 200.;
15 /// How much to move the label away from the rectangle
16 const LABEL_OFFSET: f32 = (RECTANGLE_SIDE / 2.) + 25.;
17
18 fn main() {
19 App::new()
20 .add_plugins(DefaultPlugins.build().disable::<AudioPlugin>())
21 .add_systems(Startup, setup)
22 .run();
23 }
24
25 fn setup(
26 mut commands: Commands,
27 asset_server: Res<AssetServer>,
28 mut meshes: ResMut<Assets<Mesh>>,
29 mut materials: ResMut<Assets<ColorMaterial>>,
30 ) {
31 // #11111: We use a duplicated image so that it can be load with and without
32 // settings
33 let image_with_default_sampler =
34 asset_server.load("textures/fantasy_ui_borders/panel-border-010.png");
35 let image_with_repeated_sampler = asset_server
36 .load_builder()
37 .with_settings(|s: &mut _| {
38 *s = ImageLoaderSettings {
39 sampler: ImageSampler::Descriptor(ImageSamplerDescriptor {
40 // rewriting mode to repeat image,
41 address_mode_u: ImageAddressMode::Repeat,
42 address_mode_v: ImageAddressMode::Repeat,
43 ..default()
44 }),
45 ..default()
46 }
47 })
48 .load("textures/fantasy_ui_borders/panel-border-010-repeated.png");
49
50 // central rectangle with not repeated texture
51 commands.spawn((
52 Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
53 MeshMaterial2d(materials.add(ColorMaterial {
54 texture: Some(image_with_default_sampler.clone()),
55 ..default()
56 })),
57 Transform::from_translation(Vec3::ZERO),
58 children![(
59 Text2d::new("Control"),
60 Transform::from_xyz(0., LABEL_OFFSET, 0.),
61 )],
62 ));
63
64 // left rectangle with repeated texture
65 commands.spawn((
66 Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
67 MeshMaterial2d(materials.add(ColorMaterial {
68 texture: Some(image_with_repeated_sampler),
69 // uv_transform used here for proportions only, but it is full Affine2
70 // that's why you can use rotation and shift also
71 uv_transform: Affine2::from_scale(Vec2::new(2., 3.)),
72 ..default()
73 })),
74 Transform::from_xyz(-RECTANGLE_OFFSET, 0.0, 0.0),
75 children![(
76 Text2d::new("Repeat On"),
77 Transform::from_xyz(0., LABEL_OFFSET, 0.),
78 )],
79 ));
80
81 // right rectangle with scaled texture, but with default sampler.
82 commands.spawn((
83 Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
84 MeshMaterial2d(materials.add(ColorMaterial {
85 // there is no sampler set, that's why
86 // by default you see only one small image in a row/column
87 // and other space is filled by image edge
88 texture: Some(image_with_default_sampler),
89
90 // uv_transform used here for proportions only, but it is full Affine2
91 // that's why you can use rotation and shift also
92 uv_transform: Affine2::from_scale(Vec2::new(2., 3.)),
93 ..default()
94 })),
95 Transform::from_xyz(RECTANGLE_OFFSET, 0.0, 0.0),
96 children![(
97 Text2d::new("Repeat Off"),
98 Transform::from_xyz(0., LABEL_OFFSET, 0.),
99 )],
100 ));
101
102 // camera
103 commands.spawn((
104 Camera2d,
105 Transform::default().looking_at(Vec3::ZERO, Vec3::Y),
106 ));
107 }