diff options
author | RĂ©mi Verschelde <rverschelde@gmail.com> | 2020-12-14 07:35:02 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-12-14 07:35:02 +0100 |
commit | fe49eaa54479ac1e568bd204cabc854930936a07 (patch) | |
tree | 576d8a3a04b752f74f205dbfbf44cb3a8fead55c /editor | |
parent | b006fafad9d5439b7597d4794a00b38386a5f2f5 (diff) | |
parent | 77a045e902db9f5f0ea7961e827c337541a6436c (diff) |
Merge pull request #44319 from reduz/integrate-meshoptimizer
Rework Mesh handling on scene importing.
Diffstat (limited to 'editor')
-rw-r--r-- | editor/editor_node.cpp | 3 | ||||
-rw-r--r-- | editor/import/editor_import_collada.cpp | 39 | ||||
-rw-r--r-- | editor/import/editor_scene_importer_gltf.cpp | 37 | ||||
-rw-r--r-- | editor/import/editor_scene_importer_gltf.h | 8 | ||||
-rw-r--r-- | editor/import/resource_importer_obj.cpp | 26 | ||||
-rw-r--r-- | editor/import/resource_importer_scene.cpp | 328 | ||||
-rw-r--r-- | editor/import/resource_importer_scene.h | 87 |
7 files changed, 485 insertions, 43 deletions
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 66c54c4267..8cdb865937 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -3654,6 +3654,9 @@ void EditorNode::register_editor_types() { ClassDB::register_class<ScriptCreateDialog>(); ClassDB::register_class<EditorFeatureProfile>(); ClassDB::register_class<EditorSpinSlider>(); + ClassDB::register_class<EditorSceneImporterMesh>(); + ClassDB::register_class<EditorSceneImporterMeshNode>(); + ClassDB::register_virtual_class<FileSystemDock>(); // FIXME: Is this stuff obsolete, or should it be ported to new APIs? diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 270bdc3821..4e93fe6f12 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -67,7 +67,7 @@ struct ColladaImport { Map<String, NodeMap> node_map; //map from collada node to engine node Map<String, String> node_name_map; //map from collada node to engine node - Map<String, Ref<ArrayMesh>> mesh_cache; + Map<String, Ref<EditorSceneImporterMesh>> mesh_cache; Map<String, Ref<Curve3D>> curve_cache; Map<String, Ref<Material>> material_cache; Map<Collada::Node *, Skeleton3D *> skeleton_map; @@ -83,7 +83,7 @@ struct ColladaImport { Error _create_scene(Collada::Node *p_node, Node3D *p_parent); Error _create_resources(Collada::Node *p_node, bool p_use_compression); Error _create_material(const String &p_target); - Error _create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh>> p_morph_meshes = Vector<Ref<ArrayMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false); + Error _create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes = Vector<Ref<EditorSceneImporterMesh>>(), bool p_use_compression = false, bool p_use_mesh_material = false); Error load(const String &p_path, int p_flags, bool p_force_make_tangents = false, bool p_use_compression = false); void _fix_param_animation_tracks(); void create_animation(int p_clip, bool p_make_tracks_in_all_bones, bool p_import_value_tracks); @@ -278,8 +278,8 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) { node = memnew(Path3D); } else { //mesh since nothing else - node = memnew(MeshInstance3D); - //Object::cast_to<MeshInstance3D>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true); + node = memnew(EditorSceneImporterMeshNode); + //Object::cast_to<EditorSceneImporterMeshNode>(node)->set_flag(GeometryInstance3D::FLAG_USE_BAKED_LIGHT, true); } } break; case Collada::Node::TYPE_SKELETON: { @@ -440,7 +440,7 @@ Error ColladaImport::_create_material(const String &p_target) { return OK; } -Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<ArrayMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) { +Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<EditorSceneImporterMesh> &p_mesh, const Map<String, Collada::NodeGeometry::Material> &p_material_map, const Collada::MeshData &meshdata, const Transform &p_local_xform, const Vector<int> &bone_remap, const Collada::SkinControllerData *p_skin_controller, const Collada::MorphControllerData *p_morph_data, Vector<Ref<EditorSceneImporterMesh>> p_morph_meshes, bool p_use_compression, bool p_use_mesh_material) { bool local_xform_mirror = p_local_xform.basis.determinant() < 0; if (p_morph_data) { @@ -457,9 +457,9 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me p_mesh->add_blend_shape(name); } if (p_morph_data->mode == "RELATIVE") { - p_mesh->set_blend_shape_mode(ArrayMesh::BLEND_SHAPE_MODE_RELATIVE); + p_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_RELATIVE); } else if (p_morph_data->mode == "NORMALIZED") { - p_mesh->set_blend_shape_mode(ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED); + p_mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); } } @@ -897,7 +897,7 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me //////////////////////////// for (int mi = 0; mi < p_morph_meshes.size(); mi++) { - Array a = p_morph_meshes[mi]->surface_get_arrays(surface); + Array a = p_morph_meshes[mi]->get_surface_arrays(surface); //add valid weight and bone arrays if they exist, TODO check if they are unique to shape (generally not) if (has_weights) { @@ -910,14 +910,15 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me mr.push_back(a); } - p_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), 0); - + String surface_name; + Ref<Material> mat; if (material.is_valid()) { if (p_use_mesh_material) { - p_mesh->surface_set_material(surface, material); + mat = material; } - p_mesh->surface_set_name(surface, material->get_name()); + surface_name = material->get_name(); } + p_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, d, mr, Dictionary(), mat, surface_name); } /*****************/ @@ -1002,10 +1003,10 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres } } - if (Object::cast_to<MeshInstance3D>(node)) { + if (Object::cast_to<EditorSceneImporterMeshNode>(node)) { Collada::NodeGeometry *ng2 = static_cast<Collada::NodeGeometry *>(p_node); - MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(node); + EditorSceneImporterMeshNode *mi = Object::cast_to<EditorSceneImporterMeshNode>(node); ERR_FAIL_COND_V(!mi, ERR_BUG); @@ -1014,7 +1015,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres String meshid; Transform apply_xform; Vector<int> bone_remap; - Vector<Ref<ArrayMesh>> morphs; + Vector<Ref<EditorSceneImporterMesh>> morphs; if (ng2->controller) { String ngsource = ng2->source; @@ -1083,10 +1084,10 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres for (int i = 0; i < names.size(); i++) { String meshid2 = names[i]; if (collada.state.mesh_data_map.has(meshid2)) { - Ref<ArrayMesh> mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); + Ref<EditorSceneImporterMesh> mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh)); const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid2]; mesh->set_name(meshdata.name); - Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<ArrayMesh>>(), false); + Error err = _create_mesh_surfaces(false, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, nullptr, Vector<Ref<EditorSceneImporterMesh>>(), false); ERR_FAIL_COND_V(err, err); morphs.push_back(mesh); @@ -1109,7 +1110,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres meshid = ng2->source; } - Ref<ArrayMesh> mesh; + Ref<EditorSceneImporterMesh> mesh; if (mesh_cache.has(meshid)) { mesh = mesh_cache[meshid]; } else { @@ -1117,7 +1118,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres //bleh, must ignore invalid ERR_FAIL_COND_V(!collada.state.mesh_data_map.has(meshid), ERR_INVALID_DATA); - mesh = Ref<ArrayMesh>(memnew(ArrayMesh)); + mesh = Ref<EditorSceneImporterMesh>(memnew(EditorSceneImporterMesh)); const Collada::MeshData &meshdata = collada.state.mesh_data_map[meshid]; mesh->set_name(meshdata.name); Error err = _create_mesh_surfaces(morphs.size() == 0, mesh, ng2->material_map, meshdata, apply_xform, bone_remap, skin, morph, morphs, p_use_compression, use_mesh_builtin_materials); diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index ac76f67ef9..1059692ca0 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -970,8 +970,6 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { return OK; } - uint32_t mesh_flags = 0; - Array meshes = state.json["meshes"]; for (GLTFMeshIndex i = 0; i < meshes.size(); i++) { print_verbose("glTF: Parsing mesh: " + itos(i)); @@ -979,6 +977,7 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { GLTFMesh mesh; mesh.mesh.instance(); + bool has_vertex_color = false; ERR_FAIL_COND_V(!d.has("primitives"), ERR_PARSE_ERROR); @@ -1034,6 +1033,7 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { } if (a.has("COLOR_0")) { array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(state, a["COLOR_0"], true); + has_vertex_color = true; } if (a.has("JOINTS_0")) { array[Mesh::ARRAY_BONES] = _decode_accessor_as_ints(state, a["JOINTS_0"], true); @@ -1112,7 +1112,7 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { //ideally BLEND_SHAPE_MODE_RELATIVE since gltf2 stores in displacement //but it could require a larger refactor? - mesh.mesh->set_blend_shape_mode(ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED); + mesh.mesh->set_blend_shape_mode(Mesh::BLEND_SHAPE_MODE_NORMALIZED); if (j == 0) { const Array &target_names = extras.has("targetNames") ? (Array)extras["targetNames"] : Array(); @@ -1226,21 +1226,25 @@ Error EditorSceneImporterGLTF::_parse_meshes(GLTFState &state) { } //just add it - mesh.mesh->add_surface_from_arrays(primitive, array, morphs, Dictionary(), mesh_flags); + Ref<Material> mat; if (p.has("material")) { const int material = p["material"]; ERR_FAIL_INDEX_V(material, state.materials.size(), ERR_FILE_CORRUPT); - const Ref<Material> &mat = state.materials[material]; - - mesh.mesh->surface_set_material(mesh.mesh->get_surface_count() - 1, mat); - } else { - Ref<StandardMaterial3D> mat; - mat.instance(); - mat->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + Ref<StandardMaterial3D> mat3d = state.materials[material]; + if (has_vertex_color) { + mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + } + mat = mat3d; - mesh.mesh->surface_set_material(mesh.mesh->get_surface_count() - 1, mat); + } else if (has_vertex_color) { + Ref<StandardMaterial3D> mat3d; + mat3d.instance(); + mat3d->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + mat = mat3d; } + + mesh.mesh->add_surface(primitive, array, morphs, Dictionary(), mat); } mesh.blend_weights.resize(mesh.mesh->get_blend_shape_count()); @@ -1440,7 +1444,8 @@ Error EditorSceneImporterGLTF::_parse_materials(GLTFState &state) { if (d.has("name")) { material->set_name(d["name"]); } - material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); + //don't do this here only if vertex color exists + //material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true); if (d.has("pbrMetallicRoughness")) { const Dictionary &mr = d["pbrMetallicRoughness"]; @@ -2586,12 +2591,12 @@ BoneAttachment3D *EditorSceneImporterGLTF::_generate_bone_attachment(GLTFState & return bone_attachment; } -MeshInstance3D *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) { +EditorSceneImporterMeshNode *EditorSceneImporterGLTF::_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index) { const GLTFNode *gltf_node = state.nodes[node_index]; ERR_FAIL_INDEX_V(gltf_node->mesh, state.meshes.size(), nullptr); - MeshInstance3D *mi = memnew(MeshInstance3D); + EditorSceneImporterMeshNode *mi = memnew(EditorSceneImporterMeshNode); print_verbose("glTF: Creating mesh for: " + gltf_node->name); GLTFMesh &mesh = state.meshes.write[gltf_node->mesh]; @@ -3058,7 +3063,7 @@ void EditorSceneImporterGLTF::_process_mesh_instances(GLTFState &state, Node3D * const GLTFSkinIndex skin_i = node->skin; Map<GLTFNodeIndex, Node *>::Element *mi_element = state.scene_nodes.find(node_i); - MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get()); + EditorSceneImporterMeshNode *mi = Object::cast_to<EditorSceneImporterMeshNode>(mi_element->get()); ERR_FAIL_COND(mi == nullptr); const GLTFSkeletonIndex skel_i = state.skins[node->skin].skeleton; diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h index 5ea8bf17b8..6390f46524 100644 --- a/editor/import/editor_scene_importer_gltf.h +++ b/editor/import/editor_scene_importer_gltf.h @@ -38,7 +38,7 @@ class AnimationPlayer; class BoneAttachment3D; -class MeshInstance3D; +class EditorSceneImporterMeshNode; class EditorSceneImporterGLTF : public EditorSceneImporter { GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter); @@ -199,7 +199,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { }; struct GLTFMesh { - Ref<ArrayMesh> mesh; + Ref<EditorSceneImporterMesh> mesh; Vector<float> blend_weights; }; @@ -262,7 +262,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { Vector<GLTFAccessor> accessors; Vector<GLTFMesh> meshes; //meshes are loaded directly, no reason not to. - Vector<Ref<Material>> materials; + Vector<Ref<StandardMaterial3D>> materials; String scene_name; Vector<int> root_nodes; @@ -355,7 +355,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter { Error _parse_animations(GLTFState &state); BoneAttachment3D *_generate_bone_attachment(GLTFState &state, Skeleton3D *skeleton, const GLTFNodeIndex node_index); - MeshInstance3D *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); + EditorSceneImporterMeshNode *_generate_mesh_instance(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); Camera3D *_generate_camera(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); Light3D *_generate_light(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); Node3D *_generate_spatial(GLTFState &state, Node *scene_parent, const GLTFNodeIndex node_index); diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index d4560a2984..30c7b2920a 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -225,6 +225,8 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ String current_material_library; String current_material; String current_group; + uint32_t smooth_group = 0; + bool smoothing = true; while (true) { String l = f->get_line().strip_edges(); @@ -315,6 +317,10 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ Vector3 vertex = vertices[vtx]; //if (weld_vertices) // vertex.snap(Vector3(weld_tolerance, weld_tolerance, weld_tolerance)); + if (!smoothing) { + smooth_group++; + } + surf_tool->set_smooth_group(smooth_group); surf_tool->add_vertex(vertex); } @@ -322,10 +328,15 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ } } else if (l.begins_with("s ")) { //smoothing String what = l.substr(2, l.length()).strip_edges(); + bool do_smooth; if (what == "off") { - surf_tool->add_smooth_group(false); + do_smooth = false; } else { - surf_tool->add_smooth_group(true); + do_smooth = true; + } + if (do_smooth != smoothing) { + smooth_group++; + smoothing = do_smooth; } } else if (/*l.begins_with("g ") ||*/ l.begins_with("usemtl ") || (l.begins_with("o ") || f->eof_reached())) { //commit group to mesh //groups are too annoying @@ -426,8 +437,15 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in Node3D *scene = memnew(Node3D); for (List<Ref<Mesh>>::Element *E = meshes.front(); E; E = E->next()) { - MeshInstance3D *mi = memnew(MeshInstance3D); - mi->set_mesh(E->get()); + Ref<EditorSceneImporterMesh> mesh; + mesh.instance(); + Ref<Mesh> m = E->get(); + for (int i = 0; i < m->get_surface_count(); i++) { + mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i)); + } + + EditorSceneImporterMeshNode *mi = memnew(EditorSceneImporterMeshNode); + mi->set_mesh(mesh); mi->set_name(E->get()->get_name()); scene->add_child(mi); mi->set_owner(scene); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index fc4f673ec4..5abae339df 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -119,6 +119,304 @@ void EditorSceneImporter::_bind_methods() { BIND_CONSTANT(IMPORT_USE_COMPRESSION); } +//////////////////////////////////////////////// + +void EditorSceneImporterMesh::add_blend_shape(const String &p_name) { + ERR_FAIL_COND(surfaces.size() > 0); + blend_shapes.push_back(p_name); +} + +int EditorSceneImporterMesh::get_blend_shape_count() const { + return blend_shapes.size(); +} + +String EditorSceneImporterMesh::get_blend_shape_name(int p_blend_shape) const { + ERR_FAIL_INDEX_V(p_blend_shape, blend_shapes.size(), String()); + return blend_shapes[p_blend_shape]; +} + +void EditorSceneImporterMesh::set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode) { + blend_shape_mode = p_blend_shape_mode; +} +Mesh::BlendShapeMode EditorSceneImporterMesh::get_blend_shape_mode() const { + return blend_shape_mode; +} + +void EditorSceneImporterMesh::add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, const Dictionary &p_lods, const Ref<Material> &p_material, const String &p_name) { + ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size()); + ERR_FAIL_COND(p_arrays.size() != Mesh::ARRAY_MAX); + Surface s; + s.primitive = p_primitive; + s.arrays = p_arrays; + s.name = p_name; + + for (int i = 0; i < blend_shapes.size(); i++) { + Array bsdata = p_blend_shapes[i]; + ERR_FAIL_COND(bsdata.size() != Mesh::ARRAY_MAX); + Surface::BlendShape bs; + bs.arrays = bsdata; + s.blend_shape_data.push_back(bs); + } + + List<Variant> lods; + p_lods.get_key_list(&lods); + for (List<Variant>::Element *E = lods.front(); E; E = E->next()) { + ERR_CONTINUE(!E->get().is_num()); + Surface::LOD lod; + lod.distance = E->get(); + lod.indices = p_lods[E->get()]; + ERR_CONTINUE(lod.indices.size() == 0); + s.lods.push_back(lod); + } + + s.material = p_material; + + surfaces.push_back(s); + mesh.unref(); +} +int EditorSceneImporterMesh::get_surface_count() const { + return surfaces.size(); +} + +Mesh::PrimitiveType EditorSceneImporterMesh::get_surface_primitive_type(int p_surface) { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Mesh::PRIMITIVE_MAX); + return surfaces[p_surface].primitive; +} +Array EditorSceneImporterMesh::get_surface_arrays(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array()); + return surfaces[p_surface].arrays; +} +String EditorSceneImporterMesh::get_surface_name(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), String()); + return surfaces[p_surface].name; +} +Array EditorSceneImporterMesh::get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Array()); + ERR_FAIL_INDEX_V(p_blend_shape, surfaces[p_surface].blend_shape_data.size(), Array()); + return surfaces[p_surface].blend_shape_data[p_blend_shape].arrays; +} +int EditorSceneImporterMesh::get_surface_lod_count(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0); + return surfaces[p_surface].lods.size(); +} +Vector<int> EditorSceneImporterMesh::get_surface_lod_indices(int p_surface, int p_lod) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Vector<int>()); + ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), Vector<int>()); + + return surfaces[p_surface].lods[p_lod].indices; +} + +float EditorSceneImporterMesh::get_surface_lod_size(int p_surface, int p_lod) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), 0); + ERR_FAIL_INDEX_V(p_lod, surfaces[p_surface].lods.size(), 0); + return surfaces[p_surface].lods[p_lod].distance; +} + +Ref<Material> EditorSceneImporterMesh::get_surface_material(int p_surface) const { + ERR_FAIL_INDEX_V(p_surface, surfaces.size(), Ref<Material>()); + return surfaces[p_surface].material; +} + +bool EditorSceneImporterMesh::has_mesh() const { + return mesh.is_valid(); +} + +Ref<ArrayMesh> EditorSceneImporterMesh::get_mesh() { + ERR_FAIL_COND_V(surfaces.size() == 0, Ref<ArrayMesh>()); + + if (mesh.is_null()) { + mesh.instance(); + for (int i = 0; i < blend_shapes.size(); i++) { + mesh->add_blend_shape(blend_shapes[i]); + } + mesh->set_blend_shape_mode(blend_shape_mode); + for (int i = 0; i < surfaces.size(); i++) { + Array bs_data; + if (surfaces[i].blend_shape_data.size()) { + for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) { + bs_data.push_back(surfaces[i].blend_shape_data[j].arrays); + } + } + Dictionary lods; + if (surfaces[i].lods.size()) { + for (int j = 0; j < surfaces[i].lods.size(); j++) { + lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices; + } + } + + mesh->add_surface_from_arrays(surfaces[i].primitive, surfaces[i].arrays, bs_data, lods); + if (surfaces[i].material.is_valid()) { + mesh->surface_set_material(mesh->get_surface_count() - 1, surfaces[i].material); + } + if (surfaces[i].name != String()) { + mesh->surface_set_name(mesh->get_surface_count() - 1, surfaces[i].name); + } + } + } + + return mesh; +} + +void EditorSceneImporterMesh::clear() { + surfaces.clear(); + blend_shapes.clear(); + mesh.unref(); +} + +void EditorSceneImporterMesh::_set_data(const Dictionary &p_data) { + clear(); + if (p_data.has("blend_shape_names")) { + blend_shapes = p_data["blend_shape_names"]; + } + if (p_data.has("surfaces")) { + Array surface_arr = p_data["surfaces"]; + for (int i = 0; i < surface_arr.size(); i++) { + Dictionary s = surface_arr[i]; + ERR_CONTINUE(!s.has("primitive")); + ERR_CONTINUE(!s.has("arrays")); + Mesh::PrimitiveType prim = Mesh::PrimitiveType(int(s["primitive"])); + ERR_CONTINUE(prim >= Mesh::PRIMITIVE_MAX); + Array arr = s["arrays"]; + Dictionary lods; + String name; + if (s.has("name")) { + name = s["name"]; + } + if (s.has("lods")) { + lods = s["lods"]; + } + Array blend_shapes; + if (s.has("blend_shapes")) { + blend_shapes = s["blend_shapes"]; + } + Ref<Material> material; + if (s.has("material")) { + material = s["material"]; + } + add_surface(prim, arr, blend_shapes, lods, material, name); + } + } +} +Dictionary EditorSceneImporterMesh::_get_data() const { + Dictionary data; + if (blend_shapes.size()) { + data["blend_shape_names"] = blend_shapes; + } + Array surface_arr; + for (int i = 0; i < surfaces.size(); i++) { + Dictionary d; + d["primitive"] = surfaces[i].primitive; + d["arrays"] = surfaces[i].arrays; + if (surfaces[i].blend_shape_data.size()) { + Array bs_data; + for (int j = 0; j < surfaces[i].blend_shape_data.size(); j++) { + bs_data.push_back(surfaces[i].blend_shape_data[j].arrays); + } + d["blend_shapes"] = bs_data; + } + if (surfaces[i].lods.size()) { + Dictionary lods; + for (int j = 0; j < surfaces[i].lods.size(); j++) { + lods[surfaces[i].lods[j].distance] = surfaces[i].lods[j].indices; + } + d["lods"] = lods; + } + + if (surfaces[i].material.is_valid()) { + d["material"] = surfaces[i].material; + } + + if (surfaces[i].name != String()) { + d["name"] = surfaces[i].name; + } + + surface_arr.push_back(d); + } + data["surfaces"] = surface_arr; + return data; +} + +void EditorSceneImporterMesh::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &EditorSceneImporterMesh::add_blend_shape); + ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &EditorSceneImporterMesh::get_blend_shape_count); + ClassDB::bind_method(D_METHOD("get_blend_shape_name", "blend_shape_idx"), &EditorSceneImporterMesh::get_blend_shape_name); + + ClassDB::bind_method(D_METHOD("set_blend_shape_mode", "mode"), &EditorSceneImporterMesh::set_blend_shape_mode); + ClassDB::bind_method(D_METHOD("get_blend_shape_mode"), &EditorSceneImporterMesh::get_blend_shape_mode); + + ClassDB::bind_method(D_METHOD("add_surface", "primitive", "arrays", "blend_shapes", "lods", "material"), &EditorSceneImporterMesh::add_surface, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(Ref<Material>()), DEFVAL(String())); + + ClassDB::bind_method(D_METHOD("get_surface_count"), &EditorSceneImporterMesh::get_surface_count); + ClassDB::bind_method(D_METHOD("get_surface_primitive_type", "surface_idx"), &EditorSceneImporterMesh::get_surface_primitive_type); + ClassDB::bind_method(D_METHOD("get_surface_name", "surface_idx"), &EditorSceneImporterMesh::get_surface_name); + ClassDB::bind_method(D_METHOD("get_surface_arrays", "surface_idx"), &EditorSceneImporterMesh::get_surface_arrays); + ClassDB::bind_method(D_METHOD("get_surface_blend_shape_arrays", "surface_idx", "blend_shape_idx"), &EditorSceneImporterMesh::get_surface_blend_shape_arrays); + ClassDB::bind_method(D_METHOD("get_surface_lod_count", "surface_idx"), &EditorSceneImporterMesh::get_surface_lod_count); + ClassDB::bind_method(D_METHOD("get_surface_lod_size", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_size); + ClassDB::bind_method(D_METHOD("get_surface_lod_indices", "surface_idx", "lod_idx"), &EditorSceneImporterMesh::get_surface_lod_indices); + ClassDB::bind_method(D_METHOD("get_surface_material", "surface_idx"), &EditorSceneImporterMesh::get_surface_material); + + ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMesh::get_mesh); + ClassDB::bind_method(D_METHOD("clear"), &EditorSceneImporterMesh::clear); + + ClassDB::bind_method(D_METHOD("_set_data", "data"), &EditorSceneImporterMesh::_set_data); + ClassDB::bind_method(D_METHOD("_get_data"), &EditorSceneImporterMesh::_get_data); + + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data"); +} + +void EditorSceneImporterMeshNode::set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh) { + mesh = p_mesh; +} +Ref<EditorSceneImporterMesh> EditorSceneImporterMeshNode::get_mesh() const { + return mesh; +} + +void EditorSceneImporterMeshNode::set_skin(const Ref<Skin> &p_skin) { + skin = p_skin; +} +Ref<Skin> EditorSceneImporterMeshNode::get_skin() const { + return skin; +} + +void EditorSceneImporterMeshNode::set_surface_material(int p_idx, const Ref<Material> &p_material) { + ERR_FAIL_COND(p_idx < 0); + if (p_idx >= surface_materials.size()) { + surface_materials.resize(p_idx + 1); + } + + surface_materials.write[p_idx] = p_material; +} +Ref<Material> EditorSceneImporterMeshNode::get_surface_material(int p_idx) const { + ERR_FAIL_COND_V(p_idx < 0, Ref<Material>()); + if (p_idx >= surface_materials.size()) { + return Ref<Material>(); + } + return surface_materials[p_idx]; +} + +void EditorSceneImporterMeshNode::set_skeleton_path(const NodePath &p_path) { + skeleton_path = p_path; +} +NodePath EditorSceneImporterMeshNode::get_skeleton_path() const { + return skeleton_path; +} + +void EditorSceneImporterMeshNode::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &EditorSceneImporterMeshNode::set_mesh); + ClassDB::bind_method(D_METHOD("get_mesh"), &EditorSceneImporterMeshNode::get_mesh); + + ClassDB::bind_method(D_METHOD("set_skin", "skin"), &EditorSceneImporterMeshNode::set_skin); + ClassDB::bind_method(D_METHOD("get_skin"), &EditorSceneImporterMeshNode::get_skin); + + ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &EditorSceneImporterMeshNode::set_skeleton_path); + ClassDB::bind_method(D_METHOD("get_skeleton_path"), &EditorSceneImporterMeshNode::get_skeleton_path); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "EditorSceneImporterMesh"), "set_mesh", "get_mesh"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin"); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path"); +} + ///////////////////////////////// void EditorScenePostImport::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::OBJECT, "post_import", PropertyInfo(Variant::OBJECT, "scene"))); @@ -1219,6 +1517,34 @@ Ref<Animation> ResourceImporterScene::import_animation_from_other_importer(Edito return importer->import_animation(p_path, p_flags, p_bake_fps); } +void ResourceImporterScene::_generate_meshes(Node *p_node) { + EditorSceneImporterMeshNode *src_mesh = Object::cast_to<EditorSceneImporterMeshNode>(p_node); + if (src_mesh != nullptr) { + //is mesh + MeshInstance3D *mesh_node = memnew(MeshInstance3D); + mesh_node->set_transform(src_mesh->get_transform()); + mesh_node->set_skin(src_mesh->get_skin()); + mesh_node->set_skeleton_path(src_mesh->get_skeleton_path()); + + Ref<ArrayMesh> mesh; + if (!src_mesh->get_mesh()->has_mesh()) { + //do mesh processing + } + mesh = src_mesh->get_mesh()->get_mesh(); + mesh_node->set_mesh(mesh); + for (int i = 0; i < mesh->get_surface_count(); i++) { + mesh_node->set_surface_material(i, src_mesh->get_surface_material(i)); + } + + p_node->replace_by(mesh_node); + memdelete(p_node); + p_node = mesh_node; + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + _generate_meshes(p_node->get_child(i)); + } +} Error ResourceImporterScene::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) { const String &src_path = p_source_file; @@ -1315,6 +1641,8 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p scene->set_name(p_save_path.get_file().get_basename()); } + _generate_meshes(scene); + err = OK; String animation_filter = String(p_options["animation/filter_script"]).strip_edges(); diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index cd61ec01f2..758390b367 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -32,9 +32,11 @@ #define RESOURCEIMPORTERSCENE_H #include "core/io/resource_importer.h" +#include "scene/3d/node_3d.h" #include "scene/resources/animation.h" #include "scene/resources/mesh.h" #include "scene/resources/shape_3d.h" +#include "scene/resources/skin.h" class Material; @@ -88,6 +90,90 @@ public: EditorScenePostImport(); }; +// The following classes are used by importers instead of ArrayMesh and MeshInstance3D +// so the data is not reginstered (hence, quality loss), importing happens faster and +// its easier to modify before saving + +class EditorSceneImporterMesh : public Resource { + GDCLASS(EditorSceneImporterMesh, Resource) + + struct Surface { + Mesh::PrimitiveType primitive; + Array arrays; + struct BlendShape { + Array arrays; + }; + Vector<BlendShape> blend_shape_data; + struct LOD { + Vector<int> indices; + float distance; + }; + Vector<LOD> lods; + Ref<Material> material; + String name; + }; + Vector<Surface> surfaces; + Vector<String> blend_shapes; + Mesh::BlendShapeMode blend_shape_mode = Mesh::BLEND_SHAPE_MODE_NORMALIZED; + + Ref<ArrayMesh> mesh; + +protected: + void _set_data(const Dictionary &p_data); + Dictionary _get_data() const; + + static void _bind_methods(); + +public: + void add_blend_shape(const String &p_name); + int get_blend_shape_count() const; + String get_blend_shape_name(int p_blend_shape) const; + + void add_surface(Mesh::PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), const Dictionary &p_lods = Dictionary(), const Ref<Material> &p_material = Ref<Material>(), const String &p_name = String()); + int get_surface_count() const; + + void set_blend_shape_mode(Mesh::BlendShapeMode p_blend_shape_mode); + Mesh::BlendShapeMode get_blend_shape_mode() const; + + Mesh::PrimitiveType get_surface_primitive_type(int p_surface); + String get_surface_name(int p_surface) const; + Array get_surface_arrays(int p_surface) const; + Array get_surface_blend_shape_arrays(int p_surface, int p_blend_shape) const; + int get_surface_lod_count(int p_surface) const; + Vector<int> get_surface_lod_indices(int p_surface, int p_lod) const; + float get_surface_lod_size(int p_surface, int p_lod) const; + Ref<Material> get_surface_material(int p_surface) const; + + bool has_mesh() const; + Ref<ArrayMesh> get_mesh(); + void clear(); +}; + +class EditorSceneImporterMeshNode : public Node3D { + GDCLASS(EditorSceneImporterMeshNode, Node3D) + + Ref<EditorSceneImporterMesh> mesh; + Ref<Skin> skin; + NodePath skeleton_path; + Vector<Ref<Material>> surface_materials; + +protected: + static void _bind_methods(); + +public: + void set_mesh(const Ref<EditorSceneImporterMesh> &p_mesh); + Ref<EditorSceneImporterMesh> get_mesh() const; + + void set_skin(const Ref<Skin> &p_skin); + Ref<Skin> get_skin() const; + + void set_surface_material(int p_idx, const Ref<Material> &p_material); + Ref<Material> get_surface_material(int p_idx) const; + + void set_skeleton_path(const NodePath &p_path); + NodePath get_skeleton_path() const; +}; + class ResourceImporterScene : public ResourceImporter { GDCLASS(ResourceImporterScene, ResourceImporter); @@ -119,6 +205,7 @@ class ResourceImporterScene : public ResourceImporter { }; void _replace_owner(Node *p_node, Node *p_scene, Node *p_new_owner); + void _generate_meshes(Node *p_node); public: static ResourceImporterScene *get_singleton() { return singleton; } |