Demonstrates the use of an orthographic camera with the pan-orbit-zoom controller.
While this is supported, there are some special considerations when using an orthographic camera. See comments in the code below!
mod pan_orbit_camera_custom_input_plugin;
use bevy::camera_controller::pan_orbit_camera::prelude::*;
use bevy::prelude::*;
use crate::pan_orbit_camera_custom_input_plugin::CustomInputPlugin;
fn main() {
App::new()
.add_plugins((
DefaultPlugins,
MeshPickingPlugin,
DefaultPanOrbitCameraPlugins,
CustomInputPlugin,
))
.add_systems(Startup, (setup, setup_ui))
.run();
}
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let diffuse_map = asset_server.load("environment_maps/pisa_diffuse_rgb9e5_zstd.ktx2");
let specular_map = asset_server.load("environment_maps/pisa_specular_rgb9e5_zstd.ktx2");
let translation = Vec3::new(10.0, 10.0, 10.0);
commands.spawn((
Camera3d::default(),
Transform::from_translation(translation).looking_at(Vec3::ZERO, Vec3::Y),
Projection::Orthographic(OrthographicProjection {
scale: 0.01,
..OrthographicProjection::default_3d()
}),
EnvironmentMapLight {
intensity: 5000.0,
diffuse_map: diffuse_map.clone(),
specular_map: specular_map.clone(),
rotation: default(),
affects_lightmapped_mesh_diffuse: true,
},
// This component makes the camera controllable with this plugin.
//
// Important: the `with_initial_anchor_depth` is critical for an orthographic camera. Unlike
// perspective, we can't rely on distant things being small to hide precision artifacts.
// This means we need to be careful with the near and far plane of the camera, especially
// because in orthographic, the depth precision is linear.
//
// This plugin uses the anchor (the point in space the user is interested in) to set the
// orthographic scale, as well as the near and far planes. This can be a bit tricky if you
// are unfamiliar with orthographic projections. Consider using an pseudo-ortho projection
// if you don't need a true ortho projection.
PanOrbitCamera::default().with_initial_anchor_depth(-translation.length() as f64),
// This is an extension made specifically for orthographic cameras. Because an ortho camera
// projection has no field of view, a skybox can't be sensibly rendered, only a single point
// on the skybox would be visible to the camera at any given time. While this is technically
// correct to what the camera would see, it is not visually helpful nor appealing. It is
// common for CAD software to render a skybox with a field of view that is decoupled from
// the camera field of view.
bevy::camera_controller::pan_orbit_camera::extensions::independent_skybox::IndependentSkybox::new(
diffuse_map,
2500.0,
default(),
),
));
spawn_helmets(27, &asset_server, &mut commands);
}
fn spawn_helmets(n: usize, asset_server: &AssetServer, commands: &mut Commands) {
let half_width = ((ops::powf(n as f32, 1.0 / 3.0) - 1.0) / 2.0) as i32;
let scene = asset_server.load("https://raw.githubusercontent.com/bevyengine/bevy_asset_files/refs/heads/main/PlaneEngine/scene.gltf#Scene0");
let width = -half_width..=half_width;
for x in width.clone() {
for y in width.clone() {
for z in width.clone() {
commands.spawn((
WorldAssetRoot(scene.clone()),
Transform::from_translation(IVec3::new(x, y, z).as_vec3() * 2.0)
.with_scale(Vec3::splat(1.)),
));
}
}
}
}
fn setup_ui(mut commands: Commands) {
let text = "\
Left Mouse - Pan
Right Mouse - Orbit
Scroll - Zoom";
commands.spawn((
Text::new(text),
TextFont {
font_size: FontSize::Px(20.0),
..default()
},
Node {
margin: UiRect::all(Val::Px(20.0)),
..Default::default()
},
));
}