Skip to content

Add Image constructor specialised for rendering to a texture #17209

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

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions crates/bevy_image/src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,56 @@ impl Image {
Image::new(size, dimension, data, format, asset_usage)
}

/// Create a new zero-filled image with a given size, which can be rendered to.
/// Useful for mirrors, UI, or exporting images for example.
/// This is primarily for use as a render target for a [`Camera`].
/// See [`RenderTarget::Image`].
///
/// For Standard Dynamic Range (SDR) images you can use [`TextureFormat::Rgba8UnormSrgb`].
/// For High Dynamic Range (HDR) images you can use [`TextureFormat::Rgba16Float`].
///
/// The default [`TextureUsages`] are
/// [`TEXTURE_BINDING`](TextureUsages::TEXTURE_BINDING),
/// [`COPY_DST`](TextureUsages::COPY_DST),
/// [`RENDER_ATTACHMENT`](TextureUsages::RENDER_ATTACHMENT).
///
/// The default [`RenderAssetUsages`] is [`MAIN_WORLD | RENDER_WORLD`](RenderAssetUsages::default)
/// so that it is accessible from the CPU and GPU.
/// You can customize this by changing the [`asset_usage`](Image::asset_usage) field.
///
/// [`Camera`]: https://docs.rs/bevy/latest/bevy/render/camera/struct.Camera.html
/// [`RenderTarget::Image`]: https://docs.rs/bevy/latest/bevy/render/camera/enum.RenderTarget.html#variant.Image
pub fn new_target_texture(width: u32, height: u32, format: TextureFormat) -> Self {
let size = Extent3d {
width,
height,
..Default::default()
};
// You need to set these texture usage flags in order to use the image as a render target
let usage = TextureUsages::TEXTURE_BINDING
| TextureUsages::COPY_DST
| TextureUsages::RENDER_ATTACHMENT;
// Fill with zeroes
let data = vec![0; format.pixel_size() * size.volume()];

Image {
data: Some(data),
texture_descriptor: TextureDescriptor {
size,
format,
dimension: TextureDimension::D2,
label: None,
mip_level_count: 1,
sample_count: 1,
usage,
view_formats: &[],
},
sampler: ImageSampler::Default,
texture_view_descriptor: None,
asset_usage: RenderAssetUsages::default(),
}
}

/// Returns the width of a 2D image.
#[inline]
pub fn width(&self) -> u32 {
Expand Down
23 changes: 2 additions & 21 deletions examples/3d/render_to_texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ use std::f32::consts::PI;

use bevy::{
prelude::*,
render::{
render_asset::RenderAssetUsages,
render_resource::{Extent3d, TextureDimension, TextureFormat, TextureUsages},
view::RenderLayers,
},
render::{render_resource::TextureFormat, view::RenderLayers},
};

fn main() {
Expand All @@ -33,23 +29,8 @@ fn setup(
mut materials: ResMut<Assets<StandardMaterial>>,
mut images: ResMut<Assets<Image>>,
) {
let size = Extent3d {
width: 512,
height: 512,
..default()
};

// This is the texture that will be rendered to.
let mut image = Image::new_fill(
size,
TextureDimension::D2,
&[0, 0, 0, 0],
TextureFormat::Bgra8UnormSrgb,
RenderAssetUsages::default(),
);
// You need to set these texture usage flags in order to use the image as a render target
image.texture_descriptor.usage =
TextureUsages::TEXTURE_BINDING | TextureUsages::COPY_DST | TextureUsages::RENDER_ATTACHMENT;
let image = Image::new_target_texture(512, 512, TextureFormat::bevy_default());

let image_handle = images.add(image);

Expand Down
29 changes: 9 additions & 20 deletions examples/app/headless_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ use bevy::{
prelude::*,
render::{
camera::RenderTarget,
render_asset::{RenderAssetUsages, RenderAssets},
render_asset::RenderAssets,
render_graph::{self, NodeRunError, RenderGraph, RenderGraphContext, RenderLabel},
render_resource::{
Buffer, BufferDescriptor, BufferUsages, CommandEncoderDescriptor, Extent3d, Maintain,
MapMode, TexelCopyBufferInfo, TexelCopyBufferLayout, TextureDimension, TextureFormat,
TextureUsages,
MapMode, TexelCopyBufferInfo, TexelCopyBufferLayout, TextureFormat, TextureUsages,
},
renderer::{RenderContext, RenderDevice, RenderQueue},
Extract, Render, RenderApp, RenderSystems,
},
window::ExitCondition,
winit::WinitPlugin,
};
use crossbeam_channel::{Receiver, Sender};
Expand Down Expand Up @@ -93,7 +93,7 @@ fn main() {
primary_window: None,
// Don’t automatically exit due to having no windows.
// Instead, the code in `update()` will explicitly produce an `AppExit` event.
exit_condition: bevy::window::ExitCondition::DontExit,
exit_condition: ExitCondition::DontExit,
..default()
})
// WinitPlugin will panic in environments without a display server.
Expand Down Expand Up @@ -248,25 +248,14 @@ fn setup_render_target(
};

// This is the texture that will be rendered to.
let mut render_target_image = Image::new_fill(
size,
TextureDimension::D2,
&[0; 4],
TextureFormat::bevy_default(),
RenderAssetUsages::default(),
);
render_target_image.texture_descriptor.usage |=
TextureUsages::COPY_SRC | TextureUsages::RENDER_ATTACHMENT | TextureUsages::TEXTURE_BINDING;
let mut render_target_image =
Image::new_target_texture(size.width, size.height, TextureFormat::bevy_default());
render_target_image.texture_descriptor.usage |= TextureUsages::COPY_SRC;
let render_target_image_handle = images.add(render_target_image);

// This is the texture that will be copied to.
let cpu_image = Image::new_fill(
size,
TextureDimension::D2,
&[0; 4],
TextureFormat::bevy_default(),
RenderAssetUsages::default(),
);
let cpu_image =
Image::new_target_texture(size.width, size.height, TextureFormat::bevy_default());
let cpu_image_handle = images.add(cpu_image);

commands.spawn(ImageCopier::new(
Expand Down
13 changes: 2 additions & 11 deletions examples/shader/compute_shader_game_of_life.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,8 @@ fn main() {
}

fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
let mut image = Image::new_fill(
Extent3d {
width: SIZE.0,
height: SIZE.1,
depth_or_array_layers: 1,
},
TextureDimension::D2,
&[0, 0, 0, 255],
TextureFormat::R32Float,
RenderAssetUsages::RENDER_WORLD,
);
let mut image = Image::new_target_texture(SIZE.0, SIZE.1, TextureFormat::R32Float);
image.asset_usage = RenderAssetUsages::RENDER_WORLD;
image.texture_descriptor.usage =
TextureUsages::COPY_DST | TextureUsages::STORAGE_BINDING | TextureUsages::TEXTURE_BINDING;
let image0 = images.add(image.clone());
Expand Down