Skip to content

Instantly share code, notes, and snippets.

@DGriffin91
Last active July 6, 2022 16:36
Show Gist options
  • Select an option

  • Save DGriffin91/5e80bf868191a1ba3565f45226b938c9 to your computer and use it in GitHub Desktop.

Select an option

Save DGriffin91/5e80bf868191a1ba3565f45226b938c9 to your computer and use it in GitHub Desktop.
Double Buffer Swap Example
// License: Apache-2.0 / MIT
use bevy::{
core_pipeline::clear_color::ClearColorConfig,
prelude::*,
render::{
camera::RenderTarget,
render_resource::{
Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
},
},
};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.add_system(cube_rotator_system)
.add_system(update_handles)
.add_system(swap_buffers)
.run();
}
#[derive(Component)]
struct Cube {
rotate_speed: f32,
}
#[derive(Component)]
struct DoubleBuffer {
buf_a: Handle<Image>,
buf_b: Handle<Image>,
phase: bool,
}
impl DoubleBuffer {
fn swap(&mut self) {
self.phase = !self.phase;
}
fn get(&self) -> Handle<Image> {
if self.phase {
self.buf_a.clone()
} else {
self.buf_b.clone()
}
}
}
fn swap_buffers(mut buffers: Query<&mut DoubleBuffer>) {
for mut double_buffer in buffers.iter_mut() {
double_buffer.swap()
}
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut images: ResMut<Assets<Image>>,
) {
let size = Extent3d {
width: 512,
height: 512,
..default()
};
let mut image_a = Image {
texture_descriptor: TextureDescriptor {
label: None,
size,
dimension: TextureDimension::D2,
format: TextureFormat::Bgra8UnormSrgb,
mip_level_count: 1,
sample_count: 1,
usage: TextureUsages::TEXTURE_BINDING
| TextureUsages::COPY_DST
| TextureUsages::RENDER_ATTACHMENT,
},
..default()
};
image_a.resize(size);
let image_handle_a = images.add(image_a);
let mut image_b = Image {
texture_descriptor: TextureDescriptor {
label: None,
size,
dimension: TextureDimension::D2,
format: TextureFormat::Bgra8UnormSrgb,
mip_level_count: 1,
sample_count: 1,
usage: TextureUsages::TEXTURE_BINDING
| TextureUsages::COPY_DST
| TextureUsages::RENDER_ATTACHMENT,
},
..default()
};
image_b.resize(size);
let image_handle_b = images.add(image_b);
let cube_handle = meshes.add(Mesh::from(shape::Cube { size: 4.0 }));
let cube_material_handle = materials.add(StandardMaterial {
base_color: Color::rgb(0.8, 0.7, 0.6),
reflectance: 0.02,
unlit: false,
..default()
});
// The cube that will be rendered to the texture.
commands
.spawn_bundle(PbrBundle {
mesh: cube_handle,
material: cube_material_handle,
transform: Transform::from_translation(Vec3::new(0.0, -2.5, 1.0)),
..default()
})
.insert(Cube { rotate_speed: 1.0 });
commands.spawn_bundle(PointLightBundle {
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 10.0)),
..default()
});
commands
.spawn_bundle(Camera3dBundle {
camera_3d: Camera3d {
clear_color: ClearColorConfig::Custom(Color::WHITE),
..default()
},
camera: Camera {
// render before the "main pass" camera
priority: -1,
target: RenderTarget::Image(image_handle_a.clone()),
..default()
},
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 15.0))
.looking_at(Vec3::default(), Vec3::Y),
..default()
})
.insert(DoubleBuffer {
buf_a: image_handle_a.clone(),
buf_b: image_handle_b.clone(),
phase: true,
});
let cube_size = 4.0;
let cube_handle = meshes.add(Mesh::from(shape::Box::new(cube_size, cube_size, cube_size)));
// This material has the texture that has been rendered.
let material_handle = materials.add(StandardMaterial {
base_color_texture: Some(image_handle_b.clone()),
reflectance: 0.02,
unlit: false,
..default()
});
commands
.spawn_bundle(PbrBundle {
mesh: cube_handle,
material: material_handle,
transform: Transform {
translation: Vec3::new(0.0, 2.5, 1.5),
rotation: Quat::from_rotation_x(-std::f32::consts::PI / 5.0),
..default()
},
..default()
})
.insert(Cube { rotate_speed: 1.3 })
.insert(DoubleBuffer {
buf_a: image_handle_a.clone(),
buf_b: image_handle_b.clone(),
phase: false,
});
// The main pass camera.
commands.spawn_bundle(Camera3dBundle {
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 15.0))
.looking_at(Vec3::default(), Vec3::Y),
..default()
});
}
fn update_handles(
mut buf_cameras: Query<(&mut Camera, &DoubleBuffer), Without<Handle<StandardMaterial>>>,
mut buf_materials: Query<(&Handle<StandardMaterial>, &DoubleBuffer), Without<Camera>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
for (mut camera, double_buffer) in buf_cameras.iter_mut() {
camera.target = RenderTarget::Image(double_buffer.get())
}
for (material, double_buffer) in buf_materials.iter_mut() {
let mut material = materials.get_mut(&material).unwrap();
material.base_color_texture = Some(double_buffer.get())
}
}
/// Rotates the cubes
fn cube_rotator_system(time: Res<Time>, mut query: Query<(&mut Transform, &Cube)>) {
for (mut transform, cube) in query.iter_mut() {
transform.rotation *= Quat::from_rotation_x(cube.rotate_speed * time.delta_seconds());
transform.rotation *= Quat::from_rotation_y(cube.rotate_speed * time.delta_seconds());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment