Skip to content

Commit

Permalink
Port skinning to the importer
Browse files Browse the repository at this point in the history
  • Loading branch information
suspistew committed Feb 23, 2021
1 parent f89db16 commit 2b55026
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 16 deletions.
49 changes: 44 additions & 5 deletions amethyst_gltf/src/importer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,18 @@ use crate::{
types::{MaterialHandle, MeshHandle},
GltfSceneOptions,
};
use crate::importer::skin::load_skin;

mod gltf_bytes_converter;
mod images;
mod material;
mod mesh;
mod skin;

#[derive(Debug)]
struct SkinInfo {
pub struct SkinInfo {
skin_index: usize,
mesh_indices: Vec<usize>,
mesh_indices: Vec<Entity>,
}

/// A simple state for Importer to retain the same UUID between imports
Expand Down Expand Up @@ -107,6 +109,8 @@ impl Importer for GltfImporter {
asset_accumulator.append(&mut material_assets);
});



// TODO : load animation

let scene_index = get_scene_index(&doc, options).expect("No scene has been found !");
Expand All @@ -115,11 +119,29 @@ impl Importer for GltfImporter {
.nth(scene_index)
.expect("Tried to load a scene which does not exist");

let mut skin_map = HashMap::new();
let mut node_map = HashMap::new();

scene.nodes().into_iter().for_each(|node| {
let mut node_assets = load_node(&node, &mut world, op, state, &options, &buffers, None);
let mut node_assets = load_node(&node, &mut world, op, state, &options, &buffers, None, &mut node_map, &mut skin_map);
asset_accumulator.append(&mut node_assets);
});

// load skins
for (entity, skin_info) in skin_map {
load_skin(
&doc.skins().nth(skin_info.skin_index).expect(
"Unreachable: `skin_map` is initialized with indexes from the `Gltf` object",
),
&buffers,
entity,
&skin_info,
&node_map,
&mut world
);
}


let legion_prefab = legion_prefab::Prefab::new(world);
let scene_prefab = Prefab::new(legion_prefab);

Expand Down Expand Up @@ -156,8 +178,11 @@ fn load_node(
options: &GltfSceneOptions,
buffers: &Vec<Data>,
parent_node_entity: Option<&Entity>,
node_map: &mut HashMap<usize, Entity>,
skin_map: &mut HashMap<Entity, SkinInfo>
) -> Vec<ImportedAsset> {
let current_node_entity = world.push(());
node_map.insert(node.index(), current_node_entity);
let mut imported_assets = Vec::new();
let current_transform = {
if let Some(transform) = load_transform(node) {
Expand Down Expand Up @@ -258,8 +283,9 @@ fn load_node(
)));

// if we have a skin we need to track the mesh entities
if let Some(ref mut _skin) = skin {
if let Some(ref mut skin) = skin {
// Should add an entity per primitive
skin.mesh_indices.push(current_node_entity);
}
}
}
Expand All @@ -283,7 +309,7 @@ fn load_node(
asset_data: Box::new(mesh_data),
});

world.push((
let current_primitive_entity = world.push((
current_transform.expect("Meshes must have a transform component"),
MeshHandle(make_handle(mesh_asset_id)),
MaterialHandle(make_handle(
Expand All @@ -297,11 +323,17 @@ fn load_node(
))
));
primitive_index += 1;

// Should add an entity per primitive
if let Some(ref mut skin) = skin {
skin.mesh_indices.push(current_primitive_entity);
}
}
}
_ => {
// Nothing to do here
}

}
}

Expand All @@ -315,10 +347,17 @@ fn load_node(
options,
buffers,
Some(&current_node_entity),
node_map,
skin_map
);
imported_assets.append(&mut child_assets);
}

// propagate skin information
if let Some(skin) = skin {
skin_map.insert(current_node_entity, skin);
}

imported_assets
}

Expand Down
84 changes: 84 additions & 0 deletions amethyst_gltf/src/importer/skin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use gltf::buffer::Data;
use amethyst_core::ecs::{Entity, World, EntityStore};
use crate::importer::SkinInfo;
use amethyst_error::Error;
use std::collections::HashMap;
use amethyst_core::math::{Matrix4, convert};
use amethyst_animation::{Skin, Joint};
use amethyst_rendy::skinning::JointTransforms;

struct JointTransformInfos{
pub skin: Entity,
pub size: usize,
}

pub fn load_skin(
skin: &gltf::Skin<'_>,
buffers: &Vec<Data>,
entity: Entity,
skin_infos: &SkinInfo,
node_map: &HashMap<usize, Entity>,
world: &mut World
) -> Result<(), Error> {
let joint_entities = skin
.joints()
.map(|j| {
node_map.get(&j.index()).cloned().expect(
"Unreachable: `node_map` is initialized with the indexes from the `Gltf` object",
)
})
.collect::<Vec<_>>();

let reader = skin.reader(|buffer| Some(buffers.get(buffer.index())
.expect("Error while reading skin buffer")
.0.as_slice()));

let inverse_bind_matrices = reader
.read_inverse_bind_matrices()
.map(|matrices| {
matrices
.map(Matrix4::from)
.map(convert::<_, Matrix4<f32>>)
.collect()
})
.unwrap_or_else(|| vec![Matrix4::identity(); joint_entities.len()]);

let mut aggregator = HashMap::<Entity, Vec<Entity>>::new();

for (_bind_index, joint_entity) in joint_entities.iter().enumerate() {
aggregator
.entry(*joint_entity)
.or_insert_with(||Vec::new())
.push(entity);
}

for (entity, skins) in aggregator.iter(){
let joint = Joint {
skins: skins.clone(),
};
world.entry(*entity)
.expect("This can't be reached because the entity comes from this world")
.add_component(joint);
}

let joint_transforms = JointTransforms{ skin: entity, matrices: vec![Matrix4::identity(); joint_entities.len()] };
for mesh_entity in &skin_infos.mesh_indices {
world.entry(*mesh_entity)
.expect("This can't be reached because the entity comes from this world")
.add_component(joint_transforms.clone());
}
let len = joint_entities.len();
let skin = Skin {
joints: joint_entities,
meshes: skin_infos.mesh_indices.clone(),
bind_shape_matrix: Matrix4::identity(),
inverse_bind_matrices,
joint_matrices: Vec::with_capacity(len),
};

world.entry(entity)
.expect("This can't be reached because the entity comes from this world")
.add_component(skin);

Ok(())
}
20 changes: 10 additions & 10 deletions examples/gltf_scene/assets/gltf/sample.glb.meta
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,25 @@
id: Some("b3e0fa67-a3cc-48e4-b5f6-520da449112f"),
images_uuids: None,
material_uuids: Some({
"1_occlusion": "ae73af59-18d3-410b-ade5-de548d91fff2",
"0_cavity": "835e0b69-d771-41f4-a941-24c3b88132fc",
"1_cavity": "6d79a654-59fd-4244-b39c-e38dd52cea09",
"1_albedo": "82e0b4d6-155e-4810-bb76-e611f5ce8d02",
"0_occlusion": "2a27982b-9e3c-4987-bf0a-a0beb9a519f1",
"1_metallic_roughness": "2cf5e343-22a3-4894-aec5-0bb06a166f1c",
"1_emission": "da781873-d48e-4f3d-8bd8-b6f673ac6a4f",
"0_metallic_roughness": "7d8570db-3188-4c30-b0f1-9db0ab5d5ce6",
"0_emission": "68b20023-f5ab-47dc-8853-44913b572e0a",
"1": "34cd6fb1-62b1-4102-ae66-d9e157ee14c3",
"1_metallic_roughness": "2cf5e343-22a3-4894-aec5-0bb06a166f1c",
"0_albedo": "f41b200e-fd49-4bb4-beda-b0698db3e5f0",
"0": "47b766b2-8e9f-49a5-8a4e-82e5a38b6594",
"0_metallic_roughness": "7d8570db-3188-4c30-b0f1-9db0ab5d5ce6",
"1_cavity": "6d79a654-59fd-4244-b39c-e38dd52cea09",
"0_normal": "bf0381e4-f156-43c2-a643-0cd22aeb688e",
"0_emission": "68b20023-f5ab-47dc-8853-44913b572e0a",
"0_albedo": "f41b200e-fd49-4bb4-beda-b0698db3e5f0",
"1_albedo": "82e0b4d6-155e-4810-bb76-e611f5ce8d02",
"1_occlusion": "ae73af59-18d3-410b-ade5-de548d91fff2",
"1_emission": "da781873-d48e-4f3d-8bd8-b6f673ac6a4f",
"0_cavity": "835e0b69-d771-41f4-a941-24c3b88132fc",
"1_normal": "47bed74e-a9a6-4c1f-ae09-1c9c19cc19cc",
}),
material_transparencies: Some([]),
mesh_uuids: Some({
"Cube_0": "3dc66b63-cc81-42f6-b53d-1e9be940d03d",
"Cube_1": "3355a8b1-11dc-4690-b55a-2485f6b69ffe",
"Cube_0": "3dc66b63-cc81-42f6-b53d-1e9be940d03d",
}),
),
)
2 changes: 1 addition & 1 deletion examples/gltf_scene/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl SimpleState for GltfExample {

fn main() -> Result<(), amethyst::Error> {
let config = amethyst::LoggerConfig {
level_filter: amethyst::LogLevelFilter::Trace,
level_filter: amethyst::LogLevelFilter::Warn,
module_levels: vec![],
..Default::default()
};
Expand Down

0 comments on commit 2b55026

Please sign in to comment.