diff --git a/crates/bevy_vrm/src/layers.rs b/crates/bevy_vrm/src/layers.rs index 1d510d3..fabf9e3 100644 --- a/crates/bevy_vrm/src/layers.rs +++ b/crates/bevy_vrm/src/layers.rs @@ -1,7 +1,8 @@ use std::sync::LazyLock; use bevy::{render::view::RenderLayers, utils::HashMap}; -use serde_vrm::vrm0::FirstPersonFlag; + +pub use serde_vrm::vrm0::FirstPersonFlag; pub const FIRST_PERSON_LAYER: usize = 7; pub const THIRD_PERSON_LAYER: usize = 8; diff --git a/crates/vrm_viewer/src/lib.rs b/crates/vrm_viewer/src/lib.rs index 14d88b9..d22bec6 100644 --- a/crates/vrm_viewer/src/lib.rs +++ b/crates/vrm_viewer/src/lib.rs @@ -2,10 +2,16 @@ use std::f32::consts::PI; -use bevy::{asset::AssetMetaCheck, prelude::*}; +use bevy::{asset::AssetMetaCheck, prelude::*, render::view::RenderLayers}; use bevy_egui::EguiPlugin; use bevy_panorbit_camera::{PanOrbitCamera, PanOrbitCameraPlugin}; -use bevy_vrm::{loader::Vrm, mtoon::MtoonSun, VrmBundle, VrmPlugins}; +use bevy_vrm::{ + layers::{FirstPersonFlag, RENDER_LAYERS}, + loader::Vrm, + mtoon::MtoonSun, + VrmBundle, VrmPlugins, +}; +use ui::RenderLayer; mod draw_spring_bones; mod move_leg; @@ -39,6 +45,7 @@ impl Plugin for VrmViewerPlugin { draw_spring_bones::move_avatar, move_leg::move_leg, read_dropped_files, + set_render_layers, ui::update_ui, ), ); @@ -48,8 +55,9 @@ impl Plugin for VrmViewerPlugin { #[derive(Resource, Default)] struct Settings { pub draw_spring_bones: bool, - pub move_leg: bool, pub move_avatar: bool, + pub move_leg: bool, + pub render_layer: RenderLayer, } const VRM_PATH: &str = "alicia.vrm"; @@ -92,6 +100,31 @@ fn setup(mut commands: Commands, asset_server: Res) { }); } +fn set_render_layers( + cameras: Query>, + mut commands: Commands, + mut prev: Local, + settings: Res, +) { + for entity in cameras.iter() { + let flag = match settings.render_layer { + RenderLayer::Both => FirstPersonFlag::Both, + RenderLayer::FirstPerson => FirstPersonFlag::FirstPersonOnly, + RenderLayer::ThirdPerson => FirstPersonFlag::ThirdPersonOnly, + }; + + if flag != *prev { + *prev = flag; + + let layers = RENDER_LAYERS[&flag].clone(); + + commands + .entity(entity) + .insert(layers.union(&RenderLayers::layer(0))); + } + } +} + fn read_dropped_files( mut commands: Commands, mut events: EventReader, diff --git a/crates/vrm_viewer/src/ui.rs b/crates/vrm_viewer/src/ui.rs index 0c39b4d..dbb7bb6 100644 --- a/crates/vrm_viewer/src/ui.rs +++ b/crates/vrm_viewer/src/ui.rs @@ -1,8 +1,39 @@ use bevy::prelude::*; -use bevy_egui::EguiContexts; +use bevy_egui::{egui::ComboBox, EguiContexts}; use crate::Settings; +#[derive(Copy, Clone, Default, PartialEq, Eq)] +pub enum RenderLayer { + #[default] + Both, + FirstPerson, + ThirdPerson, +} + +impl RenderLayer { + fn as_str(&self) -> &str { + match self { + Self::Both => "Both", + Self::FirstPerson => "FirstPersonOnly", + Self::ThirdPerson => "ThirdPersonOnly", + } + } + + fn from_str(s: &str) -> Option { + match s { + "Both" => Some(Self::Both), + "FirstPersonOnly" => Some(Self::FirstPerson), + "ThirdPersonOnly" => Some(Self::ThirdPerson), + _ => None, + } + } + + fn variants() -> &'static [&'static str] { + &["Both", "FirstPersonOnly", "ThirdPersonOnly"] + } +} + pub fn update_ui(mut contexts: EguiContexts, mut settings: ResMut) { bevy_egui::egui::Window::new("VRM Viewer").show(contexts.ctx_mut(), |ui| { ui.vertical(|ui| { @@ -26,6 +57,18 @@ pub fn update_ui(mut contexts: EguiContexts, mut settings: ResMut) { ui.checkbox(&mut settings.move_leg, "Move leg bone"); ui.checkbox(&mut settings.move_avatar, "Move avatar"); + ComboBox::from_label("Render layers") + .selected_text(settings.render_layer.as_str()) + .show_ui(ui, |ui| { + for variant in RenderLayer::variants() { + ui.selectable_value( + &mut settings.render_layer, + RenderLayer::from_str(variant).unwrap(), + *variant, + ); + } + }); + ui.separator(); ui.vertical_centered(|ui| {