Skip to content

Commit

Permalink
Add an example
Browse files Browse the repository at this point in the history
  • Loading branch information
HackerFoo committed Dec 28, 2021
1 parent 69da092 commit 4de71ea
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,10 @@ path = "examples/3d/shadow_caster_receiver.rs"
name = "texture"
path = "examples/3d/texture.rs"

[[example]]
name = "render_to_texture"
path = "examples/3d/render_to_texture.rs"

[[example]]
name = "update_gltf_scene"
path = "examples/3d/update_gltf_scene.rs"
Expand Down
216 changes: 216 additions & 0 deletions examples/3d/render_to_texture.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
use bevy::{
core_pipeline::{draw_3d_graph, node, AlphaMask3d, Opaque3d, Transparent3d},
prelude::*,
reflect::TypeUuid,
render::{
camera::{ActiveCameras, Camera, CameraProjection, ExtractedCameraNames, RenderTarget},
render_graph::{NodeRunError, RenderGraph, RenderGraphContext, SlotValue},
render_phase::RenderPhase,
render_resource::{
Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
},
renderer::RenderContext,
view::RenderLayers,
RenderApp, RenderStage,
},
};

pub const RENDER_IMAGE_HANDLE: HandleUntyped =
HandleUntyped::weak_from_u64(Image::TYPE_UUID, 13378939762009864029);

pub const FIRST_PASS_DRIVER: &str = "first_pass_driver";
pub const FIRST_PASS_CAMERA: &str = "first_pass_camera";

#[derive(Component)]
struct FirstPassCube;
#[derive(Component)]
struct MainPassCube;

/// rotates the inner cube (first pass)
fn rotator_system(time: Res<Time>, mut query: Query<&mut Transform, With<FirstPassCube>>) {
for mut transform in query.iter_mut() {
transform.rotation *= Quat::from_rotation_x(1.5 * time.delta_seconds());
transform.rotation *= Quat::from_rotation_z(1.3 * time.delta_seconds());
}
}

/// rotates the outer cube (main pass)
fn cube_rotator_system(time: Res<Time>, mut query: Query<&mut Transform, With<MainPassCube>>) {
for mut transform in query.iter_mut() {
transform.rotation *= Quat::from_rotation_x(1.0 * time.delta_seconds());
transform.rotation *= Quat::from_rotation_y(0.7 * time.delta_seconds());
}
}

fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut active_cameras: ResMut<ActiveCameras>,
mut images: ResMut<Assets<Image>>,
mut clear_color: ResMut<ClearColor>,
) {
let size = Extent3d {
width: 512,
height: 512,
..Default::default()
};
let image = Image {
data: vec![0; size.width as usize * size.height as usize * 4],
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::default()
};
let image_handle = images.set(RENDER_IMAGE_HANDLE, image);

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::default()
});

commands
.spawn_bundle(PbrBundle {
mesh: cube_handle,
material: cube_material_handle,
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 1.0)),
..Default::default()
})
.insert(FirstPassCube)
.insert(RenderLayers::layer(1));

// light
// note: currently lights are shared between passes!
commands.spawn_bundle(PointLightBundle {
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 10.0)),
..Default::default()
});

// camera
let render_target = RenderTarget::Image(image_handle);
clear_color.insert(render_target.clone(), Color::WHITE);
let mut first_pass_camera = PerspectiveCameraBundle {
camera: Camera {
name: Some(FIRST_PASS_CAMERA.to_string()),
target: render_target,
..Default::default()
},
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 15.0))
.looking_at(Vec3::default(), Vec3::Y),
..Default::default()
};
active_cameras.add(FIRST_PASS_CAMERA);

let camera_projection = &mut first_pass_camera.perspective_projection;
camera_projection.update(size.width as f32, size.height as f32);
first_pass_camera.camera.projection_matrix = camera_projection.get_projection_matrix();
first_pass_camera.camera.depth_calculation = camera_projection.depth_calculation();

commands
.spawn_bundle(first_pass_camera)
.insert(RenderLayers::layer(1));
// NOTE: omitting the RenderLayers component may cause a validation error:
//
// thread 'main' panicked at 'wgpu error: Validation Error
//
// Caused by:
// In a RenderPass
// note: encoder = `<CommandBuffer-(0, 1, Metal)>`
// In a pass parameter
// note: command buffer = `<CommandBuffer-(0, 1, Metal)>`
// Attempted to use texture (5, 1, Metal) mips 0..1 layers 0..1 as a combination of COLOR_TARGET within a usage scope.

