
# Objective
Fixes `StandardMaterial` texture update (see sample code below).
Most probably fixes #3674 (did not test)
## Solution
Material updates, such as PBR update, reference the underlying `GpuImage`. Like here: 9a7852db0f/crates/bevy_pbr/src/pbr_material.rs (L177)
However, currently the `GpuImage` update may actually happen *after* the material update fetches the gpu image. Resulting in the material actually not being updated for the correct gpu image.
In this pull req, I introduce new systemlabels for the renderassetplugin. Also assigned the RenderAssetPlugin::<Image> to the `PreAssetExtract` stage, so that it is executed before any material updates.
Code to test.
Expected behavior:
* should update to red texture
Unexpected behavior (before this merge):
* texture stays randomly as green one (depending on the execution order of systems)
```rust
use bevy::{
prelude::*,
render::render_resource::{Extent3d, TextureDimension, TextureFormat},
};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.add_system(changes)
.run();
}
struct Iteration(usize);
#[derive(Component)]
struct MyComponent;
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut images: ResMut<Assets<Image>>,
) {
commands.spawn_bundle(PointLightBundle {
point_light: PointLight {
..Default::default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..Default::default()
});
commands.spawn_bundle(PerspectiveCameraBundle {
transform: Transform::from_xyz(-2.0, 0.0, 5.0)
.looking_at(Vec3::new(0.0, 0.0, 0.0), Vec3::Y),
..Default::default()
});
commands.insert_resource(Iteration(0));
commands
.spawn_bundle(PbrBundle {
mesh: meshes.add(Mesh::from(shape::Quad::new(Vec2::new(3., 2.)))),
material: materials.add(StandardMaterial {
base_color_texture: Some(images.add(Image::new(
Extent3d {
width: 600,
height: 400,
depth_or_array_layers: 1,
},
TextureDimension::D2,
[0, 255, 0, 128].repeat(600 * 400), // GREEN
TextureFormat::Rgba8Unorm,
))),
..Default::default()
}),
..Default::default()
})
.insert(MyComponent);
}
fn changes(
mut materials: ResMut<Assets<StandardMaterial>>,
mut images: ResMut<Assets<Image>>,
mut iteration: ResMut<Iteration>,
webview_query: Query<&Handle<StandardMaterial>, With<MyComponent>>,
) {
if iteration.0 == 2 {
let material = materials.get_mut(webview_query.single()).unwrap();
let image = images
.get_mut(material.base_color_texture.as_ref().unwrap())
.unwrap();
image
.data
.copy_from_slice(&[255, 0, 0, 255].repeat(600 * 400));
}
iteration.0 += 1;
}
```
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
88 lines
2.3 KiB
Rust
88 lines
2.3 KiB
Rust
#[cfg(feature = "basis-universal")]
|
|
mod basis;
|
|
#[cfg(feature = "dds")]
|
|
mod dds;
|
|
#[cfg(feature = "hdr")]
|
|
mod hdr_texture_loader;
|
|
#[allow(clippy::module_inception)]
|
|
mod image;
|
|
mod image_texture_loader;
|
|
#[cfg(feature = "ktx2")]
|
|
mod ktx2;
|
|
mod texture_cache;
|
|
|
|
pub(crate) mod image_texture_conversion;
|
|
|
|
pub use self::image::*;
|
|
#[cfg(feature = "ktx2")]
|
|
pub use self::ktx2::*;
|
|
#[cfg(feature = "dds")]
|
|
pub use dds::*;
|
|
#[cfg(feature = "hdr")]
|
|
pub use hdr_texture_loader::*;
|
|
|
|
pub use image_texture_loader::*;
|
|
pub use texture_cache::*;
|
|
|
|
use crate::{
|
|
render_asset::{PrepareAssetLabel, RenderAssetPlugin},
|
|
RenderApp, RenderStage,
|
|
};
|
|
use bevy_app::{App, Plugin};
|
|
use bevy_asset::{AddAsset, Assets};
|
|
|
|
// TODO: replace Texture names with Image names?
|
|
/// Adds the [`Image`] as an asset and makes sure that they are extracted and prepared for the GPU.
|
|
pub struct ImagePlugin;
|
|
|
|
impl Plugin for ImagePlugin {
|
|
fn build(&self, app: &mut App) {
|
|
#[cfg(any(
|
|
feature = "png",
|
|
feature = "dds",
|
|
feature = "tga",
|
|
feature = "jpeg",
|
|
feature = "bmp",
|
|
feature = "basis-universal",
|
|
feature = "ktx2",
|
|
))]
|
|
{
|
|
app.init_asset_loader::<ImageTextureLoader>();
|
|
}
|
|
|
|
#[cfg(feature = "hdr")]
|
|
{
|
|
app.init_asset_loader::<HdrTextureLoader>();
|
|
}
|
|
|
|
app.add_plugin(RenderAssetPlugin::<Image>::with_prepare_asset_label(
|
|
PrepareAssetLabel::PreAssetPrepare,
|
|
))
|
|
.add_asset::<Image>();
|
|
app.world
|
|
.resource_mut::<Assets<Image>>()
|
|
.set_untracked(DEFAULT_IMAGE_HANDLE, Image::default());
|
|
|
|
if let Ok(render_app) = app.get_sub_app_mut(RenderApp) {
|
|
render_app
|
|
.init_resource::<TextureCache>()
|
|
.add_system_to_stage(RenderStage::Cleanup, update_texture_cache_system);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait BevyDefault {
|
|
fn bevy_default() -> Self;
|
|
}
|
|
|
|
impl BevyDefault for wgpu::TextureFormat {
|
|
fn bevy_default() -> Self {
|
|
if cfg!(target_os = "android") || cfg!(target_arch = "wasm32") {
|
|
// Bgra8UnormSrgb texture missing on some Android devices
|
|
wgpu::TextureFormat::Rgba8UnormSrgb
|
|
} else {
|
|
wgpu::TextureFormat::Bgra8UnormSrgb
|
|
}
|
|
}
|
|
}
|