diff --git a/Makefile b/Makefile index f034dc6..9f57311 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,12 @@ export-clean: rm -f assets/blender/scripts/tmp-*.blend import-vrm: export-clean + mkdir -p assets/blender/scripts/shapes/male assets/blender/scripts/shapes/female $(BLENDER) -b -Y -P assets/blender/scripts/import_vrm.py +export2edit: import-vrm + $(BLENDER) -b -Y -P assets/blender/scripts/export_for_modelling.py + export-models: export-clean import-vrm $(BLENDER) -b -Y -P assets/blender/scripts/export_models.py diff --git a/assets/blender/scripts/export_for_modelling.py b/assets/blender/scripts/export_for_modelling.py index c6484e7..b33c877 100644 --- a/assets/blender/scripts/export_for_modelling.py +++ b/assets/blender/scripts/export_for_modelling.py @@ -14,21 +14,7 @@ from mixamo.lib.armature import * #from mixamo.mixamoroot import import_armature #from mixamo.import_mixamo_root_motion import import_mixamo_root_motion -basepath = os.getcwd() -class VRMDataFemale: - path = "jane2-dress.vrm" - outfile = "vrm-vroid-normal-female.blend" - armature_name = "female" - mixamo_animation_path = basepath + "/assets/blender/mixamo/female/" - mixamo_animations = ["idle", "walking", "running", "jump", "left_turn", "right_turn"] - fbx_scale = 0.89 -class VRMDataMale: - path = "buch1.vrm" - outfile = "vrm-vroid-normal-male.blend" - armature_name = "male" - mixamo_animation_path = basepath + "/assets/blender/mixamo/male/" - mixamo_animations = ["idle", "walking", "running", "jump", "left_turn", "right_turn"] - fbx_scale = 1.0 +from settings import VRMDataFemale, VRMDataMale, basepath imports = [VRMDataFemale(), VRMDataMale()] @@ -132,4 +118,4 @@ for imp in imports: main_armature.select_set(False) bpy.context.view_layer.objects.active = None - bpy.ops.wm.save_as_mainfile(filepath=(basepath + "/assets/blender/" + imp.outfile)) + bpy.ops.wm.save_as_mainfile(filepath=(basepath + "/assets/blender/" + imp.editfile)) diff --git a/assets/blender/scripts/export_models.py b/assets/blender/scripts/export_models.py index b9d6209..3b6d24a 100644 --- a/assets/blender/scripts/export_models.py +++ b/assets/blender/scripts/export_models.py @@ -9,7 +9,7 @@ from mathutils import Vector, Matrix from math import radians, pi sys.path.insert(0, os.getcwd() + "/assets/blender/scripts") -from settings import ExportMappingFemale, ExportMappingMale +from settings import ExportMappingFemale, ExportMappingMale, ExportMappingMaleBabyShape basepath = os.getcwd() def check_bone(bname): @@ -179,7 +179,7 @@ def extra_linear(angle, offset): ret += offt return ret -for mapping in [ExportMappingFemale(), ExportMappingMale()]: +for mapping in [ExportMappingFemale(), ExportMappingMale(), ExportMappingMaleBabyShape()]: #for mapping in [ExportMappingFemale()]: print("Initializing...") bpy.ops.wm.read_homefile(use_empty=True) diff --git a/assets/blender/scripts/import_vrm.py b/assets/blender/scripts/import_vrm.py index fddbc93..690cabb 100644 --- a/assets/blender/scripts/import_vrm.py +++ b/assets/blender/scripts/import_vrm.py @@ -13,10 +13,10 @@ from mixamo import mixamo_rig from mixamo.lib.armature import * #from mixamo.mixamoroot import import_armature #from mixamo.import_mixamo_root_motion import import_mixamo_root_motion -from settings import VRMDataFemale, VRMDataMale, basepath +from settings import VRMDataFemale, VRMDataMale, VRMDataMaleBabyShape, basepath -imports = [VRMDataFemale(), VRMDataMale()] +imports = [VRMDataFemale(), VRMDataMale(), VRMDataMaleBabyShape()] class mkrig: diff --git a/src/modules/stream/npc/importer.cpp b/src/modules/stream/npc/importer.cpp new file mode 100644 index 0000000..d790290 --- /dev/null +++ b/src/modules/stream/npc/importer.cpp @@ -0,0 +1,292 @@ +#define TOOLS_ENABLED +#undef NDEBUG +#include +#include +#include +#include "importer.h" + +#ifdef TOOLS_ENABLED +EditorImportNPC::EditorImportNPC() + : EditorSceneImporterGLTF() +{ +} + +uint32_t EditorImportNPC::get_import_flags() const +{ + return EditorSceneImporterGLTF::get_import_flags(); +} +void EditorImportNPC::get_extensions(List *r_extensions) const +{ + r_extensions->push_back("npc"); +} +Node *EditorImportNPC::import_scene(const String &p_path, uint32_t p_flags, + int p_bake_fps, uint32_t p_compress_flags, + List *r_missing_deps, Error *r_err) +{ + Node *result; + List queue; + Ref importer; + ConfigFile config; + String config_path = + p_path.replace(".npc", ".conf") + .replace("/character-data/", "/character/"); + Error err = config.load(config_path); + print_line("config path: " + config_path); + if (err == OK) + print_line("config loaded..."); + importer.instance(); + result = importer->import_scene(p_path, p_flags, p_bake_fps, + p_compress_flags, r_missing_deps, r_err, + Ref()); + queue.push_back(result); + while (!queue.empty()) { + bool do_destroy = false; + int i, count; + Node *item = queue.front()->get(); + queue.pop_front(); + MeshInstance *mi = Object::cast_to(item); + if (mi) { + String mesh_name = mi->get_name(); + mesh_name = mesh_name.to_lower().strip_edges(); + String section = mesh_name; + Ref mesh = mi->get_mesh(); + if (config.has_section(section) && mesh.is_valid()) { + print_line("section: " + section); + print_line("has section: " + section); + int surf_count = mesh->get_surface_count(); + HashMap > split_meshes; + for (i = 0; i < surf_count; i++) { + String surf_section = mesh_name + + "/surfaces/" + + itos(i); + print_line("surf_section: " + + surf_section); + if (!config.has_section(surf_section)) + continue; + print_line("has section: " + + surf_section); + bool transparent = config.get_value( + surf_section, "transparent", + false); + bool alpha_scissors = config.get_value( + surf_section, "alpha_scissors", + false); + Ref mat = + mesh->surface_get_material(i); + if (mat.is_valid()) { + mat->set_feature( + SpatialMaterial:: + FEATURE_TRANSPARENT, + transparent); + mat->set_flag( + SpatialMaterial:: + FLAG_USE_ALPHA_SCISSOR, + alpha_scissors); + } + if (config.has_section_key(surf_section, + "split")) { + Array split = config.get_value( + surf_section, "split", + Array()); + Ref new_mesh; + ArrayMesh::PrimitiveType ptype; + Array surface, bshapes; + String split_name = split[0]; + MeshInstance *split_mi; + if (split_meshes.has( + split_name)) + new_mesh = split_meshes + [split_name]; + else { + new_mesh.instance(); + new_mesh->set_storage_mode( + ArrayMesh:: + STORAGE_MODE_CPU); + split_meshes[split_name] = + new_mesh; + split_mi = memnew( + MeshInstance); + mi->get_parent() + ->add_child( + split_mi); + split_mi->set_owner( + mi->get_owner()); + split_mi->set_mesh( + new_mesh); + split_mi->set_name( + split_name); + } + ptype = mesh->surface_get_primitive_type( + i); + surface = + mesh->surface_get_arrays( + i); + bshapes = + mesh->surface_get_blend_shape_arrays( + i); + new_mesh->add_surface_from_arrays( + ptype, surface, + bshapes); + new_mesh->surface_set_material( + new_mesh->get_surface_count() - + 1, + mat); + } + } +#if 0 + if (mesh_name == "body") { + if (mesh.is_valid()) { + Ref new_body, + clothes; + new_body.instance(); + new_body->set_storage_mode( + ArrayMesh:: + STORAGE_MODE_CPU); + int surf_count = + mesh->get_surface_count(); + if (surf_count > 0) { + MeshInstance *clothes_mi = + memnew(MeshInstance); + mi->get_parent()->add_child( + clothes_mi); + clothes_mi->set_owner( + mi->get_owner()); + clothes.instance(); + clothes->set_storage_mode( + ArrayMesh:: + STORAGE_MODE_CPU); + clothes_mi->set_mesh( + clothes); + } + for (i = 0; i < surf_count; + i++) { + uint32_t sformat = + mesh->surface_get_format( + i); + ArrayMesh::PrimitiveType ptype = + mesh->surface_get_primitive_type( + i); + Array surface = + mesh->surface_get_arrays( + i); + Array bshapes = + mesh->surface_get_blend_shape_arrays( + i); + + if (i == 0) + new_body->add_surface_from_arrays( + ptype, + surface, + bshapes); + else + clothes->add_surface_from_arrays( + ptype, + surface, + bshapes); + Ref mat = + mesh->surface_get_material( + i); + if (i == 0) + new_body->surface_set_material( + i, mat); + else + clothes->surface_set_material( + i - 1, + mat); + if (mat.is_valid()) { + String pname = + mat->get_name(); + assert(pname.size() > + 0); + if (i == 0) + new_body->surface_set_name( + i, + pname); + else + clothes->surface_set_name( + i - 1, + pname); + } + } + for (i = 0; i < surf_count; + i++) { + Ref mat = + mesh->surface_get_material( + i); + if (mat.is_valid()) { + mat->set_feature( + SpatialMaterial:: + FEATURE_TRANSPARENT, + false); + if (i >= 2) + mat->set_flag( + SpatialMaterial:: + FLAG_USE_ALPHA_SCISSOR, + true); + else + mat->set_flag( + SpatialMaterial:: + FLAG_USE_ALPHA_SCISSOR, + false); + } + } + mi->set_mesh(new_body); + new_body->set_storage_mode( + ArrayMesh:: + STORAGE_MODE_GPU); + if (clothes.is_valid()) + clothes->set_storage_mode( + ArrayMesh:: + STORAGE_MODE_GPU); + } + } + if (mesh_name == "hair") { + if (mesh.is_valid()) { + int surf_count = + mesh->get_surface_count(); + for (i = 0; i < surf_count; + i++) { + Ref mat = + mesh->surface_get_material( + i); + if (mat.is_valid()) { + mat->set_feature( + SpatialMaterial:: + FEATURE_TRANSPARENT, + false); + mat->set_flag( + SpatialMaterial:: + FLAG_USE_ALPHA_SCISSOR, + false); + } + } + } + } +#endif + List mesh_keys; + split_meshes.get_key_list(&mesh_keys); + List::Element *e = mesh_keys.front(); + while (e) { + split_meshes[e->get()]->set_storage_mode( + ArrayMesh::STORAGE_MODE_GPU); + e = e->next(); + } + } + do_destroy = + config.get_value(section, "destroy", false); + } + count = item->get_child_count(); + for (i = 0; i < count; i++) + queue.push_back(item->get_child(i)); + if (do_destroy) + item->queue_delete(); + } + return result; +} +Ref EditorImportNPC::import_animation(const String &p_path, + uint32_t p_flags, + int p_bake_fps) +{ + return Ref(); +} +#endif diff --git a/src/modules/stream/npc/importer.h b/src/modules/stream/npc/importer.h new file mode 100644 index 0000000..4c253ac --- /dev/null +++ b/src/modules/stream/npc/importer.h @@ -0,0 +1,23 @@ +/* ~/godot-projects/streaming_world/src/modules/stream/npc/importer.h */ +#ifndef NPC_IMPORTER_H_ +#define NPC_IMPORTER_H_ +#include +#ifdef TOOLS_ENABLED +class EditorImportNPC : public EditorSceneImporterGLTF { + GDCLASS(EditorImportNPC, EditorSceneImporterGLTF) +public: + EditorImportNPC(); + +protected: + virtual uint32_t get_import_flags() const; + virtual void get_extensions(List *r_extensions) const; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, + int p_bake_fps, uint32_t p_compress_flags, + List *r_missing_deps = nullptr, + Error *r_err = nullptr); + virtual Ref import_animation(const String &p_path, + uint32_t p_flags, + int p_bake_fps); +}; +#endif +#endif // IMPORTER_H_ \ No newline at end of file