let cube_size = 4.0;
let cube_handle = meshes.add(Mesh::from(shape::Box::new(cube_size, cube_size, cube_size)));

let material_handle = materials.add(StandardMaterial {
base_color_texture: Some(RENDER_IMAGE_HANDLE.typed()),
reflectance: 0.02,
unlit: false,
..Default::default()
});

// add entities to the world
commands
.spawn_bundle(PbrBundle {
mesh: cube_handle,
material: material_handle,
transform: Transform {
translation: Vec3::new(0.0, 0.0, 1.5),
rotation: Quat::from_rotation_x(-std::f32::consts::PI / 5.0),
..Default::default()
},
..Default::default()
})
.insert(MainPassCube);

commands.spawn_bundle(PerspectiveCameraBundle {
transform: Transform::from_translation(Vec3::new(0.0, 0.0, 15.0))
.looking_at(Vec3::default(), Vec3::Y),
..Default::default()
});
}

fn main() {
let mut app = App::new();
app.insert_resource(Msaa { samples: 4 })
.add_plugins(DefaultPlugins)
.add_startup_system(setup)
.add_system(cube_rotator_system)
.add_system(rotator_system);

let render_app = app.sub_app(RenderApp);
render_app.add_system_to_stage(RenderStage::Extract, extract_first_pass_camera_phases);
let mut graph = render_app.world.get_resource_mut::<RenderGraph>().unwrap();
graph.add_node(FIRST_PASS_DRIVER, FirstPassCameraDriver);
graph
.add_node_edge(node::MAIN_PASS_DEPENDENCIES, FIRST_PASS_DRIVER)
.unwrap();
graph
.add_node_edge(node::CLEAR_PASS_DRIVER, FIRST_PASS_DRIVER)
.unwrap();
graph
.add_node_edge(FIRST_PASS_DRIVER, node::MAIN_PASS_DRIVER)
.unwrap();
app.run();
}

fn extract_first_pass_camera_phases(mut commands: Commands, active_cameras: Res<ActiveCameras>) {
if let Some(camera) = active_cameras.get(FIRST_PASS_CAMERA) {
if let Some(entity) = camera.entity {
commands.get_or_spawn(entity).insert_bundle((
RenderPhase::<Opaque3d>::default(),
RenderPhase::<AlphaMask3d>::default(),
RenderPhase::<Transparent3d>::default(),
));
}
}
}

struct FirstPassCameraDriver;
impl bevy::render::render_graph::Node for FirstPassCameraDriver {
fn run(
&self,
graph: &mut RenderGraphContext,
_render_context: &mut RenderContext,
world: &World,
) -> Result<(), NodeRunError> {
let extracted_cameras = world.get_resource::<ExtractedCameraNames>().unwrap();
if let Some(camera_3d) = extracted_cameras.entities.get(FIRST_PASS_CAMERA) {
// ***
graph.run_sub_graph(draw_3d_graph::NAME, vec![SlotValue::Entity(*camera_3d)])?;
}
Ok(())
}
}
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ Example | File | Description
`orthographic` | [`3d/orthographic.rs`](./3d/orthographic.rs) | Shows how to create a 3D orthographic view (for isometric-look games or CAD applications)
`parenting` | [`3d/parenting.rs`](./3d/parenting.rs) | Demonstrates parent->child relationships and relative transformations
`pbr` | [`3d/pbr.rs`](./3d/pbr.rs) | Demonstrates use of Physically Based Rendering (PBR) properties
`render_to_texture` | [`3d/render_to_texture.rs`](./3d/render_to_texture.rs) | Shows how to render to texture
`shadow_caster_receiver` | [`3d/shadow_caster_receiver.rs`](./3d/shadow_caster_receiver.rs) | Demonstrates how to prevent meshes from casting/receiving shadows in a 3d scene
`shadow_biases` | [`3d/shadow_biases.rs`](./3d/shadow_biases.rs) | Demonstrates how shadow biases affect shadows in a 3d scene
`texture` | [`3d/texture.rs`](./3d/texture.rs) | Shows configuration of texture materials
Expand Down

0 comments on commit 4de71ea

Please sign in to comment.