Skip to content

Commit

Permalink
add basic vrm 0.0 mtoon support
Browse files Browse the repository at this point in the history
  • Loading branch information
kayhhh committed Oct 31, 2023
1 parent 65b4a8a commit 9404347
Show file tree
Hide file tree
Showing 10 changed files with 254 additions and 35 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ opt-level = 'z'

[dependencies]
bevy = "0.11.3"
bevy_shader_mtoon = "0.0.1"
goth-gltf = "0.1.1"
nanoserde = "0.1.35"
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@
Supports both the VRM 0.0 and VRM 1.0 standards.

![image](https://github.com/unavi-xyz/bevy_vrm/assets/92771507/bdf5d2b6-29b2-4d5b-aa67-79d1de247b34)

## MToon

Uses the [bevy_shader_mtoon](https://github.com/unavi-xyz/bevy_shader_mtoon) crate,
and re-exports it's contents under `bevy_vrm::mtoon`.
Binary file added assets/cool_loops.vrm
Binary file not shown.
19 changes: 16 additions & 3 deletions examples/load_vrm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ fn main() {
struct VrmTag;

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let mut transform = Transform::from_xyz(0.0, -1.0, -4.0);
let mut transform = Transform::from_xyz(0.0, -1.0, -3.0);
transform.rotate_y(PI);

commands.spawn((
Expand All @@ -27,11 +27,24 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
VrmTag,
));

commands.spawn(Camera3dBundle::default());
commands.spawn((Camera3dBundle::default(), bevy_vrm::mtoon::MtoonMainCamera));

commands.spawn((
DirectionalLightBundle {
directional_light: DirectionalLight {
shadows_enabled: true,
illuminance: 10_000.0,
..default()
},
transform: Transform::from_xyz(0.0, 5.0, -5.0),
..default()
},
bevy_vrm::mtoon::MtoonSun,
));
}

fn rotate_vrm(time: Res<Time>, mut query: Query<&mut Transform, With<VrmTag>>) {
for mut transform in query.iter_mut() {
transform.rotate(Quat::from_rotation_y(time.delta_seconds()));
transform.rotate(Quat::from_rotation_y(time.delta_seconds() / 3.0));
}
}
50 changes: 25 additions & 25 deletions src/extensions/vrm0.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,32 +46,32 @@ pub struct Meta {
#[derive(DeJson, SerJson, Debug, Clone)]
pub struct Humanoid {
#[nserde(rename = "humanBones")]
pub human_bones: Vec<Bone>,
pub human_bones: Option<Vec<Bone>>,
#[nserde(rename = "armStretch")]
pub arm_stretch: f32,
pub arm_stretch: Option<f32>,
#[nserde(rename = "legStretch")]
pub leg_stretch: f32,
pub leg_stretch: Option<f32>,
#[nserde(rename = "upperArmTwist")]
pub upper_arm_twist: f32,
pub upper_arm_twist: Option<f32>,
#[nserde(rename = "lowerArmTwist")]
pub lower_arm_twist: f32,
pub lower_arm_twist: Option<f32>,
#[nserde(rename = "upperLegTwist")]
pub upper_leg_twist: f32,
pub upper_leg_twist: Option<f32>,
#[nserde(rename = "lowerLegTwist")]
pub lower_leg_twist: f32,
pub lower_leg_twist: Option<f32>,
#[nserde(rename = "feetSpacing")]
pub feet_spacing: f32,
pub feet_spacing: Option<f32>,
#[nserde(rename = "hasTranslationDoF")]
pub has_translation_dof: bool,
pub has_translation_dof: Option<bool>,
}

#[derive(DeJson, SerJson, Debug, Clone)]
pub struct Bone {
#[nserde(rename = "bone")]
pub name: String,
pub node: u32,
pub name: Option<String>,
pub node: Option<u32>,
#[nserde(rename = "useDefaultValues")]
pub use_default_values: bool,
pub use_default_values: Option<bool>,
}

#[derive(DeJson, SerJson, Debug, Clone)]
Expand Down Expand Up @@ -103,11 +103,11 @@ pub struct MeshAnnotation {

#[derive(DeJson, SerJson, Debug, Clone)]
pub struct LookAtCurve {
pub curve: [u32; 8],
pub curve: [f32; 8],
#[nserde(rename = "xRange")]
pub x_range: u32,
pub x_range: f32,
#[nserde(rename = "yRange")]
pub y_range: u32,
pub y_range: f32,
}

#[derive(DeJson, SerJson, Debug, Clone)]
Expand Down Expand Up @@ -142,7 +142,7 @@ pub struct MaterialBind {
pub struct Bind {
pub mesh: u32,
pub index: u32,
pub weight: u32,
pub weight: f32,
}

#[derive(DeJson, SerJson, Debug, Clone)]
Expand Down Expand Up @@ -194,7 +194,7 @@ pub struct Vec3 {
pub struct MaterialProperty {
pub name: String,
#[nserde(rename = "renderQueue")]
pub render_queue: u32,
pub render_queue: i32,
pub shader: String,
#[nserde(rename = "floatProperties")]
pub float: FloatProperties,
Expand Down Expand Up @@ -225,25 +225,25 @@ pub struct FloatProperties {
#[derive(DeJson, SerJson, Debug, Clone)]
pub struct TextureProperties {
#[nserde(rename = "_MainTex")]
pub main_tex: u32,
pub main_tex: Option<u32>,
#[nserde(rename = "_ShadeTexture")]
pub shade_texture: u32,
pub shade_texture: Option<u32>,
#[nserde(rename = "_BumpMap")]
pub bump_map: u32,
pub bump_map: Option<u32>,
#[nserde(rename = "_SphereAdd")]
pub sphere_add: u32,
pub sphere_add: Option<u32>,
#[nserde(rename = "_EmissionMap")]
pub emission_map: u32,
pub emission_map: Option<u32>,
}

#[derive(DeJson, SerJson, Debug, Clone)]
pub struct VectorProperties {
#[nserde(rename = "_Color")]
pub color: [f32; 4],
pub color: Option<[f32; 4]>,
#[nserde(rename = "_ShadeColor")]
pub shade_color: [f32; 4],
pub shade_color: Option<[f32; 4]>,
#[nserde(rename = "_OutlineColor")]
pub outline_color: [f32; 4],
pub outline_color: Option<[f32; 4]>,
}

#[derive(DeJson, SerJson, Debug, Clone)]
Expand Down
65 changes: 63 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,73 @@
use bevy::prelude::*;
use bevy::{
gltf::GltfMesh,
prelude::*,
reflect::{TypePath, TypeUuid},
};
use bevy_shader_mtoon::MtoonPlugin;

mod extensions;
pub mod loader;

pub mod mtoon {
pub use bevy_shader_mtoon::*;
}

pub struct VrmPlugin;

impl Plugin for VrmPlugin {
fn build(&self, app: &mut App) {
app.init_asset_loader::<loader::VrmLoader>();
app.add_plugins(MtoonPlugin)
.add_asset::<MtoonReplaceMat>()
.init_asset_loader::<loader::VrmLoader>()
.add_systems(Update, replace_mtoon_materials);
}
}

#[derive(TypeUuid, TypePath, Debug, Clone)]
#[uuid = "e16c60c0-fa00-4ead-b76f-f97823b8404e"]
pub struct MtoonReplaceMat {
mesh: Handle<GltfMesh>,
primitive: usize,
mtoon: Handle<mtoon::MtoonMaterial>,
}

fn replace_mtoon_materials(
mut commands: Commands,
mut replacements: ResMut<Assets<MtoonReplaceMat>>,
gltf_meshes: Res<Assets<GltfMesh>>,
meshes: Query<(Entity, &Handle<Mesh>), Without<Handle<mtoon::MtoonMaterial>>>,
) {
let mut to_remove = Vec::new();

for (replacement_handle, replacement) in replacements.iter() {
let target = gltf_meshes.get(&replacement.mesh).unwrap();

target
.primitives
.iter()
.enumerate()
.for_each(|(i, primitive)| {
if i != replacement.primitive {
return;
}

for (ent, ent_mesh) in meshes.iter() {
if *ent_mesh != primitive.mesh {
continue;
}

commands
.entity(ent)
.remove::<Handle<StandardMaterial>>()
.insert(replacement.mtoon.clone());

to_remove.push(replacement_handle);
break;
}
});
}

for handle in to_remove {
replacements.remove(handle);
}
}
16 changes: 11 additions & 5 deletions src/loader/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use std::fmt::Debug;

use bevy::{
asset::AssetLoader, gltf::GltfLoader, prelude::*, render::texture::CompressedImageFormats,
asset::{AssetLoader, LoadContext},
gltf::GltfLoader,
prelude::*,
render::texture::CompressedImageFormats,
utils::HashMap,
};
use goth_gltf::default_extensions;
Expand All @@ -26,7 +29,7 @@ impl AssetLoader for VrmLoader {

Box::pin(async move {
gltf_loader.load(bytes, load_context).await?;
load_vrm_extensions(bytes).await?;
load_vrm_extensions(bytes, load_context).await?;
Ok(())
})
}
Expand Down Expand Up @@ -58,12 +61,15 @@ impl goth_gltf::Extensions for Extensions {
type BufferViewExtensions = default_extensions::BufferViewExtensions;
}

async fn load_vrm_extensions(bytes: &[u8]) -> Result<(), DeJsonErr> {
async fn load_vrm_extensions<'a, 'b>(
bytes: &'a [u8],
load_context: &'a mut LoadContext<'b>,
) -> Result<(), DeJsonErr> {
let (gltf, _) = goth_gltf::Gltf::from_bytes(&bytes)?;

if let Ok(_) = vrm0::load_gltf(&gltf) {
if let Ok(_) = vrm0::load_gltf(&gltf, load_context) {
info!("VRM 0.0 loaded");
} else if let Ok(_) = vrm::load_gltf(&gltf) {
} else if let Ok(_) = vrm::load_gltf(&gltf, load_context) {
info!("VRM 1.0 loaded");
} else {
error!("VRM extension not found");
Expand Down
3 changes: 3 additions & 0 deletions src/loader/vrm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use bevy::asset::LoadContext;

pub fn load_gltf(
gltf: &goth_gltf::Gltf<super::Extensions>,
load_context: &mut LoadContext,
) -> Result<(), Box<dyn std::error::Error>> {
let vrmc_vrm = gltf.extensions.vrmc_vrm.as_ref();

Expand Down
Loading

0 comments on commit 9404347

Please sign in to comment.