-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add a repeating texture example #11161
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
//! By default Bevy loads images to textures with sampler settings that clamps the image to the edges | ||
//! (UV coordinates outside of the range `0..=1` are clamped to `0..=1`). | ||
//! This example shows how to change the sampler settings to repeat the image instead. | ||
|
||
use bevy::app::App; | ||
use bevy::app::Startup; | ||
use bevy::asset::AssetServer; | ||
use bevy::asset::Assets; | ||
use bevy::math::Vec3; | ||
use bevy::prelude::*; | ||
use bevy::render::camera::ScalingMode; | ||
use bevy::render::mesh::Indices; | ||
use bevy::render::mesh::PrimitiveTopology; | ||
use bevy::render::texture::ImageAddressMode; | ||
use bevy::render::texture::ImageLoaderSettings; | ||
use bevy::render::texture::ImageSampler; | ||
use bevy::render::texture::ImageSamplerDescriptor; | ||
use bevy::sprite::MaterialMesh2dBundle; | ||
|
||
fn main() { | ||
App::new() | ||
.add_plugins(DefaultPlugins) | ||
.add_systems(Startup, setup) | ||
.run(); | ||
} | ||
|
||
fn setup( | ||
mut commands: Commands, | ||
mut meshes: ResMut<Assets<Mesh>>, | ||
mut materials: ResMut<Assets<ColorMaterial>>, | ||
asset_server: ResMut<AssetServer>, | ||
) { | ||
commands.spawn(Camera2dBundle { | ||
projection: OrthographicProjection { | ||
scaling_mode: ScalingMode::AutoMin { | ||
min_width: 2., | ||
min_height: 1., | ||
}, | ||
far: 1000., | ||
near: -1000., | ||
..default() | ||
}, | ||
..default() | ||
}); | ||
|
||
// Texture from ambientCG.com, licensed under the Creative Commons CC0 1.0 Universal License. | ||
// https://ambientCG.com/a/Facade018A | ||
|
||
// By default Bevy loads images to textures with sampler settings that clamp the image to the edges. | ||
let image = asset_server.load("textures/facade018a.png"); | ||
|
||
// Here we override the sampler settings to repeat the image instead. | ||
let image_repeat = asset_server.load_with_settings( | ||
// We are using another file name, because Bevy ignores different loader settings for the same file. | ||
// https://github.com/bevyengine/bevy/issues/11111 | ||
"textures/facade018a_copy.png", | ||
|s: &mut ImageLoaderSettings| match &mut s.sampler { | ||
ImageSampler::Default => { | ||
s.sampler = ImageSampler::Descriptor(ImageSamplerDescriptor { | ||
address_mode_u: ImageAddressMode::Repeat, | ||
address_mode_v: ImageAddressMode::Repeat, | ||
..default() | ||
}); | ||
} | ||
ImageSampler::Descriptor(sampler) => { | ||
sampler.address_mode_u = ImageAddressMode::Repeat; | ||
sampler.address_mode_v = ImageAddressMode::Repeat; | ||
} | ||
}, | ||
); | ||
|
||
// Instead of using a standard quad with UV coordinates in the range `0..=1` (spanning the entire texture), | ||
// we create a quad with UV coordinates in the range `-1..=2`, going beyond the texture by one entire unit in each direction. | ||
// Texture behaviour then depends on the selected sampler mode. | ||
// By default (`ImageAddressMode::ClampToEdge`) the out-of-bounds UV coordinates will map to the edge of the texture. | ||
// When `ImageAddressMode::Repeat` is specified the out-of-bounds UV coordinates will repeat the texture. | ||
let mesh = meshes.add(quad_with_custom_uv(-1.0, 2.0)); | ||
|
||
commands.spawn(MaterialMesh2dBundle { | ||
mesh: mesh.clone().into(), | ||
material: materials.add(ColorMaterial { | ||
texture: Some(image), | ||
..default() | ||
}), | ||
transform: Transform::from_translation(Vec3::new(-0.95, -0.45, 0.)) | ||
.with_scale(Vec3::new(0.9, 0.9, 0.9)), | ||
..default() | ||
}); | ||
|
||
commands.spawn(MaterialMesh2dBundle { | ||
mesh: mesh.into(), | ||
material: materials.add(ColorMaterial { | ||
texture: Some(image_repeat), | ||
..default() | ||
}), | ||
transform: Transform::from_translation(Vec3::new(0.05, -0.45, 0.)) | ||
.with_scale(Vec3::new(0.9, 0.9, 0.9)), | ||
..default() | ||
}); | ||
} | ||
|
||
/// Creates a quad with UV coordinates in range `uv_low..=uv_high`, instead of the usual UV range `0..=1`. | ||
fn quad_with_custom_uv(uv_low: f32, uv_high: f32) -> Mesh { | ||
let mut mesh = Mesh::new(PrimitiveTopology::TriangleList); | ||
mesh.insert_attribute( | ||
Mesh::ATTRIBUTE_POSITION, | ||
vec![[0., 0., 0.], [1., 0., 0.], [1., 1., 0.], [0., 1., 0.]], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the vertex positions should match those of Bevy's "default quad." Users putting together code from various Bevy examples might be surprised that this quad isn't "anchored" on its center like the default one. I personally feel like we should just modify the default There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Modifying the default Quad might be better, I'll at least fix the mesh coordinates. A better function name is welcome, although |
||
); | ||
mesh.insert_attribute( | ||
Mesh::ATTRIBUTE_UV_0, | ||
vec![ | ||
[uv_low, uv_high], | ||
[uv_high, uv_high], | ||
[uv_high, uv_low], | ||
[uv_low, uv_low], | ||
], | ||
); | ||
mesh.set_indices(Some(Indices::U16(vec![0, 1, 2, 2, 3, 0]))); | ||
mesh | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My opinion, which has very little weight in this context would be this:
Less text is better, because those who read the example, would have to spend less time and energy reading it.
There's no such thing as "standard quad with UV coordinates". For example, if you have a mesh for a sphere, it usually contains hundreds quads, and none of them use coordinates 0..1. Quads with XY and UV coordinates 0..1 are used mostly in examples (and probably in Minecraft).
Also the comments below "usual UV range
0..=1
", "custom UV coordinates" are not exactly correct for the same reason.Texture behavior always depends on the sampler more, not "then". Perhaps you meant "Texture behaviour then depends on the selected address mode", which indeed then depends, because when UV is in range 0..=1, it does not depend on address mode.
These would be the redundant comments because they
Again, feel free to ignore this comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You make a good point in regards to the sampler vs address mode, that should be reworded.
As per what a standard quad UV means, you're right that when you're talking about quad as a graphics primitive (part of a mesh), it could have any UVs for any reason, but when one talks about a quad as a mesh itself (a geometric quadrilateral) it does occur to me only as natural to use UV coordinates as usual.
I said usual UV range
0..=1
, because in that range lie UVs of most meshes people come into contact with (3D designers don't typically make their UVs sample outside of a texture from my experience).You're right the comment does seem to give a bunch of redundant information that could be found in the docstrings for
ImageAddressMode
, though the purpose of the comment is mainly to explain why it takes user-handled in UV coordinates + a change in address mode to achieve the desired repeating effect, because just changing the adress mode would not actually produce any noticeable effects.I'll consider shortening this part to a refference to the appropriate docs.
Anyway if someone gives me another opinion on this, I'll rewrite it.