diff --git a/Assets/Luneraria/Art.meta b/Assets/Luneraria/Art.meta
new file mode 100644
index 0000000..10f304c
--- /dev/null
+++ b/Assets/Luneraria/Art.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 50ac3333ebb2c4d7a9f94a41495626b4
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Buildings.meta b/Assets/Luneraria/Art/Buildings.meta
new file mode 100644
index 0000000..a206112
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 1f40c6a05032444fdbf7dd895f45db6f
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Buildings/ancient.export.json b/Assets/Luneraria/Art/Buildings/ancient.export.json
new file mode 100644
index 0000000..33aa7d2
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/ancient.export.json
@@ -0,0 +1,1191 @@
+{
+ "id": "ancient",
+ "group": "Buildings",
+ "source": "assets-source/luneraria/g2/ancient.blend",
+ "exporter_version": 5,
+ "blender": "5.2.2 LTS",
+ "fbx_settings": {
+ "use_selection": true,
+ "use_visible": false,
+ "use_active_collection": false,
+ "global_scale": 1.0,
+ "apply_unit_scale": true,
+ "apply_scale_options": "FBX_SCALE_UNITS",
+ "axis_forward": "Y",
+ "axis_up": "Z",
+ "bake_space_transform": false,
+ "object_types": [
+ "ARMATURE",
+ "EMPTY",
+ "MESH"
+ ],
+ "use_mesh_modifiers": true,
+ "use_mesh_modifiers_render": true,
+ "mesh_smooth_type": "OFF",
+ "use_subsurf": false,
+ "use_mesh_edges": false,
+ "use_tspace": true,
+ "use_triangles": false,
+ "colors_type": "LINEAR",
+ "prioritize_active_color": true,
+ "use_custom_props": false,
+ "add_leaf_bones": false,
+ "primary_bone_axis": "Y",
+ "secondary_bone_axis": "X",
+ "use_armature_deform_only": true,
+ "armature_nodetype": "NULL",
+ "bake_anim": true,
+ "bake_anim_use_all_bones": true,
+ "bake_anim_use_nla_strips": false,
+ "bake_anim_use_all_actions": true,
+ "bake_anim_force_startend_keying": true,
+ "bake_anim_step": 1.0,
+ "bake_anim_simplify_factor": 0.0,
+ "path_mode": "STRIP",
+ "embed_textures": false,
+ "batch_mode": "OFF"
+ },
+ "checks": [
+ {
+ "check": "turn_applied",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "units_metric",
+ "ok": true,
+ "detail": "METRIC"
+ },
+ {
+ "check": "unit_scale_1",
+ "ok": true,
+ "detail": "1.0"
+ },
+ {
+ "check": "no_negative_scale",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "object_scale_1",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "mesh_names_unique",
+ "ok": true,
+ "detail": "['Banner_L', 'Banner_R', 'Blade_0', 'Blade_1', 'Blade_2', 'Blade_3', 'Crest_A', 'Crest_B', 'Crown', 'Crystal', 'Dais', 'Fragment_0', 'Fragment_1', 'Fragment_2', 'Fragment_3', 'Fragment_4', 'Fragment_5', 'Pedestal', 'Ring_Inner', 'Ring_Outer', 'Ruin_Crystal', 'Ruin_Rubble', 'Satellite_0', 'Satellite_1', 'Satellite_2', 'Satellite_3', 'Satellite_4']"
+ },
+ {
+ "check": "material_slots_filled",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangent_prerequisites",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "no_blend_shapes",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "triangles_match_godot",
+ "ok": true,
+ "detail": "19032 fbx / 19032 godot"
+ },
+ {
+ "check": "mesh_names_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "materials_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_match_godot",
+ "ok": true,
+ "detail": "largest difference 0.00000 m"
+ },
+ {
+ "check": "no_armature",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_triangles",
+ "ok": true,
+ "detail": "19032 / 19032"
+ },
+ {
+ "check": "roundtrip_materials",
+ "ok": true,
+ "detail": "[]"
+ }
+ ],
+ "source_sha256": "57524632f468641d63970c19493e4e8161e812093d29fb41beeadae17a2e4e9d",
+ "removed_modifiers": 0,
+ "kind": "static",
+ "fps": 30.0,
+ "objects": 27,
+ "meshes": {
+ "Dais": {
+ "mesh": "Dais",
+ "triangles": 1844,
+ "vertices": 1025,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Pale",
+ "LN_Rune_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -4.0,
+ -0.06,
+ -4.0
+ ],
+ "max": [
+ 4.0,
+ 0.155,
+ 4.0
+ ]
+ }
+ },
+ "Pedestal": {
+ "mesh": "Pedestal",
+ "triangles": 4320,
+ "vertices": 2232,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Rune_Team",
+ "LN_Metal_Iron",
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -4.2035,
+ -0.05,
+ -3.3021
+ ],
+ "max": [
+ 4.2035,
+ 6.75,
+ 2.6721
+ ]
+ }
+ },
+ "Blade_0": {
+ "mesh": "Blade_0",
+ "triangles": 804,
+ "vertices": 408,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Rune_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -2.7776,
+ 3.3728,
+ -0.2944
+ ],
+ "max": [
+ -0.4238,
+ 8.7139,
+ 0.2944
+ ]
+ }
+ },
+ "Blade_1": {
+ "mesh": "Blade_1",
+ "triangles": 804,
+ "vertices": 408,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Rune_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2944,
+ 3.3728,
+ 0.4238
+ ],
+ "max": [
+ 0.2944,
+ 8.7139,
+ 2.7776
+ ]
+ }
+ },
+ "Blade_2": {
+ "mesh": "Blade_2",
+ "triangles": 804,
+ "vertices": 408,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Rune_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.4238,
+ 3.3728,
+ -0.2944
+ ],
+ "max": [
+ 2.7776,
+ 8.7139,
+ 0.2944
+ ]
+ }
+ },
+ "Blade_3": {
+ "mesh": "Blade_3",
+ "triangles": 804,
+ "vertices": 408,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Rune_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2944,
+ 3.3728,
+ -2.7776
+ ],
+ "max": [
+ 0.2944,
+ 8.7139,
+ -0.4238
+ ]
+ }
+ },
+ "Crown": {
+ "mesh": "Crown",
+ "triangles": 720,
+ "vertices": 400,
+ "ngons": 0,
+ "materials": [
+ "LN_Metal_Team",
+ "LN_Rune_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.71,
+ 8.51,
+ -0.71
+ ],
+ "max": [
+ 0.71,
+ 8.73,
+ 0.71
+ ]
+ }
+ },
+ "Crystal": {
+ "mesh": "Crystal",
+ "triangles": 366,
+ "vertices": 185,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.8693,
+ 0.0623,
+ -0.8297
+ ],
+ "max": [
+ 0.8227,
+ 3.6929,
+ 0.8668
+ ]
+ }
+ },
+ "Satellite_0": {
+ "mesh": "Satellite_0",
+ "triangles": 350,
+ "vertices": 177,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3285,
+ 1.0131,
+ -0.2995
+ ],
+ "max": [
+ 0.284,
+ 2.485,
+ 0.3444
+ ]
+ }
+ },
+ "Satellite_1": {
+ "mesh": "Satellite_1",
+ "triangles": 350,
+ "vertices": 177,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3192,
+ 1.0019,
+ -0.291
+ ],
+ "max": [
+ 0.2948,
+ 2.5016,
+ 0.3245
+ ]
+ }
+ },
+ "Satellite_2": {
+ "mesh": "Satellite_2",
+ "triangles": 350,
+ "vertices": 177,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3041,
+ 1.0088,
+ -0.3269
+ ],
+ "max": [
+ 0.3093,
+ 2.4967,
+ 0.2897
+ ]
+ }
+ },
+ "Satellite_3": {
+ "mesh": "Satellite_3",
+ "triangles": 350,
+ "vertices": 177,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3041,
+ 1.0088,
+ -0.3269
+ ],
+ "max": [
+ 0.3093,
+ 2.4967,
+ 0.2897
+ ]
+ }
+ },
+ "Satellite_4": {
+ "mesh": "Satellite_4",
+ "triangles": 350,
+ "vertices": 177,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3192,
+ 1.0019,
+ -0.291
+ ],
+ "max": [
+ 0.2948,
+ 2.5016,
+ 0.3245
+ ]
+ }
+ },
+ "Ring_Outer": {
+ "mesh": "Ring_Outer",
+ "triangles": 1008,
+ "vertices": 560,
+ "ngons": 0,
+ "materials": [
+ "LN_Metal_Team",
+ "LN_Rune_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.928,
+ -0.4324,
+ -1.8965
+ ],
+ "max": [
+ 1.928,
+ 0.4324,
+ 1.8965
+ ]
+ }
+ },
+ "Ring_Inner": {
+ "mesh": "Ring_Inner",
+ "triangles": 1008,
+ "vertices": 560,
+ "ngons": 0,
+ "materials": [
+ "LN_Metal_Team",
+ "LN_Rune_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.2809,
+ -0.9881,
+ -1.4781
+ ],
+ "max": [
+ 1.2809,
+ 0.9881,
+ 1.4781
+ ]
+ }
+ },
+ "Fragment_0": {
+ "mesh": "Fragment_0",
+ "triangles": 20,
+ "vertices": 12,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -3.1026,
+ 3.0077,
+ 0.7335
+ ],
+ "max": [
+ -2.6949,
+ 3.7223,
+ 1.0569
+ ]
+ }
+ },
+ "Fragment_1": {
+ "mesh": "Fragment_1",
+ "triangles": 20,
+ "vertices": 12,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.0624,
+ 3.9084,
+ 2.7577
+ ],
+ "max": [
+ -0.1185,
+ 4.4007,
+ 3.1904
+ ]
+ }
+ },
+ "Fragment_2": {
+ "mesh": "Fragment_2",
+ "triangles": 20,
+ "vertices": 12,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 2.0295,
+ 4.5758,
+ 1.9129
+ ],
+ "max": [
+ 2.5456,
+ 5.1245,
+ 2.2273
+ ]
+ }
+ },
+ "Fragment_3": {
+ "mesh": "Fragment_3",
+ "triangles": 20,
+ "vertices": 12,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 2.635,
+ 2.7535,
+ -1.1147
+ ],
+ "max": [
+ 3.1571,
+ 3.6783,
+ -0.6799
+ ]
+ }
+ },
+ "Fragment_4": {
+ "mesh": "Fragment_4",
+ "triangles": 20,
+ "vertices": 12,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.2453,
+ 3.884,
+ -3.127
+ ],
+ "max": [
+ 0.9747,
+ 4.2616,
+ -2.812
+ ]
+ }
+ },
+ "Fragment_5": {
+ "mesh": "Fragment_5",
+ "triangles": 20,
+ "vertices": 12,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -2.6379,
+ 4.6095,
+ -2.2876
+ ],
+ "max": [
+ -1.9684,
+ 5.3196,
+ -1.8621
+ ]
+ }
+ },
+ "Banner_L": {
+ "mesh": "Banner_L",
+ "triangles": 168,
+ "vertices": 105,
+ "ngons": 0,
+ "materials": [
+ "LN_Cloth_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -4.1738,
+ 3.0,
+ -3.2133
+ ],
+ "max": [
+ -3.5049,
+ 5.9,
+ -2.2778
+ ]
+ }
+ },
+ "Banner_R": {
+ "mesh": "Banner_R",
+ "triangles": 168,
+ "vertices": 105,
+ "ngons": 0,
+ "materials": [
+ "LN_Cloth_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 3.5049,
+ 3.0,
+ -3.2133
+ ],
+ "max": [
+ 4.1738,
+ 5.9,
+ -2.2778
+ ]
+ }
+ },
+ "Ruin_Crystal": {
+ "mesh": "Ruin_Crystal",
+ "triangles": 280,
+ "vertices": 168,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -2.7547,
+ -0.0345,
+ -2.8068
+ ],
+ "max": [
+ 2.3534,
+ 1.9235,
+ 2.3412
+ ]
+ }
+ },
+ "Ruin_Rubble": {
+ "mesh": "Ruin_Rubble",
+ "triangles": 600,
+ "vertices": 360,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale",
+ "LN_Metal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -4.1598,
+ -0.0084,
+ -2.7989
+ ],
+ "max": [
+ 3.5162,
+ 3.7388,
+ 3.8217
+ ]
+ }
+ },
+ "Crest_A": {
+ "mesh": "Crest_A",
+ "triangles": 1296,
+ "vertices": 658,
+ "ngons": 0,
+ "materials": [
+ "LN_Metal_Team",
+ "LN_Rune_Team",
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.1289,
+ 8.6353,
+ -0.28
+ ],
+ "max": [
+ 1.1289,
+ 10.3668,
+ 0.28
+ ]
+ }
+ },
+ "Crest_B": {
+ "mesh": "Crest_B",
+ "triangles": 2168,
+ "vertices": 1104,
+ "ngons": 0,
+ "materials": [
+ "LN_Metal_Team",
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.3137,
+ 8.6731,
+ -1.1427
+ ],
+ "max": [
+ 1.2379,
+ 9.918,
+ 1.2954
+ ]
+ }
+ }
+ },
+ "armatures": {},
+ "empties": {},
+ "bounds_unity": {
+ "min": [
+ -4.2035,
+ -0.9881,
+ -4.0
+ ],
+ "max": [
+ 4.2035,
+ 10.3668,
+ 4.0
+ ]
+ },
+ "clips": [],
+ "expected_from_godot": {
+ "triangles": 19032,
+ "bounds_godot": {
+ "min": [
+ -4.2035,
+ -0.9881,
+ -4.0
+ ],
+ "max": [
+ 4.2035,
+ 10.3668,
+ 4.0
+ ]
+ },
+ "resource_path": "res://assets/luneraria/g2/ancient.glb"
+ },
+ "meshes_without_uv": [
+ "Crystal",
+ "Fragment_0",
+ "Fragment_1",
+ "Fragment_2",
+ "Fragment_3",
+ "Fragment_4",
+ "Fragment_5",
+ "Ruin_Crystal",
+ "Ruin_Rubble",
+ "Satellite_0",
+ "Satellite_1",
+ "Satellite_2",
+ "Satellite_3",
+ "Satellite_4"
+ ],
+ "triangles": 19032,
+ "fbx": "Assets/Luneraria/Art/Buildings/ancient.fbx",
+ "fbx_bytes": 1266572,
+ "ok": true
+}
diff --git a/Assets/Luneraria/Art/Buildings/ancient.export.json.meta b/Assets/Luneraria/Art/Buildings/ancient.export.json.meta
new file mode 100644
index 0000000..f53e81b
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/ancient.export.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 4a082f612d76242bd8aebf43e93aeca2
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Buildings/ancient.fbx b/Assets/Luneraria/Art/Buildings/ancient.fbx
new file mode 100644
index 0000000..db75ade
Binary files /dev/null and b/Assets/Luneraria/Art/Buildings/ancient.fbx differ
diff --git a/Assets/Luneraria/Art/Buildings/ancient.fbx.meta b/Assets/Luneraria/Art/Buildings/ancient.fbx.meta
new file mode 100644
index 0000000..8f9df77
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/ancient.fbx.meta
@@ -0,0 +1,111 @@
+fileFormatVersion: 2
+guid: a0437d8104fe34013aacb4fb7c2a5a6c
+ModelImporter:
+ serializedVersion: 24300
+ internalIDToNameTable: []
+ externalObjects: {}
+ materials:
+ materialImportMode: 2
+ materialName: 0
+ materialSearch: 1
+ materialLocation: 1
+ searchTexturesGlobally: 0
+ animations:
+ legacyGenerateAnimations: 4
+ bakeSimulation: 0
+ resampleCurves: 0
+ optimizeGameObjects: 0
+ removeConstantScaleCurves: 0
+ motionNodeName:
+ animationImportErrors:
+ animationImportWarnings:
+ animationRetargetingWarnings:
+ animationDoRetargetingWarnings: 0
+ importAnimatedCustomProperties: 0
+ importConstraints: 0
+ animationCompression: 0
+ animationRotationError: 0.5
+ animationPositionError: 0.5
+ animationScaleError: 0.5
+ animationWrapMode: 0
+ extraExposedTransformPaths: []
+ extraUserProperties: []
+ clipAnimations: []
+ isReadable: 1
+ meshes:
+ lODScreenPercentages: []
+ globalScale: 1
+ meshCompression: 0
+ addColliders: 0
+ useSRGBMaterialColor: 1
+ sortHierarchyByName: 1
+ importPhysicalCameras: 1
+ importVisibility: 0
+ importBlendShapes: 0
+ importCameras: 0
+ importLights: 0
+ nodeNameCollisionStrategy: 1
+ fileIdsGeneration: 2
+ swapUVChannels: 0
+ generateSecondaryUV: 0
+ useFileUnits: 1
+ keepQuads: 0
+ weldVertices: 1
+ bakeAxisConversion: 1
+ preserveHierarchy: 0
+ skinWeightsMode: 0
+ maxBonesPerVertex: 4
+ minBoneWeight: 0.001
+ optimizeBones: 1
+ generateMeshLods: 0
+ meshLodGenerationFlags: 0
+ maximumMeshLod: -1
+ meshOptimizationFlags: -1
+ indexFormat: 0
+ secondaryUVAngleDistortion: 8
+ secondaryUVAreaDistortion: 15.000001
+ secondaryUVHardAngle: 88
+ secondaryUVMarginMethod: 1
+ secondaryUVMinLightmapResolution: 40
+ secondaryUVMinObjectScale: 1
+ secondaryUVPackMargin: 4
+ useFileScale: 1
+ strictVertexDataChecks: 0
+ tangentSpace:
+ normalSmoothAngle: 60
+ normalImportMode: 0
+ tangentImportMode: 0
+ normalCalculationMode: 4
+ legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
+ blendShapeNormalImportMode: 1
+ normalSmoothingSource: 0
+ referencedClips: []
+ importAnimation: 0
+ humanDescription:
+ serializedVersion: 3
+ human: []
+ skeleton: []
+ armTwist: 0.5
+ foreArmTwist: 0.5
+ upperLegTwist: 0.5
+ legTwist: 0.5
+ armStretch: 0.05
+ legStretch: 0.05
+ feetSpacing: 0
+ globalScale: 1
+ rootMotionBoneName:
+ hasTranslationDoF: 0
+ hasExtraRoot: 0
+ skeletonHasParents: 1
+ lastHumanDescriptionAvatarSource: {instanceID: 0}
+ autoGenerateAvatarMappingIfUnspecified: 1
+ animationType: 0
+ humanoidOversampling: 1
+ avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 1
+ importBlendShapeDeformPercent: 1
+ remapMaterialsIfMaterialImportModeIsNone: 0
+ additionalBone: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Buildings/bastion.export.json b/Assets/Luneraria/Art/Buildings/bastion.export.json
new file mode 100644
index 0000000..388c985
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/bastion.export.json
@@ -0,0 +1,602 @@
+{
+ "id": "bastion",
+ "group": "Buildings",
+ "source": "assets-source/luneraria/g2/bastion.blend",
+ "exporter_version": 5,
+ "blender": "5.2.2 LTS",
+ "fbx_settings": {
+ "use_selection": true,
+ "use_visible": false,
+ "use_active_collection": false,
+ "global_scale": 1.0,
+ "apply_unit_scale": true,
+ "apply_scale_options": "FBX_SCALE_UNITS",
+ "axis_forward": "Y",
+ "axis_up": "Z",
+ "bake_space_transform": false,
+ "object_types": [
+ "ARMATURE",
+ "EMPTY",
+ "MESH"
+ ],
+ "use_mesh_modifiers": true,
+ "use_mesh_modifiers_render": true,
+ "mesh_smooth_type": "OFF",
+ "use_subsurf": false,
+ "use_mesh_edges": false,
+ "use_tspace": true,
+ "use_triangles": false,
+ "colors_type": "LINEAR",
+ "prioritize_active_color": true,
+ "use_custom_props": false,
+ "add_leaf_bones": false,
+ "primary_bone_axis": "Y",
+ "secondary_bone_axis": "X",
+ "use_armature_deform_only": true,
+ "armature_nodetype": "NULL",
+ "bake_anim": true,
+ "bake_anim_use_all_bones": true,
+ "bake_anim_use_nla_strips": false,
+ "bake_anim_use_all_actions": true,
+ "bake_anim_force_startend_keying": true,
+ "bake_anim_step": 1.0,
+ "bake_anim_simplify_factor": 0.0,
+ "path_mode": "STRIP",
+ "embed_textures": false,
+ "batch_mode": "OFF"
+ },
+ "checks": [
+ {
+ "check": "turn_applied",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "units_metric",
+ "ok": true,
+ "detail": "METRIC"
+ },
+ {
+ "check": "unit_scale_1",
+ "ok": true,
+ "detail": "1.0"
+ },
+ {
+ "check": "no_negative_scale",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "object_scale_1",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "mesh_names_unique",
+ "ok": true,
+ "detail": "['Crystal', 'Debris', 'Lower', 'Pennant', 'Ring', 'Ruin', 'Shard_0', 'Shard_1', 'Shard_2', 'Upper', 'Upper_Damaged']"
+ },
+ {
+ "check": "material_slots_filled",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangent_prerequisites",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "no_blend_shapes",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "triangles_match_godot",
+ "ok": true,
+ "detail": "9364 fbx / 9364 godot"
+ },
+ {
+ "check": "mesh_names_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "materials_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_match_godot",
+ "ok": true,
+ "detail": "largest difference 0.00000 m"
+ },
+ {
+ "check": "no_armature",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_triangles",
+ "ok": true,
+ "detail": "9364 / 9364"
+ },
+ {
+ "check": "roundtrip_materials",
+ "ok": true,
+ "detail": "[]"
+ }
+ ],
+ "source_sha256": "5ac677fe95f3c65364fa4003b9cae694ad58734b157238f196f4d926de655d60",
+ "removed_modifiers": 0,
+ "kind": "static",
+ "fps": 30.0,
+ "objects": 11,
+ "meshes": {
+ "Lower": {
+ "mesh": "Lower",
+ "triangles": 658,
+ "vertices": 368,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Metal_Iron"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.7395,
+ 0.0,
+ -2.25
+ ],
+ "max": [
+ 1.7395,
+ 2.6655,
+ 1.6437
+ ]
+ }
+ },
+ "Upper": {
+ "mesh": "Upper",
+ "triangles": 3272,
+ "vertices": 1722,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Rune_Team",
+ "LN_Stone_Dark",
+ "LN_Metal_Iron",
+ "LN_Wood"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.5347,
+ 2.4409,
+ -1.5347
+ ],
+ "max": [
+ 1.5347,
+ 7.1605,
+ 1.5347
+ ]
+ }
+ },
+ "Upper_Damaged": {
+ "mesh": "Upper_Damaged",
+ "triangles": 2948,
+ "vertices": 1554,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Rune_Team",
+ "LN_Stone_Dark",
+ "LN_Metal_Iron",
+ "LN_Wood"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.5368,
+ 2.3209,
+ -1.5372
+ ],
+ "max": [
+ 1.4687,
+ 7.1605,
+ 1.5405
+ ]
+ }
+ },
+ "Debris": {
+ "mesh": "Debris",
+ "triangles": 316,
+ "vertices": 178,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale",
+ "LN_Metal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -2.1156,
+ -0.3891,
+ -1.7064
+ ],
+ "max": [
+ 1.8813,
+ 0.54,
+ 1.9496
+ ]
+ }
+ },
+ "Crystal": {
+ "mesh": "Crystal",
+ "triangles": 24,
+ "vertices": 14,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.4934,
+ 5.54,
+ -0.4411
+ ],
+ "max": [
+ 0.4885,
+ 7.06,
+ 0.409
+ ]
+ }
+ },
+ "Ring": {
+ "mesh": "Ring",
+ "triangles": 640,
+ "vertices": 320,
+ "ngons": 0,
+ "materials": [
+ "LN_Metal_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.865,
+ 6.15,
+ -0.865
+ ],
+ "max": [
+ 0.865,
+ 6.25,
+ 0.865
+ ]
+ }
+ },
+ "Shard_0": {
+ "mesh": "Shard_0",
+ "triangles": 20,
+ "vertices": 12,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.1308,
+ 6.17,
+ -0.106
+ ],
+ "max": [
+ -0.9277,
+ 6.61,
+ 0.1012
+ ]
+ }
+ },
+ "Shard_1": {
+ "mesh": "Shard_1",
+ "triangles": 20,
+ "vertices": 12,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.397,
+ 6.17,
+ 0.7782
+ ],
+ "max": [
+ 0.601,
+ 6.61,
+ 0.9923
+ ]
+ }
+ },
+ "Shard_2": {
+ "mesh": "Shard_2",
+ "triangles": 20,
+ "vertices": 12,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.3992,
+ 6.17,
+ -0.9903
+ ],
+ "max": [
+ 0.6009,
+ 6.61,
+ -0.779
+ ]
+ }
+ },
+ "Pennant": {
+ "mesh": "Pennant",
+ "triangles": 64,
+ "vertices": 45,
+ "ngons": 0,
+ "materials": [
+ "LN_Cloth_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.06,
+ 5.65,
+ -1.46
+ ],
+ "max": [
+ 0.76,
+ 6.8,
+ -1.46
+ ]
+ }
+ },
+ "Ruin": {
+ "mesh": "Ruin",
+ "triangles": 1382,
+ "vertices": 770,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -2.0369,
+ -0.3691,
+ -2.5389
+ ],
+ "max": [
+ 2.9008,
+ 2.6896,
+ 1.9476
+ ]
+ }
+ }
+ },
+ "armatures": {},
+ "empties": {},
+ "bounds_unity": {
+ "min": [
+ -2.1156,
+ -0.3891,
+ -2.5389
+ ],
+ "max": [
+ 2.9008,
+ 7.1605,
+ 1.9496
+ ]
+ },
+ "clips": [],
+ "expected_from_godot": {
+ "triangles": 9364,
+ "bounds_godot": {
+ "min": [
+ -1.7395,
+ 0.0,
+ -2.25
+ ],
+ "max": [
+ 1.7395,
+ 7.1605,
+ 1.6437
+ ]
+ },
+ "resource_path": "res://assets/luneraria/g2/bastion.glb"
+ },
+ "meshes_without_uv": [
+ "Crystal",
+ "Debris",
+ "Lower",
+ "Shard_0",
+ "Shard_1",
+ "Shard_2"
+ ],
+ "triangles": 9364,
+ "fbx": "Assets/Luneraria/Art/Buildings/bastion.fbx",
+ "fbx_bytes": 618812,
+ "ok": true
+}
diff --git a/Assets/Luneraria/Art/Buildings/bastion.export.json.meta b/Assets/Luneraria/Art/Buildings/bastion.export.json.meta
new file mode 100644
index 0000000..a2d3359
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/bastion.export.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: b6d3f51223b7f4f00b4ae9778a64127e
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Buildings/bastion.fbx b/Assets/Luneraria/Art/Buildings/bastion.fbx
new file mode 100644
index 0000000..4941c12
Binary files /dev/null and b/Assets/Luneraria/Art/Buildings/bastion.fbx differ
diff --git a/Assets/Luneraria/Art/Buildings/bastion.fbx.meta b/Assets/Luneraria/Art/Buildings/bastion.fbx.meta
new file mode 100644
index 0000000..aeb6f8d
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/bastion.fbx.meta
@@ -0,0 +1,111 @@
+fileFormatVersion: 2
+guid: 6633f0fd87c194e13a26c46c8a57a3a8
+ModelImporter:
+ serializedVersion: 24300
+ internalIDToNameTable: []
+ externalObjects: {}
+ materials:
+ materialImportMode: 2
+ materialName: 0
+ materialSearch: 1
+ materialLocation: 1
+ searchTexturesGlobally: 0
+ animations:
+ legacyGenerateAnimations: 4
+ bakeSimulation: 0
+ resampleCurves: 0
+ optimizeGameObjects: 0
+ removeConstantScaleCurves: 0
+ motionNodeName:
+ animationImportErrors:
+ animationImportWarnings:
+ animationRetargetingWarnings:
+ animationDoRetargetingWarnings: 0
+ importAnimatedCustomProperties: 0
+ importConstraints: 0
+ animationCompression: 0
+ animationRotationError: 0.5
+ animationPositionError: 0.5
+ animationScaleError: 0.5
+ animationWrapMode: 0
+ extraExposedTransformPaths: []
+ extraUserProperties: []
+ clipAnimations: []
+ isReadable: 1
+ meshes:
+ lODScreenPercentages: []
+ globalScale: 1
+ meshCompression: 0
+ addColliders: 0
+ useSRGBMaterialColor: 1
+ sortHierarchyByName: 1
+ importPhysicalCameras: 1
+ importVisibility: 0
+ importBlendShapes: 0
+ importCameras: 0
+ importLights: 0
+ nodeNameCollisionStrategy: 1
+ fileIdsGeneration: 2
+ swapUVChannels: 0
+ generateSecondaryUV: 0
+ useFileUnits: 1
+ keepQuads: 0
+ weldVertices: 1
+ bakeAxisConversion: 1
+ preserveHierarchy: 0
+ skinWeightsMode: 0
+ maxBonesPerVertex: 4
+ minBoneWeight: 0.001
+ optimizeBones: 1
+ generateMeshLods: 0
+ meshLodGenerationFlags: 0
+ maximumMeshLod: -1
+ meshOptimizationFlags: -1
+ indexFormat: 0
+ secondaryUVAngleDistortion: 8
+ secondaryUVAreaDistortion: 15.000001
+ secondaryUVHardAngle: 88
+ secondaryUVMarginMethod: 1
+ secondaryUVMinLightmapResolution: 40
+ secondaryUVMinObjectScale: 1
+ secondaryUVPackMargin: 4
+ useFileScale: 1
+ strictVertexDataChecks: 0
+ tangentSpace:
+ normalSmoothAngle: 60
+ normalImportMode: 0
+ tangentImportMode: 0
+ normalCalculationMode: 4
+ legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
+ blendShapeNormalImportMode: 1
+ normalSmoothingSource: 0
+ referencedClips: []
+ importAnimation: 0
+ humanDescription:
+ serializedVersion: 3
+ human: []
+ skeleton: []
+ armTwist: 0.5
+ foreArmTwist: 0.5
+ upperLegTwist: 0.5
+ legTwist: 0.5
+ armStretch: 0.05
+ legStretch: 0.05
+ feetSpacing: 0
+ globalScale: 1
+ rootMotionBoneName:
+ hasTranslationDoF: 0
+ hasExtraRoot: 0
+ skeletonHasParents: 1
+ lastHumanDescriptionAvatarSource: {instanceID: 0}
+ autoGenerateAvatarMappingIfUnspecified: 1
+ animationType: 0
+ humanoidOversampling: 1
+ avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 1
+ importBlendShapeDeformPercent: 1
+ remapMaterialsIfMaterialImportModeIsNone: 0
+ additionalBone: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Buildings/bossgrotte.export.json b/Assets/Luneraria/Art/Buildings/bossgrotte.export.json
new file mode 100644
index 0000000..35130eb
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/bossgrotte.export.json
@@ -0,0 +1,632 @@
+{
+ "id": "bossgrotte",
+ "group": "Buildings",
+ "source": "assets-source/luneraria/g2/bossgrotte.blend",
+ "exporter_version": 5,
+ "blender": "5.2.2 LTS",
+ "fbx_settings": {
+ "use_selection": true,
+ "use_visible": false,
+ "use_active_collection": false,
+ "global_scale": 1.0,
+ "apply_unit_scale": true,
+ "apply_scale_options": "FBX_SCALE_UNITS",
+ "axis_forward": "Y",
+ "axis_up": "Z",
+ "bake_space_transform": false,
+ "object_types": [
+ "ARMATURE",
+ "EMPTY",
+ "MESH"
+ ],
+ "use_mesh_modifiers": true,
+ "use_mesh_modifiers_render": true,
+ "mesh_smooth_type": "OFF",
+ "use_subsurf": false,
+ "use_mesh_edges": false,
+ "use_tspace": true,
+ "use_triangles": false,
+ "colors_type": "LINEAR",
+ "prioritize_active_color": true,
+ "use_custom_props": false,
+ "add_leaf_bones": false,
+ "primary_bone_axis": "Y",
+ "secondary_bone_axis": "X",
+ "use_armature_deform_only": true,
+ "armature_nodetype": "NULL",
+ "bake_anim": true,
+ "bake_anim_use_all_bones": true,
+ "bake_anim_use_nla_strips": false,
+ "bake_anim_use_all_actions": true,
+ "bake_anim_force_startend_keying": true,
+ "bake_anim_step": 1.0,
+ "bake_anim_simplify_factor": 0.0,
+ "path_mode": "STRIP",
+ "embed_textures": false,
+ "batch_mode": "OFF"
+ },
+ "checks": [
+ {
+ "check": "turn_applied",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "units_metric",
+ "ok": true,
+ "detail": "METRIC"
+ },
+ {
+ "check": "unit_scale_1",
+ "ok": true,
+ "detail": "1.0"
+ },
+ {
+ "check": "no_negative_scale",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "object_scale_1",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "mesh_names_unique",
+ "ok": true,
+ "detail": "['Altar', 'Cave', 'CaveGlow', 'Channel', 'Floor', 'Gate', 'PillarCrystals', 'Pillars', 'Platform', 'Rocks', 'Runes', 'Source']"
+ },
+ {
+ "check": "material_slots_filled",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangent_prerequisites",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "no_blend_shapes",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "triangles_match_godot",
+ "ok": true,
+ "detail": "15182 fbx / 15182 godot"
+ },
+ {
+ "check": "mesh_names_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "materials_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_match_godot",
+ "ok": true,
+ "detail": "largest difference 0.00000 m"
+ },
+ {
+ "check": "no_armature",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_triangles",
+ "ok": true,
+ "detail": "15182 / 15182"
+ },
+ {
+ "check": "roundtrip_materials",
+ "ok": true,
+ "detail": "[]"
+ }
+ ],
+ "source_sha256": "c3a87a8e7b0b8e0778ba7f9f274584e98e5c70a8229bc1cbee7ed9fd6aba7d9e",
+ "removed_modifiers": 0,
+ "kind": "static",
+ "fps": 30.0,
+ "objects": 12,
+ "meshes": {
+ "Floor": {
+ "mesh": "Floor",
+ "triangles": 2108,
+ "vertices": 1097,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Grotto"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -7.7775,
+ -0.4,
+ -7.7874
+ ],
+ "max": [
+ 7.7755,
+ 0.26,
+ 7.7976
+ ]
+ }
+ },
+ "Runes": {
+ "mesh": "Runes",
+ "triangles": 1164,
+ "vertices": 712,
+ "ngons": 0,
+ "materials": [
+ "LN_Rune_Grotto"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -4.72,
+ 0.104,
+ -7.9255
+ ],
+ "max": [
+ 7.9255,
+ 5.899,
+ 4.72
+ ]
+ }
+ },
+ "Platform": {
+ "mesh": "Platform",
+ "triangles": 808,
+ "vertices": 433,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Grotto"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.8,
+ -0.02,
+ -3.8
+ ],
+ "max": [
+ 3.8,
+ 0.125,
+ 0.8
+ ]
+ }
+ },
+ "Altar": {
+ "mesh": "Altar",
+ "triangles": 552,
+ "vertices": 280,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Grotto"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 1.7789,
+ -0.05,
+ -4.4738
+ ],
+ "max": [
+ 4.4738,
+ 3.45,
+ -1.7789
+ ]
+ }
+ },
+ "Source": {
+ "mesh": "Source",
+ "triangles": 192,
+ "vertices": 112,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Grotto"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 2.64,
+ 0.5,
+ -3.4746
+ ],
+ "max": [
+ 3.6064,
+ 2.7,
+ -2.7716
+ ]
+ }
+ },
+ "Gate": {
+ "mesh": "Gate",
+ "triangles": 3944,
+ "vertices": 2016,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Grotto",
+ "LN_Metal_Bronze"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 3.2222,
+ -0.5,
+ -9.435
+ ],
+ "max": [
+ 9.435,
+ 7.499,
+ -3.2222
+ ]
+ }
+ },
+ "Cave": {
+ "mesh": "Cave",
+ "triangles": 424,
+ "vertices": 232,
+ "ngons": 0,
+ "materials": [
+ "LN_Cave",
+ "LN_Stone_Dark"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 4.575,
+ -1.93,
+ -10.0692
+ ],
+ "max": [
+ 10.0692,
+ 3.7,
+ -4.575
+ ]
+ }
+ },
+ "CaveGlow": {
+ "mesh": "CaveGlow",
+ "triangles": 182,
+ "vertices": 117,
+ "ngons": 0,
+ "materials": [
+ "LN_Water_Glow",
+ "LN_Crystal_Grotto"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 5.1204,
+ -0.97,
+ -9.4328
+ ],
+ "max": [
+ 9.5452,
+ 2.7,
+ -5.4993
+ ]
+ }
+ },
+ "Channel": {
+ "mesh": "Channel",
+ "triangles": 600,
+ "vertices": 304,
+ "ngons": 0,
+ "materials": [
+ "LN_Water_Glow"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3712,
+ 0.26,
+ -7.0092
+ ],
+ "max": [
+ 7.0092,
+ 0.28,
+ 0.3712
+ ]
+ }
+ },
+ "Pillars": {
+ "mesh": "Pillars",
+ "triangles": 4328,
+ "vertices": 2280,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Grotto"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -7.7579,
+ -0.05,
+ -7.5321
+ ],
+ "max": [
+ 7.5454,
+ 5.961,
+ 7.7587
+ ]
+ }
+ },
+ "PillarCrystals": {
+ "mesh": "PillarCrystals",
+ "triangles": 80,
+ "vertices": 48,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Grotto"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -6.4468,
+ 5.23,
+ -7.0317
+ ],
+ "max": [
+ 7.014,
+ 6.03,
+ 6.441
+ ]
+ }
+ },
+ "Rocks": {
+ "mesh": "Rocks",
+ "triangles": 800,
+ "vertices": 420,
+ "ngons": 0,
+ "materials": [
+ "LN_Rock"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -2.9737,
+ -0.6391,
+ -10.4646
+ ],
+ "max": [
+ 10.5442,
+ 7.6927,
+ 2.8772
+ ]
+ }
+ }
+ },
+ "armatures": {},
+ "empties": {},
+ "bounds_unity": {
+ "min": [
+ -7.7775,
+ -1.93,
+ -10.4646
+ ],
+ "max": [
+ 10.5442,
+ 7.6927,
+ 7.7976
+ ]
+ },
+ "clips": [],
+ "expected_from_godot": {
+ "triangles": 15182,
+ "bounds_godot": {
+ "min": [
+ -10.5442,
+ -1.93,
+ -10.4646
+ ],
+ "max": [
+ 7.7775,
+ 7.6927,
+ 7.7976
+ ]
+ },
+ "resource_path": "res://assets/luneraria/g2/bossgrotte.glb"
+ },
+ "meshes_without_uv": [
+ "Cave",
+ "PillarCrystals",
+ "Rocks",
+ "Source"
+ ],
+ "triangles": 15182,
+ "fbx": "Assets/Luneraria/Art/Buildings/bossgrotte.fbx",
+ "fbx_bytes": 989708,
+ "ok": true
+}
diff --git a/Assets/Luneraria/Art/Buildings/bossgrotte.export.json.meta b/Assets/Luneraria/Art/Buildings/bossgrotte.export.json.meta
new file mode 100644
index 0000000..61966bd
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/bossgrotte.export.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: b3c1a5924044546adb0dba298c3ddc35
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Buildings/bossgrotte.fbx b/Assets/Luneraria/Art/Buildings/bossgrotte.fbx
new file mode 100644
index 0000000..7e25661
Binary files /dev/null and b/Assets/Luneraria/Art/Buildings/bossgrotte.fbx differ
diff --git a/Assets/Luneraria/Art/Buildings/bossgrotte.fbx.meta b/Assets/Luneraria/Art/Buildings/bossgrotte.fbx.meta
new file mode 100644
index 0000000..439db90
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/bossgrotte.fbx.meta
@@ -0,0 +1,111 @@
+fileFormatVersion: 2
+guid: 39a4b40e68ab84129824e427365b5868
+ModelImporter:
+ serializedVersion: 24300
+ internalIDToNameTable: []
+ externalObjects: {}
+ materials:
+ materialImportMode: 2
+ materialName: 0
+ materialSearch: 1
+ materialLocation: 1
+ searchTexturesGlobally: 0
+ animations:
+ legacyGenerateAnimations: 4
+ bakeSimulation: 0
+ resampleCurves: 0
+ optimizeGameObjects: 0
+ removeConstantScaleCurves: 0
+ motionNodeName:
+ animationImportErrors:
+ animationImportWarnings:
+ animationRetargetingWarnings:
+ animationDoRetargetingWarnings: 0
+ importAnimatedCustomProperties: 0
+ importConstraints: 0
+ animationCompression: 0
+ animationRotationError: 0.5
+ animationPositionError: 0.5
+ animationScaleError: 0.5
+ animationWrapMode: 0
+ extraExposedTransformPaths: []
+ extraUserProperties: []
+ clipAnimations: []
+ isReadable: 1
+ meshes:
+ lODScreenPercentages: []
+ globalScale: 1
+ meshCompression: 0
+ addColliders: 0
+ useSRGBMaterialColor: 1
+ sortHierarchyByName: 1
+ importPhysicalCameras: 1
+ importVisibility: 0
+ importBlendShapes: 0
+ importCameras: 0
+ importLights: 0
+ nodeNameCollisionStrategy: 1
+ fileIdsGeneration: 2
+ swapUVChannels: 0
+ generateSecondaryUV: 0
+ useFileUnits: 1
+ keepQuads: 0
+ weldVertices: 1
+ bakeAxisConversion: 1
+ preserveHierarchy: 0
+ skinWeightsMode: 0
+ maxBonesPerVertex: 4
+ minBoneWeight: 0.001
+ optimizeBones: 1
+ generateMeshLods: 0
+ meshLodGenerationFlags: 0
+ maximumMeshLod: -1
+ meshOptimizationFlags: -1
+ indexFormat: 0
+ secondaryUVAngleDistortion: 8
+ secondaryUVAreaDistortion: 15.000001
+ secondaryUVHardAngle: 88
+ secondaryUVMarginMethod: 1
+ secondaryUVMinLightmapResolution: 40
+ secondaryUVMinObjectScale: 1
+ secondaryUVPackMargin: 4
+ useFileScale: 1
+ strictVertexDataChecks: 0
+ tangentSpace:
+ normalSmoothAngle: 60
+ normalImportMode: 0
+ tangentImportMode: 0
+ normalCalculationMode: 4
+ legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
+ blendShapeNormalImportMode: 1
+ normalSmoothingSource: 0
+ referencedClips: []
+ importAnimation: 0
+ humanDescription:
+ serializedVersion: 3
+ human: []
+ skeleton: []
+ armTwist: 0.5
+ foreArmTwist: 0.5
+ upperLegTwist: 0.5
+ legTwist: 0.5
+ armStretch: 0.05
+ legStretch: 0.05
+ feetSpacing: 0
+ globalScale: 1
+ rootMotionBoneName:
+ hasTranslationDoF: 0
+ hasExtraRoot: 0
+ skeletonHasParents: 1
+ lastHumanDescriptionAvatarSource: {instanceID: 0}
+ autoGenerateAvatarMappingIfUnspecified: 1
+ animationType: 0
+ humanoidOversampling: 1
+ avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 1
+ importBlendShapeDeformPercent: 1
+ remapMaterialsIfMaterialImportModeIsNone: 0
+ additionalBone: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Buildings/grenzwacht.export.json b/Assets/Luneraria/Art/Buildings/grenzwacht.export.json
new file mode 100644
index 0000000..38a1175
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/grenzwacht.export.json
@@ -0,0 +1,456 @@
+{
+ "id": "grenzwacht",
+ "group": "Buildings",
+ "source": "assets-source/luneraria/g2/grenzwacht.blend",
+ "exporter_version": 5,
+ "blender": "5.2.2 LTS",
+ "fbx_settings": {
+ "use_selection": true,
+ "use_visible": false,
+ "use_active_collection": false,
+ "global_scale": 1.0,
+ "apply_unit_scale": true,
+ "apply_scale_options": "FBX_SCALE_UNITS",
+ "axis_forward": "Y",
+ "axis_up": "Z",
+ "bake_space_transform": false,
+ "object_types": [
+ "ARMATURE",
+ "EMPTY",
+ "MESH"
+ ],
+ "use_mesh_modifiers": true,
+ "use_mesh_modifiers_render": true,
+ "mesh_smooth_type": "OFF",
+ "use_subsurf": false,
+ "use_mesh_edges": false,
+ "use_tspace": true,
+ "use_triangles": false,
+ "colors_type": "LINEAR",
+ "prioritize_active_color": true,
+ "use_custom_props": false,
+ "add_leaf_bones": false,
+ "primary_bone_axis": "Y",
+ "secondary_bone_axis": "X",
+ "use_armature_deform_only": true,
+ "armature_nodetype": "NULL",
+ "bake_anim": true,
+ "bake_anim_use_all_bones": true,
+ "bake_anim_use_nla_strips": false,
+ "bake_anim_use_all_actions": true,
+ "bake_anim_force_startend_keying": true,
+ "bake_anim_step": 1.0,
+ "bake_anim_simplify_factor": 0.0,
+ "path_mode": "STRIP",
+ "embed_textures": false,
+ "batch_mode": "OFF"
+ },
+ "checks": [
+ {
+ "check": "turn_applied",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "units_metric",
+ "ok": true,
+ "detail": "METRIC"
+ },
+ {
+ "check": "unit_scale_1",
+ "ok": true,
+ "detail": "1.0"
+ },
+ {
+ "check": "no_negative_scale",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "object_scale_1",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "mesh_names_unique",
+ "ok": true,
+ "detail": "['Crystal', 'Debris', 'Lower', 'Pennant', 'Ruin', 'Upper', 'Upper_Damaged']"
+ },
+ {
+ "check": "material_slots_filled",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangent_prerequisites",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "no_blend_shapes",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "triangles_match_godot",
+ "ok": true,
+ "detail": "6516 fbx / 6516 godot"
+ },
+ {
+ "check": "mesh_names_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "materials_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_match_godot",
+ "ok": true,
+ "detail": "largest difference 0.00000 m"
+ },
+ {
+ "check": "no_armature",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_triangles",
+ "ok": true,
+ "detail": "6516 / 6516"
+ },
+ {
+ "check": "roundtrip_materials",
+ "ok": true,
+ "detail": "[]"
+ }
+ ],
+ "source_sha256": "7067f4f3349918e412a3ee684651753bbb3ee958a46dd3775af6b93661d7e96f",
+ "removed_modifiers": 0,
+ "kind": "static",
+ "fps": 30.0,
+ "objects": 7,
+ "meshes": {
+ "Lower": {
+ "mesh": "Lower",
+ "triangles": 550,
+ "vertices": 296,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Pale",
+ "LN_Wood"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.3752,
+ 0.0,
+ -1.3735
+ ],
+ "max": [
+ 1.3717,
+ 2.3142,
+ 1.3678
+ ]
+ }
+ },
+ "Upper": {
+ "mesh": "Upper",
+ "triangles": 2536,
+ "vertices": 1336,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Rune_Team",
+ "LN_Stone_Dark",
+ "LN_Metal_Iron",
+ "LN_Wood"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.1568,
+ 2.18,
+ -1.1568
+ ],
+ "max": [
+ 1.1568,
+ 6.0601,
+ 1.1568
+ ]
+ }
+ },
+ "Upper_Damaged": {
+ "mesh": "Upper_Damaged",
+ "triangles": 2164,
+ "vertices": 1136,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Rune_Team",
+ "LN_Stone_Dark",
+ "LN_Wood",
+ "LN_Metal_Iron"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.1568,
+ 2.18,
+ -1.1569
+ ],
+ "max": [
+ 1.1606,
+ 6.0601,
+ 1.1364
+ ]
+ }
+ },
+ "Debris": {
+ "mesh": "Debris",
+ "triangles": 140,
+ "vertices": 84,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.0393,
+ -0.0358,
+ -1.4479
+ ],
+ "max": [
+ 1.8685,
+ 0.2255,
+ 0.2742
+ ]
+ }
+ },
+ "Crystal": {
+ "mesh": "Crystal",
+ "triangles": 24,
+ "vertices": 14,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3468,
+ 4.7,
+ -0.3102
+ ],
+ "max": [
+ 0.345,
+ 5.84,
+ 0.3126
+ ]
+ }
+ },
+ "Pennant": {
+ "mesh": "Pennant",
+ "triangles": 64,
+ "vertices": 45,
+ "ngons": 0,
+ "materials": [
+ "LN_Cloth_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.06,
+ 4.72,
+ -1.02
+ ],
+ "max": [
+ 0.68,
+ 5.72,
+ -1.02
+ ]
+ }
+ },
+ "Ruin": {
+ "mesh": "Ruin",
+ "triangles": 1038,
+ "vertices": 580,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Pale",
+ "LN_Metal_Team",
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -2.2575,
+ -0.0653,
+ -2.5526
+ ],
+ "max": [
+ 1.9658,
+ 1.7462,
+ 1.3683
+ ]
+ }
+ }
+ },
+ "armatures": {},
+ "empties": {},
+ "bounds_unity": {
+ "min": [
+ -2.2575,
+ -0.0653,
+ -2.5526
+ ],
+ "max": [
+ 1.9658,
+ 6.0601,
+ 1.3683
+ ]
+ },
+ "clips": [],
+ "expected_from_godot": {
+ "triangles": 6516,
+ "bounds_godot": {
+ "min": [
+ -1.3717,
+ 0.0,
+ -1.3735
+ ],
+ "max": [
+ 1.3752,
+ 6.0601,
+ 1.3678
+ ]
+ },
+ "resource_path": "res://assets/luneraria/g2/grenzwacht.glb"
+ },
+ "meshes_without_uv": [
+ "Crystal",
+ "Debris"
+ ],
+ "triangles": 6516,
+ "fbx": "Assets/Luneraria/Art/Buildings/grenzwacht.fbx",
+ "fbx_bytes": 457404,
+ "ok": true
+}
diff --git a/Assets/Luneraria/Art/Buildings/grenzwacht.export.json.meta b/Assets/Luneraria/Art/Buildings/grenzwacht.export.json.meta
new file mode 100644
index 0000000..9e34c26
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/grenzwacht.export.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 81cb37d5386d048999e1ca915d0cb88d
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Buildings/grenzwacht.fbx b/Assets/Luneraria/Art/Buildings/grenzwacht.fbx
new file mode 100644
index 0000000..28f4d9e
Binary files /dev/null and b/Assets/Luneraria/Art/Buildings/grenzwacht.fbx differ
diff --git a/Assets/Luneraria/Art/Buildings/grenzwacht.fbx.meta b/Assets/Luneraria/Art/Buildings/grenzwacht.fbx.meta
new file mode 100644
index 0000000..41b7961
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/grenzwacht.fbx.meta
@@ -0,0 +1,111 @@
+fileFormatVersion: 2
+guid: 5b76880584cb448b5b6c8a5f93db8b54
+ModelImporter:
+ serializedVersion: 24300
+ internalIDToNameTable: []
+ externalObjects: {}
+ materials:
+ materialImportMode: 2
+ materialName: 0
+ materialSearch: 1
+ materialLocation: 1
+ searchTexturesGlobally: 0
+ animations:
+ legacyGenerateAnimations: 4
+ bakeSimulation: 0
+ resampleCurves: 0
+ optimizeGameObjects: 0
+ removeConstantScaleCurves: 0
+ motionNodeName:
+ animationImportErrors:
+ animationImportWarnings:
+ animationRetargetingWarnings:
+ animationDoRetargetingWarnings: 0
+ importAnimatedCustomProperties: 0
+ importConstraints: 0
+ animationCompression: 0
+ animationRotationError: 0.5
+ animationPositionError: 0.5
+ animationScaleError: 0.5
+ animationWrapMode: 0
+ extraExposedTransformPaths: []
+ extraUserProperties: []
+ clipAnimations: []
+ isReadable: 1
+ meshes:
+ lODScreenPercentages: []
+ globalScale: 1
+ meshCompression: 0
+ addColliders: 0
+ useSRGBMaterialColor: 1
+ sortHierarchyByName: 1
+ importPhysicalCameras: 1
+ importVisibility: 0
+ importBlendShapes: 0
+ importCameras: 0
+ importLights: 0
+ nodeNameCollisionStrategy: 1
+ fileIdsGeneration: 2
+ swapUVChannels: 0
+ generateSecondaryUV: 0
+ useFileUnits: 1
+ keepQuads: 0
+ weldVertices: 1
+ bakeAxisConversion: 1
+ preserveHierarchy: 0
+ skinWeightsMode: 0
+ maxBonesPerVertex: 4
+ minBoneWeight: 0.001
+ optimizeBones: 1
+ generateMeshLods: 0
+ meshLodGenerationFlags: 0
+ maximumMeshLod: -1
+ meshOptimizationFlags: -1
+ indexFormat: 0
+ secondaryUVAngleDistortion: 8
+ secondaryUVAreaDistortion: 15.000001
+ secondaryUVHardAngle: 88
+ secondaryUVMarginMethod: 1
+ secondaryUVMinLightmapResolution: 40
+ secondaryUVMinObjectScale: 1
+ secondaryUVPackMargin: 4
+ useFileScale: 1
+ strictVertexDataChecks: 0
+ tangentSpace:
+ normalSmoothAngle: 60
+ normalImportMode: 0
+ tangentImportMode: 0
+ normalCalculationMode: 4
+ legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
+ blendShapeNormalImportMode: 1
+ normalSmoothingSource: 0
+ referencedClips: []
+ importAnimation: 0
+ humanDescription:
+ serializedVersion: 3
+ human: []
+ skeleton: []
+ armTwist: 0.5
+ foreArmTwist: 0.5
+ upperLegTwist: 0.5
+ legTwist: 0.5
+ armStretch: 0.05
+ legStretch: 0.05
+ feetSpacing: 0
+ globalScale: 1
+ rootMotionBoneName:
+ hasTranslationDoF: 0
+ hasExtraRoot: 0
+ skeletonHasParents: 1
+ lastHumanDescriptionAvatarSource: {instanceID: 0}
+ autoGenerateAvatarMappingIfUnspecified: 1
+ animationType: 0
+ humanoidOversampling: 1
+ avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 1
+ importBlendShapeDeformPercent: 1
+ remapMaterialsIfMaterialImportModeIsNone: 0
+ additionalBone: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Buildings/kernwacht.export.json b/Assets/Luneraria/Art/Buildings/kernwacht.export.json
new file mode 100644
index 0000000..e094fb2
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/kernwacht.export.json
@@ -0,0 +1,526 @@
+{
+ "id": "kernwacht",
+ "group": "Buildings",
+ "source": "assets-source/luneraria/g2/kernwacht.blend",
+ "exporter_version": 5,
+ "blender": "5.2.2 LTS",
+ "fbx_settings": {
+ "use_selection": true,
+ "use_visible": false,
+ "use_active_collection": false,
+ "global_scale": 1.0,
+ "apply_unit_scale": true,
+ "apply_scale_options": "FBX_SCALE_UNITS",
+ "axis_forward": "Y",
+ "axis_up": "Z",
+ "bake_space_transform": false,
+ "object_types": [
+ "ARMATURE",
+ "EMPTY",
+ "MESH"
+ ],
+ "use_mesh_modifiers": true,
+ "use_mesh_modifiers_render": true,
+ "mesh_smooth_type": "OFF",
+ "use_subsurf": false,
+ "use_mesh_edges": false,
+ "use_tspace": true,
+ "use_triangles": false,
+ "colors_type": "LINEAR",
+ "prioritize_active_color": true,
+ "use_custom_props": false,
+ "add_leaf_bones": false,
+ "primary_bone_axis": "Y",
+ "secondary_bone_axis": "X",
+ "use_armature_deform_only": true,
+ "armature_nodetype": "NULL",
+ "bake_anim": true,
+ "bake_anim_use_all_bones": true,
+ "bake_anim_use_nla_strips": false,
+ "bake_anim_use_all_actions": true,
+ "bake_anim_force_startend_keying": true,
+ "bake_anim_step": 1.0,
+ "bake_anim_simplify_factor": 0.0,
+ "path_mode": "STRIP",
+ "embed_textures": false,
+ "batch_mode": "OFF"
+ },
+ "checks": [
+ {
+ "check": "turn_applied",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "units_metric",
+ "ok": true,
+ "detail": "METRIC"
+ },
+ {
+ "check": "unit_scale_1",
+ "ok": true,
+ "detail": "1.0"
+ },
+ {
+ "check": "no_negative_scale",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "object_scale_1",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "mesh_names_unique",
+ "ok": true,
+ "detail": "['Banner_L', 'Banner_R', 'Crystal', 'Debris', 'Lower', 'Ring', 'Ruin', 'Upper', 'Upper_Damaged']"
+ },
+ {
+ "check": "material_slots_filled",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangent_prerequisites",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "no_blend_shapes",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "triangles_match_godot",
+ "ok": true,
+ "detail": "9224 fbx / 9224 godot"
+ },
+ {
+ "check": "mesh_names_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "materials_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_match_godot",
+ "ok": true,
+ "detail": "largest difference 0.00000 m"
+ },
+ {
+ "check": "no_armature",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_triangles",
+ "ok": true,
+ "detail": "9224 / 9224"
+ },
+ {
+ "check": "roundtrip_materials",
+ "ok": true,
+ "detail": "[]"
+ }
+ ],
+ "source_sha256": "2797f6f7b705a99333dbfdfce029a2f4894a74d2fb7939eb108ab2eaf7edd09e",
+ "removed_modifiers": 0,
+ "kind": "static",
+ "fps": 30.0,
+ "objects": 9,
+ "meshes": {
+ "Lower": {
+ "mesh": "Lower",
+ "triangles": 548,
+ "vertices": 304,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Pale",
+ "LN_Rune_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.8139,
+ 0.0,
+ -1.8017
+ ],
+ "max": [
+ 1.8045,
+ 2.76,
+ 1.806
+ ]
+ }
+ },
+ "Upper": {
+ "mesh": "Upper",
+ "triangles": 3280,
+ "vertices": 1660,
+ "ngons": 0,
+ "materials": [
+ "LN_Metal_Team",
+ "LN_Crystal_Team",
+ "LN_Stone_Pale",
+ "LN_Metal_Iron"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.6442,
+ 2.5345,
+ -1.0915
+ ],
+ "max": [
+ 1.6442,
+ 8.33,
+ 1.734
+ ]
+ }
+ },
+ "Upper_Damaged": {
+ "mesh": "Upper_Damaged",
+ "triangles": 3280,
+ "vertices": 1660,
+ "ngons": 0,
+ "materials": [
+ "LN_Metal_Team",
+ "LN_Crystal_Team",
+ "LN_Stone_Pale",
+ "LN_Metal_Iron"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.6442,
+ 2.5345,
+ -1.0915
+ ],
+ "max": [
+ 1.6442,
+ 8.33,
+ 1.734
+ ]
+ }
+ },
+ "Debris": {
+ "mesh": "Debris",
+ "triangles": 160,
+ "vertices": 96,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Pale"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -2.1991,
+ -0.0421,
+ -1.8567
+ ],
+ "max": [
+ 1.8296,
+ 0.2606,
+ 0.2916
+ ]
+ }
+ },
+ "Crystal": {
+ "mesh": "Crystal",
+ "triangles": 24,
+ "vertices": 14,
+ "ngons": 0,
+ "materials": [
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.5554,
+ 4.51,
+ -0.4884
+ ],
+ "max": [
+ 0.5682,
+ 6.25,
+ 0.5124
+ ]
+ }
+ },
+ "Ring": {
+ "mesh": "Ring",
+ "triangles": 640,
+ "vertices": 320,
+ "ngons": 0,
+ "materials": [
+ "LN_Metal_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.03,
+ 5.195,
+ -1.03
+ ],
+ "max": [
+ 1.03,
+ 5.305,
+ 1.03
+ ]
+ }
+ },
+ "Banner_L": {
+ "mesh": "Banner_L",
+ "triangles": 80,
+ "vertices": 55,
+ "ngons": 0,
+ "materials": [
+ "LN_Cloth_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 1.5597,
+ 3.9,
+ -1.2585
+ ],
+ "max": [
+ 1.8697,
+ 5.5,
+ -0.7215
+ ]
+ }
+ },
+ "Banner_R": {
+ "mesh": "Banner_R",
+ "triangles": 80,
+ "vertices": 55,
+ "ngons": 0,
+ "materials": [
+ "LN_Cloth_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.8697,
+ 3.9,
+ -1.2585
+ ],
+ "max": [
+ -1.5597,
+ 5.5,
+ -0.7215
+ ]
+ }
+ },
+ "Ruin": {
+ "mesh": "Ruin",
+ "triangles": 1132,
+ "vertices": 632,
+ "ngons": 0,
+ "materials": [
+ "LN_Stone_Dark",
+ "LN_Stone_Pale",
+ "LN_Rune_Team",
+ "LN_Crystal_Team"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -6.0762,
+ -2.3959,
+ -2.1939
+ ],
+ "max": [
+ 2.3962,
+ 2.0939,
+ 1.8126
+ ]
+ }
+ }
+ },
+ "armatures": {},
+ "empties": {},
+ "bounds_unity": {
+ "min": [
+ -6.0762,
+ -2.3959,
+ -2.1939
+ ],
+ "max": [
+ 2.3962,
+ 8.33,
+ 1.8126
+ ]
+ },
+ "clips": [],
+ "expected_from_godot": {
+ "triangles": 9224,
+ "bounds_godot": {
+ "min": [
+ -1.8045,
+ 0.0,
+ -1.8017
+ ],
+ "max": [
+ 1.8139,
+ 8.33,
+ 1.806
+ ]
+ },
+ "resource_path": "res://assets/luneraria/g2/kernwacht.glb"
+ },
+ "meshes_without_uv": [
+ "Crystal",
+ "Debris"
+ ],
+ "triangles": 9224,
+ "fbx": "Assets/Luneraria/Art/Buildings/kernwacht.fbx",
+ "fbx_bytes": 732684,
+ "ok": true
+}
diff --git a/Assets/Luneraria/Art/Buildings/kernwacht.export.json.meta b/Assets/Luneraria/Art/Buildings/kernwacht.export.json.meta
new file mode 100644
index 0000000..9a2f870
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/kernwacht.export.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5dc29c90a350446e480591bab7513b23
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Buildings/kernwacht.fbx b/Assets/Luneraria/Art/Buildings/kernwacht.fbx
new file mode 100644
index 0000000..b828974
Binary files /dev/null and b/Assets/Luneraria/Art/Buildings/kernwacht.fbx differ
diff --git a/Assets/Luneraria/Art/Buildings/kernwacht.fbx.meta b/Assets/Luneraria/Art/Buildings/kernwacht.fbx.meta
new file mode 100644
index 0000000..0b512b7
--- /dev/null
+++ b/Assets/Luneraria/Art/Buildings/kernwacht.fbx.meta
@@ -0,0 +1,111 @@
+fileFormatVersion: 2
+guid: 2d354ddf8728c467da524d4c540efccd
+ModelImporter:
+ serializedVersion: 24300
+ internalIDToNameTable: []
+ externalObjects: {}
+ materials:
+ materialImportMode: 2
+ materialName: 0
+ materialSearch: 1
+ materialLocation: 1
+ searchTexturesGlobally: 0
+ animations:
+ legacyGenerateAnimations: 4
+ bakeSimulation: 0
+ resampleCurves: 0
+ optimizeGameObjects: 0
+ removeConstantScaleCurves: 0
+ motionNodeName:
+ animationImportErrors:
+ animationImportWarnings:
+ animationRetargetingWarnings:
+ animationDoRetargetingWarnings: 0
+ importAnimatedCustomProperties: 0
+ importConstraints: 0
+ animationCompression: 0
+ animationRotationError: 0.5
+ animationPositionError: 0.5
+ animationScaleError: 0.5
+ animationWrapMode: 0
+ extraExposedTransformPaths: []
+ extraUserProperties: []
+ clipAnimations: []
+ isReadable: 1
+ meshes:
+ lODScreenPercentages: []
+ globalScale: 1
+ meshCompression: 0
+ addColliders: 0
+ useSRGBMaterialColor: 1
+ sortHierarchyByName: 1
+ importPhysicalCameras: 1
+ importVisibility: 0
+ importBlendShapes: 0
+ importCameras: 0
+ importLights: 0
+ nodeNameCollisionStrategy: 1
+ fileIdsGeneration: 2
+ swapUVChannels: 0
+ generateSecondaryUV: 0
+ useFileUnits: 1
+ keepQuads: 0
+ weldVertices: 1
+ bakeAxisConversion: 1
+ preserveHierarchy: 0
+ skinWeightsMode: 0
+ maxBonesPerVertex: 4
+ minBoneWeight: 0.001
+ optimizeBones: 1
+ generateMeshLods: 0
+ meshLodGenerationFlags: 0
+ maximumMeshLod: -1
+ meshOptimizationFlags: -1
+ indexFormat: 0
+ secondaryUVAngleDistortion: 8
+ secondaryUVAreaDistortion: 15.000001
+ secondaryUVHardAngle: 88
+ secondaryUVMarginMethod: 1
+ secondaryUVMinLightmapResolution: 40
+ secondaryUVMinObjectScale: 1
+ secondaryUVPackMargin: 4
+ useFileScale: 1
+ strictVertexDataChecks: 0
+ tangentSpace:
+ normalSmoothAngle: 60
+ normalImportMode: 0
+ tangentImportMode: 0
+ normalCalculationMode: 4
+ legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
+ blendShapeNormalImportMode: 1
+ normalSmoothingSource: 0
+ referencedClips: []
+ importAnimation: 0
+ humanDescription:
+ serializedVersion: 3
+ human: []
+ skeleton: []
+ armTwist: 0.5
+ foreArmTwist: 0.5
+ upperLegTwist: 0.5
+ legTwist: 0.5
+ armStretch: 0.05
+ legStretch: 0.05
+ feetSpacing: 0
+ globalScale: 1
+ rootMotionBoneName:
+ hasTranslationDoF: 0
+ hasExtraRoot: 0
+ skeletonHasParents: 1
+ lastHumanDescriptionAvatarSource: {instanceID: 0}
+ autoGenerateAvatarMappingIfUnspecified: 1
+ animationType: 0
+ humanoidOversampling: 1
+ avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 1
+ importBlendShapeDeformPercent: 1
+ remapMaterialsIfMaterialImportModeIsNone: 0
+ additionalBone: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Characters.meta b/Assets/Luneraria/Art/Characters.meta
new file mode 100644
index 0000000..4297995
--- /dev/null
+++ b/Assets/Luneraria/Art/Characters.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: f870578f70b3a45ccbfa68cceccd2579
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Characters/funkenlanze.export.json b/Assets/Luneraria/Art/Characters/funkenlanze.export.json
new file mode 100644
index 0000000..c757004
--- /dev/null
+++ b/Assets/Luneraria/Art/Characters/funkenlanze.export.json
@@ -0,0 +1,405 @@
+{
+ "id": "funkenlanze",
+ "group": "Characters",
+ "source": "assets-source/phase18/funkenlanze.blend",
+ "exporter_version": 5,
+ "blender": "5.2.2 LTS",
+ "fbx_settings": {
+ "use_selection": true,
+ "use_visible": false,
+ "use_active_collection": false,
+ "global_scale": 1.0,
+ "apply_unit_scale": true,
+ "apply_scale_options": "FBX_SCALE_UNITS",
+ "axis_forward": "Y",
+ "axis_up": "Z",
+ "bake_space_transform": false,
+ "object_types": [
+ "ARMATURE",
+ "EMPTY",
+ "MESH"
+ ],
+ "use_mesh_modifiers": true,
+ "use_mesh_modifiers_render": true,
+ "mesh_smooth_type": "OFF",
+ "use_subsurf": false,
+ "use_mesh_edges": false,
+ "use_tspace": true,
+ "use_triangles": false,
+ "colors_type": "LINEAR",
+ "prioritize_active_color": true,
+ "use_custom_props": false,
+ "add_leaf_bones": false,
+ "primary_bone_axis": "Y",
+ "secondary_bone_axis": "X",
+ "use_armature_deform_only": true,
+ "armature_nodetype": "NULL",
+ "bake_anim": true,
+ "bake_anim_use_all_bones": true,
+ "bake_anim_use_nla_strips": false,
+ "bake_anim_use_all_actions": true,
+ "bake_anim_force_startend_keying": true,
+ "bake_anim_step": 1.0,
+ "bake_anim_simplify_factor": 0.0,
+ "path_mode": "STRIP",
+ "embed_textures": false,
+ "batch_mode": "OFF"
+ },
+ "checks": [
+ {
+ "check": "turn_applied",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "units_metric",
+ "ok": true,
+ "detail": "METRIC"
+ },
+ {
+ "check": "unit_scale_1",
+ "ok": true,
+ "detail": "1.0"
+ },
+ {
+ "check": "no_negative_scale",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "object_scale_1",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "mesh_names_unique",
+ "ok": true,
+ "detail": "['FunkenBody']"
+ },
+ {
+ "check": "material_slots_filled",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangent_prerequisites",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "no_blend_shapes",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "triangles_match_godot",
+ "ok": true,
+ "detail": "24036 fbx / 24036 godot"
+ },
+ {
+ "check": "mesh_names_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_match_godot",
+ "ok": true,
+ "detail": "largest difference 0.00005 m"
+ },
+ {
+ "check": "one_armature",
+ "ok": true,
+ "detail": "['FunkenRig']"
+ },
+ {
+ "check": "single_root_bone",
+ "ok": true,
+ "detail": "['Root']"
+ },
+ {
+ "check": "root_bone_name",
+ "ok": true,
+ "detail": "['Root']"
+ },
+ {
+ "check": "bone_count_match_godot",
+ "ok": true,
+ "detail": "26 / 26"
+ },
+ {
+ "check": "bone_names_portable",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "skinned_meshes_present",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "clips_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "required_clips_present",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_triangles",
+ "ok": true,
+ "detail": "24036 / 24036"
+ },
+ {
+ "check": "roundtrip_materials",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_bones",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_clips",
+ "ok": true,
+ "detail": "['ability', 'attack_a', 'attack_b', 'death', 'hit', 'idle', 'start', 'stop', 'walk']"
+ }
+ ],
+ "source_sha256": "e21714e04a93f6266aae2edbf7db69c25d33b00429ebf62c01c6f832e18a771f",
+ "removed_modifiers": 0,
+ "joined_parts": 104,
+ "kind": "skinned",
+ "fps": 30.0,
+ "objects": 2,
+ "meshes": {
+ "FunkenBody": {
+ "mesh": "FunkenBody",
+ "triangles": 24036,
+ "vertices": 12226,
+ "ngons": 0,
+ "materials": [
+ "FL_Basalt",
+ "FL_BurnishedBronze",
+ "FL_Obsidian",
+ "FL_Ember",
+ "FL_Joint",
+ "FL_BronzeEdge",
+ "FL_Iron",
+ "FL_Crystal"
+ ],
+ "uv_layers": [
+ "UVMap"
+ ],
+ "color_attributes": [
+ "SurfaceColor"
+ ],
+ "active_color": "SurfaceColor",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": true,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.5652,
+ -0.0104,
+ -0.2945
+ ],
+ "max": [
+ 0.43,
+ 2.0212,
+ 1.435
+ ]
+ }
+ }
+ },
+ "armatures": {
+ "FunkenRig": {
+ "bones": [
+ "Root",
+ "Pelvis",
+ "Spine",
+ "Chest",
+ "Neck",
+ "Head",
+ "Clavicle.L",
+ "UpperArm.L",
+ "Forearm.L",
+ "Hand.L",
+ "Index.L",
+ "Clavicle.R",
+ "UpperArm.R",
+ "Forearm.R",
+ "Hand.R",
+ "Index.R",
+ "Weapon",
+ "Bolt",
+ "Crystal",
+ "Chamber",
+ "Thigh.L",
+ "Shin.L",
+ "Foot.L",
+ "Thigh.R",
+ "Shin.R",
+ "Foot.R"
+ ],
+ "roots": [
+ "Root"
+ ]
+ }
+ },
+ "empties": {},
+ "bounds_unity": {
+ "min": [
+ -0.5652,
+ -0.0104,
+ -0.2945
+ ],
+ "max": [
+ 0.43,
+ 2.0212,
+ 1.435
+ ]
+ },
+ "clips": [
+ {
+ "name": "ability",
+ "frames": [
+ 0.0,
+ 39.0
+ ],
+ "seconds": 1.3,
+ "loop": false,
+ "contact_seconds": 0.9
+ },
+ {
+ "name": "attack_a",
+ "frames": [
+ 0.0,
+ 39.0
+ ],
+ "seconds": 1.3,
+ "loop": false,
+ "contact_seconds": 0.9
+ },
+ {
+ "name": "attack_b",
+ "frames": [
+ 0.0,
+ 39.0
+ ],
+ "seconds": 1.3,
+ "loop": false,
+ "contact_seconds": 0.9
+ },
+ {
+ "name": "death",
+ "frames": [
+ 0.0,
+ 60.0
+ ],
+ "seconds": 2.0,
+ "loop": false,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "hit",
+ "frames": [
+ 0.0,
+ 15.0
+ ],
+ "seconds": 0.5,
+ "loop": false,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "idle",
+ "frames": [
+ 0.0,
+ 90.0
+ ],
+ "seconds": 3.0,
+ "loop": true,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "start",
+ "frames": [
+ 0.0,
+ 12.0
+ ],
+ "seconds": 0.4,
+ "loop": false,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "stop",
+ "frames": [
+ 0.0,
+ 12.0
+ ],
+ "seconds": 0.4,
+ "loop": false,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "walk",
+ "frames": [
+ 0.0,
+ 36.0
+ ],
+ "seconds": 1.2,
+ "loop": true,
+ "contact_seconds": -1.0
+ }
+ ],
+ "expected_from_godot": {
+ "triangles": 24036,
+ "bounds_godot": {
+ "min": [
+ -0.4300000071525574,
+ -0.010409347712993622,
+ -0.2945486903190613
+ ],
+ "max": [
+ 0.5651692152023315,
+ 2.021195411682129,
+ 1.4350000619888306
+ ]
+ },
+ "bones": 26,
+ "clips": [
+ "idle",
+ "start",
+ "walk",
+ "stop",
+ "attack_a",
+ "attack_b",
+ "hit",
+ "ability",
+ "death"
+ ],
+ "resource_path": "res://assets/characters/funkenlanze.glb"
+ },
+ "meshes_without_uv": [],
+ "triangles": 24036,
+ "fbx": "Assets/Luneraria/Art/Characters/funkenlanze.fbx",
+ "fbx_bytes": 3675308,
+ "ok": true
+}
diff --git a/Assets/Luneraria/Art/Characters/funkenlanze.export.json.meta b/Assets/Luneraria/Art/Characters/funkenlanze.export.json.meta
new file mode 100644
index 0000000..cfd8e1d
--- /dev/null
+++ b/Assets/Luneraria/Art/Characters/funkenlanze.export.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 373bb56c33f234adeac31c870ede9072
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Characters/funkenlanze.fbx b/Assets/Luneraria/Art/Characters/funkenlanze.fbx
new file mode 100644
index 0000000..0179b07
Binary files /dev/null and b/Assets/Luneraria/Art/Characters/funkenlanze.fbx differ
diff --git a/Assets/Luneraria/Art/Characters/funkenlanze.fbx.meta b/Assets/Luneraria/Art/Characters/funkenlanze.fbx.meta
new file mode 100644
index 0000000..6cd96b0
--- /dev/null
+++ b/Assets/Luneraria/Art/Characters/funkenlanze.fbx.meta
@@ -0,0 +1,393 @@
+fileFormatVersion: 2
+guid: 652ee682a82c34ff99c2eb11cd218f5e
+ModelImporter:
+ serializedVersion: 24300
+ internalIDToNameTable: []
+ externalObjects: {}
+ materials:
+ materialImportMode: 2
+ materialName: 0
+ materialSearch: 1
+ materialLocation: 1
+ searchTexturesGlobally: 0
+ animations:
+ legacyGenerateAnimations: 4
+ bakeSimulation: 0
+ resampleCurves: 0
+ optimizeGameObjects: 0
+ removeConstantScaleCurves: 0
+ motionNodeName:
+ animationImportErrors:
+ animationImportWarnings:
+ animationRetargetingWarnings:
+ animationDoRetargetingWarnings: 0
+ importAnimatedCustomProperties: 0
+ importConstraints: 0
+ animationCompression: 0
+ animationRotationError: 0.5
+ animationPositionError: 0.5
+ animationScaleError: 0.5
+ animationWrapMode: 0
+ extraExposedTransformPaths: []
+ extraUserProperties: []
+ clipAnimations:
+ - serializedVersion: 16
+ name: ability
+ takeName: FunkenRig|ability
+ internalID: -1787258805998246360
+ firstFrame: 0
+ lastFrame: 39
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events:
+ - time: 0.6923077
+ functionName: OnLuneContact
+ data:
+ objectReferenceParameter: {instanceID: 0}
+ floatParameter: 0
+ intParameter: 0
+ messageOptions: 0
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: attack_a
+ takeName: FunkenRig|attack_a
+ internalID: -6628820121952251911
+ firstFrame: 0
+ lastFrame: 39
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events:
+ - time: 0.6923077
+ functionName: OnLuneContact
+ data:
+ objectReferenceParameter: {instanceID: 0}
+ floatParameter: 0
+ intParameter: 0
+ messageOptions: 0
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: attack_b
+ takeName: FunkenRig|attack_b
+ internalID: -2963360793056117044
+ firstFrame: 0
+ lastFrame: 39
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events:
+ - time: 0.6923077
+ functionName: OnLuneContact
+ data:
+ objectReferenceParameter: {instanceID: 0}
+ floatParameter: 0
+ intParameter: 0
+ messageOptions: 0
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: death
+ takeName: FunkenRig|death
+ internalID: 9159963757730041032
+ firstFrame: 0
+ lastFrame: 60
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: hit
+ takeName: FunkenRig|hit
+ internalID: -4707179913997139171
+ firstFrame: 0
+ lastFrame: 15
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: idle
+ takeName: FunkenRig|idle
+ internalID: -1348917559068937310
+ firstFrame: 0
+ lastFrame: 90
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 1
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: start
+ takeName: FunkenRig|start
+ internalID: 6150794267048699607
+ firstFrame: 0
+ lastFrame: 12
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: stop
+ takeName: FunkenRig|stop
+ internalID: 637536857275861776
+ firstFrame: 0
+ lastFrame: 12
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: walk
+ takeName: FunkenRig|walk
+ internalID: 7607972658950073716
+ firstFrame: 0
+ lastFrame: 36
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 1
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ isReadable: 1
+ meshes:
+ lODScreenPercentages: []
+ globalScale: 1
+ meshCompression: 0
+ addColliders: 0
+ useSRGBMaterialColor: 1
+ sortHierarchyByName: 1
+ importPhysicalCameras: 1
+ importVisibility: 0
+ importBlendShapes: 0
+ importCameras: 0
+ importLights: 0
+ nodeNameCollisionStrategy: 1
+ fileIdsGeneration: 2
+ swapUVChannels: 0
+ generateSecondaryUV: 0
+ useFileUnits: 1
+ keepQuads: 0
+ weldVertices: 1
+ bakeAxisConversion: 1
+ preserveHierarchy: 0
+ skinWeightsMode: 0
+ maxBonesPerVertex: 4
+ minBoneWeight: 0.001
+ optimizeBones: 1
+ generateMeshLods: 0
+ meshLodGenerationFlags: 0
+ maximumMeshLod: -1
+ meshOptimizationFlags: -1
+ indexFormat: 0
+ secondaryUVAngleDistortion: 8
+ secondaryUVAreaDistortion: 15.000001
+ secondaryUVHardAngle: 88
+ secondaryUVMarginMethod: 1
+ secondaryUVMinLightmapResolution: 40
+ secondaryUVMinObjectScale: 1
+ secondaryUVPackMargin: 4
+ useFileScale: 1
+ strictVertexDataChecks: 0
+ tangentSpace:
+ normalSmoothAngle: 60
+ normalImportMode: 0
+ tangentImportMode: 0
+ normalCalculationMode: 4
+ legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
+ blendShapeNormalImportMode: 1
+ normalSmoothingSource: 0
+ referencedClips: []
+ importAnimation: 1
+ humanDescription:
+ serializedVersion: 3
+ human: []
+ skeleton: []
+ armTwist: 0.5
+ foreArmTwist: 0.5
+ upperLegTwist: 0.5
+ legTwist: 0.5
+ armStretch: 0.05
+ legStretch: 0.05
+ feetSpacing: 0
+ globalScale: 1
+ rootMotionBoneName:
+ hasTranslationDoF: 0
+ hasExtraRoot: 0
+ skeletonHasParents: 1
+ lastHumanDescriptionAvatarSource: {instanceID: 0}
+ autoGenerateAvatarMappingIfUnspecified: 1
+ animationType: 2
+ humanoidOversampling: 1
+ avatarSetup: 1
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 1
+ importBlendShapeDeformPercent: 1
+ remapMaterialsIfMaterialImportModeIsNone: 0
+ additionalBone: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Characters/schlundkrone.export.json b/Assets/Luneraria/Art/Characters/schlundkrone.export.json
new file mode 100644
index 0000000..e4d4ae1
--- /dev/null
+++ b/Assets/Luneraria/Art/Characters/schlundkrone.export.json
@@ -0,0 +1,431 @@
+{
+ "id": "schlundkrone",
+ "group": "Characters",
+ "source": "assets-source/luneraria/g2/schlundkrone.blend",
+ "exporter_version": 5,
+ "blender": "5.2.2 LTS",
+ "fbx_settings": {
+ "use_selection": true,
+ "use_visible": false,
+ "use_active_collection": false,
+ "global_scale": 1.0,
+ "apply_unit_scale": true,
+ "apply_scale_options": "FBX_SCALE_UNITS",
+ "axis_forward": "Y",
+ "axis_up": "Z",
+ "bake_space_transform": false,
+ "object_types": [
+ "ARMATURE",
+ "EMPTY",
+ "MESH"
+ ],
+ "use_mesh_modifiers": true,
+ "use_mesh_modifiers_render": true,
+ "mesh_smooth_type": "OFF",
+ "use_subsurf": false,
+ "use_mesh_edges": false,
+ "use_tspace": true,
+ "use_triangles": false,
+ "colors_type": "LINEAR",
+ "prioritize_active_color": true,
+ "use_custom_props": false,
+ "add_leaf_bones": false,
+ "primary_bone_axis": "Y",
+ "secondary_bone_axis": "X",
+ "use_armature_deform_only": true,
+ "armature_nodetype": "NULL",
+ "bake_anim": true,
+ "bake_anim_use_all_bones": true,
+ "bake_anim_use_nla_strips": false,
+ "bake_anim_use_all_actions": true,
+ "bake_anim_force_startend_keying": true,
+ "bake_anim_step": 1.0,
+ "bake_anim_simplify_factor": 0.0,
+ "path_mode": "STRIP",
+ "embed_textures": false,
+ "batch_mode": "OFF"
+ },
+ "checks": [
+ {
+ "check": "turn_applied",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "units_metric",
+ "ok": true,
+ "detail": "METRIC"
+ },
+ {
+ "check": "unit_scale_1",
+ "ok": true,
+ "detail": "1.0"
+ },
+ {
+ "check": "no_negative_scale",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "object_scale_1",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "mesh_names_unique",
+ "ok": true,
+ "detail": "['SchlundkroneBody']"
+ },
+ {
+ "check": "material_slots_filled",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangent_prerequisites",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "no_blend_shapes",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "triangles_match_godot",
+ "ok": true,
+ "detail": "5712 fbx / 5712 godot"
+ },
+ {
+ "check": "materials_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_match_godot",
+ "ok": true,
+ "detail": "largest difference 0.00000 m"
+ },
+ {
+ "check": "one_armature",
+ "ok": true,
+ "detail": "['SchlundkroneRig']"
+ },
+ {
+ "check": "single_root_bone",
+ "ok": true,
+ "detail": "['Root']"
+ },
+ {
+ "check": "root_bone_name",
+ "ok": true,
+ "detail": "['Root']"
+ },
+ {
+ "check": "bone_names_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bone_count_match_godot",
+ "ok": true,
+ "detail": "24 / 24"
+ },
+ {
+ "check": "bone_names_portable",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "skinned_meshes_present",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "clips_match_godot",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "required_clips_present",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "clip_lengths_match_godot",
+ "ok": true,
+ "detail": "largest difference 0.0000 s"
+ },
+ {
+ "check": "roundtrip_mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_triangles",
+ "ok": true,
+ "detail": "5712 / 5712"
+ },
+ {
+ "check": "roundtrip_materials",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_bones",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_clips",
+ "ok": true,
+ "detail": "['ability', 'attack_a', 'attack_b', 'death', 'hit', 'idle', 'roar', 'start', 'stop', 'victory', 'walk']"
+ }
+ ],
+ "source_sha256": "21f116f3ccf293b7f4c86bd23c07f86a41bd5d29c032f28bdb5c44043e9c6d7b",
+ "removed_modifiers": 0,
+ "kind": "skinned",
+ "fps": 30.0,
+ "objects": 2,
+ "meshes": {
+ "SchlundkroneBody": {
+ "mesh": "SchlundkroneBody",
+ "triangles": 5712,
+ "vertices": 3048,
+ "ngons": 0,
+ "materials": [
+ "LN_Boss_Hide",
+ "LN_Boss_Bone",
+ "LN_Crystal_Boss",
+ "LN_Boss_Bronze"
+ ],
+ "uv_layers": [
+ "UVMap",
+ "UVRest"
+ ],
+ "color_attributes": [
+ "Col"
+ ],
+ "active_color": "Col",
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": true,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.3273,
+ 0.0053,
+ -0.5532
+ ],
+ "max": [
+ 1.2307,
+ 3.3182,
+ 0.9253
+ ]
+ }
+ }
+ },
+ "armatures": {
+ "SchlundkroneRig": {
+ "bones": [
+ "Root",
+ "Hips",
+ "Spine",
+ "Chest",
+ "Neck",
+ "Head",
+ "Jaw",
+ "Crown",
+ "Maw.L",
+ "Shoulder.L",
+ "UpperArm.L",
+ "Forearm.L",
+ "Hand.L",
+ "Maw.R",
+ "Shoulder.R",
+ "UpperArm.R",
+ "Forearm.R",
+ "Hand.R",
+ "Thigh.L",
+ "Shin.L",
+ "Foot.L",
+ "Thigh.R",
+ "Shin.R",
+ "Foot.R"
+ ],
+ "roots": [
+ "Root"
+ ]
+ }
+ },
+ "empties": {},
+ "bounds_unity": {
+ "min": [
+ -1.3273,
+ 0.0053,
+ -0.5532
+ ],
+ "max": [
+ 1.2307,
+ 3.3182,
+ 0.9253
+ ]
+ },
+ "clips": [
+ {
+ "name": "ability",
+ "frames": [
+ 0.0,
+ 39.0
+ ],
+ "seconds": 1.3,
+ "loop": false,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "attack_a",
+ "frames": [
+ 0.0,
+ 39.0
+ ],
+ "seconds": 1.3,
+ "loop": false,
+ "contact_seconds": 0.9
+ },
+ {
+ "name": "attack_b",
+ "frames": [
+ 0.0,
+ 39.0
+ ],
+ "seconds": 1.3,
+ "loop": false,
+ "contact_seconds": 0.9
+ },
+ {
+ "name": "death",
+ "frames": [
+ 0.0,
+ 66.0
+ ],
+ "seconds": 2.2,
+ "loop": false,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "hit",
+ "frames": [
+ 0.0,
+ 15.0
+ ],
+ "seconds": 0.5,
+ "loop": false,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "idle",
+ "frames": [
+ 0.0,
+ 90.0
+ ],
+ "seconds": 3.0,
+ "loop": true,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "roar",
+ "frames": [
+ 0.0,
+ 60.0
+ ],
+ "seconds": 2.0,
+ "loop": false,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "start",
+ "frames": [
+ 0.0,
+ 12.0
+ ],
+ "seconds": 0.4,
+ "loop": false,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "stop",
+ "frames": [
+ 0.0,
+ 12.0
+ ],
+ "seconds": 0.4,
+ "loop": false,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "victory",
+ "frames": [
+ 0.0,
+ 60.0
+ ],
+ "seconds": 2.0,
+ "loop": false,
+ "contact_seconds": -1.0
+ },
+ {
+ "name": "walk",
+ "frames": [
+ 0.0,
+ 48.0
+ ],
+ "seconds": 1.6,
+ "loop": true,
+ "contact_seconds": -1.0
+ }
+ ],
+ "expected_from_godot": {
+ "triangles": 5712,
+ "bounds_godot": {
+ "min": [
+ -1.2307,
+ 0.0053,
+ -0.5532
+ ],
+ "max": [
+ 1.3273,
+ 3.3182,
+ 0.9253
+ ]
+ },
+ "bones": 24,
+ "clips": [
+ "ability",
+ "attack_a",
+ "attack_b",
+ "death",
+ "hit",
+ "idle",
+ "roar",
+ "start",
+ "stop",
+ "victory",
+ "walk"
+ ],
+ "resource_path": "res://assets/luneraria/g2/schlundkrone.glb"
+ },
+ "meshes_without_uv": [],
+ "triangles": 5712,
+ "fbx": "Assets/Luneraria/Art/Characters/schlundkrone.fbx",
+ "fbx_bytes": 2838956,
+ "ok": true
+}
diff --git a/Assets/Luneraria/Art/Characters/schlundkrone.export.json.meta b/Assets/Luneraria/Art/Characters/schlundkrone.export.json.meta
new file mode 100644
index 0000000..90df0b1
--- /dev/null
+++ b/Assets/Luneraria/Art/Characters/schlundkrone.export.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 96a195571f91340e5b420cd273a91231
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Characters/schlundkrone.fbx b/Assets/Luneraria/Art/Characters/schlundkrone.fbx
new file mode 100644
index 0000000..d61b17e
Binary files /dev/null and b/Assets/Luneraria/Art/Characters/schlundkrone.fbx differ
diff --git a/Assets/Luneraria/Art/Characters/schlundkrone.fbx.meta b/Assets/Luneraria/Art/Characters/schlundkrone.fbx.meta
new file mode 100644
index 0000000..db29389
--- /dev/null
+++ b/Assets/Luneraria/Art/Characters/schlundkrone.fbx.meta
@@ -0,0 +1,444 @@
+fileFormatVersion: 2
+guid: b2dd57798499c4b7b8698ee56e676c45
+ModelImporter:
+ serializedVersion: 24300
+ internalIDToNameTable: []
+ externalObjects: {}
+ materials:
+ materialImportMode: 2
+ materialName: 0
+ materialSearch: 1
+ materialLocation: 1
+ searchTexturesGlobally: 0
+ animations:
+ legacyGenerateAnimations: 4
+ bakeSimulation: 0
+ resampleCurves: 0
+ optimizeGameObjects: 0
+ removeConstantScaleCurves: 0
+ motionNodeName:
+ animationImportErrors:
+ animationImportWarnings:
+ animationRetargetingWarnings:
+ animationDoRetargetingWarnings: 0
+ importAnimatedCustomProperties: 0
+ importConstraints: 0
+ animationCompression: 0
+ animationRotationError: 0.5
+ animationPositionError: 0.5
+ animationScaleError: 0.5
+ animationWrapMode: 0
+ extraExposedTransformPaths: []
+ extraUserProperties: []
+ clipAnimations:
+ - serializedVersion: 16
+ name: ability
+ takeName: SchlundkroneRig|ability
+ internalID: 8816013596772264376
+ firstFrame: 0
+ lastFrame: 39
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: attack_a
+ takeName: SchlundkroneRig|attack_a
+ internalID: -3581854836903996656
+ firstFrame: 0
+ lastFrame: 39
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events:
+ - time: 0.6923077
+ functionName: OnLuneContact
+ data:
+ objectReferenceParameter: {instanceID: 0}
+ floatParameter: 0
+ intParameter: 0
+ messageOptions: 0
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: attack_b
+ takeName: SchlundkroneRig|attack_b
+ internalID: 7137080732755112609
+ firstFrame: 0
+ lastFrame: 39
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events:
+ - time: 0.6923077
+ functionName: OnLuneContact
+ data:
+ objectReferenceParameter: {instanceID: 0}
+ floatParameter: 0
+ intParameter: 0
+ messageOptions: 0
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: death
+ takeName: SchlundkroneRig|death
+ internalID: 3223440528613674463
+ firstFrame: 0
+ lastFrame: 66
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: hit
+ takeName: SchlundkroneRig|hit
+ internalID: -1153443838369333364
+ firstFrame: 0
+ lastFrame: 15
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: idle
+ takeName: SchlundkroneRig|idle
+ internalID: 2159908019584541609
+ firstFrame: 0
+ lastFrame: 90
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 1
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: roar
+ takeName: SchlundkroneRig|roar
+ internalID: 1662885906025357955
+ firstFrame: 0
+ lastFrame: 60
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: start
+ takeName: SchlundkroneRig|start
+ internalID: -8546801627699338383
+ firstFrame: 0
+ lastFrame: 12
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: stop
+ takeName: SchlundkroneRig|stop
+ internalID: 8440139490132052637
+ firstFrame: 0
+ lastFrame: 12
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: victory
+ takeName: SchlundkroneRig|victory
+ internalID: 7279649719363434968
+ firstFrame: 0
+ lastFrame: 60
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 0
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ - serializedVersion: 16
+ name: walk
+ takeName: SchlundkroneRig|walk
+ internalID: -395723189595340628
+ firstFrame: 0
+ lastFrame: 48
+ wrapMode: 0
+ orientationOffsetY: 0
+ level: 0
+ cycleOffset: 0
+ loop: 0
+ hasAdditiveReferencePose: 0
+ loopTime: 1
+ loopBlend: 0
+ loopBlendOrientation: 0
+ loopBlendPositionY: 0
+ loopBlendPositionXZ: 0
+ keepOriginalOrientation: 0
+ keepOriginalPositionY: 1
+ keepOriginalPositionXZ: 0
+ heightFromFeet: 0
+ mirror: 0
+ bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
+ curves: []
+ events: []
+ transformMask: []
+ maskType: 3
+ maskSource: {instanceID: 0}
+ additiveReferencePoseFrame: 0
+ isReadable: 1
+ meshes:
+ lODScreenPercentages: []
+ globalScale: 1
+ meshCompression: 0
+ addColliders: 0
+ useSRGBMaterialColor: 1
+ sortHierarchyByName: 1
+ importPhysicalCameras: 1
+ importVisibility: 0
+ importBlendShapes: 0
+ importCameras: 0
+ importLights: 0
+ nodeNameCollisionStrategy: 1
+ fileIdsGeneration: 2
+ swapUVChannels: 0
+ generateSecondaryUV: 0
+ useFileUnits: 1
+ keepQuads: 0
+ weldVertices: 1
+ bakeAxisConversion: 1
+ preserveHierarchy: 0
+ skinWeightsMode: 0
+ maxBonesPerVertex: 4
+ minBoneWeight: 0.001
+ optimizeBones: 1
+ generateMeshLods: 0
+ meshLodGenerationFlags: 0
+ maximumMeshLod: -1
+ meshOptimizationFlags: -1
+ indexFormat: 0
+ secondaryUVAngleDistortion: 8
+ secondaryUVAreaDistortion: 15.000001
+ secondaryUVHardAngle: 88
+ secondaryUVMarginMethod: 1
+ secondaryUVMinLightmapResolution: 40
+ secondaryUVMinObjectScale: 1
+ secondaryUVPackMargin: 4
+ useFileScale: 1
+ strictVertexDataChecks: 0
+ tangentSpace:
+ normalSmoothAngle: 60
+ normalImportMode: 0
+ tangentImportMode: 0
+ normalCalculationMode: 4
+ legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
+ blendShapeNormalImportMode: 1
+ normalSmoothingSource: 0
+ referencedClips: []
+ importAnimation: 1
+ humanDescription:
+ serializedVersion: 3
+ human: []
+ skeleton: []
+ armTwist: 0.5
+ foreArmTwist: 0.5
+ upperLegTwist: 0.5
+ legTwist: 0.5
+ armStretch: 0.05
+ legStretch: 0.05
+ feetSpacing: 0
+ globalScale: 1
+ rootMotionBoneName:
+ hasTranslationDoF: 0
+ hasExtraRoot: 0
+ skeletonHasParents: 1
+ lastHumanDescriptionAvatarSource: {instanceID: 0}
+ autoGenerateAvatarMappingIfUnspecified: 1
+ animationType: 2
+ humanoidOversampling: 1
+ avatarSetup: 1
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 1
+ importBlendShapeDeformPercent: 1
+ remapMaterialsIfMaterialImportModeIsNone: 0
+ additionalBone: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Environment.meta b/Assets/Luneraria/Art/Environment.meta
new file mode 100644
index 0000000..2f4ad10
--- /dev/null
+++ b/Assets/Luneraria/Art/Environment.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2cf6ff2112f7d4fd5bcff4710800659a
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Environment/map_props.export.json b/Assets/Luneraria/Art/Environment/map_props.export.json
new file mode 100644
index 0000000..50b038f
--- /dev/null
+++ b/Assets/Luneraria/Art/Environment/map_props.export.json
@@ -0,0 +1,684 @@
+{
+ "id": "map_props",
+ "group": "Environment",
+ "source": "assets-source/luneraria/map_props.blend",
+ "exporter_version": 5,
+ "blender": "5.2.2 LTS",
+ "fbx_settings": {
+ "use_selection": true,
+ "use_visible": false,
+ "use_active_collection": false,
+ "global_scale": 1.0,
+ "apply_unit_scale": true,
+ "apply_scale_options": "FBX_SCALE_UNITS",
+ "axis_forward": "Y",
+ "axis_up": "Z",
+ "bake_space_transform": false,
+ "object_types": [
+ "ARMATURE",
+ "EMPTY",
+ "MESH"
+ ],
+ "use_mesh_modifiers": true,
+ "use_mesh_modifiers_render": true,
+ "mesh_smooth_type": "OFF",
+ "use_subsurf": false,
+ "use_mesh_edges": false,
+ "use_tspace": true,
+ "use_triangles": false,
+ "colors_type": "LINEAR",
+ "prioritize_active_color": true,
+ "use_custom_props": false,
+ "add_leaf_bones": false,
+ "primary_bone_axis": "Y",
+ "secondary_bone_axis": "X",
+ "use_armature_deform_only": true,
+ "armature_nodetype": "NULL",
+ "bake_anim": true,
+ "bake_anim_use_all_bones": true,
+ "bake_anim_use_nla_strips": false,
+ "bake_anim_use_all_actions": true,
+ "bake_anim_force_startend_keying": true,
+ "bake_anim_step": 1.0,
+ "bake_anim_simplify_factor": 0.0,
+ "path_mode": "STRIP",
+ "embed_textures": false,
+ "batch_mode": "OFF"
+ },
+ "checks": [
+ {
+ "check": "turn_applied",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "units_metric",
+ "ok": true,
+ "detail": "METRIC"
+ },
+ {
+ "check": "unit_scale_1",
+ "ok": true,
+ "detail": "1.0"
+ },
+ {
+ "check": "no_negative_scale",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "object_scale_1",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "mesh_names_unique",
+ "ok": true,
+ "detail": "['Banner', 'Bridge', 'Curb', 'EdgeCliff', 'Oak_0', 'Oak_1', 'Oak_2', 'Pine_0', 'Pine_1', 'Pine_2', 'Rock_0', 'Rock_1', 'Rock_2', 'Shrub_0', 'Shrub_1']"
+ },
+ {
+ "check": "material_slots_filled",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangent_prerequisites",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "no_blend_shapes",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "no_armature",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_triangles",
+ "ok": true,
+ "detail": "7338 / 7338"
+ },
+ {
+ "check": "roundtrip_materials",
+ "ok": true,
+ "detail": "[]"
+ }
+ ],
+ "source_sha256": "e2e723fc53da0d4bb686800ddba36ebebe7708e0944c32a81fd6d9c159e30e68",
+ "removed_modifiers": 0,
+ "kind": "static",
+ "fps": 24.0,
+ "objects": 15,
+ "meshes": {
+ "Bridge": {
+ "mesh": "Deck_0",
+ "triangles": 1088,
+ "vertices": 656,
+ "ngons": 0,
+ "materials": [
+ "ENV_paving",
+ "ENV_limestone",
+ "ENV_brass"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -5.515,
+ -1.3,
+ -3.9
+ ],
+ "max": [
+ 5.515,
+ 1.46,
+ 3.9
+ ]
+ }
+ },
+ "Curb": {
+ "mesh": "Curb",
+ "triangles": 12,
+ "vertices": 8,
+ "ngons": 0,
+ "materials": [
+ "ENV_limestone"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.65,
+ -0.01,
+ -0.21
+ ],
+ "max": [
+ 0.65,
+ 0.25,
+ 0.21
+ ]
+ }
+ },
+ "Pine_0": {
+ "mesh": "Trunk",
+ "triangles": 358,
+ "vertices": 191,
+ "ngons": 0,
+ "materials": [
+ "ENV_bark",
+ "ENV_leaf_dark",
+ "ENV_leaf_mid"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.411,
+ 0.0,
+ -1.3761
+ ],
+ "max": [
+ 1.2882,
+ 4.332,
+ 1.3462
+ ]
+ }
+ },
+ "Pine_1": {
+ "mesh": "Trunk.001",
+ "triangles": 358,
+ "vertices": 191,
+ "ngons": 0,
+ "materials": [
+ "ENV_bark",
+ "ENV_leaf_dark",
+ "ENV_leaf_mid"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.4442,
+ 0.0,
+ -1.4865
+ ],
+ "max": [
+ 1.434,
+ 5.244,
+ 1.3943
+ ]
+ }
+ },
+ "Pine_2": {
+ "mesh": "Trunk.002",
+ "triangles": 358,
+ "vertices": 191,
+ "ngons": 0,
+ "materials": [
+ "ENV_bark",
+ "ENV_leaf_dark",
+ "ENV_leaf_mid"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.5452,
+ 0.0,
+ -1.5182
+ ],
+ "max": [
+ 1.4493,
+ 3.648,
+ 1.5733
+ ]
+ }
+ },
+ "Oak_0": {
+ "mesh": "Trunk.003",
+ "triangles": 1270,
+ "vertices": 669,
+ "ngons": 0,
+ "materials": [
+ "ENV_bark",
+ "ENV_leaf_mid",
+ "ENV_leaf_light",
+ "ENV_leaf_dark"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.7039,
+ -0.0306,
+ -1.8912
+ ],
+ "max": [
+ 1.373,
+ 4.02,
+ 1.5742
+ ]
+ }
+ },
+ "Oak_1": {
+ "mesh": "Trunk.004",
+ "triangles": 1270,
+ "vertices": 669,
+ "ngons": 0,
+ "materials": [
+ "ENV_bark",
+ "ENV_leaf_mid",
+ "ENV_leaf_light",
+ "ENV_leaf_dark"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.7964,
+ -0.0255,
+ -1.5792
+ ],
+ "max": [
+ 1.5389,
+ 4.6442,
+ 1.6028
+ ]
+ }
+ },
+ "Oak_2": {
+ "mesh": "Trunk.005",
+ "triangles": 1270,
+ "vertices": 669,
+ "ngons": 0,
+ "materials": [
+ "ENV_bark",
+ "ENV_leaf_mid",
+ "ENV_leaf_light",
+ "ENV_leaf_dark"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.7448,
+ -0.0387,
+ -1.4185
+ ],
+ "max": [
+ 1.6053,
+ 3.4947,
+ 1.7902
+ ]
+ }
+ },
+ "Rock_0": {
+ "mesh": "Rock",
+ "triangles": 140,
+ "vertices": 78,
+ "ngons": 0,
+ "materials": [
+ "ENV_cliff",
+ "ENV_leaf_dark",
+ "ENV_limestone"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.7155,
+ -0.04,
+ -1.0953
+ ],
+ "max": [
+ 1.0683,
+ 1.0416,
+ 1.0294
+ ]
+ }
+ },
+ "Rock_1": {
+ "mesh": "Rock.001",
+ "triangles": 140,
+ "vertices": 78,
+ "ngons": 0,
+ "materials": [
+ "ENV_cliff",
+ "ENV_leaf_dark",
+ "ENV_limestone"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -2.4291,
+ -0.055,
+ -1.4554
+ ],
+ "max": [
+ 1.8589,
+ 1.5017,
+ 1.32
+ ]
+ }
+ },
+ "Rock_2": {
+ "mesh": "Rock.002",
+ "triangles": 140,
+ "vertices": 78,
+ "ngons": 0,
+ "materials": [
+ "ENV_cliff",
+ "ENV_leaf_dark",
+ "ENV_limestone"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.2032,
+ -0.025,
+ -0.7362
+ ],
+ "max": [
+ 0.776,
+ 0.6172,
+ 0.7375
+ ]
+ }
+ },
+ "Shrub_0": {
+ "mesh": "Shrub",
+ "triangles": 80,
+ "vertices": 42,
+ "ngons": 0,
+ "materials": [
+ "ENV_leaf_mid"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.813,
+ 0.135,
+ -0.8861
+ ],
+ "max": [
+ 0.7211,
+ 0.8205,
+ 0.7093
+ ]
+ }
+ },
+ "Shrub_1": {
+ "mesh": "Shrub.001",
+ "triangles": 80,
+ "vertices": 42,
+ "ngons": 0,
+ "materials": [
+ "ENV_leaf_dark"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.0772,
+ 0.135,
+ -0.8513
+ ],
+ "max": [
+ 0.9518,
+ 0.9641,
+ 0.8895
+ ]
+ }
+ },
+ "Banner": {
+ "mesh": "Pole",
+ "triangles": 74,
+ "vertices": 48,
+ "ngons": 0,
+ "materials": [
+ "ENV_brass",
+ "PR_Banner"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -1.13,
+ 0.0,
+ -0.0866
+ ],
+ "max": [
+ 0.1,
+ 4.5,
+ 0.0866
+ ]
+ }
+ },
+ "EdgeCliff": {
+ "mesh": "Block_0",
+ "triangles": 700,
+ "vertices": 378,
+ "ngons": 0,
+ "materials": [
+ "ENV_cliff",
+ "ENV_leaf_mid"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": false,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -7.3684,
+ 0.4308,
+ -2.0375
+ ],
+ "max": [
+ 7.4555,
+ 4.1121,
+ 1.9761
+ ]
+ }
+ }
+ },
+ "armatures": {},
+ "empties": {},
+ "bounds_unity": {
+ "min": [
+ -7.3684,
+ -1.3,
+ -3.9
+ ],
+ "max": [
+ 7.4555,
+ 5.244,
+ 3.9
+ ]
+ },
+ "clips": [],
+ "expected_from_godot": {},
+ "meshes_without_uv": [
+ "Banner",
+ "Bridge",
+ "Curb",
+ "EdgeCliff",
+ "Oak_0",
+ "Oak_1",
+ "Oak_2",
+ "Pine_0",
+ "Pine_1",
+ "Pine_2",
+ "Rock_0",
+ "Rock_1",
+ "Rock_2",
+ "Shrub_0",
+ "Shrub_1"
+ ],
+ "triangles": 7338,
+ "fbx": "Assets/Luneraria/Art/Environment/map_props.fbx",
+ "fbx_bytes": 236284,
+ "ok": true
+}
diff --git a/Assets/Luneraria/Art/Environment/map_props.export.json.meta b/Assets/Luneraria/Art/Environment/map_props.export.json.meta
new file mode 100644
index 0000000..a05398e
--- /dev/null
+++ b/Assets/Luneraria/Art/Environment/map_props.export.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 712d173cb82314d19a6d0689762cb0ef
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Environment/map_props.fbx b/Assets/Luneraria/Art/Environment/map_props.fbx
new file mode 100644
index 0000000..9d10bb2
Binary files /dev/null and b/Assets/Luneraria/Art/Environment/map_props.fbx differ
diff --git a/Assets/Luneraria/Art/Environment/map_props.fbx.meta b/Assets/Luneraria/Art/Environment/map_props.fbx.meta
new file mode 100644
index 0000000..a02ef2c
--- /dev/null
+++ b/Assets/Luneraria/Art/Environment/map_props.fbx.meta
@@ -0,0 +1,111 @@
+fileFormatVersion: 2
+guid: 9a6862867d0c9498892d42d256fbe886
+ModelImporter:
+ serializedVersion: 24300
+ internalIDToNameTable: []
+ externalObjects: {}
+ materials:
+ materialImportMode: 2
+ materialName: 0
+ materialSearch: 1
+ materialLocation: 1
+ searchTexturesGlobally: 0
+ animations:
+ legacyGenerateAnimations: 4
+ bakeSimulation: 0
+ resampleCurves: 0
+ optimizeGameObjects: 0
+ removeConstantScaleCurves: 0
+ motionNodeName:
+ animationImportErrors:
+ animationImportWarnings:
+ animationRetargetingWarnings:
+ animationDoRetargetingWarnings: 0
+ importAnimatedCustomProperties: 0
+ importConstraints: 0
+ animationCompression: 0
+ animationRotationError: 0.5
+ animationPositionError: 0.5
+ animationScaleError: 0.5
+ animationWrapMode: 0
+ extraExposedTransformPaths: []
+ extraUserProperties: []
+ clipAnimations: []
+ isReadable: 1
+ meshes:
+ lODScreenPercentages: []
+ globalScale: 1
+ meshCompression: 0
+ addColliders: 0
+ useSRGBMaterialColor: 1
+ sortHierarchyByName: 1
+ importPhysicalCameras: 1
+ importVisibility: 0
+ importBlendShapes: 0
+ importCameras: 0
+ importLights: 0
+ nodeNameCollisionStrategy: 1
+ fileIdsGeneration: 2
+ swapUVChannels: 0
+ generateSecondaryUV: 0
+ useFileUnits: 1
+ keepQuads: 0
+ weldVertices: 1
+ bakeAxisConversion: 1
+ preserveHierarchy: 0
+ skinWeightsMode: 0
+ maxBonesPerVertex: 4
+ minBoneWeight: 0.001
+ optimizeBones: 1
+ generateMeshLods: 0
+ meshLodGenerationFlags: 0
+ maximumMeshLod: -1
+ meshOptimizationFlags: -1
+ indexFormat: 0
+ secondaryUVAngleDistortion: 8
+ secondaryUVAreaDistortion: 15.000001
+ secondaryUVHardAngle: 88
+ secondaryUVMarginMethod: 1
+ secondaryUVMinLightmapResolution: 40
+ secondaryUVMinObjectScale: 1
+ secondaryUVPackMargin: 4
+ useFileScale: 1
+ strictVertexDataChecks: 0
+ tangentSpace:
+ normalSmoothAngle: 60
+ normalImportMode: 0
+ tangentImportMode: 0
+ normalCalculationMode: 4
+ legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
+ blendShapeNormalImportMode: 1
+ normalSmoothingSource: 0
+ referencedClips: []
+ importAnimation: 0
+ humanDescription:
+ serializedVersion: 3
+ human: []
+ skeleton: []
+ armTwist: 0.5
+ foreArmTwist: 0.5
+ upperLegTwist: 0.5
+ legTwist: 0.5
+ armStretch: 0.05
+ legStretch: 0.05
+ feetSpacing: 0
+ globalScale: 1
+ rootMotionBoneName:
+ hasTranslationDoF: 0
+ hasExtraRoot: 0
+ skeletonHasParents: 1
+ lastHumanDescriptionAvatarSource: {instanceID: 0}
+ autoGenerateAvatarMappingIfUnspecified: 1
+ animationType: 0
+ humanoidOversampling: 1
+ avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 1
+ importBlendShapeDeformPercent: 1
+ remapMaterialsIfMaterialImportModeIsNone: 0
+ additionalBone: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Units.meta b/Assets/Luneraria/Art/Units.meta
new file mode 100644
index 0000000..f565e1c
--- /dev/null
+++ b/Assets/Luneraria/Art/Units.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 01c1714cee0714bbe9b65e1e6009cd0c
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Units/g01.export.json b/Assets/Luneraria/Art/Units/g01.export.json
new file mode 100644
index 0000000..58c8cd9
--- /dev/null
+++ b/Assets/Luneraria/Art/Units/g01.export.json
@@ -0,0 +1,4747 @@
+{
+ "id": "g01",
+ "group": "Units",
+ "source": "assets-source/phase4/blend/g01.blend",
+ "exporter_version": 5,
+ "blender": "5.2.2 LTS",
+ "fbx_settings": {
+ "use_selection": true,
+ "use_visible": false,
+ "use_active_collection": false,
+ "global_scale": 1.0,
+ "apply_unit_scale": true,
+ "apply_scale_options": "FBX_SCALE_UNITS",
+ "axis_forward": "Y",
+ "axis_up": "Z",
+ "bake_space_transform": false,
+ "object_types": [
+ "ARMATURE",
+ "EMPTY",
+ "MESH"
+ ],
+ "use_mesh_modifiers": true,
+ "use_mesh_modifiers_render": true,
+ "mesh_smooth_type": "OFF",
+ "use_subsurf": false,
+ "use_mesh_edges": false,
+ "use_tspace": true,
+ "use_triangles": false,
+ "colors_type": "LINEAR",
+ "prioritize_active_color": true,
+ "use_custom_props": false,
+ "add_leaf_bones": false,
+ "primary_bone_axis": "Y",
+ "secondary_bone_axis": "X",
+ "use_armature_deform_only": true,
+ "armature_nodetype": "NULL",
+ "bake_anim": true,
+ "bake_anim_use_all_bones": true,
+ "bake_anim_use_nla_strips": false,
+ "bake_anim_use_all_actions": true,
+ "bake_anim_force_startend_keying": true,
+ "bake_anim_step": 1.0,
+ "bake_anim_simplify_factor": 0.0,
+ "path_mode": "STRIP",
+ "embed_textures": false,
+ "batch_mode": "OFF"
+ },
+ "checks": [
+ {
+ "check": "logical_names_unique",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "turn_applied",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "units_metric",
+ "ok": true,
+ "detail": "METRIC"
+ },
+ {
+ "check": "unit_scale_1",
+ "ok": true,
+ "detail": "1.0"
+ },
+ {
+ "check": "no_negative_scale",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "object_scale_1",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "mesh_names_unique",
+ "ok": true,
+ "detail": "['ArmL_Elbow', 'ArmL_ForearmArmor', 'ArmL_ForearmCore', 'ArmL_Knuckle0_Head', 'ArmL_Knuckle0_Seat', 'ArmL_Knuckle1_Head', 'ArmL_Knuckle1_Seat', 'ArmL_Knuckle2_Head', 'ArmL_Knuckle2_Seat', 'ArmL_Palm', 'ArmL_Shoulder', 'ArmL_ShoulderJoint', 'ArmL_ShoulderTrim', 'ArmL_UpperArmor', 'ArmL_UpperBand', 'ArmL_UpperBandRivet_Head', 'ArmL_UpperBandRivet_Seat', 'ArmL_UpperCore', 'ArmL_WristBand', 'ArmL_WristBandRivet_Head', 'ArmL_WristBandRivet_Seat', 'ArmR_Elbow', 'ArmR_ForearmArmor', 'ArmR_ForearmCore', 'ArmR_Knuckle0_Head', 'ArmR_Knuckle0_Seat', 'ArmR_Knuckle1_Head', 'ArmR_Knuckle1_Seat', 'ArmR_Knuckle2_Head', 'ArmR_Knuckle2_Seat', 'ArmR_Palm', 'ArmR_Shoulder', 'ArmR_ShoulderJoint', 'ArmR_ShoulderTrim', 'ArmR_UpperArmor', 'ArmR_UpperBand', 'ArmR_UpperBandRivet_Head', 'ArmR_UpperBandRivet_Seat', 'ArmR_UpperCore', 'ArmR_WristBand', 'ArmR_WristBandRivet_Head', 'ArmR_WristBandRivet_Seat', 'Body_DorsalSpine0', 'Body_DorsalSpine1', 'Body_DorsalSpine2', 'Body_LavaCore', 'Body_Shell0_0', 'Body_Shell0_1', 'Body_Shell0_2', 'Body_Shell0_3', 'Body_Shell1_0', 'Body_Shell1_1', 'Body_Shell1_2', 'Body_Shell1_3', 'Body_Shell2_0', 'Body_Shell2_1', 'Body_Shell2_2', 'Body_Shell2_3', 'Head_BrowL', 'Head_BrowR', 'Head_CheekL', 'Head_CheekR', 'Head_Chin', 'Head_EyeL', 'Head_EyeR', 'Head_JawCavity', 'Head_LowerToothL0', 'Head_LowerToothL1', 'Head_LowerToothL2', 'Head_LowerToothL3', 'Head_LowerToothR0', 'Head_LowerToothR1', 'Head_LowerToothR2', 'Head_LowerToothR3', 'Head_MouthEmber', 'Head_UpperToothL0', 'Head_UpperToothL1', 'Head_UpperToothL2', 'Head_UpperToothL3', 'Head_UpperToothR0', 'Head_UpperToothR1', 'Head_UpperToothR2', 'Head_UpperToothR3', 'LegL_AnkleCuff', 'LegL_AnklePin', 'LegL_AnklePivot', 'LegL_AnkleRim', 'LegL_HipPin', 'LegL_HipPivot', 'LegL_HipRim', 'LegL_InnerShin', 'LegL_InnerThigh', 'LegL_KneeGuard', 'LegL_KneePin', 'LegL_KneePivot', 'LegL_KneeRim', 'LegL_ShinArmor', 'LegL_ThighArmor', 'LegL_Toe0', 'LegL_Toe1', 'LegL_Toe2', 'LegL_ToeCap0', 'LegL_ToeCap1', 'LegL_ToeCap2', 'LegR_AnkleCuff', 'LegR_AnklePin', 'LegR_AnklePivot', 'LegR_AnkleRim', 'LegR_HipPin', 'LegR_HipPivot', 'LegR_HipRim', 'LegR_InnerShin', 'LegR_InnerThigh', 'LegR_KneeGuard', 'LegR_KneePin', 'LegR_KneePivot', 'LegR_KneeRim', 'LegR_ShinArmor', 'LegR_ThighArmor', 'LegR_Toe0', 'LegR_Toe1', 'LegR_Toe2', 'LegR_ToeCap0', 'LegR_ToeCap1', 'LegR_ToeCap2', 'WeaponL_Claw0', 'WeaponL_Claw1', 'WeaponL_Claw2', 'WeaponR_Claw0', 'WeaponR_Claw1', 'WeaponR_Claw2']"
+ },
+ {
+ "check": "material_slots_filled",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangent_prerequisites",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "no_blend_shapes",
+ "ok": true,
+ "detail": "{}"
+ },
+ {
+ "check": "triangles_match_godot",
+ "ok": true,
+ "detail": "79780 fbx / 79780 godot"
+ },
+ {
+ "check": "bounds_match_godot",
+ "ok": true,
+ "detail": "largest difference 0.00004 m"
+ },
+ {
+ "check": "no_armature",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "forward_marker_unity_plus_z",
+ "ok": true,
+ "detail": "[0.0, 0.0, 0.75]"
+ },
+ {
+ "check": "roundtrip_mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "roundtrip_triangles",
+ "ok": true,
+ "detail": "79780 / 79780"
+ },
+ {
+ "check": "roundtrip_materials",
+ "ok": true,
+ "detail": "[]"
+ }
+ ],
+ "source_sha256": "79baa9e4adfdf91730cdb7a79b0c8417e57ade2b546c49e0220a2999b4f3720e",
+ "removed_modifiers": 36,
+ "logical_names": {
+ "objects": 133,
+ "materials": 7,
+ "merged_materials": 0
+ },
+ "kind": "rigid",
+ "fps": 24.0,
+ "objects": 133,
+ "meshes": {
+ "LegL_InnerThigh": {
+ "mesh": "LegL_InnerThigh_Mesh.003",
+ "triangles": 236,
+ "vertices": 120,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1175,
+ 0.1604,
+ -0.1951
+ ],
+ "max": [
+ 0.3158,
+ 0.3757,
+ -0.0312
+ ]
+ }
+ },
+ "LegL_InnerShin": {
+ "mesh": "LegL_InnerShin_Mesh.003",
+ "triangles": 236,
+ "vertices": 120,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1606,
+ 0.0464,
+ -0.1631
+ ],
+ "max": [
+ 0.3209,
+ 0.2393,
+ 0.0235
+ ]
+ }
+ },
+ "LegL_ThighArmor": {
+ "mesh": "LegL_ThighArmor_Mesh.003",
+ "triangles": 598,
+ "vertices": 301,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.0676,
+ 0.1766,
+ -0.2207
+ ],
+ "max": [
+ 0.3693,
+ 0.3551,
+ -0.0019
+ ]
+ }
+ },
+ "LegL_ShinArmor": {
+ "mesh": "LegL_ShinArmor_Mesh.003",
+ "triangles": 566,
+ "vertices": 285,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.11,
+ 0.0595,
+ -0.1872
+ ],
+ "max": [
+ 0.3733,
+ 0.2269,
+ 0.0512
+ ]
+ }
+ },
+ "LegL_HipPivot": {
+ "mesh": "LegL_HipPivot_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1025,
+ 0.2662,
+ -0.0371
+ ],
+ "max": [
+ 0.2827,
+ 0.4464,
+ 0.0159
+ ]
+ }
+ },
+ "LegL_HipPin": {
+ "mesh": "LegL_HipPin_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1475,
+ 0.3112,
+ 0.0189
+ ],
+ "max": [
+ 0.2377,
+ 0.4014,
+ 0.0401
+ ]
+ }
+ },
+ "LegL_HipRim": {
+ "mesh": "LegL_HipRim_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1726,
+ 0.3363,
+ 0.0362
+ ],
+ "max": [
+ 0.2126,
+ 0.3763,
+ 0.0603
+ ]
+ }
+ },
+ "LegL_KneePivot": {
+ "mesh": "LegL_KneePivot_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1506,
+ 0.0897,
+ -0.0419
+ ],
+ "max": [
+ 0.3309,
+ 0.2699,
+ 0.0111
+ ]
+ }
+ },
+ "LegL_KneePin": {
+ "mesh": "LegL_KneePin_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1957,
+ 0.1347,
+ 0.0141
+ ],
+ "max": [
+ 0.2858,
+ 0.2248,
+ 0.0353
+ ]
+ }
+ },
+ "LegL_KneeRim": {
+ "mesh": "LegL_KneeRim_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.2207,
+ 0.1598,
+ 0.0314
+ ],
+ "max": [
+ 0.2608,
+ 0.1998,
+ 0.0555
+ ]
+ }
+ },
+ "LegL_AnklePivot": {
+ "mesh": "LegL_AnklePivot_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1506,
+ 0.0158,
+ 0.0496
+ ],
+ "max": [
+ 0.3309,
+ 0.1961,
+ 0.1026
+ ]
+ }
+ },
+ "LegL_AnklePin": {
+ "mesh": "LegL_AnklePin_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1957,
+ 0.0609,
+ 0.1056
+ ],
+ "max": [
+ 0.2858,
+ 0.151,
+ 0.1267
+ ]
+ }
+ },
+ "LegL_AnkleRim": {
+ "mesh": "LegL_AnkleRim_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.2207,
+ 0.0859,
+ 0.1229
+ ],
+ "max": [
+ 0.2608,
+ 0.126,
+ 0.147
+ ]
+ }
+ },
+ "LegL_Toe0": {
+ "mesh": "LegL_Toe0_Mesh.003",
+ "triangles": 238,
+ "vertices": 121,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.2798,
+ 0.0,
+ -0.0529
+ ],
+ "max": [
+ 0.3772,
+ 0.1254,
+ 0.1974
+ ]
+ }
+ },
+ "LegL_ToeCap0": {
+ "mesh": "LegL_ToeCap0_Mesh.003",
+ "triangles": 188,
+ "vertices": 96,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.2896,
+ 0.0299,
+ 0.1372
+ ],
+ "max": [
+ 0.3672,
+ 0.0761,
+ 0.1806
+ ]
+ }
+ },
+ "LegL_Toe1": {
+ "mesh": "LegL_Toe1_Mesh.003",
+ "triangles": 238,
+ "vertices": 121,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1922,
+ 0.0,
+ -0.0529
+ ],
+ "max": [
+ 0.2896,
+ 0.1254,
+ 0.1974
+ ]
+ }
+ },
+ "LegL_ToeCap1": {
+ "mesh": "LegL_ToeCap1_Mesh.003",
+ "triangles": 188,
+ "vertices": 96,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.2019,
+ 0.0299,
+ 0.1372
+ ],
+ "max": [
+ 0.2795,
+ 0.0761,
+ 0.1806
+ ]
+ }
+ },
+ "LegL_Toe2": {
+ "mesh": "LegL_Toe2_Mesh.003",
+ "triangles": 238,
+ "vertices": 121,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1046,
+ 0.0,
+ -0.0529
+ ],
+ "max": [
+ 0.2019,
+ 0.1254,
+ 0.1974
+ ]
+ }
+ },
+ "LegL_ToeCap2": {
+ "mesh": "LegL_ToeCap2_Mesh.003",
+ "triangles": 188,
+ "vertices": 96,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1143,
+ 0.0299,
+ 0.1372
+ ],
+ "max": [
+ 0.1919,
+ 0.0761,
+ 0.1806
+ ]
+ }
+ },
+ "LegL_AnkleCuff": {
+ "mesh": "LegL_AnkleCuff_Mesh.003",
+ "triangles": 188,
+ "vertices": 96,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.0749,
+ 0.1324,
+ -0.1155
+ ],
+ "max": [
+ 0.4066,
+ 0.195,
+ 0.0963
+ ]
+ }
+ },
+ "LegL_KneeGuard": {
+ "mesh": "LegL_KneeGuard_Mesh.002",
+ "triangles": 238,
+ "vertices": 121,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_edge"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1456,
+ 0.0407,
+ 0.0053
+ ],
+ "max": [
+ 0.3358,
+ 0.2664,
+ 0.0775
+ ]
+ }
+ },
+ "LegR_InnerThigh": {
+ "mesh": "LegR_InnerThigh_Mesh.003",
+ "triangles": 236,
+ "vertices": 120,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3158,
+ 0.1604,
+ -0.1951
+ ],
+ "max": [
+ -0.1175,
+ 0.3757,
+ -0.0312
+ ]
+ }
+ },
+ "LegR_InnerShin": {
+ "mesh": "LegR_InnerShin_Mesh.003",
+ "triangles": 236,
+ "vertices": 120,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3209,
+ 0.0464,
+ -0.1631
+ ],
+ "max": [
+ -0.1606,
+ 0.2393,
+ 0.0235
+ ]
+ }
+ },
+ "LegR_ThighArmor": {
+ "mesh": "LegR_ThighArmor_Mesh.003",
+ "triangles": 608,
+ "vertices": 306,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3644,
+ 0.1794,
+ -0.2205
+ ],
+ "max": [
+ -0.07,
+ 0.3584,
+ -0.0068
+ ]
+ }
+ },
+ "LegR_ShinArmor": {
+ "mesh": "LegR_ShinArmor_Mesh.003",
+ "triangles": 604,
+ "vertices": 304,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.373,
+ 0.0566,
+ -0.1925
+ ],
+ "max": [
+ -0.1141,
+ 0.2247,
+ 0.0502
+ ]
+ }
+ },
+ "LegR_HipPivot": {
+ "mesh": "LegR_HipPivot_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2827,
+ 0.2662,
+ -0.0371
+ ],
+ "max": [
+ -0.1025,
+ 0.4464,
+ 0.0159
+ ]
+ }
+ },
+ "LegR_HipPin": {
+ "mesh": "LegR_HipPin_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2377,
+ 0.3112,
+ 0.0189
+ ],
+ "max": [
+ -0.1475,
+ 0.4014,
+ 0.0401
+ ]
+ }
+ },
+ "LegR_HipRim": {
+ "mesh": "LegR_HipRim_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2126,
+ 0.3363,
+ 0.0362
+ ],
+ "max": [
+ -0.1726,
+ 0.3763,
+ 0.0603
+ ]
+ }
+ },
+ "LegR_KneePivot": {
+ "mesh": "LegR_KneePivot_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3309,
+ 0.0897,
+ -0.0419
+ ],
+ "max": [
+ -0.1506,
+ 0.2699,
+ 0.0111
+ ]
+ }
+ },
+ "LegR_KneePin": {
+ "mesh": "LegR_KneePin_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2858,
+ 0.1347,
+ 0.0141
+ ],
+ "max": [
+ -0.1957,
+ 0.2248,
+ 0.0353
+ ]
+ }
+ },
+ "LegR_KneeRim": {
+ "mesh": "LegR_KneeRim_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2608,
+ 0.1598,
+ 0.0314
+ ],
+ "max": [
+ -0.2207,
+ 0.1998,
+ 0.0555
+ ]
+ }
+ },
+ "LegR_AnklePivot": {
+ "mesh": "LegR_AnklePivot_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3309,
+ 0.0158,
+ 0.0496
+ ],
+ "max": [
+ -0.1506,
+ 0.1961,
+ 0.1026
+ ]
+ }
+ },
+ "LegR_AnklePin": {
+ "mesh": "LegR_AnklePin_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2858,
+ 0.0609,
+ 0.1056
+ ],
+ "max": [
+ -0.1957,
+ 0.151,
+ 0.1267
+ ]
+ }
+ },
+ "LegR_AnkleRim": {
+ "mesh": "LegR_AnkleRim_Mesh.003",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2608,
+ 0.0859,
+ 0.1229
+ ],
+ "max": [
+ -0.2207,
+ 0.126,
+ 0.147
+ ]
+ }
+ },
+ "LegR_Toe0": {
+ "mesh": "LegR_Toe0_Mesh.003",
+ "triangles": 238,
+ "vertices": 121,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2016,
+ 0.0,
+ -0.0529
+ ],
+ "max": [
+ -0.1043,
+ 0.1254,
+ 0.1974
+ ]
+ }
+ },
+ "LegR_ToeCap0": {
+ "mesh": "LegR_ToeCap0_Mesh.003",
+ "triangles": 188,
+ "vertices": 96,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.1919,
+ 0.0299,
+ 0.1372
+ ],
+ "max": [
+ -0.1143,
+ 0.0761,
+ 0.1806
+ ]
+ }
+ },
+ "LegR_Toe1": {
+ "mesh": "LegR_Toe1_Mesh.003",
+ "triangles": 238,
+ "vertices": 121,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2893,
+ 0.0,
+ -0.0529
+ ],
+ "max": [
+ -0.1919,
+ 0.1254,
+ 0.1974
+ ]
+ }
+ },
+ "LegR_ToeCap1": {
+ "mesh": "LegR_ToeCap1_Mesh.003",
+ "triangles": 188,
+ "vertices": 96,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2795,
+ 0.0299,
+ 0.1372
+ ],
+ "max": [
+ -0.2019,
+ 0.0761,
+ 0.1806
+ ]
+ }
+ },
+ "LegR_Toe2": {
+ "mesh": "LegR_Toe2_Mesh.003",
+ "triangles": 238,
+ "vertices": 121,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3769,
+ 0.0,
+ -0.0529
+ ],
+ "max": [
+ -0.2795,
+ 0.1254,
+ 0.1974
+ ]
+ }
+ },
+ "LegR_ToeCap2": {
+ "mesh": "LegR_ToeCap2_Mesh.003",
+ "triangles": 188,
+ "vertices": 96,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3672,
+ 0.0299,
+ 0.1372
+ ],
+ "max": [
+ -0.2896,
+ 0.0761,
+ 0.1806
+ ]
+ }
+ },
+ "LegR_AnkleCuff": {
+ "mesh": "LegR_AnkleCuff_Mesh.003",
+ "triangles": 188,
+ "vertices": 96,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.4066,
+ 0.1324,
+ -0.1155
+ ],
+ "max": [
+ -0.0749,
+ 0.195,
+ 0.0963
+ ]
+ }
+ },
+ "LegR_KneeGuard": {
+ "mesh": "LegR_KneeGuard_Mesh.002",
+ "triangles": 238,
+ "vertices": 121,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_edge"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3358,
+ 0.0407,
+ 0.0053
+ ],
+ "max": [
+ -0.1456,
+ 0.2664,
+ 0.0775
+ ]
+ }
+ },
+ "Body_LavaCore": {
+ "mesh": "Body_LavaCore_Mesh",
+ "triangles": 640,
+ "vertices": 322,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_ember"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3376,
+ 0.3469,
+ -0.3505
+ ],
+ "max": [
+ 0.3281,
+ 1.0792,
+ 0.1897
+ ]
+ }
+ },
+ "Body_Shell0_0": {
+ "mesh": "Body_Shell0_0_Mesh",
+ "triangles": 2102,
+ "vertices": 1053,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.496,
+ 0.3031,
+ -0.1857
+ ],
+ "max": [
+ -0.1452,
+ 0.6916,
+ 0.0664
+ ]
+ }
+ },
+ "Body_Shell0_1": {
+ "mesh": "Body_Shell0_1_Mesh",
+ "triangles": 2176,
+ "vertices": 1090,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3731,
+ 0.2946,
+ -0.3651
+ ],
+ "max": [
+ -0.0208,
+ 0.6829,
+ -0.1119
+ ]
+ }
+ },
+ "Body_Shell0_2": {
+ "mesh": "Body_Shell0_2_Mesh",
+ "triangles": 2240,
+ "vertices": 1122,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.0973,
+ 0.3007,
+ -0.421
+ ],
+ "max": [
+ 0.2432,
+ 0.6863,
+ -0.1458
+ ]
+ }
+ },
+ "Body_Shell0_3": {
+ "mesh": "Body_Shell0_3_Mesh",
+ "triangles": 572,
+ "vertices": 288,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1161,
+ 0.3095,
+ -0.2937
+ ],
+ "max": [
+ 0.4615,
+ 0.6787,
+ -0.0165
+ ]
+ }
+ },
+ "Body_Shell1_0": {
+ "mesh": "Body_Shell1_0_Mesh",
+ "triangles": 2400,
+ "vertices": 1202,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.4744,
+ 0.573,
+ -0.2493
+ ],
+ "max": [
+ -0.1448,
+ 0.9433,
+ 0.0411
+ ]
+ }
+ },
+ "Body_Shell1_1": {
+ "mesh": "Body_Shell1_1_Mesh",
+ "triangles": 2326,
+ "vertices": 1165,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3133,
+ 0.5835,
+ -0.412
+ ],
+ "max": [
+ 0.0207,
+ 0.9536,
+ -0.1224
+ ]
+ }
+ },
+ "Body_Shell1_2": {
+ "mesh": "Body_Shell1_2_Mesh",
+ "triangles": 2208,
+ "vertices": 1106,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.0395,
+ 0.5714,
+ -0.4174
+ ],
+ "max": [
+ 0.2917,
+ 0.9417,
+ -0.1248
+ ]
+ }
+ },
+ "Body_Shell1_3": {
+ "mesh": "Body_Shell1_3_Mesh",
+ "triangles": 2380,
+ "vertices": 1192,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1472,
+ 0.5796,
+ -0.2727
+ ],
+ "max": [
+ 0.4645,
+ 0.944,
+ 0.0397
+ ]
+ }
+ },
+ "Body_Shell2_0": {
+ "mesh": "Body_Shell2_0_Mesh",
+ "triangles": 536,
+ "vertices": 270,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.4753,
+ 0.8382,
+ -0.2121
+ ],
+ "max": [
+ -0.1601,
+ 1.1819,
+ 0.092
+ ]
+ }
+ },
+ "Body_Shell2_1": {
+ "mesh": "Body_Shell2_1_Mesh",
+ "triangles": 2296,
+ "vertices": 1150,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3569,
+ 0.8428,
+ -0.396
+ ],
+ "max": [
+ -0.0312,
+ 1.1824,
+ -0.078
+ ]
+ }
+ },
+ "Body_Shell2_2": {
+ "mesh": "Body_Shell2_2_Mesh",
+ "triangles": 2416,
+ "vertices": 1210,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.0943,
+ 0.8338,
+ -0.4473
+ ],
+ "max": [
+ 0.2269,
+ 1.1833,
+ -0.1234
+ ]
+ }
+ },
+ "Body_Shell2_3": {
+ "mesh": "Body_Shell2_3_Mesh",
+ "triangles": 2386,
+ "vertices": 1195,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1274,
+ 0.8394,
+ -0.3285
+ ],
+ "max": [
+ 0.4408,
+ 1.1802,
+ 0.0062
+ ]
+ }
+ },
+ "Head_JawCavity": {
+ "mesh": "Head_JawCavity_Mesh",
+ "triangles": 524,
+ "vertices": 264,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.3477,
+ 0.5094,
+ 0.0401
+ ],
+ "max": [
+ 0.3305,
+ 0.9505,
+ 0.3214
+ ]
+ }
+ },
+ "Head_MouthEmber": {
+ "mesh": "Head_MouthEmber_Mesh",
+ "triangles": 382,
+ "vertices": 193,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_ember"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2865,
+ 0.5888,
+ 0.261
+ ],
+ "max": [
+ 0.2865,
+ 0.8268,
+ 0.2879
+ ]
+ }
+ },
+ "Head_BrowL": {
+ "mesh": "Head_BrowL_Mesh",
+ "triangles": 2246,
+ "vertices": 1125,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.0105,
+ 0.8302,
+ 0.0358
+ ],
+ "max": [
+ 0.387,
+ 1.106,
+ 0.3514
+ ]
+ }
+ },
+ "Head_EyeL": {
+ "mesh": "Head_EyeL_Mesh.005",
+ "triangles": 108,
+ "vertices": 56,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_hot"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.0844,
+ 0.9082,
+ 0.3334
+ ],
+ "max": [
+ 0.2827,
+ 0.9741,
+ 0.3775
+ ]
+ }
+ },
+ "Head_CheekL": {
+ "mesh": "Head_CheekL_Mesh",
+ "triangles": 1936,
+ "vertices": 970,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1763,
+ 0.5808,
+ 0.0229
+ ],
+ "max": [
+ 0.4361,
+ 0.9661,
+ 0.3229
+ ]
+ }
+ },
+ "Head_UpperToothL0": {
+ "mesh": "Head_UpperToothL0_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_edge"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.0193,
+ 0.7511,
+ 0.2092
+ ],
+ "max": [
+ 0.0867,
+ 0.9385,
+ 0.3587
+ ]
+ }
+ },
+ "Head_LowerToothL0": {
+ "mesh": "Head_LowerToothL0_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.0212,
+ 0.4668,
+ 0.1688
+ ],
+ "max": [
+ 0.0886,
+ 0.6741,
+ 0.3368
+ ]
+ }
+ },
+ "Head_UpperToothL1": {
+ "mesh": "Head_UpperToothL1_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_edge"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.0481,
+ 0.7395,
+ 0.2091
+ ],
+ "max": [
+ 0.1541,
+ 0.923,
+ 0.3586
+ ]
+ }
+ },
+ "Head_LowerToothL1": {
+ "mesh": "Head_LowerToothL1_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.0462,
+ 0.4843,
+ 0.1702
+ ],
+ "max": [
+ 0.156,
+ 0.6837,
+ 0.3368
+ ]
+ }
+ },
+ "Head_UpperToothL2": {
+ "mesh": "Head_UpperToothL2_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_edge"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1156,
+ 0.728,
+ 0.2091
+ ],
+ "max": [
+ 0.2215,
+ 0.9075,
+ 0.3585
+ ]
+ }
+ },
+ "Head_LowerToothL2": {
+ "mesh": "Head_LowerToothL2_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.1136,
+ 0.5017,
+ 0.1719
+ ],
+ "max": [
+ 0.2234,
+ 0.6933,
+ 0.3368
+ ]
+ }
+ },
+ "Head_UpperToothL3": {
+ "mesh": "Head_UpperToothL3_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_edge"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.183,
+ 0.7164,
+ 0.209
+ ],
+ "max": [
+ 0.2889,
+ 0.892,
+ 0.3584
+ ]
+ }
+ },
+ "Head_LowerToothL3": {
+ "mesh": "Head_LowerToothL3_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.181,
+ 0.5189,
+ 0.1738
+ ],
+ "max": [
+ 0.2908,
+ 0.703,
+ 0.3368
+ ]
+ }
+ },
+ "ArmL_UpperCore": {
+ "mesh": "ArmL_UpperCore_Mesh.006",
+ "triangles": 236,
+ "vertices": 120,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.3562,
+ 0.6473,
+ -0.1599
+ ],
+ "max": [
+ 0.5875,
+ 0.9512,
+ 0.0299
+ ]
+ }
+ },
+ "ArmL_ForearmCore": {
+ "mesh": "ArmL_ForearmCore_Mesh.006",
+ "triangles": 236,
+ "vertices": 120,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.4361,
+ 0.4329,
+ -0.1105
+ ],
+ "max": [
+ 0.6328,
+ 0.7226,
+ 0.1635
+ ]
+ }
+ },
+ "ArmL_Elbow": {
+ "mesh": "ArmL_Elbow_Mesh.006",
+ "triangles": 636,
+ "vertices": 320,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.4033,
+ 0.5551,
+ -0.1601
+ ],
+ "max": [
+ 0.6358,
+ 0.7902,
+ 0.0711
+ ]
+ }
+ },
+ "ArmL_UpperArmor": {
+ "mesh": "ArmL_UpperArmor_Mesh.006",
+ "triangles": 582,
+ "vertices": 293,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.3357,
+ 0.6599,
+ -0.1808
+ ],
+ "max": [
+ 0.6069,
+ 0.937,
+ 0.0465
+ ]
+ }
+ },
+ "ArmL_ForearmArmor": {
+ "mesh": "ArmL_ForearmArmor_Mesh.006",
+ "triangles": 614,
+ "vertices": 309,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.3821,
+ 0.4145,
+ -0.1098
+ ],
+ "max": [
+ 0.6842,
+ 0.734,
+ 0.1638
+ ]
+ }
+ },
+ "ArmL_Shoulder": {
+ "mesh": "ArmL_Shoulder_Mesh.006",
+ "triangles": 2546,
+ "vertices": 1275,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.2404,
+ 0.7736,
+ -0.2501
+ ],
+ "max": [
+ 0.607,
+ 1.0761,
+ 0.0816
+ ]
+ }
+ },
+ "ArmL_ShoulderJoint": {
+ "mesh": "ArmL_ShoulderJoint_Mesh.006",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.3347,
+ 0.8355,
+ 0.0029
+ ],
+ "max": [
+ 0.5127,
+ 1.0134,
+ 0.053
+ ]
+ }
+ },
+ "ArmL_UpperBand": {
+ "mesh": "ArmL_UpperBand_Mesh.006",
+ "triangles": 284,
+ "vertices": 144,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.3638,
+ 0.4323,
+ -0.1211
+ ],
+ "max": [
+ 0.7097,
+ 0.6924,
+ 0.1965
+ ]
+ }
+ },
+ "ArmL_UpperBandRivet_Seat": {
+ "mesh": "ArmL_UpperBandRivet_Seat_Mesh.006",
+ "triangles": 444,
+ "vertices": 224,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.5107,
+ 0.5364,
+ 0.2019
+ ],
+ "max": [
+ 0.5627,
+ 0.5884,
+ 0.2105
+ ]
+ }
+ },
+ "ArmL_UpperBandRivet_Head": {
+ "mesh": "ArmL_UpperBandRivet_Head_Mesh.006",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.5194,
+ 0.545,
+ 0.2062
+ ],
+ "max": [
+ 0.5541,
+ 0.5797,
+ 0.2235
+ ]
+ }
+ },
+ "ArmL_WristBand": {
+ "mesh": "ArmL_WristBand_Mesh.006",
+ "triangles": 284,
+ "vertices": 144,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.3716,
+ 0.3803,
+ -0.0834
+ ],
+ "max": [
+ 0.7175,
+ 0.6404,
+ 0.2342
+ ]
+ }
+ },
+ "ArmL_WristBandRivet_Seat": {
+ "mesh": "ArmL_WristBandRivet_Seat_Mesh.006",
+ "triangles": 444,
+ "vertices": 224,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.5185,
+ 0.4844,
+ 0.2396
+ ],
+ "max": [
+ 0.5705,
+ 0.5364,
+ 0.2482
+ ]
+ }
+ },
+ "ArmL_WristBandRivet_Head": {
+ "mesh": "ArmL_WristBandRivet_Head_Mesh.006",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.5272,
+ 0.493,
+ 0.2439
+ ],
+ "max": [
+ 0.5619,
+ 0.5277,
+ 0.2612
+ ]
+ }
+ },
+ "ArmL_Palm": {
+ "mesh": "ArmL_Palm_Mesh.006",
+ "triangles": 558,
+ "vertices": 281,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.415,
+ 0.3443,
+ -0.0299
+ ],
+ "max": [
+ 0.6838,
+ 0.6169,
+ 0.2193
+ ]
+ }
+ },
+ "WeaponL_Claw0": {
+ "mesh": "WeaponL_Claw0_Mesh",
+ "triangles": 574,
+ "vertices": 289,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.6225,
+ 0.1541,
+ 0.0951
+ ],
+ "max": [
+ 0.7924,
+ 0.6199,
+ 0.4473
+ ]
+ }
+ },
+ "ArmL_Knuckle0_Seat": {
+ "mesh": "ArmL_Knuckle0_Seat_Mesh",
+ "triangles": 444,
+ "vertices": 224,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.663,
+ 0.5571,
+ 0.1979
+ ],
+ "max": [
+ 0.7237,
+ 0.6177,
+ 0.2066
+ ]
+ }
+ },
+ "ArmL_Knuckle0_Head": {
+ "mesh": "ArmL_Knuckle0_Head_Mesh",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.6731,
+ 0.5672,
+ 0.2022
+ ],
+ "max": [
+ 0.7135,
+ 0.6076,
+ 0.2196
+ ]
+ }
+ },
+ "WeaponL_Claw1": {
+ "mesh": "WeaponL_Claw1_Mesh",
+ "triangles": 574,
+ "vertices": 289,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.4877,
+ 0.1541,
+ 0.0951
+ ],
+ "max": [
+ 0.6576,
+ 0.6199,
+ 0.4473
+ ]
+ }
+ },
+ "ArmL_Knuckle1_Seat": {
+ "mesh": "ArmL_Knuckle1_Seat_Mesh",
+ "triangles": 444,
+ "vertices": 224,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.5282,
+ 0.5571,
+ 0.1979
+ ],
+ "max": [
+ 0.5888,
+ 0.6177,
+ 0.2066
+ ]
+ }
+ },
+ "ArmL_Knuckle1_Head": {
+ "mesh": "ArmL_Knuckle1_Head_Mesh",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.5383,
+ 0.5672,
+ 0.2022
+ ],
+ "max": [
+ 0.5787,
+ 0.6076,
+ 0.2196
+ ]
+ }
+ },
+ "WeaponL_Claw2": {
+ "mesh": "WeaponL_Claw2_Mesh",
+ "triangles": 574,
+ "vertices": 289,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.3529,
+ 0.1541,
+ 0.0951
+ ],
+ "max": [
+ 0.5228,
+ 0.6199,
+ 0.4473
+ ]
+ }
+ },
+ "ArmL_Knuckle2_Seat": {
+ "mesh": "ArmL_Knuckle2_Seat_Mesh",
+ "triangles": 444,
+ "vertices": 224,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.3934,
+ 0.5571,
+ 0.1979
+ ],
+ "max": [
+ 0.454,
+ 0.6177,
+ 0.2066
+ ]
+ }
+ },
+ "ArmL_Knuckle2_Head": {
+ "mesh": "ArmL_Knuckle2_Head_Mesh",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.4035,
+ 0.5672,
+ 0.2022
+ ],
+ "max": [
+ 0.4439,
+ 0.6076,
+ 0.2196
+ ]
+ }
+ },
+ "ArmL_ShoulderTrim": {
+ "mesh": "ArmL_ShoulderTrim_Mesh",
+ "triangles": 238,
+ "vertices": 121,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.3094,
+ 0.9119,
+ 0.0434
+ ],
+ "max": [
+ 0.4995,
+ 1.0641,
+ 0.0819
+ ]
+ }
+ },
+ "Head_BrowR": {
+ "mesh": "Head_BrowR_Mesh",
+ "triangles": 2302,
+ "vertices": 1153,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.381,
+ 0.8241,
+ 0.0243
+ ],
+ "max": [
+ 0.0183,
+ 1.1115,
+ 0.3586
+ ]
+ }
+ },
+ "Head_EyeR": {
+ "mesh": "Head_EyeR_Mesh.005",
+ "triangles": 108,
+ "vertices": 56,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_hot"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2827,
+ 0.9082,
+ 0.3334
+ ],
+ "max": [
+ -0.0844,
+ 0.9741,
+ 0.3775
+ ]
+ }
+ },
+ "Head_CheekR": {
+ "mesh": "Head_CheekR_Mesh",
+ "triangles": 2426,
+ "vertices": 1215,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.4589,
+ 0.5769,
+ 0.0446
+ ],
+ "max": [
+ -0.1508,
+ 0.9503,
+ 0.2989
+ ]
+ }
+ },
+ "Head_UpperToothR0": {
+ "mesh": "Head_UpperToothR0_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_edge"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.0867,
+ 0.7511,
+ 0.2092
+ ],
+ "max": [
+ 0.0193,
+ 0.9385,
+ 0.3587
+ ]
+ }
+ },
+ "Head_LowerToothR0": {
+ "mesh": "Head_LowerToothR0_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.0886,
+ 0.4668,
+ 0.1688
+ ],
+ "max": [
+ 0.0212,
+ 0.6741,
+ 0.3368
+ ]
+ }
+ },
+ "Head_UpperToothR1": {
+ "mesh": "Head_UpperToothR1_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_edge"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.1541,
+ 0.7395,
+ 0.2091
+ ],
+ "max": [
+ -0.0481,
+ 0.923,
+ 0.3586
+ ]
+ }
+ },
+ "Head_LowerToothR1": {
+ "mesh": "Head_LowerToothR1_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.156,
+ 0.4843,
+ 0.1702
+ ],
+ "max": [
+ -0.0462,
+ 0.6837,
+ 0.3368
+ ]
+ }
+ },
+ "Head_UpperToothR2": {
+ "mesh": "Head_UpperToothR2_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_edge"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2215,
+ 0.728,
+ 0.2091
+ ],
+ "max": [
+ -0.1156,
+ 0.9075,
+ 0.3585
+ ]
+ }
+ },
+ "Head_LowerToothR2": {
+ "mesh": "Head_LowerToothR2_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2234,
+ 0.5017,
+ 0.1719
+ ],
+ "max": [
+ -0.1136,
+ 0.6933,
+ 0.3368
+ ]
+ }
+ },
+ "Head_UpperToothR3": {
+ "mesh": "Head_UpperToothR3_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_edge"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2889,
+ 0.7164,
+ 0.209
+ ],
+ "max": [
+ -0.183,
+ 0.892,
+ 0.3584
+ ]
+ }
+ },
+ "Head_LowerToothR3": {
+ "mesh": "Head_LowerToothR3_Mesh",
+ "triangles": 94,
+ "vertices": 49,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2908,
+ 0.5189,
+ 0.1738
+ ],
+ "max": [
+ -0.181,
+ 0.703,
+ 0.3368
+ ]
+ }
+ },
+ "ArmR_UpperCore": {
+ "mesh": "ArmR_UpperCore_Mesh.006",
+ "triangles": 236,
+ "vertices": 120,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.5875,
+ 0.6473,
+ -0.1599
+ ],
+ "max": [
+ -0.3562,
+ 0.9512,
+ 0.0299
+ ]
+ }
+ },
+ "ArmR_ForearmCore": {
+ "mesh": "ArmR_ForearmCore_Mesh.006",
+ "triangles": 236,
+ "vertices": 120,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.6328,
+ 0.4329,
+ -0.1105
+ ],
+ "max": [
+ -0.4361,
+ 0.7226,
+ 0.1635
+ ]
+ }
+ },
+ "ArmR_Elbow": {
+ "mesh": "ArmR_Elbow_Mesh.006",
+ "triangles": 570,
+ "vertices": 287,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.6355,
+ 0.5591,
+ -0.1548
+ ],
+ "max": [
+ -0.4031,
+ 0.7881,
+ 0.074
+ ]
+ }
+ },
+ "ArmR_UpperArmor": {
+ "mesh": "ArmR_UpperArmor_Mesh.006",
+ "triangles": 664,
+ "vertices": 334,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.6124,
+ 0.6611,
+ -0.1776
+ ],
+ "max": [
+ -0.3317,
+ 0.9359,
+ 0.052
+ ]
+ }
+ },
+ "ArmR_ForearmArmor": {
+ "mesh": "ArmR_ForearmArmor_Mesh.006",
+ "triangles": 638,
+ "vertices": 321,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.6853,
+ 0.414,
+ -0.113
+ ],
+ "max": [
+ -0.3891,
+ 0.732,
+ 0.1643
+ ]
+ }
+ },
+ "ArmR_Shoulder": {
+ "mesh": "ArmR_Shoulder_Mesh.006",
+ "triangles": 608,
+ "vertices": 306,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.6036,
+ 0.7671,
+ -0.2565
+ ],
+ "max": [
+ -0.2408,
+ 1.0741,
+ 0.0735
+ ]
+ }
+ },
+ "ArmR_ShoulderJoint": {
+ "mesh": "ArmR_ShoulderJoint_Mesh.006",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.5127,
+ 0.8355,
+ 0.0029
+ ],
+ "max": [
+ -0.3347,
+ 1.0134,
+ 0.053
+ ]
+ }
+ },
+ "ArmR_UpperBand": {
+ "mesh": "ArmR_UpperBand_Mesh.006",
+ "triangles": 284,
+ "vertices": 144,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.7097,
+ 0.4323,
+ -0.1211
+ ],
+ "max": [
+ -0.3638,
+ 0.6924,
+ 0.1965
+ ]
+ }
+ },
+ "ArmR_UpperBandRivet_Seat": {
+ "mesh": "ArmR_UpperBandRivet_Seat_Mesh.006",
+ "triangles": 444,
+ "vertices": 224,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.5627,
+ 0.5364,
+ 0.2019
+ ],
+ "max": [
+ -0.5107,
+ 0.5884,
+ 0.2105
+ ]
+ }
+ },
+ "ArmR_UpperBandRivet_Head": {
+ "mesh": "ArmR_UpperBandRivet_Head_Mesh.006",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.5541,
+ 0.545,
+ 0.2062
+ ],
+ "max": [
+ -0.5194,
+ 0.5797,
+ 0.2235
+ ]
+ }
+ },
+ "ArmR_WristBand": {
+ "mesh": "ArmR_WristBand_Mesh.006",
+ "triangles": 284,
+ "vertices": 144,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.7175,
+ 0.3803,
+ -0.0834
+ ],
+ "max": [
+ -0.3716,
+ 0.6404,
+ 0.2342
+ ]
+ }
+ },
+ "ArmR_WristBandRivet_Seat": {
+ "mesh": "ArmR_WristBandRivet_Seat_Mesh.006",
+ "triangles": 444,
+ "vertices": 224,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.5705,
+ 0.4844,
+ 0.2396
+ ],
+ "max": [
+ -0.5185,
+ 0.5364,
+ 0.2482
+ ]
+ }
+ },
+ "ArmR_WristBandRivet_Head": {
+ "mesh": "ArmR_WristBandRivet_Head_Mesh.006",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.5619,
+ 0.493,
+ 0.2439
+ ],
+ "max": [
+ -0.5272,
+ 0.5277,
+ 0.2612
+ ]
+ }
+ },
+ "ArmR_Palm": {
+ "mesh": "ArmR_Palm_Mesh.006",
+ "triangles": 604,
+ "vertices": 304,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.6905,
+ 0.3482,
+ -0.0262
+ ],
+ "max": [
+ -0.4111,
+ 0.6225,
+ 0.2176
+ ]
+ }
+ },
+ "WeaponR_Claw0": {
+ "mesh": "WeaponR_Claw0_Mesh",
+ "triangles": 574,
+ "vertices": 289,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.5228,
+ 0.1541,
+ 0.0951
+ ],
+ "max": [
+ -0.3529,
+ 0.6199,
+ 0.4473
+ ]
+ }
+ },
+ "ArmR_Knuckle0_Seat": {
+ "mesh": "ArmR_Knuckle0_Seat_Mesh",
+ "triangles": 444,
+ "vertices": 224,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.454,
+ 0.5571,
+ 0.1979
+ ],
+ "max": [
+ -0.3934,
+ 0.6177,
+ 0.2066
+ ]
+ }
+ },
+ "ArmR_Knuckle0_Head": {
+ "mesh": "ArmR_Knuckle0_Head_Mesh",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.4439,
+ 0.5672,
+ 0.2022
+ ],
+ "max": [
+ -0.4035,
+ 0.6076,
+ 0.2196
+ ]
+ }
+ },
+ "WeaponR_Claw1": {
+ "mesh": "WeaponR_Claw1_Mesh",
+ "triangles": 574,
+ "vertices": 289,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.6576,
+ 0.1541,
+ 0.0951
+ ],
+ "max": [
+ -0.4877,
+ 0.6199,
+ 0.4473
+ ]
+ }
+ },
+ "ArmR_Knuckle1_Seat": {
+ "mesh": "ArmR_Knuckle1_Seat_Mesh",
+ "triangles": 444,
+ "vertices": 224,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.5888,
+ 0.5571,
+ 0.1979
+ ],
+ "max": [
+ -0.5282,
+ 0.6177,
+ 0.2066
+ ]
+ }
+ },
+ "ArmR_Knuckle1_Head": {
+ "mesh": "ArmR_Knuckle1_Head_Mesh",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.5787,
+ 0.5672,
+ 0.2022
+ ],
+ "max": [
+ -0.5383,
+ 0.6076,
+ 0.2196
+ ]
+ }
+ },
+ "WeaponR_Claw2": {
+ "mesh": "WeaponR_Claw2_Mesh",
+ "triangles": 574,
+ "vertices": 289,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.7924,
+ 0.1541,
+ 0.0951
+ ],
+ "max": [
+ -0.6225,
+ 0.6199,
+ 0.4473
+ ]
+ }
+ },
+ "ArmR_Knuckle2_Seat": {
+ "mesh": "ArmR_Knuckle2_Seat_Mesh",
+ "triangles": 444,
+ "vertices": 224,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_dark"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.7237,
+ 0.5571,
+ 0.1979
+ ],
+ "max": [
+ -0.663,
+ 0.6177,
+ 0.2066
+ ]
+ }
+ },
+ "ArmR_Knuckle2_Head": {
+ "mesh": "ArmR_Knuckle2_Head_Mesh",
+ "triangles": 508,
+ "vertices": 256,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold_light"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.7135,
+ 0.5672,
+ 0.2022
+ ],
+ "max": [
+ -0.6731,
+ 0.6076,
+ 0.2196
+ ]
+ }
+ },
+ "ArmR_ShoulderTrim": {
+ "mesh": "ArmR_ShoulderTrim_Mesh",
+ "triangles": 238,
+ "vertices": 121,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_gold"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.4995,
+ 0.9119,
+ 0.0434
+ ],
+ "max": [
+ -0.3094,
+ 1.0641,
+ 0.0819
+ ]
+ }
+ },
+ "Body_DorsalSpine0": {
+ "mesh": "Body_DorsalSpine0_Mesh",
+ "triangles": 412,
+ "vertices": 208,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ 0.0298,
+ 0.9534,
+ -0.2918
+ ],
+ "max": [
+ 0.2646,
+ 1.35,
+ -0.0555
+ ]
+ }
+ },
+ "Body_DorsalSpine1": {
+ "mesh": "Body_DorsalSpine1_Mesh",
+ "triangles": 106,
+ "vertices": 55,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.1185,
+ 0.9558,
+ -0.2935
+ ],
+ "max": [
+ 0.1185,
+ 1.2615,
+ -0.0604
+ ]
+ }
+ },
+ "Body_DorsalSpine2": {
+ "mesh": "Body_DorsalSpine2_Mesh",
+ "triangles": 412,
+ "vertices": 208,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.2583,
+ 0.9538,
+ -0.2918
+ ],
+ "max": [
+ -0.0249,
+ 1.3485,
+ -0.0556
+ ]
+ }
+ },
+ "Head_Chin": {
+ "mesh": "Head_Chin_Mesh",
+ "triangles": 2208,
+ "vertices": 1106,
+ "ngons": 0,
+ "materials": [
+ "SW_HD_basalt"
+ ],
+ "uv_layers": [
+ "UV-Map"
+ ],
+ "color_attributes": [],
+ "active_color": null,
+ "custom_normals": true,
+ "normals_unit_length": true,
+ "shape_keys": 0,
+ "skinned": false,
+ "scale": [
+ 1.0,
+ 1.0,
+ 1.0
+ ],
+ "bounds_unity": {
+ "min": [
+ -0.1651,
+ 0.3329,
+ -0.0585
+ ],
+ "max": [
+ 0.1774,
+ 0.6532,
+ 0.3289
+ ]
+ }
+ }
+ },
+ "armatures": {},
+ "empties": {
+ "Model_g01": [
+ 0.0,
+ 0.0,
+ 0.0
+ ],
+ "Forward": [
+ 0.0,
+ 0.0,
+ 0.75
+ ]
+ },
+ "bounds_unity": {
+ "min": [
+ -0.7924,
+ 0.0,
+ -0.4473
+ ],
+ "max": [
+ 0.7924,
+ 1.35,
+ 0.4473
+ ]
+ },
+ "clips": [],
+ "expected_from_godot": {
+ "triangles": 79780,
+ "bounds_godot": {
+ "min": [
+ -0.7924438118934631,
+ 0.0,
+ -0.44730144739151
+ ],
+ "max": [
+ 0.7924438118934631,
+ 1.350000023841858,
+ 0.4473014771938324
+ ]
+ },
+ "resource_path": "res://assets/models/unit_g01.glb"
+ },
+ "meshes_without_uv": [
+ "ArmL_ShoulderTrim",
+ "ArmR_ShoulderTrim",
+ "Body_DorsalSpine0",
+ "Body_DorsalSpine1",
+ "Body_DorsalSpine2",
+ "Head_EyeL",
+ "Head_EyeR",
+ "Head_LowerToothL0",
+ "Head_LowerToothL1",
+ "Head_LowerToothL2",
+ "Head_LowerToothL3",
+ "Head_LowerToothR0",
+ "Head_LowerToothR1",
+ "Head_LowerToothR2",
+ "Head_LowerToothR3",
+ "Head_MouthEmber",
+ "Head_UpperToothL0",
+ "Head_UpperToothL1",
+ "Head_UpperToothL2",
+ "Head_UpperToothL3",
+ "Head_UpperToothR0",
+ "Head_UpperToothR1",
+ "Head_UpperToothR2",
+ "Head_UpperToothR3",
+ "LegL_KneeGuard",
+ "LegL_Toe0",
+ "LegL_Toe1",
+ "LegL_Toe2",
+ "LegR_KneeGuard",
+ "LegR_Toe0",
+ "LegR_Toe1",
+ "LegR_Toe2",
+ "WeaponL_Claw0",
+ "WeaponL_Claw1",
+ "WeaponL_Claw2",
+ "WeaponR_Claw0",
+ "WeaponR_Claw1",
+ "WeaponR_Claw2"
+ ],
+ "triangles": 79780,
+ "fbx": "Assets/Luneraria/Art/Units/g01.fbx",
+ "fbx_bytes": 5752668,
+ "ok": true
+}
diff --git a/Assets/Luneraria/Art/Units/g01.export.json.meta b/Assets/Luneraria/Art/Units/g01.export.json.meta
new file mode 100644
index 0000000..b34c62a
--- /dev/null
+++ b/Assets/Luneraria/Art/Units/g01.export.json.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: d7a4fb253a9584d0ba79fa033c20eb6b
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Art/Units/g01.fbx b/Assets/Luneraria/Art/Units/g01.fbx
new file mode 100644
index 0000000..a966bb0
Binary files /dev/null and b/Assets/Luneraria/Art/Units/g01.fbx differ
diff --git a/Assets/Luneraria/Art/Units/g01.fbx.meta b/Assets/Luneraria/Art/Units/g01.fbx.meta
new file mode 100644
index 0000000..b1f7e5e
--- /dev/null
+++ b/Assets/Luneraria/Art/Units/g01.fbx.meta
@@ -0,0 +1,111 @@
+fileFormatVersion: 2
+guid: 416c29115e263420dbef5a876b74571c
+ModelImporter:
+ serializedVersion: 24300
+ internalIDToNameTable: []
+ externalObjects: {}
+ materials:
+ materialImportMode: 2
+ materialName: 0
+ materialSearch: 1
+ materialLocation: 1
+ searchTexturesGlobally: 0
+ animations:
+ legacyGenerateAnimations: 4
+ bakeSimulation: 0
+ resampleCurves: 0
+ optimizeGameObjects: 0
+ removeConstantScaleCurves: 0
+ motionNodeName:
+ animationImportErrors:
+ animationImportWarnings:
+ animationRetargetingWarnings:
+ animationDoRetargetingWarnings: 0
+ importAnimatedCustomProperties: 0
+ importConstraints: 0
+ animationCompression: 0
+ animationRotationError: 0.5
+ animationPositionError: 0.5
+ animationScaleError: 0.5
+ animationWrapMode: 0
+ extraExposedTransformPaths: []
+ extraUserProperties: []
+ clipAnimations: []
+ isReadable: 1
+ meshes:
+ lODScreenPercentages: []
+ globalScale: 1
+ meshCompression: 0
+ addColliders: 0
+ useSRGBMaterialColor: 1
+ sortHierarchyByName: 1
+ importPhysicalCameras: 1
+ importVisibility: 0
+ importBlendShapes: 0
+ importCameras: 0
+ importLights: 0
+ nodeNameCollisionStrategy: 1
+ fileIdsGeneration: 2
+ swapUVChannels: 0
+ generateSecondaryUV: 0
+ useFileUnits: 1
+ keepQuads: 0
+ weldVertices: 1
+ bakeAxisConversion: 1
+ preserveHierarchy: 0
+ skinWeightsMode: 0
+ maxBonesPerVertex: 4
+ minBoneWeight: 0.001
+ optimizeBones: 1
+ generateMeshLods: 0
+ meshLodGenerationFlags: 0
+ maximumMeshLod: -1
+ meshOptimizationFlags: -1
+ indexFormat: 0
+ secondaryUVAngleDistortion: 8
+ secondaryUVAreaDistortion: 15.000001
+ secondaryUVHardAngle: 88
+ secondaryUVMarginMethod: 1
+ secondaryUVMinLightmapResolution: 40
+ secondaryUVMinObjectScale: 1
+ secondaryUVPackMargin: 4
+ useFileScale: 1
+ strictVertexDataChecks: 0
+ tangentSpace:
+ normalSmoothAngle: 60
+ normalImportMode: 0
+ tangentImportMode: 0
+ normalCalculationMode: 4
+ legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
+ blendShapeNormalImportMode: 1
+ normalSmoothingSource: 0
+ referencedClips: []
+ importAnimation: 0
+ humanDescription:
+ serializedVersion: 3
+ human: []
+ skeleton: []
+ armTwist: 0.5
+ foreArmTwist: 0.5
+ upperLegTwist: 0.5
+ legTwist: 0.5
+ armStretch: 0.05
+ legStretch: 0.05
+ feetSpacing: 0
+ globalScale: 1
+ rootMotionBoneName:
+ hasTranslationDoF: 0
+ hasExtraRoot: 0
+ skeletonHasParents: 1
+ lastHumanDescriptionAvatarSource: {instanceID: 0}
+ autoGenerateAvatarMappingIfUnspecified: 1
+ animationType: 0
+ humanoidOversampling: 1
+ avatarSetup: 0
+ addHumanoidExtraRootOnlyWhenUsingAvatar: 1
+ importBlendShapeDeformPercent: 1
+ remapMaterialsIfMaterialImportModeIsNone: 0
+ additionalBone: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Editor.meta b/Assets/Luneraria/Editor.meta
new file mode 100644
index 0000000..c0157b6
--- /dev/null
+++ b/Assets/Luneraria/Editor.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4460d353d8e864b71bbfb46336516b2d
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Editor/Art.meta b/Assets/Luneraria/Editor/Art.meta
new file mode 100644
index 0000000..4c06659
--- /dev/null
+++ b/Assets/Luneraria/Editor/Art.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 793ae230624f046acb4639e9b27fa0be
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Editor/Art/ExportReport.cs b/Assets/Luneraria/Editor/Art/ExportReport.cs
new file mode 100644
index 0000000..111a810
--- /dev/null
+++ b/Assets/Luneraria/Editor/Art/ExportReport.cs
@@ -0,0 +1,45 @@
+using System.Collections.Generic;
+using System.IO;
+using Newtonsoft.Json.Linq;
+
+namespace Luneraria.EditorTools
+{
+ ///
+ /// The facts and checks that tools/blender/lune_fbx_export.py writes next to every FBX
+ /// (<id>.export.json). The importer reads the clip data from it; the verifier compares
+ /// the imported model with the Blender side.
+ ///
+ public sealed class ExportReport
+ {
+ public readonly string Path;
+ public readonly JObject Data;
+
+ ExportReport(string path, JObject data)
+ {
+ Path = path;
+ Data = data;
+ }
+
+ public string Id { get { return (string)Data["id"]; } }
+ public string Kind { get { return (string)Data["kind"]; } }
+ public bool Skinned { get { return Kind == "skinned"; } }
+ public bool BlenderOk { get { return (bool)Data["ok"]; } }
+ public JObject Meshes { get { return (JObject)Data["meshes"]; } }
+ public JArray Clips { get { return (JArray)Data["clips"] ?? new JArray(); } }
+
+ /// Report of an FBX asset path, or null if the model was not exported by the pipeline.
+ public static ExportReport ForModel(string modelPath)
+ {
+ string path = System.IO.Path.ChangeExtension(modelPath, ".export.json");
+ if (!File.Exists(path))
+ return null;
+ return new ExportReport(path, JObject.Parse(File.ReadAllText(path)));
+ }
+
+ public static IEnumerable AllModels(string root)
+ {
+ foreach (string path in Directory.GetFiles(root, "*.export.json", SearchOption.AllDirectories))
+ yield return path.Replace('\\', '/').Replace(".export.json", ".fbx");
+ }
+ }
+}
diff --git a/Assets/Luneraria/Editor/Art/ExportReport.cs.meta b/Assets/Luneraria/Editor/Art/ExportReport.cs.meta
new file mode 100644
index 0000000..23c4d8d
--- /dev/null
+++ b/Assets/Luneraria/Editor/Art/ExportReport.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 2ea3ae2e05fa54b17a8ef5eed98cad51
\ No newline at end of file
diff --git a/Assets/Luneraria/Editor/Art/LuneAssetPreview.cs b/Assets/Luneraria/Editor/Art/LuneAssetPreview.cs
new file mode 100644
index 0000000..b5bb98f
--- /dev/null
+++ b/Assets/Luneraria/Editor/Art/LuneAssetPreview.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using UnityEditor;
+using UnityEditor.SceneManagement;
+using UnityEngine;
+using UnityEngine.Rendering;
+
+namespace Luneraria.EditorTools
+{
+ ///
+ /// Renders every pipeline asset in a neutral preview scene (URP, one sun, 3/4 front view) to
+ /// docs/port/screenshots/u2a/. Buildings show their intact state; the tower also its ruin;
+ /// rigged figures their bind pose and the hit frame of attack_a.
+ /// Unity -batchmode -projectPath . -executeMethod Luneraria.EditorTools.LuneAssetPreview.RenderAll
+ ///
+ public static class LuneAssetPreview
+ {
+ const int Width = 1600;
+ const int Height = 1000;
+
+ public static void RenderAll()
+ {
+ int code = 0;
+ try
+ {
+ string folder = Path.Combine(Path.GetDirectoryName(Application.dataPath), "docs/port/screenshots/u2a");
+ Directory.CreateDirectory(folder);
+ EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single);
+ var sun = new GameObject("Sun").AddComponent();
+ sun.type = LightType.Directional;
+ sun.intensity = 1.6f;
+ sun.color = new Color(1f, .89f, .74f);
+ sun.shadows = LightShadows.Soft;
+ sun.transform.rotation = Quaternion.Euler(48f, 150f, 0f);
+ RenderSettings.ambientMode = AmbientMode.Trilight;
+ RenderSettings.ambientSkyColor = new Color(.55f, .6f, .68f);
+ RenderSettings.ambientEquatorColor = new Color(.42f, .42f, .44f);
+ RenderSettings.ambientGroundColor = new Color(.2f, .19f, .18f);
+ var ground = GameObject.CreatePrimitive(PrimitiveType.Plane);
+ ground.transform.localScale = new Vector3(20f, 1f, 20f);
+ var camera = new GameObject("PreviewCamera").AddComponent();
+ camera.clearFlags = CameraClearFlags.SolidColor;
+ camera.backgroundColor = new Color(.16f, .18f, .21f);
+ camera.fieldOfView = 30f;
+ foreach (string model in ExportReport.AllModels("Assets/Luneraria/Art").OrderBy(p => p, StringComparer.Ordinal))
+ {
+ ExportReport report = ExportReport.ForModel(model);
+ var prefab = AssetDatabase.LoadAssetAtPath(model);
+ foreach (var shot in Shots(report))
+ {
+ var instance = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
+ shot.Value(instance);
+ Render(camera, instance, Path.Combine(folder, report.Id + shot.Key + ".png"));
+ UnityEngine.Object.DestroyImmediate(instance);
+ }
+ }
+ }
+ catch (Exception error)
+ {
+ Debug.LogError("LUNE_PREVIEW failed: " + error);
+ code = 1;
+ }
+ EditorApplication.Exit(code);
+ }
+
+ static IEnumerable>> Shots(ExportReport report)
+ {
+ string group = (string)report.Data["group"];
+ if (group == "Buildings")
+ {
+ yield return Shot("", go => Show(go, n => !n.StartsWith("Upper_Damaged") && !n.StartsWith("Debris") && !n.StartsWith("Ruin")));
+ if (report.Id == "grenzwacht")
+ yield return Shot("-ruin", go => Show(go, n => n.StartsWith("Ruin")));
+ }
+ else if (group == "Environment")
+ {
+ yield return Shot("", Row);
+ }
+ else if (report.Skinned)
+ {
+ yield return Shot("", go => Sample(go, "idle", 0f));
+ yield return Shot("-attack_a", go => Sample(go, "attack_a", .9f));
+ }
+ else
+ {
+ yield return Shot("", go => { });
+ }
+ }
+
+ static KeyValuePair> Shot(string suffix, Action prepare)
+ {
+ return new KeyValuePair>(suffix, prepare);
+ }
+
+ static void Show(GameObject root, Func visible)
+ {
+ foreach (Renderer renderer in root.GetComponentsInChildren(true))
+ renderer.enabled = visible(renderer.gameObject.name);
+ }
+
+ /// The prop library keeps every prop at the origin; the preview sets them out in a grid.
+ static void Row(GameObject root)
+ {
+ const int columns = 5;
+ const float cell = 7.5f;
+ int index = 0;
+ foreach (Transform child in root.transform.Cast().OrderBy(t => t.name, StringComparer.Ordinal).ToList())
+ {
+ var renderer = child.GetComponent();
+ if (renderer == null)
+ continue;
+ Vector3 center = renderer.bounds.center;
+ var slot = new Vector3((index % columns) * cell, 0f, -(index / columns) * cell);
+ child.position += slot - new Vector3(center.x, 0f, center.z);
+ index++;
+ }
+ }
+
+ static void Sample(GameObject root, string clipName, float seconds)
+ {
+ string path = AssetDatabase.GetAssetPath(PrefabUtility.GetCorrespondingObjectFromSource(root));
+ AnimationClip clip = AssetDatabase.LoadAllAssetsAtPath(path).OfType().FirstOrDefault(c => c.name == clipName);
+ if (clip != null)
+ clip.SampleAnimation(root, seconds);
+ }
+
+ static void Render(Camera camera, GameObject root, string file)
+ {
+ var renderers = root.GetComponentsInChildren().Where(r => r.enabled).ToList();
+ Bounds bounds = renderers[0].bounds;
+ foreach (Renderer renderer in renderers)
+ bounds.Encapsulate(renderer.bounds);
+ // 3/4 front view: the models face +Z, the camera stands in front, to the right, above.
+ Vector3 direction = new Vector3(.62f, .42f, 1f).normalized;
+ float radius = bounds.extents.magnitude;
+ float distance = radius / Mathf.Sin(camera.fieldOfView * .5f * Mathf.Deg2Rad) * .92f;
+ camera.aspect = (float)Width / Height;
+ camera.transform.position = bounds.center + direction * distance;
+ camera.transform.LookAt(bounds.center);
+ camera.nearClipPlane = Mathf.Max(.01f, distance - radius * 2f);
+ camera.farClipPlane = distance + radius * 4f;
+ var target = new RenderTexture(Width, Height, 24, RenderTextureFormat.ARGB32) { antiAliasing = 8 };
+ camera.targetTexture = target;
+ camera.Render();
+ RenderTexture.active = target;
+ var image = new Texture2D(Width, Height, TextureFormat.RGB24, false);
+ image.ReadPixels(new Rect(0, 0, Width, Height), 0, 0);
+ image.Apply();
+ File.WriteAllBytes(file, image.EncodeToPNG());
+ RenderTexture.active = null;
+ camera.targetTexture = null;
+ UnityEngine.Object.DestroyImmediate(target);
+ UnityEngine.Object.DestroyImmediate(image);
+ Debug.Log("LUNE_PREVIEW wrote " + file);
+ }
+ }
+}
diff --git a/Assets/Luneraria/Editor/Art/LuneAssetPreview.cs.meta b/Assets/Luneraria/Editor/Art/LuneAssetPreview.cs.meta
new file mode 100644
index 0000000..b85f3c0
--- /dev/null
+++ b/Assets/Luneraria/Editor/Art/LuneAssetPreview.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 50634406ba3e34d398502bba3379f6af
\ No newline at end of file
diff --git a/Assets/Luneraria/Editor/Art/LuneAssetVerifier.cs b/Assets/Luneraria/Editor/Art/LuneAssetVerifier.cs
new file mode 100644
index 0000000..d2a6164
--- /dev/null
+++ b/Assets/Luneraria/Editor/Art/LuneAssetVerifier.cs
@@ -0,0 +1,262 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Newtonsoft.Json.Linq;
+using UnityEditor;
+using UnityEngine;
+
+namespace Luneraria.EditorTools
+{
+ ///
+ /// Checks every imported FBX of the Blender pipeline against the facts Blender wrote next to it
+ /// (U2A): transforms free of axis rotations, mesh names, triangles, bounds, material slots,
+ /// normals, tangents, UVs, vertex colours, root bone and bone names, clips with loop flags and
+ /// contact events, forward direction. Batch entry:
+ /// Unity -batchmode -projectPath . -executeMethod Luneraria.EditorTools.LuneAssetVerifier.VerifyAll
+ /// Result: docs/port/logs/u2a/unity-verify.json; exit code 0 only if every check passed.
+ ///
+ public static class LuneAssetVerifier
+ {
+ const string Root = "Assets/Luneraria/Art";
+ const float BoundsTolerance = 0.002f;
+
+ /// Re-imports every pipeline model (after import rules or the render pipeline changed).
+ public static void ReimportArt()
+ {
+ AssetDatabase.ImportAsset(Root, ImportAssetOptions.ImportRecursive | ImportAssetOptions.ForceUpdate | ImportAssetOptions.ForceSynchronousImport);
+ Debug.Log("LUNE_VERIFY reimported " + Root);
+ EditorApplication.Exit(0);
+ }
+
+ public static void VerifyAll()
+ {
+ int code = 1;
+ try
+ {
+ AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
+ var results = new JArray();
+ bool all = true;
+ foreach (string model in ExportReport.AllModels(Root).OrderBy(p => p, StringComparer.Ordinal))
+ {
+ JObject result = Verify(model);
+ results.Add(result);
+ all &= (bool)result["ok"];
+ var failed = ((JArray)result["checks"]).Where(c => !(bool)c["ok"]).ToList();
+ Debug.Log(string.Format("LUNE_VERIFY {0} {1}: {2} checks, {3} failed{4}", failed.Count == 0 ? "OK" : "FAIL", result["id"],
+ ((JArray)result["checks"]).Count, failed.Count, string.Concat(failed.Select(c => "\n FAIL " + c["check"] + ": " + c["detail"]))));
+ }
+ string logs = Path.Combine(Path.GetDirectoryName(Application.dataPath), "docs/port/logs/u2a");
+ Directory.CreateDirectory(logs);
+ var summary = new JObject { ["unity"] = Application.unityVersion, ["ok"] = all, ["assets"] = results };
+ File.WriteAllText(Path.Combine(logs, "unity-verify.json"), summary.ToString() + "\n");
+ code = all ? 0 : 2;
+ }
+ catch (Exception error)
+ {
+ Debug.LogError("LUNE_VERIFY crashed: " + error);
+ }
+ EditorApplication.Exit(code);
+ }
+
+ sealed class Checks
+ {
+ public readonly JArray List = new JArray();
+
+ public void Add(string name, bool ok, object detail = null)
+ {
+ List.Add(new JObject { ["check"] = name, ["ok"] = ok, ["detail"] = detail == null ? "" : JToken.FromObject(detail).ToString(Newtonsoft.Json.Formatting.None) });
+ }
+
+ public bool Ok { get { return List.All(c => (bool)c["ok"]); } }
+ }
+
+ public static JObject Verify(string modelPath)
+ {
+ ExportReport report = ExportReport.ForModel(modelPath);
+ var checks = new Checks();
+ var facts = new JObject();
+ var root = AssetDatabase.LoadAssetAtPath(modelPath);
+ checks.Add("blender_checks_passed", report.BlenderOk);
+ checks.Add("imported", root != null, modelPath);
+ if (root == null)
+ return Result(report, checks, facts);
+ var importer = (ModelImporter)AssetImporter.GetAtPath(modelPath);
+ checks.Add("import_rules_applied", importer.globalScale == 1f && importer.useFileScale && importer.bakeAxisConversion
+ && importer.importNormals == ModelImporterNormals.Import && importer.importTangents == ModelImporterTangents.Import);
+ checks.Add("root_transform_identity", IsIdentity(root.transform), Describe(root.transform));
+ var bones = new HashSet();
+ foreach (var skinned in root.GetComponentsInChildren(true))
+ foreach (Transform bone in skinned.bones)
+ bones.Add(bone);
+ // Blender objects carry no rotation or scale; after the axis bake every node that is not
+ // a bone must be clean, otherwise the conversion ended up in the hierarchy.
+ var rotated = root.GetComponentsInChildren(true).Where(t => t != root.transform && !bones.Contains(t) && !IsClean(t)).Select(Describe).ToList();
+ checks.Add("node_transforms_axis_clean", rotated.Count == 0, rotated.Take(8).ToList());
+
+ var renderers = root.GetComponentsInChildren(true).Where(r => r is MeshRenderer || r is SkinnedMeshRenderer).ToList();
+ var names = renderers.Select(r => r.gameObject.name).OrderBy(n => n, StringComparer.Ordinal).ToList();
+ var expectedNames = report.Meshes.Properties().Select(p => p.Name).OrderBy(n => n, StringComparer.Ordinal).ToList();
+ checks.Add("mesh_names", names.SequenceEqual(expectedNames), names.Except(expectedNames).Concat(expectedNames.Except(names)).Take(12).ToList());
+
+ int triangles = 0;
+ var wrongTriangles = new List();
+ var wrongMaterials = new List();
+ var badNormals = new List();
+ var badTangents = new List();
+ var missingUv = new List();
+ var missingColors = new List();
+ var low = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
+ var high = new Vector3(float.MinValue, float.MinValue, float.MinValue);
+ int withoutTangents = 0;
+ foreach (Renderer renderer in renderers)
+ {
+ Mesh mesh = renderer is SkinnedMeshRenderer skinned ? skinned.sharedMesh : renderer.GetComponent().sharedMesh;
+ string name = renderer.gameObject.name;
+ var blender = (JObject)report.Meshes[name];
+ int count = mesh.triangles.Length / 3;
+ triangles += count;
+ if (blender != null && (int)blender["triangles"] != count)
+ wrongTriangles.Add(name + " " + count + "/" + blender["triangles"]);
+ if (blender != null)
+ {
+ var want = ((JArray)blender["materials"]).Select(m => (string)m).OrderBy(m => m, StringComparer.Ordinal).ToList();
+ var got = renderer.sharedMaterials.Select(m => m != null ? m.name : "").OrderBy(m => m, StringComparer.Ordinal).ToList();
+ if (!want.SequenceEqual(got))
+ wrongMaterials.Add(name + ": " + string.Join(",", got) + " / " + string.Join(",", want));
+ bool hasUv = ((JArray)blender["uv_layers"]).Count > 0;
+ if (hasUv && mesh.uv.Length != mesh.vertexCount)
+ missingUv.Add(name);
+ if (((JArray)blender["color_attributes"]).Count > 0 && mesh.colors.Length != mesh.vertexCount)
+ missingColors.Add(name);
+ Vector4[] tangents = mesh.tangents;
+ if (hasUv)
+ {
+ if (tangents.Length != mesh.vertexCount || tangents.Any(t => Mathf.Abs(Mathf.Abs(t.w) - 1f) > 1e-3f))
+ badTangents.Add(name);
+ }
+ else if (tangents.Length == 0)
+ {
+ withoutTangents++;
+ }
+ }
+ Vector3[] normals = mesh.normals;
+ if (normals.Length != mesh.vertexCount || normals.Any(n => Mathf.Abs(n.magnitude - 1f) > 1e-3f))
+ badNormals.Add(name);
+ Matrix4x4 toRoot = root.transform.worldToLocalMatrix * renderer.transform.localToWorldMatrix;
+ foreach (Vector3 vertex in mesh.vertices)
+ {
+ Vector3 p = toRoot.MultiplyPoint3x4(vertex);
+ low = Vector3.Min(low, p);
+ high = Vector3.Max(high, p);
+ }
+ }
+ facts["triangles"] = triangles;
+ facts["renderers"] = renderers.Count;
+ facts["meshes_without_uv_and_tangents"] = withoutTangents;
+ checks.Add("triangles", triangles == (int)report.Data["triangles"] && wrongTriangles.Count == 0, triangles + " unity / " + report.Data["triangles"] + " blender " + string.Join("; ", wrongTriangles.Take(5)));
+ checks.Add("material_slots", wrongMaterials.Count == 0, wrongMaterials.Take(5).ToList());
+ checks.Add("normals_unit_length", badNormals.Count == 0, badNormals.Take(8).ToList());
+ checks.Add("tangents_where_uv", badTangents.Count == 0, badTangents.Take(8).ToList());
+ checks.Add("uvs_where_blender_has_uv", missingUv.Count == 0, missingUv.Take(8).ToList());
+ checks.Add("vertex_colors", missingColors.Count == 0, missingColors.Take(8).ToList());
+
+ var bounds = (JObject)report.Data["bounds_unity"];
+ if (bounds != null)
+ {
+ var wantLow = ToVector((JArray)bounds["min"]);
+ var wantHigh = ToVector((JArray)bounds["max"]);
+ float worst = Mathf.Max(MaxAbs(low - wantLow), MaxAbs(high - wantHigh));
+ facts["bounds_min"] = new JArray(low.x, low.y, low.z);
+ facts["bounds_max"] = new JArray(high.x, high.y, high.z);
+ checks.Add("bounds_axes_scale", worst < BoundsTolerance, string.Format("largest difference {0:0.00000} m; unity {1} {2}", worst, low.ToString("F3"), high.ToString("F3")));
+ }
+
+ JObject empties = (JObject)report.Data["empties"];
+ JProperty forward = empties?.Properties().FirstOrDefault(p => p.Name.StartsWith("Forward"));
+ if (forward != null)
+ {
+ Transform marker = root.GetComponentsInChildren(true).FirstOrDefault(t => t.name.StartsWith("Forward"));
+ Vector3 at = marker != null ? root.transform.InverseTransformPoint(marker.position) : Vector3.zero;
+ checks.Add("forward_is_plus_z", marker != null && at.z > 0.1f && Mathf.Abs(at.x) < 1e-3f, at.ToString("F3"));
+ }
+
+ if (report.Skinned)
+ VerifyRig(modelPath, report, root, checks, facts);
+ return Result(report, checks, facts);
+ }
+
+ static void VerifyRig(string modelPath, ExportReport report, GameObject root, Checks checks, JObject facts)
+ {
+ var skinned = root.GetComponentsInChildren(true);
+ checks.Add("skinned_mesh", skinned.Length >= 1, skinned.Length);
+ var armature = (JObject)((JObject)report.Data["armatures"]).Properties().First().Value;
+ var wantBones = ((JArray)armature["bones"]).Select(b => (string)b).OrderBy(b => b, StringComparer.Ordinal).ToList();
+ string wantRoot = (string)((JArray)armature["roots"])[0];
+ foreach (SkinnedMeshRenderer renderer in skinned)
+ {
+ var got = renderer.bones.Select(b => b.name).Distinct().OrderBy(b => b, StringComparer.Ordinal).ToList();
+ checks.Add("bone_names " + renderer.name, got.SequenceEqual(wantBones), got.Except(wantBones).Concat(wantBones.Except(got)).ToList());
+ checks.Add("root_bone " + renderer.name, renderer.rootBone != null && renderer.rootBone.name == wantRoot, renderer.rootBone != null ? renderer.rootBone.name : "none");
+ }
+ UnityEngine.Object[] assets = AssetDatabase.LoadAllAssetsAtPath(modelPath);
+ var avatar = assets.OfType().FirstOrDefault();
+ checks.Add("generic_avatar", avatar != null && avatar.isValid && !avatar.isHuman, avatar != null ? avatar.name : "none");
+ var clips = assets.OfType().Where(c => !c.name.StartsWith("__preview__")).ToDictionary(c => c.name, c => c);
+ var wrong = new List();
+ foreach (JToken clip in report.Clips)
+ {
+ string name = (string)clip["name"];
+ if (!clips.TryGetValue(name, out AnimationClip unity))
+ {
+ wrong.Add(name + " missing");
+ continue;
+ }
+ float seconds = (float)clip["seconds"];
+ float frame = 1f / (float)report.Data["fps"];
+ if (Mathf.Abs(unity.length - seconds) > frame * 0.5f)
+ wrong.Add(string.Format("{0} length {1:0.000}/{2:0.000}", name, unity.length, seconds));
+ if (unity.isLooping != (bool)clip["loop"])
+ wrong.Add(name + " loop " + unity.isLooping);
+ double contact = (double)clip["contact_seconds"];
+ AnimationEvent[] events = AnimationUtility.GetAnimationEvents(unity);
+ bool hasContact = events.Any(e => e.functionName == LuneModelPostprocessor.ContactEvent && Mathf.Abs(e.time - (float)contact) < frame);
+ if (contact > 0 && !hasContact)
+ wrong.Add(name + " contact event");
+ }
+ var extra = clips.Keys.Except(report.Clips.Select(c => (string)c["name"])).ToList();
+ checks.Add("clips", wrong.Count == 0 && extra.Count == 0, wrong.Concat(extra.Select(e => e + " unexpected")).ToList());
+ facts["clips"] = new JArray(clips.Values.OrderBy(c => c.name).Select(c => new JObject { ["name"] = c.name, ["length"] = c.length, ["loop"] = c.isLooping, ["events"] = AnimationUtility.GetAnimationEvents(c).Length }));
+ }
+
+ static JObject Result(ExportReport report, Checks checks, JObject facts)
+ {
+ return new JObject { ["id"] = report.Id, ["kind"] = report.Kind, ["ok"] = checks.Ok, ["checks"] = checks.List, ["facts"] = facts };
+ }
+
+ static bool IsIdentity(Transform t)
+ {
+ return t.localPosition.sqrMagnitude < 1e-10f && IsClean(t);
+ }
+
+ static bool IsClean(Transform t)
+ {
+ return Quaternion.Angle(t.localRotation, Quaternion.identity) < 0.01f && (t.localScale - Vector3.one).sqrMagnitude < 1e-8f;
+ }
+
+ static string Describe(Transform t)
+ {
+ return string.Format("{0} pos {1} rot {2} scale {3}", t.name, t.localPosition.ToString("F4"), t.localEulerAngles.ToString("F2"), t.localScale.ToString("F4"));
+ }
+
+ static Vector3 ToVector(JArray values)
+ {
+ return new Vector3((float)values[0], (float)values[1], (float)values[2]);
+ }
+
+ static float MaxAbs(Vector3 v)
+ {
+ return Mathf.Max(Mathf.Abs(v.x), Mathf.Max(Mathf.Abs(v.y), Mathf.Abs(v.z)));
+ }
+ }
+}
diff --git a/Assets/Luneraria/Editor/Art/LuneAssetVerifier.cs.meta b/Assets/Luneraria/Editor/Art/LuneAssetVerifier.cs.meta
new file mode 100644
index 0000000..b793b59
--- /dev/null
+++ b/Assets/Luneraria/Editor/Art/LuneAssetVerifier.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 588d50b5a3531448691e7370abd8dc6e
\ No newline at end of file
diff --git a/Assets/Luneraria/Editor/Art/LuneModelPostprocessor.cs b/Assets/Luneraria/Editor/Art/LuneModelPostprocessor.cs
new file mode 100644
index 0000000..9c80917
--- /dev/null
+++ b/Assets/Luneraria/Editor/Art/LuneModelPostprocessor.cs
@@ -0,0 +1,78 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+
+namespace Luneraria.EditorTools
+{
+ ///
+ /// Import rules for every FBX of the Blender pipeline under Assets/Luneraria/Art (U2A).
+ /// Metres stay metres, Blender's Z-up axes are converted by baking (no root rotation),
+ /// normals and tangents come from the file, rigs are generic with the Blender bone names,
+ /// and clips get their Blender action names, loop flags and contact events.
+ ///
+ public sealed class LuneModelPostprocessor : AssetPostprocessor
+ {
+ public const string ArtRoot = "Assets/Luneraria/Art/";
+ /// Raised on the figure at the hit frame of attack and ability clips.
+ public const string ContactEvent = "OnLuneContact";
+
+ public override uint GetVersion() { return 3; }
+
+ void OnPreprocessModel()
+ {
+ if (!assetPath.StartsWith(ArtRoot) || !assetPath.EndsWith(".fbx"))
+ return;
+ ExportReport report = ExportReport.ForModel(assetPath);
+ var importer = (ModelImporter)assetImporter;
+ importer.globalScale = 1f;
+ importer.useFileScale = true;
+ importer.bakeAxisConversion = true;
+ importer.importCameras = false;
+ importer.importLights = false;
+ importer.importVisibility = false;
+ importer.importBlendShapes = false;
+ importer.importNormals = ModelImporterNormals.Import;
+ importer.importTangents = ModelImporterTangents.Import;
+ importer.meshCompression = ModelImporterMeshCompression.Off;
+ importer.isReadable = true;
+ importer.materialImportMode = ModelImporterMaterialImportMode.ImportViaMaterialDescription;
+ importer.materialLocation = ModelImporterMaterialLocation.InPrefab;
+ bool skinned = report != null && report.Skinned;
+ importer.animationType = skinned ? ModelImporterAnimationType.Generic : ModelImporterAnimationType.None;
+ importer.avatarSetup = skinned ? ModelImporterAvatarSetup.CreateFromThisModel : ModelImporterAvatarSetup.NoAvatar;
+ importer.importAnimation = skinned;
+ importer.optimizeGameObjects = false;
+ importer.animationCompression = ModelImporterAnimationCompression.Off;
+ importer.resampleCurves = false;
+ }
+
+ void OnPreprocessAnimation()
+ {
+ if (!assetPath.StartsWith(ArtRoot) || !assetPath.EndsWith(".fbx"))
+ return;
+ ExportReport report = ExportReport.ForModel(assetPath);
+ if (report == null || !report.Skinned)
+ return;
+ var importer = (ModelImporter)assetImporter;
+ var blender = report.Clips.ToDictionary(c => (string)c["name"], c => c);
+ var clips = new List();
+ foreach (ModelImporterClipAnimation clip in importer.defaultClipAnimations)
+ {
+ // Blender names takes "|"; Unity keeps the action name.
+ string name = clip.takeName.Contains("|") ? clip.takeName.Substring(clip.takeName.LastIndexOf('|') + 1) : clip.takeName;
+ clip.name = name;
+ if (blender.TryGetValue(name, out var facts))
+ {
+ clip.loopTime = (bool)facts["loop"];
+ double contact = (double)facts["contact_seconds"];
+ double seconds = (double)facts["seconds"];
+ if (contact > 0.0 && seconds > 0.0)
+ clip.events = new[] { new AnimationEvent { functionName = ContactEvent, time = (float)(contact / seconds) } };
+ }
+ clips.Add(clip);
+ }
+ importer.clipAnimations = clips.ToArray();
+ }
+ }
+}
diff --git a/Assets/Luneraria/Editor/Art/LuneModelPostprocessor.cs.meta b/Assets/Luneraria/Editor/Art/LuneModelPostprocessor.cs.meta
new file mode 100644
index 0000000..7a19b10
--- /dev/null
+++ b/Assets/Luneraria/Editor/Art/LuneModelPostprocessor.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 3eb06f326c30446a4a9e3e2be3aee948
\ No newline at end of file
diff --git a/Assets/Luneraria/Editor/Luneraria.Editor.asmdef b/Assets/Luneraria/Editor/Luneraria.Editor.asmdef
new file mode 100644
index 0000000..d7b05c4
--- /dev/null
+++ b/Assets/Luneraria/Editor/Luneraria.Editor.asmdef
@@ -0,0 +1,22 @@
+{
+ "name": "Luneraria.Editor",
+ "rootNamespace": "Luneraria.EditorTools",
+ "references": [
+ "Luneraria.Core",
+ "Unity.RenderPipelines.Core.Runtime",
+ "Unity.RenderPipelines.Universal.Runtime"
+ ],
+ "includePlatforms": [
+ "Editor"
+ ],
+ "excludePlatforms": [],
+ "allowUnsafeCode": false,
+ "overrideReferences": true,
+ "precompiledReferences": [
+ "Newtonsoft.Json.dll"
+ ],
+ "autoReferenced": false,
+ "defineConstraints": [],
+ "versionDefines": [],
+ "noEngineReferences": false
+}
diff --git a/Assets/Luneraria/Editor/Luneraria.Editor.asmdef.meta b/Assets/Luneraria/Editor/Luneraria.Editor.asmdef.meta
new file mode 100644
index 0000000..89a0ce0
--- /dev/null
+++ b/Assets/Luneraria/Editor/Luneraria.Editor.asmdef.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: f6cff9d287b764627a17a7e3c7b99a6b
+AssemblyDefinitionImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Editor/Setup.meta b/Assets/Luneraria/Editor/Setup.meta
new file mode 100644
index 0000000..094d697
--- /dev/null
+++ b/Assets/Luneraria/Editor/Setup.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 695e40eeb3cef4a898659650d64902e2
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Editor/Setup/LuneProjectSetup.cs b/Assets/Luneraria/Editor/Setup/LuneProjectSetup.cs
new file mode 100644
index 0000000..401bfd0
--- /dev/null
+++ b/Assets/Luneraria/Editor/Setup/LuneProjectSetup.cs
@@ -0,0 +1,80 @@
+using System.IO;
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.Rendering;
+using UnityEngine.Rendering.Universal;
+
+namespace Luneraria.EditorTools
+{
+ ///
+ /// Rendering setup of the project (URP asset and renderer, linear colour space), idempotent.
+ /// Unity -batchmode -projectPath . -executeMethod Luneraria.EditorTools.LuneProjectSetup.ConfigureRendering
+ ///
+ public static class LuneProjectSetup
+ {
+ public const string SettingsFolder = "Assets/Luneraria/Settings/Rendering";
+ public const string PipelinePath = SettingsFolder + "/Luneraria_URP.asset";
+ public const string RendererPath = SettingsFolder + "/Luneraria_URP_Renderer.asset";
+
+ public static void ConfigureRendering()
+ {
+ int code = 0;
+ try
+ {
+ Configure();
+ }
+ catch (System.Exception error)
+ {
+ Debug.LogError("LUNE_SETUP failed: " + error);
+ code = 1;
+ }
+ EditorApplication.Exit(code);
+ }
+
+ public static UniversalRenderPipelineAsset Configure()
+ {
+ Directory.CreateDirectory(SettingsFolder);
+ AssetDatabase.Refresh();
+ var asset = AssetDatabase.LoadAssetAtPath(PipelinePath);
+ if (asset == null)
+ {
+ var renderer = ScriptableObject.CreateInstance();
+ AssetDatabase.CreateAsset(renderer, RendererPath);
+ ResourceReloader.ReloadAllNullIn(renderer, UniversalRenderPipelineAsset.packagePath);
+ asset = UniversalRenderPipelineAsset.Create(renderer);
+ AssetDatabase.CreateAsset(asset, PipelinePath);
+ }
+ // The Godot sun reaches 190 m with four splits (scripts/luneraria/view/lune_world.gd).
+ asset.shadowDistance = 190f;
+ asset.shadowCascadeCount = 4;
+ asset.supportsHDR = true;
+ asset.msaaSampleCount = 4;
+ asset.useSRPBatcher = true;
+ EditorUtility.SetDirty(asset);
+ GraphicsSettings.defaultRenderPipeline = asset;
+ int current = QualitySettings.GetQualityLevel();
+ for (int level = 0; level < QualitySettings.names.Length; level++)
+ {
+ QualitySettings.SetQualityLevel(level, false);
+ QualitySettings.renderPipeline = asset;
+ }
+ QualitySettings.SetQualityLevel(current, false);
+ PlayerSettings.colorSpace = ColorSpace.Linear;
+ MoveInto("Assets/UniversalRenderPipelineGlobalSettings.asset", SettingsFolder + "/UniversalRenderPipelineGlobalSettings.asset");
+ MoveInto("Assets/DefaultVolumeProfile.asset", SettingsFolder + "/DefaultVolumeProfile.asset");
+ AssetDatabase.SaveAssets();
+ Debug.Log("LUNE_SETUP rendering: " + PipelinePath + ", colour space " + PlayerSettings.colorSpace);
+ return asset;
+ }
+
+ static void MoveInto(string from, string to)
+ {
+ if (File.Exists(from) && !File.Exists(to))
+ {
+ string error = AssetDatabase.MoveAsset(from, to);
+ if (!string.IsNullOrEmpty(error))
+ Debug.LogWarning("LUNE_SETUP move " + from + ": " + error);
+ }
+ }
+ }
+}
diff --git a/Assets/Luneraria/Editor/Setup/LuneProjectSetup.cs.meta b/Assets/Luneraria/Editor/Setup/LuneProjectSetup.cs.meta
new file mode 100644
index 0000000..5c7f7fb
--- /dev/null
+++ b/Assets/Luneraria/Editor/Setup/LuneProjectSetup.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: e7bff4280437a4ab7bbe7bcaef5cf486
\ No newline at end of file
diff --git a/Assets/Luneraria/Settings.meta b/Assets/Luneraria/Settings.meta
new file mode 100644
index 0000000..146be7d
--- /dev/null
+++ b/Assets/Luneraria/Settings.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 9ca8da48623284af8ad6bdfdb0af7a1a
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Settings/Rendering.meta b/Assets/Luneraria/Settings/Rendering.meta
new file mode 100644
index 0000000..9cb1330
--- /dev/null
+++ b/Assets/Luneraria/Settings/Rendering.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 7d08bc5b72ee04727bf259d3ad7f45e0
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/DefaultVolumeProfile.asset b/Assets/Luneraria/Settings/Rendering/DefaultVolumeProfile.asset
similarity index 100%
rename from Assets/DefaultVolumeProfile.asset
rename to Assets/Luneraria/Settings/Rendering/DefaultVolumeProfile.asset
diff --git a/Assets/DefaultVolumeProfile.asset.meta b/Assets/Luneraria/Settings/Rendering/DefaultVolumeProfile.asset.meta
similarity index 100%
rename from Assets/DefaultVolumeProfile.asset.meta
rename to Assets/Luneraria/Settings/Rendering/DefaultVolumeProfile.asset.meta
diff --git a/Assets/Luneraria/Settings/Rendering/Luneraria_URP.asset b/Assets/Luneraria/Settings/Rendering/Luneraria_URP.asset
new file mode 100644
index 0000000..3386d2f
--- /dev/null
+++ b/Assets/Luneraria/Settings/Rendering/Luneraria_URP.asset
@@ -0,0 +1,143 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3}
+ m_Name: Luneraria_URP
+ m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalRenderPipelineAsset
+ k_AssetVersion: 13
+ k_AssetPreviousVersion: 13
+ m_RendererType: 1
+ m_RendererData: {fileID: 0}
+ m_RendererDataList:
+ - {fileID: 11400000, guid: 4f1d1577e34314798a12f2f2556faaec, type: 2}
+ m_DefaultRendererIndex: 0
+ m_RequireDepthTexture: 0
+ m_RequireOpaqueTexture: 0
+ m_OpaqueDownsampling: 1
+ m_SupportsTerrainHoles: 1
+ m_SupportsHDR: 1
+ m_HDRColorBufferPrecision: 0
+ m_MSAA: 4
+ m_RenderScale: 1
+ m_UpscalingFilter: 0
+ m_FsrOverrideSharpness: 0
+ m_FsrSharpness: 0.92
+ m_EnableLODCrossFade: 1
+ m_LODCrossFadeDitheringType: 1
+ m_ShEvalMode: 0
+ m_LightProbeSystem: 0
+ m_ProbeVolumeMemoryBudget: 1024
+ m_ProbeVolumeBlendingMemoryBudget: 256
+ m_SupportProbeVolumeGPUStreaming: 0
+ m_SupportProbeVolumeDiskStreaming: 0
+ m_SupportProbeVolumeScenarios: 0
+ m_SupportProbeVolumeScenarioBlending: 0
+ m_ProbeVolumeSHBands: 1
+ m_MainLightRenderingMode: 1
+ m_MainLightShadowsSupported: 1
+ m_MainLightShadowmapResolution: 2048
+ m_AdditionalLightsRenderingMode: 1
+ m_AdditionalLightsPerObjectLimit: 4
+ m_AdditionalLightShadowsSupported: 0
+ m_AdditionalLightsShadowmapResolution: 2048
+ m_AdditionalLightsShadowResolutionTierLow: 256
+ m_AdditionalLightsShadowResolutionTierMedium: 512
+ m_AdditionalLightsShadowResolutionTierHigh: 1024
+ m_ReflectionProbeBlending: 0
+ m_ReflectionProbeBoxProjection: 0
+ m_ReflectionProbeAtlas: 1
+ m_ShadowDistance: 190
+ m_ShadowCascadeCount: 4
+ m_Cascade2Split: 0.25
+ m_Cascade3Split: {x: 0.1, y: 0.3}
+ m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.467}
+ m_CascadeBorder: 0.2
+ m_ShadowDepthBias: 1
+ m_ShadowNormalBias: 1
+ m_AnyShadowsSupported: 1
+ m_SoftShadowsSupported: 0
+ m_ConservativeEnclosingSphere: 1
+ m_NumIterationsEnclosingSphere: 64
+ m_SoftShadowQuality: 2
+ m_AdditionalLightsCookieResolution: 2048
+ m_AdditionalLightsCookieFormat: 3
+ m_UseSRPBatcher: 1
+ m_SupportsDynamicBatching: 0
+ m_MixedLightingSupported: 1
+ m_SupportsLightCookies: 1
+ m_SupportsLightLayers: 0
+ m_DebugLevel: 0
+ m_StoreActionsOptimization: 0
+ m_UseAdaptivePerformance: 1
+ m_ColorGradingMode: 0
+ m_ColorGradingLutSize: 32
+ m_AllowPostProcessAlphaOutput: 0
+ m_UseFastSRGBLinearConversion: 0
+ m_SupportDataDrivenLensFlare: 1
+ m_SupportScreenSpaceLensFlare: 1
+ m_GPUResidentDrawerMode: 0
+ m_SmallMeshScreenPercentage: 0
+ m_GPUResidentDrawerEnableOcclusionCullingInCameras: 0
+ m_ShadowType: 1
+ m_LocalShadowsSupported: 0
+ m_LocalShadowsAtlasResolution: 256
+ m_MaxPixelLights: 0
+ m_ShadowAtlasResolution: 256
+ m_VolumeFrameworkUpdateMode: 0
+ m_VolumeProfile: {fileID: 0}
+ apvScenesData:
+ obsoleteSceneBounds:
+ m_Keys: []
+ m_Values: []
+ obsoleteHasProbeVolumes:
+ m_Keys: []
+ m_Values:
+ m_PrefilteringModeMainLightShadows: 1
+ m_PrefilteringModeAdditionalLight: 4
+ m_PrefilteringModeAdditionalLightShadows: 1
+ m_PrefilterXRKeywords: 0
+ m_PrefilteringModeForwardPlus: 1
+ m_PrefilteringModeDeferredRendering: 1
+ m_PrefilteringModeScreenSpaceOcclusion: 1
+ m_PrefilterDebugKeywords: 0
+ m_PrefilterWriteRenderingLayers: 0
+ m_PrefilterHDROutput: 0
+ m_PrefilterAlphaOutput: 0
+ m_PrefilterSSAODepthNormals: 0
+ m_PrefilterSSAOSourceDepthLow: 0
+ m_PrefilterSSAOSourceDepthMedium: 0
+ m_PrefilterSSAOSourceDepthHigh: 0
+ m_PrefilterSSAOInterleaved: 0
+ m_PrefilterSSAOBlueNoise: 0
+ m_PrefilterSSAOSampleCountLow: 0
+ m_PrefilterSSAOSampleCountMedium: 0
+ m_PrefilterSSAOSampleCountHigh: 0
+ m_PrefilterDBufferMRT1: 0
+ m_PrefilterDBufferMRT2: 0
+ m_PrefilterDBufferMRT3: 0
+ m_PrefilterSoftShadowsQualityLow: 0
+ m_PrefilterSoftShadowsQualityMedium: 0
+ m_PrefilterSoftShadowsQualityHigh: 0
+ m_PrefilterSoftShadows: 0
+ m_PrefilterScreenCoord: 0
+ m_PrefilterScreenSpaceIrradiance: 0
+ m_PrefilterNativeRenderPass: 0
+ m_PrefilterUseLegacyLightmaps: 0
+ m_PrefilterBicubicLightmapSampling: 0
+ m_PrefilterReflectionProbeRotation: 0
+ m_PrefilterReflectionProbeBlending: 0
+ m_PrefilterReflectionProbeBoxProjection: 0
+ m_PrefilterReflectionProbeAtlas: 0
+ m_ShaderVariantLogLevel: 0
+ m_ShadowCascades: 0
+ m_Textures:
+ blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3}
+ bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3}
diff --git a/Assets/Luneraria/Settings/Rendering/Luneraria_URP.asset.meta b/Assets/Luneraria/Settings/Rendering/Luneraria_URP.asset.meta
new file mode 100644
index 0000000..822b85d
--- /dev/null
+++ b/Assets/Luneraria/Settings/Rendering/Luneraria_URP.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 88b2e99a809584b278f95d7e2a3dc890
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/Luneraria/Settings/Rendering/Luneraria_URP_Renderer.asset b/Assets/Luneraria/Settings/Rendering/Luneraria_URP_Renderer.asset
new file mode 100644
index 0000000..b5df8a8
--- /dev/null
+++ b/Assets/Luneraria/Settings/Rendering/Luneraria_URP_Renderer.asset
@@ -0,0 +1,55 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!114 &11400000
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 0}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3}
+ m_Name: Luneraria_URP_Renderer
+ m_EditorClassIdentifier: Unity.RenderPipelines.Universal.Runtime::UnityEngine.Rendering.Universal.UniversalRendererData
+ debugShaders:
+ debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3}
+ hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3}
+ probeVolumeSamplingDebugComputeShader: {fileID: 7200000, guid: 53626a513ea68ce47b59dc1299fe3959, type: 3}
+ probeVolumeResources:
+ probeVolumeDebugShader: {fileID: 0}
+ probeVolumeFragmentationDebugShader: {fileID: 0}
+ probeVolumeOffsetDebugShader: {fileID: 0}
+ probeVolumeSamplingDebugShader: {fileID: 0}
+ probeSamplingDebugMesh: {fileID: 0}
+ probeSamplingDebugTexture: {fileID: 0}
+ probeVolumeBlendStatesCS: {fileID: 0}
+ m_RendererFeatures: []
+ m_RendererFeatureMap:
+ m_UseNativeRenderPass: 0
+ postProcessData: {fileID: 0}
+ m_AssetVersion: 3
+ m_PrepassLayerMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_OpaqueLayerMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_TransparentLayerMask:
+ serializedVersion: 2
+ m_Bits: 4294967295
+ m_DefaultStencilState:
+ overrideStencilState: 0
+ stencilReference: 0
+ stencilCompareFunction: 8
+ passOperation: 2
+ failOperation: 0
+ zFailOperation: 0
+ m_ShadowTransparentReceive: 1
+ m_RenderingMode: 0
+ m_DepthPrimingMode: 0
+ m_CopyDepthMode: 1
+ m_DepthAttachmentFormat: 0
+ m_DepthTextureFormat: 0
+ m_AccurateGbufferNormals: 0
+ m_IntermediateTextureMode: 1
diff --git a/Assets/Luneraria/Settings/Rendering/Luneraria_URP_Renderer.asset.meta b/Assets/Luneraria/Settings/Rendering/Luneraria_URP_Renderer.asset.meta
new file mode 100644
index 0000000..e1b6661
--- /dev/null
+++ b/Assets/Luneraria/Settings/Rendering/Luneraria_URP_Renderer.asset.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4f1d1577e34314798a12f2f2556faaec
+NativeFormatImporter:
+ externalObjects: {}
+ mainObjectFileID: 11400000
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/UniversalRenderPipelineGlobalSettings.asset b/Assets/Luneraria/Settings/Rendering/UniversalRenderPipelineGlobalSettings.asset
similarity index 100%
rename from Assets/UniversalRenderPipelineGlobalSettings.asset
rename to Assets/Luneraria/Settings/Rendering/UniversalRenderPipelineGlobalSettings.asset
diff --git a/Assets/UniversalRenderPipelineGlobalSettings.asset.meta b/Assets/Luneraria/Settings/Rendering/UniversalRenderPipelineGlobalSettings.asset.meta
similarity index 100%
rename from Assets/UniversalRenderPipelineGlobalSettings.asset.meta
rename to Assets/Luneraria/Settings/Rendering/UniversalRenderPipelineGlobalSettings.asset.meta
diff --git a/ProjectSettings/GraphicsSettings.asset b/ProjectSettings/GraphicsSettings.asset
index 0a98754..a1b69c2 100644
--- a/ProjectSettings/GraphicsSettings.asset
+++ b/ProjectSettings/GraphicsSettings.asset
@@ -37,7 +37,7 @@ GraphicsSettings:
m_PreloadedShaders: []
m_PreloadShadersBatchTimeLimit: -1
m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0}
- m_CustomRenderPipeline: {fileID: 0}
+ m_CustomRenderPipeline: {fileID: 11400000, guid: 88b2e99a809584b278f95d7e2a3dc890, type: 2}
m_TransparencySortMode: 0
m_TransparencySortAxis: {x: 0, y: 0, z: 1}
m_DefaultRenderingPath: 1
@@ -61,8 +61,8 @@ GraphicsSettings:
UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 6f0ce73cdc8074fc283478fba3d0ede7, type: 2}
m_ShaderBuildSettings:
keywordDeclarationOverrides: []
- m_LightsUseLinearIntensity: 0
- m_LightsUseColorTemperature: 0
+ m_LightsUseLinearIntensity: 1
+ m_LightsUseColorTemperature: 1
m_LogWhenShaderIsCompiled: 0
m_LightProbeOutsideHullStrategy: 1
m_CameraRelativeLightCulling: 0
diff --git a/ProjectSettings/ProjectSettings.asset b/ProjectSettings/ProjectSettings.asset
index f9d9de5..5d65bdf 100644
--- a/ProjectSettings/ProjectSettings.asset
+++ b/ProjectSettings/ProjectSettings.asset
@@ -47,7 +47,7 @@ PlayerSettings:
defaultScreenWidthWeb: 960
defaultScreenHeightWeb: 600
m_StereoRenderingPath: 0
- m_ActiveColorSpace: 0
+ m_ActiveColorSpace: 1
unsupportedMSAAFallback: 0
m_SpriteBatchMaxVertexCount: 65535
m_SpriteBatchVertexThreshold: 300
@@ -160,14 +160,18 @@ PlayerSettings:
useHDRDisplay: 0
hdrBitDepth: 0
m_ColorGamuts: 00000000
- targetPixelDensity: 0
+ targetPixelDensity: 30
resolutionScalingMode: 0
resetResolutionOnWindowResize: 0
androidSupportedAspectRatio: 1
androidMaxAspectRatio: 2.4
androidMinAspectRatio: 1
applicationIdentifier: {}
- buildNumber: {}
+ buildNumber:
+ Standalone: 0
+ VisionOS: 0
+ iPhone: 0
+ tvOS: 0
overrideDefaultApplicationIdentifier: 0
AndroidBundleVersionCode: 1
AndroidMinSdkVersion: 25
@@ -188,13 +192,13 @@ PlayerSettings:
VertexChannelCompressionMask: 4054
iPhoneSdkVersion: 988
iOSSimulatorArchitecture: 0
- iOSTargetOSVersionString:
+ iOSTargetOSVersionString: 15.0
tvOSSdkVersion: 0
tvOSSimulatorArchitecture: 0
tvOSRequireExtendedGameController: 0
- tvOSTargetOSVersionString:
+ tvOSTargetOSVersionString: 15.0
VisionOSSdkVersion: 0
- VisionOSTargetOSVersionString:
+ VisionOSTargetOSVersionString: 1.0
uIPrerenderedIcon: 0
uIRequiresPersistentWiFi: 0
uIRequiresFullScreen: 1
@@ -326,7 +330,7 @@ PlayerSettings:
locationUsageDescription:
microphoneUsageDescription:
bluetoothUsageDescription:
- macOSTargetOSVersion:
+ macOSTargetOSVersion: 12.0
switchNMETAOverride:
switchNetLibKey:
switchSocketMemoryPoolSize: 6144
diff --git a/ProjectSettings/QualitySettings.asset b/ProjectSettings/QualitySettings.asset
index 64f8aba..1257f4b 100644
--- a/ProjectSettings/QualitySettings.asset
+++ b/ProjectSettings/QualitySettings.asset
@@ -48,7 +48,7 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
- customRenderPipeline: {fileID: 0}
+ customRenderPipeline: {fileID: 11400000, guid: 88b2e99a809584b278f95d7e2a3dc890, type: 2}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
@@ -101,7 +101,7 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
- customRenderPipeline: {fileID: 0}
+ customRenderPipeline: {fileID: 11400000, guid: 88b2e99a809584b278f95d7e2a3dc890, type: 2}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
@@ -154,7 +154,7 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
- customRenderPipeline: {fileID: 0}
+ customRenderPipeline: {fileID: 11400000, guid: 88b2e99a809584b278f95d7e2a3dc890, type: 2}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
@@ -207,7 +207,7 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
- customRenderPipeline: {fileID: 0}
+ customRenderPipeline: {fileID: 11400000, guid: 88b2e99a809584b278f95d7e2a3dc890, type: 2}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
@@ -260,7 +260,7 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
- customRenderPipeline: {fileID: 0}
+ customRenderPipeline: {fileID: 11400000, guid: 88b2e99a809584b278f95d7e2a3dc890, type: 2}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
@@ -287,7 +287,7 @@ QualitySettings:
globalTextureMipmapLimit: 0
textureMipmapLimitSettings: []
anisotropicTextures: 2
- antiAliasing: 2
+ antiAliasing: 4
softParticles: 1
softVegetation: 1
realtimeReflectionProbes: 1
@@ -313,7 +313,7 @@ QualitySettings:
asyncUploadBufferSize: 16
asyncUploadPersistentBuffer: 1
resolutionScalingFixedDPIFactor: 1
- customRenderPipeline: {fileID: 0}
+ customRenderPipeline: {fileID: 11400000, guid: 88b2e99a809584b278f95d7e2a3dc890, type: 2}
terrainQualityOverrides: 0
terrainPixelError: 1
terrainDetailDensityScale: 1
diff --git a/docs/port/U2-WORLD.md b/docs/port/U2-WORLD.md
index 6e0e031..4051f55 100644
--- a/docs/port/U2-WORLD.md
+++ b/docs/port/U2-WORLD.md
@@ -1,12 +1,19 @@
# U2 · Unity-Spielwelt
-Stand: 30. September 2026 · **nicht begonnen**.
+Stand: 30. September 2026.
-Voraussetzungen: U1 grün (erfüllt außerhalb von Unity) und aktive Unity-Lizenz (fehlt).
+| Teil | Inhalt | Zustand |
+| --- | --- | --- |
+| U2A | Blender→FBX-Pipeline, sechs repräsentative Assets vollständig geprüft | **fertig** |
+| U2B | Weltgeometrie (G1-Karte, Türme, Ancients, Grotte, Aufstellungsbereiche), Materialsystem | offen |
+| U2C | Simulation/Darstellung: fester Takt, Interpolation, Bildraten-Unabhängigkeit | offen |
+| U2D | spielbare Unity-Partie, Vertical Function Test | offen |
+
+Voraussetzung U1.5 ist erfüllt ([U1.5-UNITY.md](U1.5-UNITY.md)).
## Ziel
-Die bestehende Partie läuft sichtbar in Unity (URP). Das ist noch keine grafische Neugestaltung.
+Die bestehende Partie läuft sichtbar in Unity (URP). Das ist noch keine grafische Neugestaltung; die kommt erst mit U5.
Zuerst kommen:
- die G1-Drei-Lane-Karte,
@@ -17,35 +24,127 @@ Zuerst kommen:
## Vorgaben
-- **Adapter:** Unity treibt `LuneMatch` im festen Takt (0,05 s) über einen Akkumulator, unabhängig von der Bildrate. Ansichten lesen nur; sie schreiben nie in die Regeln.
-- **Gemeinsames Materialsystem** (URP, Shader Graph oder HLSL): Stein, Metall, Holz, Vegetation, Kristall, Runen, Wasser. Die G2-Shader aus Godot (stone, metal, crystal, rune, cloth, vein, water_glow, hide) dienen als fachliche Vorlage. Automatische Materialkonvertierungen werden nicht ungeprüft übernommen.
-- **Assets:** Quelle sind die Blender-Dateien und Generatoren im Referenz-Repository. Ein zentraler, reproduzierbarer Blender-Export erzeugt FBX für Unity; GLB nur, wo keine bearbeitbare Quelle existiert.
+- **Adapter:** Unity treibt `LuneMatch` im festen Takt (0,05 s) über einen Akkumulator, unabhängig von der Bildrate. Ansichten lesen nur; sie schreiben nie in die Regeln. Beispiel: `Gebäude-HP = 0` führt zu Einsturz und Ruine, nie umgekehrt eine Animation zu einer Regelwirkung.
+- **Gemeinsames Materialsystem** (URP): Stein, Metall, Holz, Vegetation, Kristall, Runen, Wasser. Die G2-Shader aus Godot (stone, metal, crystal, rune, cloth, vein, water_glow, hide) dienen als fachliche Vorlage.
+- **Assets:** Quelle sind die Blender-Dateien und Generatoren im Referenz-Repository. Ein zentraler, reproduzierbarer Blender-Export erzeugt FBX; GLB nur, wo keine bearbeitbare Quelle existiert.
+- **Reihenfolge:** Erst sechs repräsentative Assets vollständig prüfen, dann die Welt und eine vollständige Bot-Partie. Den Batchlauf über alle Assets gibt es erst nach dem Vertical Function Test.
-## Bestand an Quellen (Godot-Referenz)
+## U2A · Blender→FBX-Pipeline
-| Gruppe | GLB | Blender-Quelle |
-| --- | ---: | --- |
-| Truppen, Monster, Sendungen (`assets/models`) | 59 | `assets-source/phase4/blend` (59 `.blend`) |
-| Figuren mit Skelett (`assets/characters`) | 6 | `assets-source/phase10`–`phase19` (je ein `.blend` plus Generator) |
-| G2-Bauwerke, Grotte, Schlundkrone (`assets/luneraria/g2`) | 6 | `assets-source/luneraria/g2` (`.blend` plus Generatoren) |
-| Völker (`assets/luneraria/peoples`) | 7 | `assets-source/luneraria/peoples` |
-| Umgebung, Vergleich, übrige | 11 | teilweise; wird im Exportinventar geklärt |
+### Aufbau
-## Prüfpunkte der Pipeline
+| Datei | Aufgabe |
+| --- | --- |
+| `tools/blender/export_manifest.json` | Asset-Liste: Blender-Quelle, Art (statisch, starre Teile, Skelett), Exportregeln und Verweis auf den Godot-Manifesteintrag des GLB, das die Referenz benutzt |
+| `tools/blender/lune_fbx_export.py` | Blender im Hintergrund: Quelle öffnen, Regeln anwenden, prüfen, FBX schreiben, FBX wieder einlesen und erneut prüfen |
+| `tools/blender/export_fbx.sh` | Einstieg; macht die FBX-Dateien byteidentisch reproduzierbar |
+| `Assets/Luneraria/Art//.fbx` und `.export.json` | Ergebnis: Modell und Protokoll (Blender-Fakten und Prüfungen) |
+| `Assets/Luneraria/Editor/Art/LuneModelPostprocessor.cs` | Importregeln in Unity |
+| `Assets/Luneraria/Editor/Art/LuneAssetVerifier.cs` | Unity-Prüfung jedes importierten Modells gegen das Blender-Protokoll |
+| `Assets/Luneraria/Editor/Art/LuneAssetPreview.cs` | Vorschaubilder in URP |
-- Maßstab (1 Einheit = 1 m) und Achsen (Godot Y-oben/−Z-vorn gegenüber Unity Y-oben/+Z-vorn).
-- Root Bone und Bone-Namen.
-- Clip-Namen: idle, walk, attack_a, attack_b, hit, ability, death, roar, victory.
-- Animation Events.
-- Materialslots.
-- Normalen und Tangenten.
-- Blend Shapes, sofern vorhanden.
+```bash
+sh tools/blender/export_fbx.sh
+```
-## Abnahme
+```bash
+/Applications/Unity/Hub/Editor/6000.3.20f1/Unity.app/Contents/MacOS/Unity -batchmode -projectPath "$PWD" -executeMethod Luneraria.EditorTools.LuneAssetVerifier.VerifyAll -logFile -
+```
+
+Weitere Einstiege: `LuneAssetVerifier.ReimportArt` (nach geänderten Importregeln) und `LuneAssetPreview.RenderAll`.
+
+### Exportregeln
+
+Die Regeln wiederholen, was die Godot-Pipeline beim GLB-Export getan hat. Sonst entstünde ein anderes Modell:
+
+- **Phase-4-Einheiten:** Die Modifikatoren „HIGH RES“ (Unterteilung und Mikrorelief) kamen erst *nach* dem Laufzeitexport in die `.blend`-Datei. Sie werden nicht angewendet (bei `g01`: 36 Stück).
+- **Logische Namen:** Die Namen stammen aus den Eigenschaften `part_name` und `material_name`; Blender hatte teils Suffixe wie `.004` ergänzt.
+- **Figuren mit Skelett:** Die `.blend`-Datei ist vor dem Zusammenfügen gespeichert. Der Export fügt die Teile wie in Godot zu einem Skin-Mesh zusammen (Funkenlanze: 104 Teile → `FunkenBody`).
+- **Achsen:** Die FBX-Datei behält Blenders Z-oben-Achsen; Unity rechnet sie beim Import mit „Bake Axis Conversion“ um, also ohne Wurzelrotation. Blender (x, y, z) wird dabei Unity (x, z, y); die Vorderseite (Blender −Y) läge auf Unity −Z.
+ - Deshalb dreht der Export jedes Asset vorher um 180° um die Hochachse und wendet die Drehung an. Danach gilt Unity = (−x, y, z) der Godot-/glTF-Koordinaten, und die Vorderseite liegt auf +Z wie in Godot.
+ - Blenders „Apply Transform“ ist für Skelette als fehlerhaft dokumentiert und wird nicht benutzt.
+- **Maßstab und Inhalt:** 1 Blender-Einheit = 1 m; Normalen, Tangenten (MikkTSpace, wo UVs existieren), lineare Vertexfarben; nur Deform-Bones, keine Leaf-Bones; jede Action wird ein Clip.
+- **Reproduzierbarkeit:** Blenders FBX-Schreiber stempelt die Uhrzeit ein und leitet Objekt-IDs aus Pythons String-Hash ab. Der Export fixiert beides (feste Uhrzeit, `PYTHONHASHSEED=0` mit `--python-use-system-env`). Zwei Läufe liefern byteidentische FBX-Dateien und identische Protokolle.
+
+### Prüfungen
+
+Blender-Seite, vor und nach dem Schreiben (Rundreise durch einen FBX-Import):
+
+| Prüfpunkt | Wie |
+| --- | --- |
+| Einheiten, Maßstab | metrisch, `scale_length` 1, keine Objektskalierung, keine negative Skalierung |
+| Achsen, Vorderseite | Drehung angewendet; Vorwärtsmarker (Phase 4: Empty `Forward`) liegt in Unity auf +Z |
+| Mesh-Namen | eindeutig; gleich den Knoten des Godot-GLB |
+| Dreiecke | gleich dem Godot-GLB, auch nach dem Wiedereinlesen |
+| Materialslots | keine leeren Slots; Materialien gleich dem Godot-GLB |
+| Normalen | Einheitslänge an allen Ecken |
+| Tangenten | Voraussetzungen (UVs, keine N-Ecke); Meshes ohne UVs sind vermerkt und werden triplanar oder unbeleuchtet schattiert |
+| Maße | Ruhelage gleich den `bounds_godot` des Godot-Manifests (Türme und Ancient: ohne Schadens- und Ruinenteile, wie dort gemessen) |
+| Skelett | genau eine Armature, ein Root Bone `Root`, Bone-Namen und -Anzahl wie im Godot-GLB, portable Namen |
+| Clips | Namen und Längen wie im Godot-GLB; Pflichtclips vorhanden; Loop-Flag und Kontaktzeit aus den Action-Eigenschaften |
+| Blend Shapes | keine in den Quellen |
+
+Unity-Seite (`LuneAssetVerifier`, gegen das Blender-Protokoll):
+
+| Prüfpunkt | Wie |
+| --- | --- |
+| Importregeln | Maßstab 1, Dateieinheiten, Achsen-Bake, Normalen und Tangenten aus der Datei |
+| Achsen | Wurzel und alle Nicht-Bone-Knoten ohne Rotation und Skalierung |
+| Mesh-Namen, Dreiecke | Menge und Anzahl je Mesh gleich |
+| Maße | aus den Vertices berechnet, Abweichung höchstens 2 mm; gemessen höchstens 0,05 mm |
+| Materialslots | Namen je Renderer gleich den Blender-Slots |
+| Normalen, Tangenten, UVs, Vertexfarben | vorhanden und gültig, wo Blender sie hat; Tangenten mit w = ±1 |
+| Vorderseite | Vorwärtsmarker auf +Z |
+| Skelett | Root Bone, Bone-Namen, gültiger Generic-Avatar |
+| Clips | Namen, Längen (auf einen halben Frame genau), Loop-Flags, Kontakt-Events (`OnLuneContact`) |
+
+### Ergebnis: sechs repräsentative Assets und drei Szenenbauten
+
+| Asset | vertritt | Dreiecke (= Godot-GLB) | Blender-Prüfungen | Unity-Prüfungen |
+| --- | --- | ---: | --- | --- |
+| `g01` Kohlenbeißer | normale Einheit, 131 benannte Teile | 79.780 | 18/18 | 14/14 |
+| `funkenlanze` | Einheit mit Skelett (Held), 26 Bones, 9 Clips | 24.036 | 26/26 | 18/18 |
+| `grenzwacht` | Turm (mit Schadens- und Ruinenteilen) | 6.516 | 18/18 | 13/13 |
+| `ancient` Mondherz | Ancient | 19.032 | 18/18 | 13/13 |
+| `schlundkrone` | Schlundkrone (Boss), 24 Bones, 11 Clips | 5.712 | 28/28 | 18/18 |
+| `map_props` | Vegetation und Kartenrequisiten (Eichen, Kiefern, Sträucher, Felsen, Brücke, Randsteine) | 7.338 | 14/14 | 13/13 |
+| `bastion`, `kernwacht`, `bossgrotte` | für die Szene in U2B (Innen- und Basisturm, Mondschlund) | 9.364, 9.224, 15.182 | je 18/18 | je 13/13 |
+
+Summe: 176 Blender-Prüfungen und 128 Unity-Prüfungen, alle bestanden. Protokolle:
+- `Assets/Luneraria/Art/*/*.export.json` (Blender).
+- `docs/port/logs/u2a/unity-verify.json` (Unity).
+
+Bilder unter `docs/port/screenshots/u2a/`:
+- je Asset eine Ansicht von vorn-rechts,
+- die Grenzwacht zusätzlich als Ruine,
+- Funkenlanze und Schlundkrone zusätzlich im Kontaktframe von `attack_a` (Clips laufen).
+
+### Bekannte Grenzen
+
+- **Materialien:** Die Vorschau benutzt URP-Lit-Materialien, die Unity aus den FBX-Materialbeschreibungen erzeugt (Blender-Palettenfarben). Das eigentliche Materialsystem (Stein, Metall, Kristall, Runen, Stoff, Wasser; Teamfarben; Vertex-AO) folgt in U2B.
+ - Stoff (Wimpel, Banner) ist einseitig modelliert und braucht dort doppelseitiges Rendern; in der Vorschau fehlt er deshalb.
+- **Ohne UVs:** Diese Meshes haben keine Tangenten (Unity meldet das beim Import): Kristalle, Trümmer, Felsen, Kartenrequisiten und einige Phase-4-Kleinteile. Sie brauchen triplanare oder unbeleuchtete Materialien.
+- **Starre Einheiten:** Die Phase-4-Einheiten werden in Godot aus benannten Teilen prozedural animiert. Die Teile kommen mit, die Animation folgt mit den Einheitenansichten.
+- **Größe:** Die FBX-Dateien liegen direkt im Repository (9 Dateien, 16 MB). Für den Batchlauf über alle Assets ist Git LFS zu erwägen.
+
+### Batchlauf (nach dem Vertical Function Test)
+
+Das Manifest enthält bisher die 9 Assets der Szene. Die übrigen Assets kommen erst nach U2D in das Manifest und werden dann mit denselben Regeln und Prüfungen exportiert:
+- 58 weitere Phase-4-Modelle.
+- 5 Figuren mit Skelett.
+- 7 Völker-Modelle. Für Zwerg und Troll fehlt die `.blend`-Datei im Referenz-Repository; sie entsteht aus dem Generator `build_peoples.py`.
+
+Bauten aus einer GLB ohne Quelle folgen nur nach Einzelfallprüfung.
+
+## U2B bis U2D
+
+Folgen in diesem Dokument.
+
+## Abnahme (gesamt)
- Die Partie läuft sichtbar.
- Die Kamera entspricht der Godot-Kamera.
- Screenshots neben den Godot-G2-Bildern mit vergleichbarer Kamera.
- Leistung gemessen, einschließlich Mono-Simulationszeit.
- Bekannte Unterschiede dokumentiert.
-- Commit auf `luneraria/u2`.
+- Commits U2A bis U2D auf `luneraria/u2`.
diff --git a/docs/port/logs/u2a/unity-verify.json b/docs/port/logs/u2a/unity-verify.json
new file mode 100644
index 0000000..921e009
--- /dev/null
+++ b/docs/port/logs/u2a/unity-verify.json
@@ -0,0 +1,968 @@
+{
+ "unity": "6000.3.20f1",
+ "ok": true,
+ "assets": [
+ {
+ "id": "ancient",
+ "kind": "static",
+ "ok": true,
+ "checks": [
+ {
+ "check": "blender_checks_passed",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "imported",
+ "ok": true,
+ "detail": "\"Assets/Luneraria/Art/Buildings/ancient.fbx\""
+ },
+ {
+ "check": "import_rules_applied",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "root_transform_identity",
+ "ok": true,
+ "detail": "\"ancient pos (0.0000, 0.0000, 0.0000) rot (0.00, 0.00, 0.00) scale (1.0000, 1.0000, 1.0000)\""
+ },
+ {
+ "check": "node_transforms_axis_clean",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "triangles",
+ "ok": true,
+ "detail": "\"19032 unity / 19032 blender \""
+ },
+ {
+ "check": "material_slots",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangents_where_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "uvs_where_blender_has_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "vertex_colors",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_axes_scale",
+ "ok": true,
+ "detail": "\"largest difference 0.00005 m; unity (-4.204, -0.988, -4.000) (4.204, 10.367, 4.000)\""
+ }
+ ],
+ "facts": {
+ "triangles": 19032,
+ "renderers": 27,
+ "meshes_without_uv_and_tangents": 14,
+ "bounds_min": [
+ -4.20353031,
+ -0.9881463,
+ -4.0
+ ],
+ "bounds_max": [
+ 4.20352936,
+ 10.3668232,
+ 4.0
+ ]
+ }
+ },
+ {
+ "id": "bastion",
+ "kind": "static",
+ "ok": true,
+ "checks": [
+ {
+ "check": "blender_checks_passed",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "imported",
+ "ok": true,
+ "detail": "\"Assets/Luneraria/Art/Buildings/bastion.fbx\""
+ },
+ {
+ "check": "import_rules_applied",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "root_transform_identity",
+ "ok": true,
+ "detail": "\"bastion pos (0.0000, 0.0000, 0.0000) rot (0.00, 0.00, 0.00) scale (1.0000, 1.0000, 1.0000)\""
+ },
+ {
+ "check": "node_transforms_axis_clean",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "triangles",
+ "ok": true,
+ "detail": "\"9364 unity / 9364 blender \""
+ },
+ {
+ "check": "material_slots",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangents_where_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "uvs_where_blender_has_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "vertex_colors",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_axes_scale",
+ "ok": true,
+ "detail": "\"largest difference 0.00005 m; unity (-2.116, -0.389, -2.539) (2.901, 7.161, 1.950)\""
+ }
+ ],
+ "facts": {
+ "triangles": 9364,
+ "renderers": 11,
+ "meshes_without_uv_and_tangents": 6,
+ "bounds_min": [
+ -2.11555481,
+ -0.3890798,
+ -2.538877
+ ],
+ "bounds_max": [
+ 2.90077925,
+ 7.160508,
+ 1.94963574
+ ]
+ }
+ },
+ {
+ "id": "bossgrotte",
+ "kind": "static",
+ "ok": true,
+ "checks": [
+ {
+ "check": "blender_checks_passed",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "imported",
+ "ok": true,
+ "detail": "\"Assets/Luneraria/Art/Buildings/bossgrotte.fbx\""
+ },
+ {
+ "check": "import_rules_applied",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "root_transform_identity",
+ "ok": true,
+ "detail": "\"bossgrotte pos (0.0000, 0.0000, 0.0000) rot (0.00, 0.00, 0.00) scale (1.0000, 1.0000, 1.0000)\""
+ },
+ {
+ "check": "node_transforms_axis_clean",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "triangles",
+ "ok": true,
+ "detail": "\"15182 unity / 15182 blender \""
+ },
+ {
+ "check": "material_slots",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangents_where_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "uvs_where_blender_has_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "vertex_colors",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_axes_scale",
+ "ok": true,
+ "detail": "\"largest difference 0.00004 m; unity (-7.777, -1.930, -10.465) (10.544, 7.693, 7.798)\""
+ }
+ ],
+ "facts": {
+ "triangles": 15182,
+ "renderers": 12,
+ "meshes_without_uv_and_tangents": 4,
+ "bounds_min": [
+ -7.77746248,
+ -1.93,
+ -10.4646072
+ ],
+ "bounds_max": [
+ 10.5441828,
+ 7.69265556,
+ 7.79764366
+ ]
+ }
+ },
+ {
+ "id": "grenzwacht",
+ "kind": "static",
+ "ok": true,
+ "checks": [
+ {
+ "check": "blender_checks_passed",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "imported",
+ "ok": true,
+ "detail": "\"Assets/Luneraria/Art/Buildings/grenzwacht.fbx\""
+ },
+ {
+ "check": "import_rules_applied",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "root_transform_identity",
+ "ok": true,
+ "detail": "\"grenzwacht pos (0.0000, 0.0000, 0.0000) rot (0.00, 0.00, 0.00) scale (1.0000, 1.0000, 1.0000)\""
+ },
+ {
+ "check": "node_transforms_axis_clean",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "triangles",
+ "ok": true,
+ "detail": "\"6516 unity / 6516 blender \""
+ },
+ {
+ "check": "material_slots",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangents_where_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "uvs_where_blender_has_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "vertex_colors",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_axes_scale",
+ "ok": true,
+ "detail": "\"largest difference 0.00005 m; unity (-2.258, -0.065, -2.553) (1.966, 6.060, 1.368)\""
+ }
+ ],
+ "facts": {
+ "triangles": 6516,
+ "renderers": 7,
+ "meshes_without_uv_and_tangents": 2,
+ "bounds_min": [
+ -2.25751829,
+ -0.06533188,
+ -2.55256557
+ ],
+ "bounds_max": [
+ 1.96584618,
+ 6.060136,
+ 1.36833835
+ ]
+ }
+ },
+ {
+ "id": "kernwacht",
+ "kind": "static",
+ "ok": true,
+ "checks": [
+ {
+ "check": "blender_checks_passed",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "imported",
+ "ok": true,
+ "detail": "\"Assets/Luneraria/Art/Buildings/kernwacht.fbx\""
+ },
+ {
+ "check": "import_rules_applied",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "root_transform_identity",
+ "ok": true,
+ "detail": "\"kernwacht pos (0.0000, 0.0000, 0.0000) rot (0.00, 0.00, 0.00) scale (1.0000, 1.0000, 1.0000)\""
+ },
+ {
+ "check": "node_transforms_axis_clean",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "triangles",
+ "ok": true,
+ "detail": "\"9224 unity / 9224 blender \""
+ },
+ {
+ "check": "material_slots",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangents_where_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "uvs_where_blender_has_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "vertex_colors",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_axes_scale",
+ "ok": true,
+ "detail": "\"largest difference 0.00004 m; unity (-6.076, -2.396, -2.194) (2.396, 8.330, 1.813)\""
+ }
+ ],
+ "facts": {
+ "triangles": 9224,
+ "renderers": 9,
+ "meshes_without_uv_and_tangents": 2,
+ "bounds_min": [
+ -6.07622528,
+ -2.39588761,
+ -2.19388914
+ ],
+ "bounds_max": [
+ 2.39623713,
+ 8.33,
+ 1.81258774
+ ]
+ }
+ },
+ {
+ "id": "funkenlanze",
+ "kind": "skinned",
+ "ok": true,
+ "checks": [
+ {
+ "check": "blender_checks_passed",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "imported",
+ "ok": true,
+ "detail": "\"Assets/Luneraria/Art/Characters/funkenlanze.fbx\""
+ },
+ {
+ "check": "import_rules_applied",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "root_transform_identity",
+ "ok": true,
+ "detail": "\"funkenlanze pos (0.0000, 0.0000, 0.0000) rot (0.00, 0.00, 0.00) scale (1.0000, 1.0000, 1.0000)\""
+ },
+ {
+ "check": "node_transforms_axis_clean",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "triangles",
+ "ok": true,
+ "detail": "\"24036 unity / 24036 blender \""
+ },
+ {
+ "check": "material_slots",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangents_where_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "uvs_where_blender_has_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "vertex_colors",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_axes_scale",
+ "ok": true,
+ "detail": "\"largest difference 0.00005 m; unity (-0.565, -0.010, -0.295) (0.430, 2.021, 1.435)\""
+ },
+ {
+ "check": "skinned_mesh",
+ "ok": true,
+ "detail": "1"
+ },
+ {
+ "check": "bone_names FunkenBody",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "root_bone FunkenBody",
+ "ok": true,
+ "detail": "\"Root\""
+ },
+ {
+ "check": "generic_avatar",
+ "ok": true,
+ "detail": "\"funkenlanzeAvatar\""
+ },
+ {
+ "check": "clips",
+ "ok": true,
+ "detail": "[]"
+ }
+ ],
+ "facts": {
+ "triangles": 24036,
+ "renderers": 1,
+ "meshes_without_uv_and_tangents": 0,
+ "bounds_min": [
+ -0.5651692,
+ -0.0104093477,
+ -0.2945487
+ ],
+ "bounds_max": [
+ 0.43,
+ 2.02119541,
+ 1.43500006
+ ],
+ "clips": [
+ {
+ "name": "ability",
+ "length": 1.3,
+ "loop": false,
+ "events": 1
+ },
+ {
+ "name": "attack_a",
+ "length": 1.3,
+ "loop": false,
+ "events": 1
+ },
+ {
+ "name": "attack_b",
+ "length": 1.3,
+ "loop": false,
+ "events": 1
+ },
+ {
+ "name": "death",
+ "length": 2.0,
+ "loop": false,
+ "events": 0
+ },
+ {
+ "name": "hit",
+ "length": 0.5,
+ "loop": false,
+ "events": 0
+ },
+ {
+ "name": "idle",
+ "length": 3.0,
+ "loop": true,
+ "events": 0
+ },
+ {
+ "name": "start",
+ "length": 0.4,
+ "loop": false,
+ "events": 0
+ },
+ {
+ "name": "stop",
+ "length": 0.4,
+ "loop": false,
+ "events": 0
+ },
+ {
+ "name": "walk",
+ "length": 1.2,
+ "loop": true,
+ "events": 0
+ }
+ ]
+ }
+ },
+ {
+ "id": "schlundkrone",
+ "kind": "skinned",
+ "ok": true,
+ "checks": [
+ {
+ "check": "blender_checks_passed",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "imported",
+ "ok": true,
+ "detail": "\"Assets/Luneraria/Art/Characters/schlundkrone.fbx\""
+ },
+ {
+ "check": "import_rules_applied",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "root_transform_identity",
+ "ok": true,
+ "detail": "\"schlundkrone pos (0.0000, 0.0000, 0.0000) rot (0.00, 0.00, 0.00) scale (1.0000, 1.0000, 1.0000)\""
+ },
+ {
+ "check": "node_transforms_axis_clean",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "triangles",
+ "ok": true,
+ "detail": "\"5712 unity / 5712 blender \""
+ },
+ {
+ "check": "material_slots",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangents_where_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "uvs_where_blender_has_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "vertex_colors",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_axes_scale",
+ "ok": true,
+ "detail": "\"largest difference 0.00005 m; unity (-1.327, 0.005, -0.553) (1.231, 3.318, 0.925)\""
+ },
+ {
+ "check": "skinned_mesh",
+ "ok": true,
+ "detail": "1"
+ },
+ {
+ "check": "bone_names SchlundkroneBody",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "root_bone SchlundkroneBody",
+ "ok": true,
+ "detail": "\"Root\""
+ },
+ {
+ "check": "generic_avatar",
+ "ok": true,
+ "detail": "\"schlundkroneAvatar\""
+ },
+ {
+ "check": "clips",
+ "ok": true,
+ "detail": "[]"
+ }
+ ],
+ "facts": {
+ "triangles": 5712,
+ "renderers": 1,
+ "meshes_without_uv_and_tangents": 0,
+ "bounds_min": [
+ -1.32726932,
+ 0.00534708425,
+ -0.5531612
+ ],
+ "bounds_max": [
+ 1.23073983,
+ 3.31821656,
+ 0.9253263
+ ],
+ "clips": [
+ {
+ "name": "ability",
+ "length": 1.3,
+ "loop": false,
+ "events": 0
+ },
+ {
+ "name": "attack_a",
+ "length": 1.3,
+ "loop": false,
+ "events": 1
+ },
+ {
+ "name": "attack_b",
+ "length": 1.3,
+ "loop": false,
+ "events": 1
+ },
+ {
+ "name": "death",
+ "length": 2.2,
+ "loop": false,
+ "events": 0
+ },
+ {
+ "name": "hit",
+ "length": 0.5,
+ "loop": false,
+ "events": 0
+ },
+ {
+ "name": "idle",
+ "length": 3.0,
+ "loop": true,
+ "events": 0
+ },
+ {
+ "name": "roar",
+ "length": 2.0,
+ "loop": false,
+ "events": 0
+ },
+ {
+ "name": "start",
+ "length": 0.4,
+ "loop": false,
+ "events": 0
+ },
+ {
+ "name": "stop",
+ "length": 0.4,
+ "loop": false,
+ "events": 0
+ },
+ {
+ "name": "victory",
+ "length": 2.0,
+ "loop": false,
+ "events": 0
+ },
+ {
+ "name": "walk",
+ "length": 1.6,
+ "loop": true,
+ "events": 0
+ }
+ ]
+ }
+ },
+ {
+ "id": "map_props",
+ "kind": "static",
+ "ok": true,
+ "checks": [
+ {
+ "check": "blender_checks_passed",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "imported",
+ "ok": true,
+ "detail": "\"Assets/Luneraria/Art/Environment/map_props.fbx\""
+ },
+ {
+ "check": "import_rules_applied",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "root_transform_identity",
+ "ok": true,
+ "detail": "\"map_props pos (0.0000, 0.0000, 0.0000) rot (0.00, 0.00, 0.00) scale (1.0000, 1.0000, 1.0000)\""
+ },
+ {
+ "check": "node_transforms_axis_clean",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "triangles",
+ "ok": true,
+ "detail": "\"7338 unity / 7338 blender \""
+ },
+ {
+ "check": "material_slots",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangents_where_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "uvs_where_blender_has_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "vertex_colors",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_axes_scale",
+ "ok": true,
+ "detail": "\"largest difference 0.00002 m; unity (-7.368, -1.300, -3.900) (7.455, 5.244, 3.900)\""
+ }
+ ],
+ "facts": {
+ "triangles": 7338,
+ "renderers": 15,
+ "meshes_without_uv_and_tangents": 15,
+ "bounds_min": [
+ -7.368419,
+ -1.3,
+ -3.90000057
+ ],
+ "bounds_max": [
+ 7.455483,
+ 5.244,
+ 3.90000057
+ ]
+ }
+ },
+ {
+ "id": "g01",
+ "kind": "rigid",
+ "ok": true,
+ "checks": [
+ {
+ "check": "blender_checks_passed",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "imported",
+ "ok": true,
+ "detail": "\"Assets/Luneraria/Art/Units/g01.fbx\""
+ },
+ {
+ "check": "import_rules_applied",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "check": "root_transform_identity",
+ "ok": true,
+ "detail": "\"g01 pos (0.0000, 0.0000, 0.0000) rot (0.00, 0.00, 0.00) scale (1.0000, 1.0000, 1.0000)\""
+ },
+ {
+ "check": "node_transforms_axis_clean",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "mesh_names",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "triangles",
+ "ok": true,
+ "detail": "\"79780 unity / 79780 blender \""
+ },
+ {
+ "check": "material_slots",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "normals_unit_length",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "tangents_where_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "uvs_where_blender_has_uv",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "vertex_colors",
+ "ok": true,
+ "detail": "[]"
+ },
+ {
+ "check": "bounds_axes_scale",
+ "ok": true,
+ "detail": "\"largest difference 0.00004 m; unity (-0.792, 0.000, -0.447) (0.792, 1.350, 0.447)\""
+ },
+ {
+ "check": "forward_is_plus_z",
+ "ok": true,
+ "detail": "\"(0.000, 0.000, 0.750)\""
+ }
+ ],
+ "facts": {
+ "triangles": 79780,
+ "renderers": 131,
+ "meshes_without_uv_and_tangents": 38,
+ "bounds_min": [
+ -0.792443752,
+ 0.0,
+ -0.447301447
+ ],
+ "bounds_max": [
+ 0.7924438,
+ 1.35,
+ 0.447301567
+ ]
+ }
+ }
+ ]
+}
diff --git a/docs/port/screenshots/u2a/ancient.png b/docs/port/screenshots/u2a/ancient.png
new file mode 100644
index 0000000..83ecd5a
Binary files /dev/null and b/docs/port/screenshots/u2a/ancient.png differ
diff --git a/docs/port/screenshots/u2a/bastion.png b/docs/port/screenshots/u2a/bastion.png
new file mode 100644
index 0000000..55e7a25
Binary files /dev/null and b/docs/port/screenshots/u2a/bastion.png differ
diff --git a/docs/port/screenshots/u2a/bossgrotte.png b/docs/port/screenshots/u2a/bossgrotte.png
new file mode 100644
index 0000000..9ef89dd
Binary files /dev/null and b/docs/port/screenshots/u2a/bossgrotte.png differ
diff --git a/docs/port/screenshots/u2a/funkenlanze-attack_a.png b/docs/port/screenshots/u2a/funkenlanze-attack_a.png
new file mode 100644
index 0000000..c99caf6
Binary files /dev/null and b/docs/port/screenshots/u2a/funkenlanze-attack_a.png differ
diff --git a/docs/port/screenshots/u2a/funkenlanze.png b/docs/port/screenshots/u2a/funkenlanze.png
new file mode 100644
index 0000000..65047cb
Binary files /dev/null and b/docs/port/screenshots/u2a/funkenlanze.png differ
diff --git a/docs/port/screenshots/u2a/g01.png b/docs/port/screenshots/u2a/g01.png
new file mode 100644
index 0000000..5dff8fe
Binary files /dev/null and b/docs/port/screenshots/u2a/g01.png differ
diff --git a/docs/port/screenshots/u2a/grenzwacht-ruin.png b/docs/port/screenshots/u2a/grenzwacht-ruin.png
new file mode 100644
index 0000000..fe46aac
Binary files /dev/null and b/docs/port/screenshots/u2a/grenzwacht-ruin.png differ
diff --git a/docs/port/screenshots/u2a/grenzwacht.png b/docs/port/screenshots/u2a/grenzwacht.png
new file mode 100644
index 0000000..96b027b
Binary files /dev/null and b/docs/port/screenshots/u2a/grenzwacht.png differ
diff --git a/docs/port/screenshots/u2a/kernwacht.png b/docs/port/screenshots/u2a/kernwacht.png
new file mode 100644
index 0000000..91c6ab7
Binary files /dev/null and b/docs/port/screenshots/u2a/kernwacht.png differ
diff --git a/docs/port/screenshots/u2a/map_props.png b/docs/port/screenshots/u2a/map_props.png
new file mode 100644
index 0000000..8ba33b7
Binary files /dev/null and b/docs/port/screenshots/u2a/map_props.png differ
diff --git a/docs/port/screenshots/u2a/schlundkrone-attack_a.png b/docs/port/screenshots/u2a/schlundkrone-attack_a.png
new file mode 100644
index 0000000..032ed4c
Binary files /dev/null and b/docs/port/screenshots/u2a/schlundkrone-attack_a.png differ
diff --git a/docs/port/screenshots/u2a/schlundkrone.png b/docs/port/screenshots/u2a/schlundkrone.png
new file mode 100644
index 0000000..ab43a22
Binary files /dev/null and b/docs/port/screenshots/u2a/schlundkrone.png differ
diff --git a/tools/blender/export_fbx.sh b/tools/blender/export_fbx.sh
new file mode 100644
index 0000000..5157f1f
--- /dev/null
+++ b/tools/blender/export_fbx.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Blender -> FBX export of the Unity port (U2A): sh tools/blender/export_fbx.sh [id,id,...]
+# Without ids every asset of tools/blender/export_manifest.json is exported. Needs Blender 5.2
+# (BLENDER, default "blender") and the Godot reference (GODOT_PROJECT, default ../saumwacht-godot).
+# PYTHONHASHSEED=0 with --python-use-system-env makes the FBX object ids reproducible.
+set -eu
+cd "$(dirname "$0")/../.."
+BLENDER="${BLENDER:-blender}"
+GODOT_PROJECT="${GODOT_PROJECT:-../saumwacht-godot}"
+PYTHONHASHSEED=0 "$BLENDER" --background --factory-startup --python-use-system-env \
+ --python tools/blender/lune_fbx_export.py -- --godot "$GODOT_PROJECT" --ids "${1:-}"
diff --git a/tools/blender/export_manifest.json b/tools/blender/export_manifest.json
new file mode 100644
index 0000000..8d52a1e
--- /dev/null
+++ b/tools/blender/export_manifest.json
@@ -0,0 +1,58 @@
+{
+ "comment": "Export rules per asset for tools/blender/lune_fbx_export.py. source: Blender file in the Godot reference (../saumwacht-godot). godot_manifest: the manifest entry of the GLB the reference game uses; the FBX must match it (triangles, names, materials, bounds, bones, clips). kind: static | rigid (named parts, animated by the view) | skinned.",
+ "assets": [
+ {
+ "id": "g01", "group": "Units", "kind": "rigid", "representative": "normal unit (Glutpakt melee, 131 named parts)",
+ "source": "assets-source/phase4/blend/g01.blend",
+ "godot_manifest": {"file": "assets/phase4_manifest.json", "id": "g01"},
+ "rules": {"skip_modifiers": ["HIGH RES"], "logical_names": true, "forward_marker": "Forward", "check_parts": false}
+ },
+ {
+ "id": "funkenlanze", "group": "Characters", "kind": "skinned", "representative": "rigged unit (hero Funkenlanze)",
+ "source": "assets-source/phase18/funkenlanze.blend",
+ "godot_manifest": {"file": "assets/phase18_manifest.json", "id": "g05"},
+ "rules": {"join": {"parent": "FunkenRig", "into": "FunkenBody"}, "rest_action": null, "root_bone": "Root",
+ "required_clips": ["idle", "walk", "attack_a", "attack_b", "hit", "ability", "death"]}
+ },
+ {
+ "id": "grenzwacht", "group": "Buildings", "kind": "static", "representative": "tower (outer lane tower)",
+ "source": "assets-source/luneraria/g2/grenzwacht.blend",
+ "godot_manifest": {"file": "assets/luneraria/g2/g2_manifest.json", "id": "grenzwacht"},
+ "rules": {"bounds_exclude": ["Upper_Damaged", "Debris", "Ruin", "Pennant", "Banner"]}
+ },
+ {
+ "id": "ancient", "group": "Buildings", "kind": "static", "representative": "Ancient (Mondherz)",
+ "source": "assets-source/luneraria/g2/ancient.blend",
+ "godot_manifest": {"file": "assets/luneraria/g2/g2_manifest.json", "id": "ancient"},
+ "rules": {"bounds_exclude": ["Banner", "Ruin_"]}
+ },
+ {
+ "id": "schlundkrone", "group": "Characters", "kind": "skinned", "representative": "Schlundkrone (boss)",
+ "source": "assets-source/luneraria/g2/schlundkrone.blend",
+ "godot_manifest": {"file": "assets/luneraria/g2/g2_manifest.json", "id": "schlundkrone"},
+ "rules": {"rest_action": null, "root_bone": "Root",
+ "required_clips": ["idle", "walk", "attack_a", "attack_b", "hit", "ability", "death", "roar", "victory"]}
+ },
+ {
+ "id": "map_props", "group": "Environment", "kind": "static", "representative": "vegetation and map props (oaks, pines, shrubs, rocks, bridge, curb)",
+ "source": "assets-source/luneraria/map_props.blend"
+ },
+ {
+ "id": "bastion", "group": "Buildings", "kind": "static",
+ "source": "assets-source/luneraria/g2/bastion.blend",
+ "godot_manifest": {"file": "assets/luneraria/g2/g2_manifest.json", "id": "bastion"},
+ "rules": {"bounds_exclude": ["Upper_Damaged", "Debris", "Ruin", "Pennant", "Banner"]}
+ },
+ {
+ "id": "kernwacht", "group": "Buildings", "kind": "static",
+ "source": "assets-source/luneraria/g2/kernwacht.blend",
+ "godot_manifest": {"file": "assets/luneraria/g2/g2_manifest.json", "id": "kernwacht"},
+ "rules": {"bounds_exclude": ["Upper_Damaged", "Debris", "Ruin", "Pennant", "Banner"]}
+ },
+ {
+ "id": "bossgrotte", "group": "Buildings", "kind": "static",
+ "source": "assets-source/luneraria/g2/bossgrotte.blend",
+ "godot_manifest": {"file": "assets/luneraria/g2/g2_manifest.json", "id": "bossgrotte"}
+ }
+ ]
+}
diff --git a/tools/blender/inspect_blend.py b/tools/blender/inspect_blend.py
new file mode 100644
index 0000000..357a925
--- /dev/null
+++ b/tools/blender/inspect_blend.py
@@ -0,0 +1,33 @@
+"""Prints a JSON summary of a .blend file (objects, meshes, materials, armatures, actions).
+Usage: blender --background --python tools/blender/inspect_blend.py -- """
+import bpy, json, sys
+out = sys.argv[sys.argv.index('--') + 1] if '--' in sys.argv else None
+scene = bpy.context.scene
+info = {'file': bpy.data.filepath, 'unit_system': scene.unit_settings.system, 'scale_length': scene.unit_settings.scale_length,
+ 'fps': scene.render.fps, 'objects': [], 'actions': []}
+for obj in bpy.data.objects:
+ entry = {'name': obj.name, 'type': obj.type, 'parent': obj.parent.name if obj.parent else None,
+ 'location': [round(v, 4) for v in obj.location], 'rotation': [round(v, 4) for v in obj.rotation_euler],
+ 'scale': [round(v, 4) for v in obj.scale], 'in_scene': obj.name in scene.objects,
+ 'hide_render': obj.hide_render}
+ if obj.type == 'MESH':
+ me = obj.data
+ entry.update({'mesh': me.name, 'verts': len(me.vertices), 'polys': len(me.polygons),
+ 'ngons': sum(1 for p in me.polygons if len(p.vertices) > 4),
+ 'materials': [m.name if m else None for m in me.materials], 'uv_layers': [uv.name for uv in me.uv_layers],
+ 'color_attributes': [(c.name, c.domain, c.data_type) for c in me.color_attributes],
+ 'custom_normals': me.has_custom_normals, 'shape_keys': [k.name for k in me.shape_keys.key_blocks] if me.shape_keys else [],
+ 'modifiers': [(m.type, m.name) for m in obj.modifiers], 'vertex_groups': len(obj.vertex_groups)})
+ if obj.type == 'ARMATURE':
+ arm = obj.data
+ entry.update({'bones': len(arm.bones), 'roots': [b.name for b in arm.bones if b.parent is None],
+ 'bone_names': [b.name for b in arm.bones][:80], 'action': obj.animation_data.action.name if obj.animation_data and obj.animation_data.action else None,
+ 'nla': [(t.name, [s.action.name for s in t.strips if s.action]) for t in obj.animation_data.nla_tracks] if obj.animation_data else []})
+ info['objects'].append(entry)
+for act in bpy.data.actions:
+ info['actions'].append({'name': act.name, 'range': [round(v, 2) for v in act.frame_range], 'users': act.users, 'fake_user': act.use_fake_user})
+text = json.dumps(info, indent=1)
+if out:
+ open(out, 'w').write(text)
+else:
+ print(text)
diff --git a/tools/blender/lune_fbx_export.py b/tools/blender/lune_fbx_export.py
new file mode 100644
index 0000000..d7ea485
--- /dev/null
+++ b/tools/blender/lune_fbx_export.py
@@ -0,0 +1,454 @@
+"""Reproducible Blender -> FBX export for the Unity port (docs/port/U2-WORLD.md, U2A).
+
+Runs headless on the Blender sources of the Godot reference, applies the per-asset export
+rules of tools/blender/export_manifest.json, checks the result and writes, per asset:
+
+ Assets/Luneraria/Art//.fbx the model for Unity
+ Assets/Luneraria/Art//.export.json facts and checks (read by Unity's importer)
+
+Checks: units and scale, up and forward axis, object transforms, mesh names, triangle counts,
+material slots, UVs, normals, tangent prerequisites, vertex colours, root bone, bone names,
+clips (names, lengths, loop flags, contact events), bounds. Expectations come from the Godot
+manifests of the GLBs the reference game uses, so the FBX must describe the same model.
+After writing, the FBX is imported into an empty scene and checked again (round trip).
+
+Usage (from the Unity project root): sh tools/blender/export_fbx.sh [id,id,...]
+ (runs blender --background --factory-startup --python-use-system-env with PYTHONHASHSEED=0
+ --python tools/blender/lune_fbx_export.py -- --godot ../saumwacht-godot --ids )
+Exit code 0 only if every check of every asset passed.
+"""
+import bpy
+import hashlib
+import json
+import math
+import sys
+from pathlib import Path
+
+from mathutils import Matrix, Vector
+
+UNITY_ROOT = Path(__file__).resolve().parents[2]
+EXPORTER_VERSION = 5
+
+# One export setting for every asset. The file keeps Blender's Z-up axes; Unity's importer
+# converts them with "Bake Axis Conversion" as Unity (x, y, z) = Blender (x, z, y), so no root
+# carries a rotation and animation data is converted with the meshes (Blender's own "Apply
+# Transform" is documented as broken for armatures). Before export every asset is turned by 180
+# degrees about Blender's Z and the turn is applied (face_unity_forward): the front (Blender -Y,
+# glTF/Godot +Z) then becomes Unity +Z, and Unity = (-x, y, z) of the Godot coordinates.
+FBX_SETTINGS = dict(
+ use_selection=True, use_visible=False, use_active_collection=False,
+ global_scale=1.0, apply_unit_scale=True, apply_scale_options='FBX_SCALE_UNITS',
+ axis_forward='Y', axis_up='Z', bake_space_transform=False,
+ object_types={'EMPTY', 'MESH', 'ARMATURE'},
+ use_mesh_modifiers=True, use_mesh_modifiers_render=True,
+ mesh_smooth_type='OFF', use_subsurf=False, use_mesh_edges=False, use_tspace=True,
+ use_triangles=False, colors_type='LINEAR', prioritize_active_color=True,
+ use_custom_props=False,
+ add_leaf_bones=False, primary_bone_axis='Y', secondary_bone_axis='X',
+ use_armature_deform_only=True, armature_nodetype='NULL',
+ bake_anim=True, bake_anim_use_all_bones=True, bake_anim_use_nla_strips=False,
+ bake_anim_use_all_actions=True, bake_anim_force_startend_keying=True,
+ bake_anim_step=1.0, bake_anim_simplify_factor=0.0,
+ path_mode='STRIP', embed_textures=False, batch_mode='OFF',
+)
+
+
+def args():
+ argv = sys.argv[sys.argv.index('--') + 1:] if '--' in sys.argv else []
+ result = {'manifest': str(UNITY_ROOT / 'tools/blender/export_manifest.json'), 'godot': str(UNITY_ROOT.parent / 'saumwacht-godot'), 'ids': ''}
+ for i in range(0, len(argv) - 1, 2):
+ result[argv[i].lstrip('-')] = argv[i + 1]
+ return result
+
+
+class Report:
+ def __init__(self, spec):
+ self.data = {'id': spec['id'], 'group': spec['group'], 'source': spec['source'], 'exporter_version': EXPORTER_VERSION,
+ 'blender': bpy.app.version_string, 'fbx_settings': {k: (sorted(v) if isinstance(v, set) else v) for k, v in FBX_SETTINGS.items()},
+ 'checks': []}
+
+ def check(self, name, ok, detail=''):
+ self.data['checks'].append({'check': name, 'ok': bool(ok), 'detail': str(detail)})
+ return ok
+
+ @property
+ def ok(self):
+ return all(c['ok'] for c in self.data['checks'])
+
+
+def godot_expectations(spec, godot_root):
+ """Facts of the GLB the reference uses, from its manifest (triangles, nodes, bounds, ...)."""
+ source = spec.get('godot_manifest')
+ if not source:
+ return {}
+ data = json.loads((godot_root / source['file']).read_text())
+ assets = data['assets'] if isinstance(data, dict) and 'assets' in data else data
+ for entry in assets:
+ if entry.get('id') == source['id']:
+ return entry
+ raise KeyError('no entry %s in %s' % (source['id'], source['file']))
+
+
+def triangles(mesh):
+ return sum(len(p.vertices) - 2 for p in mesh.polygons)
+
+
+def evaluated_mesh(obj, depsgraph):
+ evaluated = obj.evaluated_get(depsgraph)
+ return evaluated, evaluated.to_mesh()
+
+
+def prepare(spec, report):
+ """Applies the export rules of the manifest to the opened .blend (never saved)."""
+ rules = spec.get('rules', {})
+ skip = tuple(rules.get('skip_modifiers', ()))
+ removed = 0
+ if skip:
+ for obj in bpy.data.objects:
+ for modifier in list(obj.modifiers):
+ if modifier.name.startswith(skip):
+ obj.modifiers.remove(modifier)
+ removed += 1
+ report.data['removed_modifiers'] = removed
+ if rules.get('logical_names'):
+ logical_names(report)
+ join = rules.get('join')
+ if join:
+ parts = [o for o in bpy.context.scene.objects if o.type == 'MESH' and o.parent and o.parent.name == join['parent']]
+ bpy.ops.object.select_all(action='DESELECT')
+ for obj in parts:
+ obj.select_set(True)
+ bpy.context.view_layer.objects.active = parts[0]
+ bpy.ops.object.join()
+ bpy.context.object.name = join['into']
+ bpy.context.object.data.name = join['into']
+ report.data['joined_parts'] = len(parts)
+ face_unity_forward(report)
+ rest_action = rules.get('rest_action')
+ for obj in bpy.context.scene.objects:
+ if obj.type == 'ARMATURE' and obj.animation_data:
+ # Export the bind pose, not the last evaluated frame of some action.
+ obj.animation_data.action = bpy.data.actions.get(rest_action) if rest_action else None
+ bpy.context.scene.frame_set(0)
+
+
+def face_unity_forward(report):
+ """Turns every root 180 degrees about Z and applies the turn to all objects (meshes, empties,
+ armatures with their rest pose). Bone animation is stored relative to the rest pose and
+ stays valid. Shared mesh data is made single-user first."""
+ turn = Matrix.Rotation(math.pi, 4, 'Z')
+ scene_objects = [o for o in bpy.context.scene.objects if o.type in ('MESH', 'ARMATURE', 'EMPTY')]
+ for obj in scene_objects:
+ if obj.parent is None:
+ obj.matrix_world = turn @ obj.matrix_world
+ bpy.ops.object.select_all(action='DESELECT')
+ for obj in scene_objects:
+ obj.hide_set(False)
+ obj.hide_select = False
+ obj.select_set(True)
+ bpy.context.view_layer.objects.active = scene_objects[0]
+ bpy.ops.object.transform_apply(location=False, rotation=True, scale=False, isolate_users=True)
+ turned = [o.name for o in scene_objects if o.matrix_world.to_euler().z != 0.0 and abs(o.matrix_world.to_euler().z) > 1e-5]
+ report.check('turn_applied', not turned, turned[:8])
+
+
+def logical_names(report):
+ """Phase-4 sources keep their logical names in custom properties (part_name, material_name);
+ Blender may have suffixed the datablocks (.004). The Godot pipeline renamed the GLB nodes the
+ same way (assets-source/phase4/blender/pipeline.py, _canonical_glb_names). Materials that share
+ a logical name are one material and are merged."""
+ renamed = 0
+ for obj in list(bpy.data.objects):
+ if 'part_name' in obj.keys():
+ obj.name = '__lune_tmp_' + obj.name
+ for obj in list(bpy.data.objects):
+ if 'part_name' in obj.keys():
+ obj.name = obj['part_name']
+ renamed += int(obj.name == obj['part_name'])
+ groups = {}
+ for material in list(bpy.data.materials):
+ logical = material.get('material_name')
+ if logical:
+ groups.setdefault(logical, []).append(material)
+ merged = 0
+ for logical, materials in groups.items():
+ keep = materials[0]
+ for other in materials[1:]:
+ other.user_remap(keep)
+ merged += 1
+ for material in materials[1:]:
+ bpy.data.materials.remove(material)
+ keep.name = '__lune_tmp_' + logical
+ for logical in groups:
+ bpy.data.materials['__lune_tmp_' + logical].name = logical
+ collisions = [o.name for o in bpy.data.objects if 'part_name' in o.keys() and o.name != o['part_name']]
+ report.check('logical_names_unique', not collisions, collisions[:12])
+ report.data['logical_names'] = {'objects': renamed, 'materials': len(groups), 'merged_materials': merged}
+
+
+def export_objects(spec):
+ include = spec.get('rules', {}).get('objects')
+ objects = []
+ for obj in bpy.context.scene.objects:
+ if obj.type not in ('MESH', 'ARMATURE', 'EMPTY'):
+ continue
+ if include and obj.name not in include:
+ continue
+ if obj.hide_render:
+ continue
+ objects.append(obj)
+ return objects
+
+
+def to_unity(v):
+ """Blender (x, y, z), after the turn of face_unity_forward -> Unity (x, y, z) = (x, z, y)."""
+ return Vector((v.x, v.z, v.y))
+
+
+def facts(objects, depsgraph):
+ """Scene facts in Unity coordinates: meshes, materials, bounds, bones, actions."""
+ meshes = {}
+ low = Vector((math.inf,) * 3)
+ high = Vector((-math.inf,) * 3)
+ for obj in objects:
+ if obj.type != 'MESH':
+ continue
+ evaluated, mesh = evaluated_mesh(obj, depsgraph)
+ world = evaluated.matrix_world
+ # Skinned meshes: bounds of the rest pose (armature modifier is evaluated in the bind pose).
+ mesh_low = Vector((math.inf,) * 3)
+ mesh_high = Vector((-math.inf,) * 3)
+ for vertex in mesh.vertices:
+ p = to_unity(world @ vertex.co)
+ mesh_low = Vector(map(min, mesh_low, p))
+ mesh_high = Vector(map(max, mesh_high, p))
+ low = Vector(map(min, low, mesh_low))
+ high = Vector(map(max, high, mesh_high))
+ normals_ok = all(abs(n.vector.length - 1.0) < 1e-3 for n in mesh.corner_normals)
+ meshes[obj.name] = {
+ 'mesh': obj.data.name, 'triangles': triangles(mesh), 'vertices': len(mesh.vertices),
+ 'ngons': sum(1 for p in mesh.polygons if len(p.vertices) > 4),
+ 'materials': [slot.material.name if slot.material else None for slot in obj.material_slots],
+ 'uv_layers': [uv.name for uv in mesh.uv_layers],
+ 'color_attributes': [c.name for c in mesh.color_attributes],
+ 'active_color': mesh.color_attributes.active_color.name if mesh.color_attributes.active_color else None,
+ 'custom_normals': obj.data.has_custom_normals, 'normals_unit_length': normals_ok,
+ 'shape_keys': len(obj.data.shape_keys.key_blocks) - 1 if obj.data.shape_keys else 0,
+ 'skinned': any(m.type == 'ARMATURE' for m in obj.modifiers),
+ 'scale': [round(s, 6) for s in obj.matrix_world.to_scale()],
+ 'bounds_unity': {'min': [round(c, 4) for c in mesh_low], 'max': [round(c, 4) for c in mesh_high]},
+ }
+ evaluated.to_mesh_clear()
+ armatures = {}
+ for obj in objects:
+ if obj.type == 'ARMATURE':
+ bones = [b for b in obj.data.bones if b.use_deform]
+ armatures[obj.name] = {'bones': [b.name for b in bones], 'roots': [b.name for b in bones if b.parent is None or not b.parent.use_deform]}
+ empties = {o.name: [round(c, 4) for c in to_unity(o.matrix_world.translation)] for o in objects if o.type == 'EMPTY'}
+ return {'meshes': meshes, 'armatures': armatures, 'empties': empties,
+ 'bounds_unity': {'min': [round(c, 4) for c in low], 'max': [round(c, 4) for c in high]} if meshes else None}
+
+
+def clip_facts(fps):
+ clips = []
+ for action in bpy.data.actions:
+ start, end = action.frame_range
+ clips.append({'name': action.name, 'frames': [round(start, 3), round(end, 3)], 'seconds': round((end - start) / fps, 4),
+ 'loop': bool(action.get('loop', action.name in ('idle', 'walk'))),
+ 'contact_seconds': float(action.get('contact_seconds', -1.0))})
+ return clips
+
+
+def godot_to_unity_bounds(bounds):
+ """Godot/glTF bounds (x, y, z) -> Unity (-x, y, z)."""
+ lo, hi = bounds['min'], bounds['max']
+ return {'min': [-hi[0], lo[1], lo[2]], 'max': [-lo[0], hi[1], hi[2]]}
+
+
+def run_checks(spec, report, before, clips, expect):
+ scene = bpy.context.scene
+ report.check('units_metric', scene.unit_settings.system == 'METRIC', scene.unit_settings.system)
+ report.check('unit_scale_1', abs(scene.unit_settings.scale_length - 1.0) < 1e-9, scene.unit_settings.scale_length)
+ meshes = before['meshes']
+ bad_scale = {n: m['scale'] for n, m in meshes.items() if any(abs(s - 1.0) > 1e-4 for s in m['scale'])}
+ negative = {n: s for n, s in bad_scale.items() if any(c < 0 for c in s)}
+ report.check('no_negative_scale', not negative, negative)
+ report.check('object_scale_1', not bad_scale or spec.get('rules', {}).get('allow_object_scale', False), bad_scale)
+ names = [m['mesh'] for m in meshes.values()]
+ report.check('mesh_names_unique', len(set(meshes)) == len(meshes), sorted(meshes))
+ empty_slots = {n: m['materials'] for n, m in meshes.items() if None in m['materials'] or not m['materials']}
+ report.check('material_slots_filled', not empty_slots, empty_slots)
+ report.check('normals_unit_length', all(m['normals_unit_length'] for m in meshes.values()),
+ [n for n, m in meshes.items() if not m['normals_unit_length']])
+ # Tangents need UVs and faces with at most four corners; meshes without UVs are shaded
+ # triplanar or unlit and carry no tangents (recorded, not an error).
+ tangent_blockers = {n: m['ngons'] for n, m in meshes.items() if m['uv_layers'] and m['ngons']}
+ report.check('tangent_prerequisites', not tangent_blockers, tangent_blockers)
+ report.data['meshes_without_uv'] = sorted(n for n, m in meshes.items() if not m['uv_layers'])
+ # Blend shapes: none of the sources uses them; Unity imports them only when they exist.
+ shapes = {n: m['shape_keys'] for n, m in meshes.items() if m['shape_keys']}
+ report.check('no_blend_shapes', not shapes or spec.get('rules', {}).get('blend_shapes', False), shapes)
+ total = sum(m['triangles'] for m in meshes.values())
+ report.data['triangles'] = total
+ if 'triangles' in expect:
+ report.check('triangles_match_godot', total == expect['triangles'], '%d fbx / %d godot' % (total, expect['triangles']))
+ if 'nodes' in expect:
+ report.check('mesh_names_match_godot', sorted(meshes) == sorted(expect['nodes']), sorted(set(meshes) ^ set(expect['nodes'])))
+ if 'parts' in expect and spec.get('rules', {}).get('check_parts', True):
+ report.check('mesh_names_match_godot', sorted(meshes) == sorted(expect['parts']), sorted(set(meshes) ^ set(expect['parts']))[:12])
+ if 'materials' in expect:
+ used = sorted({name for m in meshes.values() for name in m['materials'] if name})
+ report.check('materials_match_godot', used == sorted(expect['materials']), sorted(set(used) ^ set(expect['materials'])))
+ if expect.get('bounds_godot') and before['bounds_unity']:
+ # The Godot manifests measure the intact model (towers: without damaged upper part,
+ # debris, ruin and cloth); bounds_exclude names those parts.
+ exclude = tuple(spec.get('rules', {}).get('bounds_exclude', ()))
+ chosen = [m['bounds_unity'] for n, m in meshes.items() if not (exclude and n.startswith(exclude))]
+ got = {'min': [min(b['min'][i] for b in chosen) for i in range(3)], 'max': [max(b['max'][i] for b in chosen) for i in range(3)]}
+ want = godot_to_unity_bounds(expect['bounds_godot'])
+ worst = max(abs(a - b) for key in ('min', 'max') for a, b in zip(got[key], want[key]))
+ report.check('bounds_match_godot', worst < 2e-3, 'largest difference %.5f m' % worst)
+ armatures = before['armatures']
+ if spec['kind'] == 'skinned':
+ report.check('one_armature', len(armatures) == 1, sorted(armatures))
+ for name, arm in armatures.items():
+ report.check('single_root_bone', len(arm['roots']) == 1, arm['roots'])
+ want_root = spec.get('rules', {}).get('root_bone', 'Root')
+ report.check('root_bone_name', arm['roots'] == [want_root], arm['roots'])
+ if 'bone_names' in expect:
+ report.check('bone_names_match_godot', sorted(arm['bones']) == sorted(expect['bone_names']), sorted(set(arm['bones']) ^ set(expect['bone_names'])))
+ if 'bones' in expect:
+ report.check('bone_count_match_godot', len(arm['bones']) == expect['bones'], '%d / %d' % (len(arm['bones']), expect['bones']))
+ bad = [b for b in arm['bones'] if not b.replace('.', '').replace('_', '').isalnum()]
+ report.check('bone_names_portable', not bad, bad)
+ report.check('skinned_meshes_present', any(m['skinned'] for m in meshes.values()), '')
+ names = sorted(c['name'] for c in clips)
+ if 'clips' in expect:
+ report.check('clips_match_godot', names == sorted(expect['clips']), sorted(set(names) ^ set(expect['clips'])))
+ required = spec.get('rules', {}).get('required_clips', [])
+ report.check('required_clips_present', all(c in names for c in required), [c for c in required if c not in names])
+ if 'clip_seconds' in expect:
+ worst = max(abs(c['seconds'] - expect['clip_seconds'][c['name']]) for c in clips if c['name'] in expect['clip_seconds'])
+ report.check('clip_lengths_match_godot', worst < 1e-3, 'largest difference %.4f s' % worst)
+ else:
+ report.check('no_armature', not armatures, sorted(armatures))
+ forward = spec.get('rules', {}).get('forward_marker')
+ if forward:
+ marker = next((p for n, p in before['empties'].items() if n.startswith(forward)), None)
+ report.check('forward_marker_unity_plus_z', marker is not None and marker[2] > 0.1 and abs(marker[0]) < 1e-3, marker)
+
+
+def reproducible_fbx():
+ """Byte-identical FBX for identical sources: Blender's FBX writer stamps the current time into
+ the header and derives object ids from Python's string hash. The clock is fixed here; the hash
+ seed comes from PYTHONHASHSEED=0 with --python-use-system-env (tools/blender/export_fbx.sh)."""
+ import datetime
+ import io_scene_fbx.export_fbx_bin as writer
+
+ class FixedClock(datetime.datetime):
+ @classmethod
+ def now(cls, tz=None):
+ return cls(2026, 1, 1, 0, 0, 0)
+
+ class Clock:
+ datetime = FixedClock
+
+ writer.datetime = Clock
+
+
+def export_fbx(path, objects):
+ bpy.ops.object.select_all(action='DESELECT')
+ for obj in objects:
+ obj.select_set(True)
+ bpy.context.view_layer.objects.active = objects[0]
+ path.parent.mkdir(parents=True, exist_ok=True)
+ bpy.ops.export_scene.fbx(filepath=str(path), **FBX_SETTINGS)
+
+
+def round_trip(path, spec, report, before, clips):
+ """Imports the written FBX into an empty file and compares names and counts."""
+ bpy.ops.wm.read_factory_settings(use_empty=True)
+ bpy.ops.import_scene.fbx(filepath=str(path), use_custom_normals=True, use_anim=True, automatic_bone_orientation=False)
+ depsgraph = bpy.context.evaluated_depsgraph_get()
+ imported = [o for o in bpy.context.scene.objects]
+ meshes = {o.name: o for o in imported if o.type == 'MESH'}
+ report.check('roundtrip_mesh_names', sorted(meshes) == sorted(before['meshes']), sorted(set(meshes) ^ set(before['meshes'])))
+ tri = 0
+ for obj in meshes.values():
+ evaluated, mesh = evaluated_mesh(obj, depsgraph)
+ tri += triangles(mesh)
+ evaluated.to_mesh_clear()
+ report.check('roundtrip_triangles', tri == report.data['triangles'], '%d / %d' % (tri, report.data['triangles']))
+ materials = sorted({s.material.name for o in meshes.values() for s in o.material_slots if s.material})
+ want = sorted({name for m in before['meshes'].values() for name in m['materials'] if name})
+ report.check('roundtrip_materials', materials == want, sorted(set(materials) ^ set(want)))
+ if spec['kind'] == 'skinned':
+ arm = next(o for o in imported if o.type == 'ARMATURE')
+ bones = sorted(b.name for b in arm.data.bones)
+ want_bones = sorted(next(iter(before['armatures'].values()))['bones'])
+ report.check('roundtrip_bones', bones == want_bones, sorted(set(bones) ^ set(want_bones)))
+ takes = sorted(a.name.split('|')[-1] for a in bpy.data.actions)
+ report.check('roundtrip_clips', takes == sorted(c['name'] for c in clips), takes)
+
+
+def export_asset(spec, godot_root):
+ report = Report(spec)
+ source = godot_root / spec['source']
+ bpy.ops.wm.open_mainfile(filepath=str(source))
+ report.data['source_sha256'] = hashlib.sha256(source.read_bytes()).hexdigest()
+ expect = godot_expectations(spec, godot_root)
+ fps = bpy.context.scene.render.fps / bpy.context.scene.render.fps_base
+ prepare(spec, report)
+ objects = export_objects(spec)
+ # Facts of the bind pose (rest), like the Godot manifests; the animation bake needs POSE again.
+ armatures = [o for o in objects if o.type == 'ARMATURE']
+ for arm in armatures:
+ arm.data.pose_position = 'REST'
+ bpy.context.view_layer.update()
+ depsgraph = bpy.context.evaluated_depsgraph_get()
+ before = facts(objects, depsgraph)
+ for arm in armatures:
+ arm.data.pose_position = 'POSE'
+ bpy.context.view_layer.update()
+ clips = clip_facts(fps) if spec['kind'] == 'skinned' else []
+ report.data.update({'kind': spec['kind'], 'fps': fps, 'objects': len(objects), 'meshes': before['meshes'], 'armatures': before['armatures'],
+ 'empties': before['empties'], 'bounds_unity': before['bounds_unity'], 'clips': clips,
+ 'expected_from_godot': {k: expect[k] for k in ('triangles', 'bounds_godot', 'bones', 'clips', 'resource_path') if k in expect}})
+ run_checks(spec, report, before, clips, expect)
+ out = UNITY_ROOT / 'Assets/Luneraria/Art' / spec['group'] / (spec['id'] + '.fbx')
+ export_fbx(out, objects)
+ report.data['fbx'] = str(out.relative_to(UNITY_ROOT))
+ report.data['fbx_bytes'] = out.stat().st_size
+ round_trip(out, spec, report, before, clips)
+ report.data['ok'] = report.ok
+ (out.with_suffix('.export.json')).write_text(json.dumps(report.data, indent=1) + '\n')
+ failed = [c for c in report.data['checks'] if not c['ok']]
+ print('LUNE_EXPORT %s %s: %d checks, %d failed%s' % ('OK' if not failed else 'FAIL', spec['id'], len(report.data['checks']), len(failed),
+ ''.join('\n FAIL %s: %s' % (c['check'], c['detail']) for c in failed)))
+ return report.ok
+
+
+def main():
+ reproducible_fbx()
+ options = args()
+ manifest = json.loads(Path(options['manifest']).read_text())
+ godot_root = Path(options['godot']).resolve()
+ wanted = [i for i in options['ids'].split(',') if i]
+ specs = [s for s in manifest['assets'] if not wanted or s['id'] in wanted]
+ missing = set(wanted) - {s['id'] for s in specs}
+ ok = not missing
+ if missing:
+ print('LUNE_EXPORT FAIL unknown ids', sorted(missing))
+ for spec in specs:
+ try:
+ ok = export_asset(spec, godot_root) and ok
+ except Exception as error: # a broken asset must not stop the batch
+ import traceback
+ traceback.print_exc()
+ print('LUNE_EXPORT FAIL %s: %s' % (spec['id'], error))
+ ok = False
+ print('LUNE_EXPORT_DONE ok=%s assets=%d' % (ok, len(specs)))
+ sys.exit(0 if ok else 1)
+
+
+main()