Last active
July 6, 2022 16:36
-
-
Save DGriffin91/5e80bf868191a1ba3565f45226b938c9 to your computer and use it in GitHub Desktop.
Double Buffer Swap Example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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