mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
0166db33f7
# Objective #11431 and #11688 implemented meshing support for Bevy's new geometric primitives. The next step is to deprecate the shapes in `bevy_render::mesh::shape` and to later remove them completely for 0.14. ## Solution Deprecate the shapes and reduce code duplication by utilizing the primitive meshing API for the old shapes where possible. Note that some shapes have behavior that can't be exactly reproduced with the new primitives yet: - `Box` is more of an AABB with min/max extents - `Plane` supports a subdivision count - `Quad` has a `flipped` property These types have not been changed to utilize the new primitives yet. --- ## Changelog - Deprecated all shapes in `bevy_render::mesh::shape` - Changed all examples to use new primitives for meshing ## Migration Guide Bevy has previously used rendering-specific types like `UVSphere` and `Quad` for primitive mesh shapes. These have now been deprecated to use the geometric primitives newly introduced in version 0.13. Some examples: ```rust let before = meshes.add(shape::Box::new(5.0, 0.15, 5.0)); let after = meshes.add(Cuboid::new(5.0, 0.15, 5.0)); let before = meshes.add(shape::Quad::default()); let after = meshes.add(Rectangle::default()); let before = meshes.add(shape::Plane::from_size(5.0)); // The surface normal can now also be specified when using `new` let after = meshes.add(Plane3d::default().mesh().size(5.0, 5.0)); let before = meshes.add( Mesh::try_from(shape::Icosphere { radius: 0.5, subdivisions: 5, }) .unwrap(), ); let after = meshes.add(Sphere::new(0.5).mesh().ico(5).unwrap()); ```
174 lines
5.2 KiB
Rust
174 lines
5.2 KiB
Rust
//! Shows how to create graphics that snap to the pixel grid by rendering to a texture in 2D
|
|
|
|
use bevy::{
|
|
prelude::*,
|
|
render::{
|
|
camera::RenderTarget,
|
|
render_resource::{
|
|
Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsages,
|
|
},
|
|
view::RenderLayers,
|
|
},
|
|
sprite::MaterialMesh2dBundle,
|
|
window::WindowResized,
|
|
};
|
|
|
|
/// In-game resolution width.
|
|
const RES_WIDTH: u32 = 160;
|
|
|
|
/// In-game resolution height.
|
|
const RES_HEIGHT: u32 = 90;
|
|
|
|
/// Default render layers for pixel-perfect rendering.
|
|
/// You can skip adding this component, as this is the default.
|
|
const PIXEL_PERFECT_LAYERS: RenderLayers = RenderLayers::layer(0);
|
|
|
|
/// Render layers for high-resolution rendering.
|
|
const HIGH_RES_LAYERS: RenderLayers = RenderLayers::layer(1);
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
|
|
.insert_resource(Msaa::Off)
|
|
.add_systems(Startup, (setup_camera, setup_sprite, setup_mesh))
|
|
.add_systems(Update, (rotate, fit_canvas))
|
|
.run();
|
|
}
|
|
|
|
/// Low-resolution texture that contains the pixel-perfect world.
|
|
/// Canvas itself is rendered to the high-resolution world.
|
|
#[derive(Component)]
|
|
struct Canvas;
|
|
|
|
/// Camera that renders the pixel-perfect world to the [`Canvas`].
|
|
#[derive(Component)]
|
|
struct InGameCamera;
|
|
|
|
/// Camera that renders the [`Canvas`] (and other graphics on [`HIGH_RES_LAYERS`]) to the screen.
|
|
#[derive(Component)]
|
|
struct OuterCamera;
|
|
|
|
#[derive(Component)]
|
|
struct Rotate;
|
|
|
|
fn setup_sprite(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
// the sample sprite that will be rendered to the pixel-perfect canvas
|
|
commands.spawn((
|
|
SpriteBundle {
|
|
texture: asset_server.load("pixel/bevy_pixel_dark.png"),
|
|
transform: Transform::from_xyz(-40., 20., 2.),
|
|
..default()
|
|
},
|
|
Rotate,
|
|
PIXEL_PERFECT_LAYERS,
|
|
));
|
|
|
|
// the sample sprite that will be rendered to the high-res "outer world"
|
|
commands.spawn((
|
|
SpriteBundle {
|
|
texture: asset_server.load("pixel/bevy_pixel_light.png"),
|
|
transform: Transform::from_xyz(-40., -20., 2.),
|
|
..default()
|
|
},
|
|
Rotate,
|
|
HIGH_RES_LAYERS,
|
|
));
|
|
}
|
|
|
|
/// Spawns a capsule mesh on the pixel-perfect layer.
|
|
fn setup_mesh(
|
|
mut commands: Commands,
|
|
mut meshes: ResMut<Assets<Mesh>>,
|
|
mut materials: ResMut<Assets<ColorMaterial>>,
|
|
) {
|
|
commands.spawn((
|
|
MaterialMesh2dBundle {
|
|
mesh: meshes.add(Capsule2d::default()).into(),
|
|
transform: Transform::from_xyz(40., 0., 2.).with_scale(Vec3::splat(32.)),
|
|
material: materials.add(Color::BLACK),
|
|
..default()
|
|
},
|
|
Rotate,
|
|
PIXEL_PERFECT_LAYERS,
|
|
));
|
|
}
|
|
|
|
fn setup_camera(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
|
|
let canvas_size = Extent3d {
|
|
width: RES_WIDTH,
|
|
height: RES_HEIGHT,
|
|
..default()
|
|
};
|
|
|
|
// this Image serves as a canvas representing the low-resolution game screen
|
|
let mut canvas = Image {
|
|
texture_descriptor: TextureDescriptor {
|
|
label: None,
|
|
size: canvas_size,
|
|
dimension: TextureDimension::D2,
|
|
format: TextureFormat::Bgra8UnormSrgb,
|
|
mip_level_count: 1,
|
|
sample_count: 1,
|
|
usage: TextureUsages::TEXTURE_BINDING
|
|
| TextureUsages::COPY_DST
|
|
| TextureUsages::RENDER_ATTACHMENT,
|
|
view_formats: &[],
|
|
},
|
|
..default()
|
|
};
|
|
|
|
// fill image.data with zeroes
|
|
canvas.resize(canvas_size);
|
|
|
|
let image_handle = images.add(canvas);
|
|
|
|
// this camera renders whatever is on `PIXEL_PERFECT_LAYERS` to the canvas
|
|
commands.spawn((
|
|
Camera2dBundle {
|
|
camera: Camera {
|
|
// render before the "main pass" camera
|
|
order: -1,
|
|
target: RenderTarget::Image(image_handle.clone()),
|
|
..default()
|
|
},
|
|
..default()
|
|
},
|
|
InGameCamera,
|
|
PIXEL_PERFECT_LAYERS,
|
|
));
|
|
|
|
// spawn the canvas
|
|
commands.spawn((
|
|
SpriteBundle {
|
|
texture: image_handle,
|
|
..default()
|
|
},
|
|
Canvas,
|
|
HIGH_RES_LAYERS,
|
|
));
|
|
|
|
// the "outer" camera renders whatever is on `HIGH_RES_LAYERS` to the screen.
|
|
// here, the canvas and one of the sample sprites will be rendered by this camera
|
|
commands.spawn((Camera2dBundle::default(), OuterCamera, HIGH_RES_LAYERS));
|
|
}
|
|
|
|
/// Rotates entities to demonstrate grid snapping.
|
|
fn rotate(time: Res<Time>, mut transforms: Query<&mut Transform, With<Rotate>>) {
|
|
for mut transform in &mut transforms {
|
|
let dt = time.delta_seconds();
|
|
transform.rotate_z(dt);
|
|
}
|
|
}
|
|
|
|
/// Scales camera projection to fit the window (integer multiples only).
|
|
fn fit_canvas(
|
|
mut resize_events: EventReader<WindowResized>,
|
|
mut projections: Query<&mut OrthographicProjection, With<OuterCamera>>,
|
|
) {
|
|
for event in resize_events.read() {
|
|
let h_scale = event.width / RES_WIDTH as f32;
|
|
let v_scale = event.height / RES_HEIGHT as f32;
|
|
let mut projection = projections.single_mut();
|
|
projection.scale = 1. / h_scale.min(v_scale).round();
|
|
}
|
|
}
|