Add uv_transform
to ColorMaterial
(#17879)
# 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`
This commit is contained in:
parent
fa85a14de1
commit
7d7c43dd62
11
Cargo.toml
11
Cargo.toml
@ -783,6 +783,17 @@ description = "Used to test alpha modes with mesh2d"
|
||||
category = "2D Rendering"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "mesh2d_repeated_texture"
|
||||
path = "examples/2d/mesh2d_repeated_texture.rs"
|
||||
doc-scrape-examples = true
|
||||
|
||||
[package.metadata.example.mesh2d_repeated_texture]
|
||||
name = "Mesh2d Repeated Texture"
|
||||
description = "Showcase of using `uv_transform` on the `ColorMaterial` of a `Mesh2d`"
|
||||
category = "2D Rendering"
|
||||
wasm = true
|
||||
|
||||
[[example]]
|
||||
name = "pixel_grid_snap"
|
||||
path = "examples/2d/pixel_grid_snap.rs"
|
||||
|
@ -3,7 +3,7 @@ use bevy_app::{App, Plugin};
|
||||
use bevy_asset::{load_internal_asset, weak_handle, Asset, AssetApp, Assets, Handle};
|
||||
use bevy_color::{Alpha, Color, ColorToComponents, LinearRgba};
|
||||
use bevy_image::Image;
|
||||
use bevy_math::Vec4;
|
||||
use bevy_math::{Affine2, Mat3, Vec4};
|
||||
use bevy_reflect::prelude::*;
|
||||
use bevy_render::{render_asset::RenderAssets, render_resource::*, texture::GpuImage};
|
||||
|
||||
@ -45,6 +45,7 @@ impl Plugin for ColorMaterialPlugin {
|
||||
pub struct ColorMaterial {
|
||||
pub color: Color,
|
||||
pub alpha_mode: AlphaMode2d,
|
||||
pub uv_transform: Affine2,
|
||||
#[texture(1)]
|
||||
#[sampler(2)]
|
||||
pub texture: Option<Handle<Image>>,
|
||||
@ -61,6 +62,7 @@ impl Default for ColorMaterial {
|
||||
fn default() -> Self {
|
||||
ColorMaterial {
|
||||
color: Color::WHITE,
|
||||
uv_transform: Affine2::default(),
|
||||
texture: None,
|
||||
// TODO should probably default to AlphaMask once supported?
|
||||
alpha_mode: AlphaMode2d::Blend,
|
||||
@ -117,6 +119,7 @@ impl ColorMaterialFlags {
|
||||
#[derive(Clone, Default, ShaderType)]
|
||||
pub struct ColorMaterialUniform {
|
||||
pub color: Vec4,
|
||||
pub uv_transform: Mat3,
|
||||
pub flags: u32,
|
||||
pub alpha_cutoff: f32,
|
||||
}
|
||||
@ -140,6 +143,7 @@ impl AsBindGroupShaderType<ColorMaterialUniform> for ColorMaterial {
|
||||
};
|
||||
ColorMaterialUniform {
|
||||
color: LinearRgba::from(self.color).to_f32_array().into(),
|
||||
uv_transform: self.uv_transform.into(),
|
||||
flags: flags.bits(),
|
||||
alpha_cutoff,
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
struct ColorMaterial {
|
||||
color: vec4<f32>,
|
||||
uv_transform: mat3x3<f32>,
|
||||
// 'flags' is a bit field indicating various options. u32 is 32 bits so we have up to 32 options.
|
||||
flags: u32,
|
||||
alpha_cutoff: f32,
|
||||
@ -34,8 +35,10 @@ fn fragment(
|
||||
output_color = output_color * mesh.color;
|
||||
#endif
|
||||
|
||||
let uv = (material.uv_transform * vec3(mesh.uv, 1.0)).xy;
|
||||
|
||||
if ((material.flags & COLOR_MATERIAL_FLAGS_TEXTURE_BIT) != 0u) {
|
||||
output_color = output_color * textureSample(texture, texture_sampler, mesh.uv);
|
||||
output_color = output_color * textureSample(texture, texture_sampler, uv);
|
||||
}
|
||||
|
||||
output_color = alpha_discard(material, output_color);
|
||||
|
@ -34,6 +34,7 @@ fn setup(
|
||||
color: WHITE.into(),
|
||||
alpha_mode: AlphaMode2d::Opaque,
|
||||
texture: Some(texture_handle.clone()),
|
||||
..default()
|
||||
})),
|
||||
Transform::from_xyz(-400.0, 0.0, 0.0),
|
||||
));
|
||||
@ -43,6 +44,7 @@ fn setup(
|
||||
color: BLUE.into(),
|
||||
alpha_mode: AlphaMode2d::Opaque,
|
||||
texture: Some(texture_handle.clone()),
|
||||
..default()
|
||||
})),
|
||||
Transform::from_xyz(-300.0, 0.0, 1.0),
|
||||
));
|
||||
@ -52,6 +54,7 @@ fn setup(
|
||||
color: GREEN.into(),
|
||||
alpha_mode: AlphaMode2d::Opaque,
|
||||
texture: Some(texture_handle.clone()),
|
||||
..default()
|
||||
})),
|
||||
Transform::from_xyz(-200.0, 0.0, -1.0),
|
||||
));
|
||||
@ -67,6 +70,7 @@ fn setup(
|
||||
color: WHITE.into(),
|
||||
alpha_mode: AlphaMode2d::Mask(0.5),
|
||||
texture: Some(texture_handle.clone()),
|
||||
..default()
|
||||
})),
|
||||
Transform::from_xyz(200.0, 0.0, 0.0),
|
||||
));
|
||||
@ -76,6 +80,7 @@ fn setup(
|
||||
color: BLUE.with_alpha(0.7).into(),
|
||||
alpha_mode: AlphaMode2d::Blend,
|
||||
texture: Some(texture_handle.clone()),
|
||||
..default()
|
||||
})),
|
||||
Transform::from_xyz(300.0, 0.0, 1.0),
|
||||
));
|
||||
@ -85,6 +90,7 @@ fn setup(
|
||||
color: GREEN.with_alpha(0.7).into(),
|
||||
alpha_mode: AlphaMode2d::Blend,
|
||||
texture: Some(texture_handle),
|
||||
..default()
|
||||
})),
|
||||
Transform::from_xyz(400.0, 0.0, -1.0),
|
||||
));
|
||||
|
107
examples/2d/mesh2d_repeated_texture.rs
Normal file
107
examples/2d/mesh2d_repeated_texture.rs
Normal file
@ -0,0 +1,107 @@
|
||||
//! 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),
|
||||
));
|
||||
}
|
@ -114,6 +114,7 @@ Example | Description
|
||||
[Mesh 2D](../examples/2d/mesh2d.rs) | Renders a 2d mesh
|
||||
[Mesh 2D With Vertex Colors](../examples/2d/mesh2d_vertex_color_texture.rs) | Renders a 2d mesh with vertex color attributes
|
||||
[Mesh2d Alpha Mode](../examples/2d/mesh2d_alpha_mode.rs) | Used to test alpha modes with mesh2d
|
||||
[Mesh2d Repeated Texture](../examples/2d/mesh2d_repeated_texture.rs) | Showcase of using `uv_transform` on the `ColorMaterial` of a `Mesh2d`
|
||||
[Move Sprite](../examples/2d/move_sprite.rs) | Changes the transform of a sprite
|
||||
[Pixel Grid Snapping](../examples/2d/pixel_grid_snap.rs) | Shows how to create graphics that snap to the pixel grid by rendering to a texture in 2D
|
||||
[Sprite](../examples/2d/sprite.rs) | Renders a sprite
|
||||
|
@ -613,6 +613,7 @@ fn init_materials(
|
||||
color: Color::WHITE,
|
||||
texture: textures.first().cloned(),
|
||||
alpha_mode,
|
||||
..default()
|
||||
}));
|
||||
|
||||
// We're seeding the PRNG here to make this example deterministic for testing purposes.
|
||||
@ -625,6 +626,7 @@ fn init_materials(
|
||||
color: Color::srgb_u8(color_rng.r#gen(), color_rng.r#gen(), color_rng.r#gen()),
|
||||
texture: textures.choose(&mut texture_rng).cloned(),
|
||||
alpha_mode,
|
||||
..default()
|
||||
})
|
||||
})
|
||||
.take(capacity - materials.len()),
|
||||
|
Loading…
Reference in New Issue
Block a user