Skip to content

Commit 888859c

Browse files
Enable load_with_settings TextureFormats (#20788)
Previously, loading an image resulted in a hard-coded TextureFormat. When loading images that are meant to be used as the `StandardMaterial::depth_map`, the data can be stored in ways that result in an `R16Uint` TextureFormat. This results in an error because the `depth_map` must be a Float sampler and not a Uint sampler. 2025-08-29T17:15:03.081069Z ERROR bevy_render::erased_render_asset: bevy_pbr::mesh_material::MeshMaterial3d<bevy_pbr::extended_material::ExtendedMaterial<bevy_pbr::pbr_material::StandardMaterial, test_uv_transform::MyExtension>> Bind group construction failed: At binding index 12, the provided image sampler `Uint` does not match the required sampler type(s) `[Float { filterable: true }]`. Setting the TextureFormat can adjust the way in which the same image data shows up in the shader. For example, an image that would otherwise be `TextureFormat::R16Uint` can be set to `TextureFormat::R16Unorm`, with no other changes, which results in the 16-bit integer data being converted to the 0-1 range for the shader. ```rust asset_server.load_with_settings( "grass_height.png", |settings: &mut ImageLoaderSettings| { settings.texture_format = Some(TextureFormat::R16Unorm); } ), ``` This PR adds the ability to set the texture format with using `load_with_settings`. Software like Substance Designer outputs height data in what becomes `R16Uint` format, but depth_map requires `R16Unorm`. -- Additional notes: - TextureFormat does not have a serde implementation, so is skipped in this PR - This PR tries to change as little as possible when it comes to Image creation, so does not add a TextureFormat option to Image constructors like `from_buffer` and `from_dynamic`, which is what is used by the ImageLoader. It also ends up relying on a conversion from [`DynamicImage`](https://docs.rs/image/0.25.6/image/enum.DynamicImage.html), which doesn't have enough information to make this judgement afaict. - Alternative strategies could include using a LoadTransformAndSave sequence to correct the data, but this is not straightforward as the tools to do this are not obvious (specifically the conversion from the Vec<u8> image crate representation + filename guessing when loading the processed image).
1 parent 1737eae commit 888859c

File tree

2 files changed

+16
-1
lines changed

2 files changed

+16
-1
lines changed

crates/bevy_image/src/compressed_image_saver.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ impl AssetSaver for CompressedImageSaver {
6969
is_srgb,
7070
sampler: image.sampler.clone(),
7171
asset_usage: image.asset_usage,
72+
texture_format: None,
7273
})
7374
}
7475
}

crates/bevy_image/src/image_loader.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,15 @@ pub enum ImageFormatSetting {
9999
/// Settings for loading an [`Image`] using an [`ImageLoader`].
100100
#[derive(Serialize, Deserialize, Debug, Clone)]
101101
pub struct ImageLoaderSettings {
102-
/// How to determine the image's format.
102+
/// How to determine the image's container format.
103103
pub format: ImageFormatSetting,
104+
/// Forcibly use a specific [`wgpu_types::TextureFormat`].
105+
/// Useful to control how data is handled when used
106+
/// in a shader.
107+
/// Ex: data that would be `R16Uint` that needs to
108+
/// be sampled as a float using `R16Snorm`.
109+
#[serde(skip)]
110+
pub texture_format: Option<wgpu_types::TextureFormat>,
104111
/// Specifies whether image data is linear
105112
/// or in sRGB space when this is not determined by
106113
/// the image format.
@@ -117,6 +124,7 @@ impl Default for ImageLoaderSettings {
117124
fn default() -> Self {
118125
Self {
119126
format: ImageFormatSetting::default(),
127+
texture_format: None,
120128
is_srgb: true,
121129
sampler: ImageSampler::Default,
122130
asset_usage: RenderAssetUsages::default(),
@@ -176,6 +184,12 @@ impl AssetLoader for ImageLoader {
176184
settings.sampler.clone(),
177185
settings.asset_usage,
178186
)
187+
.map(|mut image| {
188+
if let Some(format) = settings.texture_format {
189+
image.texture_descriptor.format = format;
190+
}
191+
image
192+
})
179193
.map_err(|err| FileTextureError {
180194
error: err,
181195
path: format!("{}", load_context.path().display()),

0 commit comments

Comments
 (0)