
# Objective Implements and closes #17515 ## Solution Add `uv_transform` to `ColorMaterial` ## Testing Create a example similar to `repeated_texture` but for `Mesh2d` and `MeshMaterial2d<ColorMaterial>` ## Showcase  ## Migration Guide Add `uv_transform` field to constructors of `ColorMaterial`
108 lines
3.8 KiB
Rust
108 lines
3.8 KiB
Rust
//! By default Bevy loads images to textures that clamps the image to the edges
|
|
//! This example shows how to configure it to repeat the image instead.
|
|
|
|
use bevy::{
|
|
audio::AudioPlugin,
|
|
image::{ImageAddressMode, ImageLoaderSettings, ImageSampler, ImageSamplerDescriptor},
|
|
math::Affine2,
|
|
prelude::*,
|
|
};
|
|
|
|
/// How much to move some rectangles away from the center
|
|
const RECTANGLE_OFFSET: f32 = 250.0;
|
|
/// Length of the sides of the rectangle
|
|
const RECTANGLE_SIDE: f32 = 200.;
|
|
/// How much to move the label away from the rectangle
|
|
const LABEL_OFFSET: f32 = (RECTANGLE_SIDE / 2.) + 25.;
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins.build().disable::<AudioPlugin>())
|
|
.add_systems(Startup, setup)
|
|
.run();
|
|
}
|
|
|
|
fn setup(
|
|
mut commands: Commands,
|
|
asset_server: Res<AssetServer>,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
) {
|
|
// #11111: We use a duplicated image so that it can be load with and without
|
|
// settings
|
|
let image_with_default_sampler =
|
|
asset_server.load("textures/fantasy_ui_borders/panel-border-010.png");
|
|
let image_with_repeated_sampler = asset_server.load_with_settings(
|
|
"textures/fantasy_ui_borders/panel-border-010-repeated.png",
|
|
|s: &mut _| {
|
|
*s = ImageLoaderSettings {
|
|
sampler: ImageSampler::Descriptor(ImageSamplerDescriptor {
|
|
// rewriting mode to repeat image,
|
|
address_mode_u: ImageAddressMode::Repeat,
|
|
address_mode_v: ImageAddressMode::Repeat,
|
|
..default()
|
|
}),
|
|
..default()
|
|
}
|
|
},
|
|
);
|
|
|
|
// central rectangle with not repeated texture
|
|
commands.spawn((
|
|
Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
|
|
MeshMaterial2d(materials.add(ColorMaterial {
|
|
texture: Some(image_with_default_sampler.clone()),
|
|
..default()
|
|
})),
|
|
Transform::from_translation(Vec3::ZERO),
|
|
children![(
|
|
Text2d::new("Control"),
|
|
Transform::from_xyz(0., LABEL_OFFSET, 0.),
|
|
)],
|
|
));
|
|
|
|
// left rectangle with repeated texture
|
|
commands.spawn((
|
|
Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
|
|
MeshMaterial2d(materials.add(ColorMaterial {
|
|
texture: Some(image_with_repeated_sampler),
|
|
// uv_transform used here for proportions only, but it is full Affine2
|
|
// that's why you can use rotation and shift also
|
|
uv_transform: Affine2::from_scale(Vec2::new(2., 3.)),
|
|
..default()
|
|
})),
|
|
Transform::from_xyz(-RECTANGLE_OFFSET, 0.0, 0.0),
|
|
children![(
|
|
Text2d::new("Repeat On"),
|
|
Transform::from_xyz(0., LABEL_OFFSET, 0.),
|
|
)],
|
|
));
|
|
|
|
// right rectangle with scaled texture, but with default sampler.
|
|
commands.spawn((
|
|
Mesh2d(meshes.add(Rectangle::new(RECTANGLE_SIDE, RECTANGLE_SIDE))),
|
|
MeshMaterial2d(materials.add(ColorMaterial {
|
|
// there is no sampler set, that's why
|
|
// by default you see only one small image in a row/column
|
|
// and other space is filled by image edge
|
|
texture: Some(image_with_default_sampler),
|
|
|
|
// uv_transform used here for proportions only, but it is full Affine2
|
|
// that's why you can use rotation and shift also
|
|
uv_transform: Affine2::from_scale(Vec2::new(2., 3.)),
|
|
..default()
|
|
})),
|
|
Transform::from_xyz(RECTANGLE_OFFSET, 0.0, 0.0),
|
|
children![(
|
|
Text2d::new("Repeat Off"),
|
|
Transform::from_xyz(0., LABEL_OFFSET, 0.),
|
|
)],
|
|
));
|
|
|
|
// camera
|
|
commands.spawn((
|
|
Camera2d,
|
|
Transform::default().looking_at(Vec3::ZERO, Vec3::Y),
|
|
));
|
|
}
|