-
-
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
Tiled/repeating textures #399
Comments
Sounds like a great idea |
I think that can already be done using |
I'm not sure how to specify a |
How about adding |
Yup adding a SamplerDescriptor to Texture has been on my "mental to-do list" for awhile. I think that's the right approach. |
GLTF loader now grabs (some) sampler information from the respective GLTF sampler struct.
GLTF loader now grabs (some) sampler information from the respective GLTF sampler struct.
In #747 I've moved the Still, when loading a texture manually (not from a GLTF file), like it's done in the texture example, we'd still need to specify the sampler somehow. Of course, we could just keep it this way, initialized with default, and the user could still mutate it after loading. |
@W4RH4WK sounds reasonable. Atelier Assets (which we will eventually migrate to) allows you to specify per-asset configuration in a ".meta" file. I think we will eventually put the SamplerDescriptor config there for formats like png. |
#747 largely resolves this problem, but I think we should probably hold off on closing this until we can do it for arbitrary texture files (aka using the ".meta" config in atelier assets) |
I've tried using this feature, and it doesn't seem to be working the way I expected as of 0.4.0. It does get as far as recreating the Sampler: I can modify a Texture's SamplerDescriptor, and the generated As an example of this, my project (at commit A workaround that works for now is to not spawn the sprite until the texture is loaded and the address modes are set (e.g. moving lines 39-52 to immediately after line 75, and also adding the resources it requires to the system). There may be a better way to do this, maybe using states or stages, but I haven't explored it much and I'm not familiar with bevy best practices in general. |
Seems to me like #747 only works for And we have another issue, with GltfLoader loading all its textures as SRGB. This can be seen here Regular textures get passed to the AssetServer as an |
It would be nice to be able to offset a repeating texture dynamically for parallax backgrounds as well |
Hey, is there a way to tile textures now? |
I think we're still waiting on the distill integration for asset parameters. |
#[derive(Default)]
struct BackgroundImage(Handle<Image>);
fn configure_background_image(background: Res<BackgroundImage>, mut images: ResMut<Assets<Image>>) {
// Doing this in response to AssetEvents seem to be broken, instead we try to set the sampler every frame
let mut image = images.get_mut(background.0.clone());
if let Some(image) = image {
image.sampler_descriptor.address_mode_u = AddressMode::Repeat;
image.sampler_descriptor.address_mode_v = AddressMode::Repeat;
}
}
const MAP_SIZE: f32 = 100.;
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut materials: ResMut<Assets<ColorMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
mut background: ResMut<BackgroundImage>,
) {
background.0 = asset_server.load("background.png");
let mut mesh = Mesh::from(shape::Quad::default());
if let Some(VertexAttributeValues::Float32x2(uvs)) = mesh.attribute_mut(Mesh::ATTRIBUTE_UV_0) {
for uv in uvs {
uv[0] *= MAP_SIZE;
uv[1] *= MAP_SIZE;
}
}
commands.spawn_bundle(ColorMesh2dBundle {
transform: Transform::from_scale(Vec3::splat(MAP_SIZE)),
material: materials.add(background.0.clone().into()),
mesh: meshes.add(mesh.into()).into(),
..Default::default()
}); I ended up doing this in a project. Relevant discord thread: https://discord.com/channels/691052431525675048/742884593551802431/932954492394164255 Would be nice to know if there is a less hacky solution that works with 0.6 |
This doesn't work. I've spent 1 hour trying this and other solutions on Discord, none of them work on 0.6. |
run into this one today, here's what worked for me: pub fn set_texture_tiled(
mut texture_events: EventReader<AssetEvent<Image>>,
mut textures: ResMut<Assets<Image>>,
) {
for event in texture_events.iter() {
match event {
AssetEvent::Created { handle } => {
if let Some(mut texture) = textures.get_mut(handle) {
texture.sampler_descriptor.address_mode_u = bevy::render::render_resource::AddressMode::Repeat;
texture.sampler_descriptor.address_mode_v = bevy::render::render_resource::AddressMode::Repeat;
texture.sampler_descriptor.address_mode_w = bevy::render::render_resource::AddressMode::Repeat;
}
}
_ => (),
}
}
} One caveat though is this system has to run before you use the pub fn startup_system(
asset_server: Res<AssetServer>,
mut terrain_mat: ResMut<TempTerrainMaterial>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
terrain_mat.tex = asset_server.load("textures/test.png");
terrain_mat.normal = asset_server.load("textures/test_n.png");
terrain_mat.material = materials.add(StandardMaterial {
base_color_texture: Some(terrain_mat.tex.clone()),
normal_map_texture: Some(terrain_mat.normal.clone()),
perceptual_roughness: 0.89,
..default()
});
}
pub fn spawn_mesh(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
terrain_mat: Res<TempTerrainMaterial>,
) {
commands.spawn_bundle(PbrBundle {
mesh: meshes.add(some_mesh),
//material: terrain_mat.material.clone(), // doesn't work
material: materials.add(StandardMaterial { // works
base_color_texture: Some(terrain_mat.tex.clone()),
normal_map_texture: Some(terrain_mat.normal.clone()),
perceptual_roughness: 0.89,
..default()
}),
..default()
});
} |
Kind of a hack based on bevyengine/bevy#399, but good enough for now.
@sanisoclem I have also ran into the issue where "pre-loaded"materials doesnt pick up the address modes if its texture! So strange. I also had to resort to re-creating the material at entity spawning time. |
@ManevilleF, do any of your PRs completely resolve this? If so, please link this issue there :) |
My MR on slicing and tiling only works on 2d texture rects, so sprites or UI |
For anyone comfortable with all of their textures using the same .insert_resource(ImageSettings {
default_sampler: SamplerDescriptor {
address_mode_u: AddressMode::Repeat,
address_mode_v: AddressMode::Repeat,
address_mode_w: AddressMode::Repeat,
..Default::default()
},
}) |
Sadly, this doesn't help when you need textures with different parameters. And current way of listening for events when image is loaded is way to cumbersome while also not working when image is attached to the material beforehand :( |
Specifying sampler works only if you have a single texture that you want to repeat. My problem is that I have a large texture (texture atlas) and I want to repeat a region of it, which is not currently possible without writing custom shader. So having support for it in |
I ended up just bypassing pub fn load_tiled_texture(
images: &mut Assets<Image>,
texture_path: &str
) -> Handle<Image> {
let ext = std::path::Path::new(texture_path).extension().unwrap().to_str().unwrap();
let img_bytes = std::fs::read(texture_path).unwrap();
let mut image = Image::from_buffer(&img_bytes, ImageType::Extension(ext), CompressedImageFormats::all(), true).unwrap();
image.sampler_descriptor = ImageSampler::Descriptor(SamplerDescriptor {
address_mode_u: AddressMode::Repeat,
address_mode_v: AddressMode::Repeat,
..Default::default()
});
images.add(image)
} |
With the new asset server in 0.12, this worked for me let sampler_desc = ImageSamplerDescriptor {
address_mode_u: ImageAddressMode::Repeat,
address_mode_v: ImageAddressMode::Repeat,
..Default::default()
};
let settings = move |s: &mut ImageLoaderSettings| {
s.sampler = ImageSampler::Descriptor(sampler_desc.clone());
};
let texture_handle = assets.load_with_settings("texture.png", settings); |
For tiling backgrounds specifically, see https://lib.rs/crates/bevy_tiling_background for prior art. |
This is now just a documentation issue: we should demonstrate the code showed by @blunted2night in a simple 2D example. |
@blunted2night how did you spawn the sprite? this is my attempt and it doesn't seem to work properly: fn load_tiled_texture(assets: Res<AssetServer>, mut commands: Commands) {
let sampler_desc = ImageSamplerDescriptor {
address_mode_u: ImageAddressMode::Repeat,
address_mode_v: ImageAddressMode::Repeat,
..default()
};
let settings = move |s: &mut ImageLoaderSettings| {
s.sampler = ImageSampler::Descriptor(sampler_desc.clone());
};
commands.spawn(SpriteBundle {
texture: assets.load_with_settings("tile.png", settings),
..default()
});
} I'm a beginner to both rust and bevy, sorry if it's a rookie mistake. |
@evrsen in my case, I was using the texture for a terrain component I was playing with. I'm not sure but I think you would need to override the set of texture coordinates used for the sprite. I assume by default it would select 0 -> 1 for both axis. commands.spawn(SpriteBundle {
sprite: Sprite {
rect: Some(Rect::new(0,0,10,1)),
..default()
},
texture: assets.load_with_settings("tile.png", settings),
..default()
}); |
Is it possible that changing the sampler after the image has already been loaded still has no effect? If so, can I somehow force the change? The reason I ask is because I want to apply the repeating effect to a texture that I'm loading from a .glb scene, so I don't really have the opportunity to call |
Adopted #8266, so copy-pasting the description from there: # Objective Support the KHR_texture_transform extension for the glTF loader. - Fixes #6335 - Fixes #11869 - Implements part of #11350 - Implements the GLTF part of #399 ## Solution As is, this only supports a single transform. Looking at Godot's source, they support one transform with an optional second one for detail, AO, and emission. glTF specifies one per texture. The public domain materials I looked at seem to share the same transform. So maybe having just one is acceptable for now. I tried to include a warning if multiple different transforms exist for the same material. Note the gltf crate doesn't expose the texture transform for the normal and occlusion textures, which it should, so I just ignored those for now. (note by @janhohenheim: this is still the case) Via `cargo run --release --example scene_viewer ~/src/clone/glTF-Sample-Models/2.0/TextureTransformTest/glTF/TextureTransformTest.gltf`: ![texture_transform](https://user-images.githubusercontent.com/283864/228938298-aa2ef524-555b-411d-9637-fd0dac226fb0.png) ## Changelog Support for the [KHR_texture_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) extension added. Texture UVs that were scaled, rotated, or offset in a GLTF are now properly handled. --------- Co-authored-by: Al McElrath <[email protected]> Co-authored-by: Kanabenki <[email protected]>
Adopted bevyengine#8266, so copy-pasting the description from there: # Objective Support the KHR_texture_transform extension for the glTF loader. - Fixes bevyengine#6335 - Fixes bevyengine#11869 - Implements part of bevyengine#11350 - Implements the GLTF part of bevyengine#399 ## Solution As is, this only supports a single transform. Looking at Godot's source, they support one transform with an optional second one for detail, AO, and emission. glTF specifies one per texture. The public domain materials I looked at seem to share the same transform. So maybe having just one is acceptable for now. I tried to include a warning if multiple different transforms exist for the same material. Note the gltf crate doesn't expose the texture transform for the normal and occlusion textures, which it should, so I just ignored those for now. (note by @janhohenheim: this is still the case) Via `cargo run --release --example scene_viewer ~/src/clone/glTF-Sample-Models/2.0/TextureTransformTest/glTF/TextureTransformTest.gltf`: ![texture_transform](https://user-images.githubusercontent.com/283864/228938298-aa2ef524-555b-411d-9637-fd0dac226fb0.png) ## Changelog Support for the [KHR_texture_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) extension added. Texture UVs that were scaled, rotated, or offset in a GLTF are now properly handled. --------- Co-authored-by: Al McElrath <[email protected]> Co-authored-by: Kanabenki <[email protected]>
Adopted bevyengine#8266, so copy-pasting the description from there: # Objective Support the KHR_texture_transform extension for the glTF loader. - Fixes bevyengine#6335 - Fixes bevyengine#11869 - Implements part of bevyengine#11350 - Implements the GLTF part of bevyengine#399 ## Solution As is, this only supports a single transform. Looking at Godot's source, they support one transform with an optional second one for detail, AO, and emission. glTF specifies one per texture. The public domain materials I looked at seem to share the same transform. So maybe having just one is acceptable for now. I tried to include a warning if multiple different transforms exist for the same material. Note the gltf crate doesn't expose the texture transform for the normal and occlusion textures, which it should, so I just ignored those for now. (note by @janhohenheim: this is still the case) Via `cargo run --release --example scene_viewer ~/src/clone/glTF-Sample-Models/2.0/TextureTransformTest/glTF/TextureTransformTest.gltf`: ![texture_transform](https://user-images.githubusercontent.com/283864/228938298-aa2ef524-555b-411d-9637-fd0dac226fb0.png) ## Changelog Support for the [KHR_texture_transform](https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_texture_transform) extension added. Texture UVs that were scaled, rotated, or offset in a GLTF are now properly handled. --------- Co-authored-by: Al McElrath <[email protected]> Co-authored-by: Kanabenki <[email protected]>
Since version 0.12 there is Bevy Asset v2. So you can add ImageSamplerDesctription settings via asset meta files near your png, instead of changing it from a code (additional profit is abbility to hotload, so you can test settings pretty fast). For example there is my config:
But it adds just abbility to Repeat texture but not abbility to set proportions. For proportions you can use StandardMaterial::uv_transform, which is pretty fresh, because it had been added for KHR_texture_transform support to current main and it will be available from next 0.14 release |
@bugsweeper would that meta file entry also work for setting only a specific texture of a gltf to repeat? |
No, bevy_gltf has code for sampler definition and it defines ImageAddressMode according to info loaded from gltf, but you can define sampler inside your gltf file, which is more appropriate way |
@bugsweeper thanks for the info, I didn't know that! Do you know whether Bevy respects these sampler settings in the gltf? If so, I'd say we can close this issue. |
Yes, it uses code I mentioned above to generate sampler for images loaded from gltf |
Nice! @alice-i-cecile, since I last blocked the closing of this issue, I think all of my concerns have been addressed, or at least they will be once 0.14 lands with my |
But I think you should try to modify your gltf, to ensure it works as you expected, and then close this issue. |
Good idea! Unfortunately I won't have time for at least a couple of weeks, but I'd be glad if someone else confirmed this :) |
It would be nice to set a texture to tile or repeat on a mesh instead of stretch.
The text was updated successfully, but these errors were encountered: