test(auto_export):
* fleshed out testing of hierarchy * added export of serialized hierarchy from the bevy side & comparing it with a reference one on the python side * various tweaks
This commit is contained in:
parent
b51a0d38e2
commit
a001ee21f6
|
@ -14,3 +14,4 @@ bevy_rapier3d = { version = "0.25.0", features = ["serde-serialize", "debug-rend
|
|||
bevy_asset_loader = { version = "0.20", features = ["standard_dynamic_assets"] }
|
||||
bevy_editor_pls = { version = "0.8" }
|
||||
rand = "0.8.5"
|
||||
json-writer ="0.3"
|
|
@ -3516,6 +3516,17 @@
|
|||
"type": "object",
|
||||
"typeInfo": "Struct"
|
||||
},
|
||||
"bevy_gltf_blueprints::animation::Animated": {
|
||||
"additionalProperties": false,
|
||||
"isComponent": true,
|
||||
"isResource": false,
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"short_name": "Animated",
|
||||
"title": "bevy_gltf_blueprints::animation::Animated",
|
||||
"type": "object",
|
||||
"typeInfo": "Struct"
|
||||
},
|
||||
"bevy_gltf_blueprints::animation::Animations": {
|
||||
"additionalProperties": false,
|
||||
"isComponent": true,
|
||||
|
|
Binary file not shown.
|
@ -1,24 +1,30 @@
|
|||
pub mod in_game;
|
||||
use std::{
|
||||
fs::{self},
|
||||
time::Duration,
|
||||
collections::HashMap, fs, time::Duration
|
||||
};
|
||||
|
||||
use bevy_gltf_blueprints::{AnimationPlayerLink, BlueprintName, BlueprintsList};
|
||||
use bevy_gltf_blueprints::{AnimationPlayerLink, Animations, BlueprintName, BlueprintsList};
|
||||
pub use in_game::*;
|
||||
|
||||
use bevy::{
|
||||
prelude::*, render::view::screenshot::ScreenshotManager, time::common_conditions::on_timer,
|
||||
window::PrimaryWindow,
|
||||
ecs::query, prelude::*, render::view::screenshot::ScreenshotManager, time::common_conditions::on_timer, window::PrimaryWindow
|
||||
};
|
||||
use bevy_gltf_worlflow_examples_common_rapier::{AppState, GameState};
|
||||
|
||||
use crate::{TupleTestF32, UnitTest};
|
||||
use json_writer::to_json_string;
|
||||
|
||||
fn start_game(mut next_app_state: ResMut<NextState<AppState>>) {
|
||||
next_app_state.set(AppState::AppLoading);
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Node {
|
||||
value: String,
|
||||
children: Vec<String>,
|
||||
}
|
||||
|
||||
// if the export from Blender worked correctly, we should have animations (simplified here by using AnimationPlayerLink)
|
||||
// if the export from Blender worked correctly, we should have an Entity called "Cylinder" that has two components: UnitTest, TupleTestF32
|
||||
// if the export from Blender worked correctly, we should have an Entity called "Blueprint4_nested" that has a child called "Blueprint3" that has a "BlueprintName" component with value Blueprint3
|
||||
|
@ -34,19 +40,10 @@ fn validate_export(
|
|||
empties_candidates: Query<(Entity, &Name, &GlobalTransform)>,
|
||||
|
||||
blueprints_list: Query<(Entity, &BlueprintsList)>,
|
||||
root: Query<(Entity, &Name, &Children), (Without<Parent>, With<Children>)>
|
||||
) {
|
||||
let animations_found = !animation_player_links.is_empty();
|
||||
|
||||
let mut cylinder_found = false;
|
||||
if let Ok(nested_cylinder) = exported_cylinder.get_single() {
|
||||
let parent_name = names
|
||||
.get(parents.get(nested_cylinder.0).unwrap().get())
|
||||
.unwrap();
|
||||
cylinder_found = parent_name.to_string() == *"Cube.001"
|
||||
&& nested_cylinder.1.to_string() == *"Cylinder"
|
||||
&& nested_cylinder.3 .0 == 75.1;
|
||||
}
|
||||
|
||||
let mut nested_blueprint_found = false;
|
||||
for (entity, name, blueprint_name) in blueprints.iter() {
|
||||
if name.to_string() == *"Blueprint4_nested" && blueprint_name.0 == *"Blueprint4_nested" {
|
||||
|
@ -71,14 +68,46 @@ fn validate_export(
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// check if there are blueprints_list components
|
||||
let blueprints_list_found = !blueprints_list.is_empty();
|
||||
|
||||
// there should be no entity named xxx____bak as it means an error in the Blender side export process
|
||||
let mut exported_names_correct = true;
|
||||
for name in names.iter() {
|
||||
if name.to_string().ends_with("___bak") {
|
||||
exported_names_correct = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// generate parent/child tree
|
||||
if !root.is_empty() {
|
||||
let root = root.single();
|
||||
let mut tree: HashMap<String, Vec<String>> = HashMap::new();
|
||||
// println!("root {}", root.1);
|
||||
|
||||
for child in children.iter_descendants(root.0) {
|
||||
let child_name:String = names.get(child).map_or(String::from("no_name"), |e| e.to_string() ); //|e| e.to_string(), || "no_name".to_string());
|
||||
//println!(" child {}", child_name);
|
||||
let parent = parents.get(child).unwrap();
|
||||
let parent_name:String = names.get(parent.get()).map_or(String::from("no_name"), |e| e.to_string() ); //|e| e.to_string(), || "no_name".to_string());
|
||||
tree.entry(parent_name).or_default().push(child_name.clone());
|
||||
}
|
||||
|
||||
let hierarchy = to_json_string(&tree);
|
||||
fs::write(
|
||||
"bevy_hierarchy.json",
|
||||
hierarchy
|
||||
)
|
||||
.expect("unable to write hierarchy file")
|
||||
}
|
||||
|
||||
|
||||
fs::write(
|
||||
"bevy_diagnostics.json",
|
||||
format!(
|
||||
"{{ \"animations\": {}, \"cylinder_found\": {} , \"nested_blueprint_found\": {}, \"empty_found\": {}, \"blueprints_list_found\": {} }}",
|
||||
animations_found, cylinder_found, nested_blueprint_found, empty_found, blueprints_list_found
|
||||
"{{ \"animations\": {}, \"nested_blueprint_found\": {}, \"empty_found\": {}, \"blueprints_list_found\": {}, \"exported_names_correct\": {} }}",
|
||||
animations_found, nested_blueprint_found, empty_found, blueprints_list_found, exported_names_correct
|
||||
),
|
||||
)
|
||||
.expect("Unable to write file");
|
||||
|
@ -97,6 +126,35 @@ fn exit_game(mut app_exit_events: ResMut<Events<bevy::app::AppExit>>) {
|
|||
app_exit_events.send(bevy::app::AppExit);
|
||||
}
|
||||
|
||||
/*
|
||||
#[derive(Resource)]
|
||||
struct Animations(Vec<Handle<AnimationClip>>);
|
||||
*/
|
||||
|
||||
fn animations(
|
||||
foo:Query<(Entity, &Name, &AnimationPlayer),(Added<AnimationPlayer>)>,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut commands: Commands,
|
||||
) {
|
||||
for bla in foo.iter() {
|
||||
let mut counter = 0;
|
||||
counter +=1;
|
||||
println!("found some animations {} {}", counter, bla.1);
|
||||
|
||||
if bla.1.to_string() == "Collection".to_string(){
|
||||
/*commands.insert_resource(Animations(vec![
|
||||
asset_server.load("models/World.glb#Animation0"),
|
||||
asset_server.load("models/World.glb#Animation1"),
|
||||
]));*/
|
||||
/*commands.entity(bla.0).insert(Animations {
|
||||
named_animations:
|
||||
})*/
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GamePlugin;
|
||||
impl Plugin for GamePlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
|
@ -104,6 +162,7 @@ impl Plugin for GamePlugin {
|
|||
.add_systems(Update, validate_export)
|
||||
.add_systems(OnEnter(AppState::MenuRunning), start_game)
|
||||
.add_systems(OnEnter(AppState::AppRunning), setup_game)
|
||||
.add_systems(Update, animations)
|
||||
.add_systems(Update, generate_screenshot.run_if(on_timer(Duration::from_secs_f32(0.2)))) // TODO: run once
|
||||
.add_systems(
|
||||
Update,
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import bpy
|
||||
|
||||
def get_standard_exporter_settings():
|
||||
for scene in bpy.data.scenes:
|
||||
if 'glTF2ExportSettings' in scene:
|
||||
print("standard exporter settings", scene['glTF2ExportSettings'])
|
|
@ -0,0 +1 @@
|
|||
{"b_Tail02_013":["b_Tail03_014"],"Blueprint4_nested.001":["Blueprint3"],"Collection 2 1":["Empty_in_sub_collection"],"b_Root_00":["b_Hip_01"],"b_LeftForeArm_010":["b_LeftHand_011"],"b_Spine01_02":["b_Spine02_03"],"Blueprint7_hierarchy.001":["Blueprint4_nested.001","Cube.001"],"b_RightLeg01_019":["b_RightLeg02_020"],"b_LeftUpperArm_09":["b_LeftForeArm_010"],"no_name":["Parent_Object","lighting_components_World","assets_list_World_components","Collection","Collection 2"],"Blueprint3":["Blueprint3_mesh","Blueprint3_mesh"],"world":["no_name"],"Parent_Object":["Cube.003","Blueprint1","Cylinder.001"],"Light":["Light","DirectionalLight Gizmo"],"Blueprint1.001":["Blueprint1_mesh"],"Blueprint7_hierarchy":["Cube.001"],"Spot":["Spot"],"b_Hip_01":["b_Spine01_02","b_Tail01_012","b_LeftLeg01_015","b_RightLeg01_019"],"Cylinder":["Cylinder.001","Cylinder.001"],"Collection 2":["Collection 2 1","Empty_in_collection","Spot"],"b_RightForeArm_07":["b_RightHand_08"],"Blueprint3_mesh":["Cylinder","Cylinder"],"Blueprint4_nested":["Blueprint3"],"Fox_mesh":["fox1"],"b_LeftLeg01_015":["b_LeftLeg02_016"],"b_Neck_04":["b_Head_05"],"b_RightFoot01_021":["b_RightFoot02_022"],"Blueprint1_mesh":["Cube.001","Cube.001"],"b_Tail01_012":["b_Tail02_013"],"Fox":["Fox_mesh","_rootJoint"],"Collection":["Blueprint1.001","Blueprint4_nested","Blueprint6_animated","Blueprint7_hierarchy","Camera","Cube","Empty","Light","Plane"],"Cube":["Cube"],"_rootJoint":["b_Root_00"],"b_RightLeg02_020":["b_RightFoot01_021"],"b_RightUpperArm_06":["b_RightForeArm_07"],"Plane":["Plane"],"Camera":["Camera Gizmo"],"Blueprint6_animated":["Fox"],"b_Spine02_03":["b_Neck_04","b_RightUpperArm_06","b_LeftUpperArm_09"],"b_LeftLeg02_016":["b_LeftFoot01_017"],"b_LeftFoot01_017":["b_LeftFoot02_018"],"Cube.001":["Cube.002","Cylinder","Cube.002","Cylinder"],"Cylinder.001":["Cylinder.002","Blueprint7_hierarchy.001","Empty_as_child"],"Blueprint1":["Blueprint1_mesh"]}
|
|
@ -5,6 +5,7 @@ import json
|
|||
import pytest
|
||||
import shutil
|
||||
|
||||
import filecmp
|
||||
from PIL import Image
|
||||
from pixelmatch.contrib.PIL import pixelmatch
|
||||
|
||||
|
@ -108,9 +109,15 @@ def test_export_complex(setup_data):
|
|||
diagnostics = json.load(diagnostics_file)
|
||||
print("diagnostics", diagnostics)
|
||||
assert diagnostics["animations"] == True
|
||||
assert diagnostics["cylinder_found"] == True
|
||||
assert diagnostics["empty_found"] == True
|
||||
assert diagnostics["blueprints_list_found"] == True
|
||||
assert diagnostics["exported_names_correct"] == True
|
||||
|
||||
with open(os.path.join(root_path, "bevy_hierarchy.json")) as hierarchy_file:
|
||||
with open(os.path.join(os.path.dirname(__file__), "expected_bevy_hierarchy.json")) as expexted_hierarchy_file:
|
||||
hierarchy = json.load(hierarchy_file)
|
||||
expected = json.load(expexted_hierarchy_file)
|
||||
assert sorted(hierarchy.items()) == sorted(expected.items())
|
||||
|
||||
# last but not least, do a visual compare
|
||||
screenshot_expected_path = os.path.join(root_path, "expected_screenshot.png")
|
||||
|
|
Loading…
Reference in New Issue