From 6cd98b38b904276bebb6c0eeef4c80b6275d9c90 Mon Sep 17 00:00:00 2001 From: copygirl Date: Fri, 7 Mar 2025 02:59:45 +0100 Subject: [PATCH] Add `TextureAtlasSources::uv_rect` to get `Rect` in UV coords (#18178) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Objective I'm building a bloxel game in which I (currently) use a texture atlas to render the blocks the world is made of. While I was coding it, I was using the `TextureAtlas...` types to build the terrain's texture atlas at runtime as shown in the [example](https://github.com/bevyengine/bevy/blob/latest/examples/2d/texture_atlas.rs). But when I was using it to build a 3D mesh out of the blocks, I found that there was no easy way get the texture rect in UV coordinates, only in pixels via `texture_rect()`. I had to resort to writing code like this: ```rs let size = layout.size.as_vec2(); if let Some(rect) = sources.texture_rect(layout, texture) { let rect = rect.as_rect(); let uvs = Rect::from_corners(rect.min / size, rect.max / size); // use the UVs here, such as to build vertex buffer } ``` That is, until I wrote a helper function that's practically identical to the one in this PR. ## Solution Add a `uv_rect` function to `TextureAtlasSources` that will return a `Rect` with coordinates in the range of 0.0 to 1.0 – that is, UV coordinates – which can then be used directly to build `Vec2` UV values to put into a buffer and send to the GPU. I'm a little unsure about the wording of the `texture_rect` documentation but I kept it intact and based mine on it. If you think this could be improved and have some advice, I'd love to include that in this PR. ## Testing I've not done any testing with the updated bevy branch, other than seeing that the original helper function (identical in functionality) worked in my currently very small project, and making sure `cargo build` doesn't error, but I'm new to making changes to Bevy so unsure if this is sufficient. ## Showcase ![image](https://github.com/user-attachments/assets/a6d25608-e4ea-4cfd-ba1f-911dc4430138) --- crates/bevy_image/src/texture_atlas.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/crates/bevy_image/src/texture_atlas.rs b/crates/bevy_image/src/texture_atlas.rs index 36e2acd864..1e9873d048 100644 --- a/crates/bevy_image/src/texture_atlas.rs +++ b/crates/bevy_image/src/texture_atlas.rs @@ -1,6 +1,6 @@ use bevy_app::prelude::*; use bevy_asset::{Asset, AssetApp as _, AssetId, Assets, Handle}; -use bevy_math::{URect, UVec2}; +use bevy_math::{Rect, URect, UVec2}; use bevy_platform_support::collections::HashMap; #[cfg(feature = "bevy_reflect")] use bevy_reflect::{std_traits::ReflectDefault, Reflect}; @@ -51,7 +51,7 @@ impl TextureAtlasSources { }) } - /// Retrieves the texture *section* rectangle of the given `texture` handle. + /// Retrieves the texture *section* rectangle of the given `texture` handle in pixels. pub fn texture_rect( &self, layout: &TextureAtlasLayout, @@ -59,6 +59,20 @@ impl TextureAtlasSources { ) -> Option { layout.textures.get(self.texture_index(texture)?).cloned() } + + /// Retrieves the texture *section* rectangle of the given `texture` handle in UV coordinates. + /// These are within the range [0..1], as a fraction of the entire texture atlas' size. + pub fn uv_rect( + &self, + layout: &TextureAtlasLayout, + texture: impl Into>, + ) -> Option { + self.texture_rect(layout, texture).map(|rect| { + let rect = rect.as_rect(); + let size = layout.size.as_vec2(); + Rect::from_corners(rect.min / size, rect.max / size) + }) + } } /// Stores a map used to lookup the position of a texture in a [`TextureAtlas`].