Added a new import type which can separate meshes based on bones.

This commit is contained in:
Relintai 2020-07-26 22:53:24 +02:00
parent 8967868163
commit 5a26317a42
2 changed files with 369 additions and 4 deletions

View File

@ -30,7 +30,7 @@ SOFTWARE.
#include "scene/resources/shape.h"
#include "scene/resources/sphere_shape.h"
const String MDRImportPluginBase::BINDING_MDR_IMPORT_TYPE = "Single,Single Merged,Multiple";
const String MDRImportPluginBase::BINDING_MDR_IMPORT_TYPE = "Single,Single Merged,Multiple,Single - Separate Bone Groups";
void MDRImportPluginBase::get_import_options(List<ImportOption> *r_options, int p_preset) const {
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "import_type", PROPERTY_HINT_ENUM, BINDING_MDR_IMPORT_TYPE), MDRImportPluginBase::MDR_IMPORT_TIME_SINGLE));
@ -63,6 +63,9 @@ Error MDRImportPluginBase::process_node(Node *n, const String &p_source_file, co
return ResourceSaver::save(p_save_path + "." + get_save_extension(), coll);
}
case MDR_IMPORT_TIME_SINGLE_WITH_SEPARATED_BONES: {
return process_node_single_separated_bones(n, p_source_file, p_save_path, p_options, r_platform_variants, r_gen_files, r_metadata);
}
}
return Error::ERR_PARSE_ERROR;
@ -112,6 +115,61 @@ Error MDRImportPluginBase::process_node_single(Node *n, const String &p_source_f
return Error::ERR_PARSE_ERROR;
}
Error MDRImportPluginBase::process_node_single_separated_bones(Node *n, 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) {
MeshDataResource::ColliderType collider_type = static_cast<MeshDataResource::ColliderType>(static_cast<int>(p_options["collider_type"]));
Vector3 scale = p_options["scale"];
ERR_FAIL_COND_V(n == NULL, Error::ERR_PARSE_ERROR);
for (int i = 0; i < n->get_child_count(); ++i) {
Node *c = n->get_child(i);
if (Object::cast_to<MeshInstance>(c)) {
Ref<MeshDataResourceCollection> coll;
coll.instance();
MeshInstance *mi = Object::cast_to<MeshInstance>(c);
Ref<ArrayMesh> mesh = mi->get_mesh();
if (!mesh.is_valid())
continue;
Vector<Array> arrays = split_mesh_bones(mesh);
for (int j = 0; j < arrays.size(); ++j) {
Array arr = arrays[j];
Ref<MeshDataResource> mdr = get_mesh_arrays(arr, p_options, collider_type, scale);
if (!mdr.is_valid())
continue;
String node_name = c->get_name();
node_name = node_name.to_lower();
String filename = p_source_file.get_basename() + "_" + node_name + "_" + String::num(j) + "." + get_save_extension();
Error err = ResourceSaver::save(filename, mdr);
ERR_CONTINUE(err != Error::OK);
Ref<MeshDataResource> mdrl = ResourceLoader::load(filename);
coll->add_mdr(mdrl);
}
return ResourceSaver::save(p_save_path + "." + get_save_extension(), coll);
}
if (process_node_single_separated_bones(c, p_source_file, p_save_path, p_options, r_platform_variants, r_gen_files, r_metadata) == Error::OK) {
return Error::OK;
}
}
return Error::ERR_PARSE_ERROR;
}
Error MDRImportPluginBase::process_node_multi(Node *n, 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, Ref<MeshDataResourceCollection> coll) {
MeshDataResource::ColliderType collider_type = static_cast<MeshDataResource::ColliderType>(static_cast<int>(p_options["collider_type"]));
@ -127,10 +185,8 @@ Error MDRImportPluginBase::process_node_multi(Node *n, const String &p_source_fi
Ref<MeshDataResource> mdr = get_mesh(mi, p_options, collider_type, scale);
String node_name = n->get_name();
String node_name = c->get_name();
node_name = node_name.to_lower();
String filename = p_source_file.get_basename() + "_" + node_name + "." + get_save_extension();
Error err = ResourceSaver::save(filename, mdr);
@ -284,11 +340,315 @@ Ref<MeshDataResource> MDRImportPluginBase::get_mesh(MeshInstance *mi, const Map<
return Ref<MeshDataResource>();
}
Ref<MeshDataResource> MDRImportPluginBase::get_mesh_arrays(Array &arrs, const Map<StringName, Variant> &p_options, MeshDataResource::ColliderType collider_type, Vector3 scale) {
ERR_FAIL_COND_V(arrs.size() < VS::ARRAY_MAX, Ref<MeshDataResource>());
Ref<ArrayMesh> mesh;
mesh.instance();
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrs);
ERR_FAIL_COND_V(mesh->get_surface_count() == 0, Ref<MeshDataResource>());
Ref<MeshDataResource> mdr;
mdr.instance();
Array arrays = mesh->surface_get_arrays(0);
mdr->set_array(apply_transforms(arrays, p_options));
if (collider_type == MeshDataResource::COLLIDER_TYPE_TRIMESH_COLLISION_SHAPE) {
Ref<ArrayMesh> m;
m.instance();
m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mdr->get_array());
Ref<Shape> shape = m->create_trimesh_shape();
if (!shape.is_null()) {
mdr->add_collision_shape(Transform(), scale_shape(shape, scale));
}
} else if (collider_type == MeshDataResource::COLLIDER_TYPE_SINGLE_CONVEX_COLLISION_SHAPE) {
Ref<ArrayMesh> m;
m.instance();
m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mdr->get_array());
Ref<Shape> shape = mesh->create_convex_shape();
if (!shape.is_null()) {
mdr->add_collision_shape(Transform(), scale_shape(shape, scale));
}
} else if (collider_type == MeshDataResource::COLLIDER_TYPE_MULTIPLE_CONVEX_COLLISION_SHAPES) {
Ref<ArrayMesh> m;
m.instance();
m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mdr->get_array());
Vector<Ref<Shape> > shapes = mesh->convex_decompose();
for (int j = 0; j < shapes.size(); ++j) {
scale_shape(shapes[j], scale);
}
for (int j = 0; j < shapes.size(); ++j) {
mdr->add_collision_shape(Transform(), shapes[j]);
}
} else if (collider_type == MeshDataResource::COLLIDER_TYPE_APPROXIMATED_BOX) {
Ref<ArrayMesh> m;
m.instance();
m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mdr->get_array());
Ref<BoxShape> shape;
shape.instance();
AABB aabb = m->get_aabb();
Vector3 size = aabb.get_size();
shape->set_extents(size * 0.5);
Vector3 pos = aabb.position;
pos += size / 2.0;
Transform t;
t.origin = pos;
mdr->add_collision_shape(t, shape);
} else if (collider_type == MeshDataResource::COLLIDER_TYPE_APPROXIMATED_CAPSULE) {
Ref<ArrayMesh> m;
m.instance();
m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mdr->get_array());
Ref<CapsuleShape> shape;
shape.instance();
AABB aabb = m->get_aabb();
Vector3 size = aabb.get_size();
shape->set_height(size.y * 0.5);
shape->set_radius(MIN(size.x, size.z) * 0.5);
Vector3 pos = aabb.position;
pos += size / 2.0;
Transform t = Transform(Basis().rotated(Vector3(1, 0, 0), M_PI_2));
t.origin = pos;
mdr->add_collision_shape(t, shape);
} else if (collider_type == MeshDataResource::COLLIDER_TYPE_APPROXIMATED_CYLINDER) {
Ref<ArrayMesh> m;
m.instance();
m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mdr->get_array());
Ref<CylinderShape> shape;
shape.instance();
AABB aabb = m->get_aabb();
Vector3 size = aabb.get_size();
shape->set_height(size.y * 0.5);
shape->set_radius(MIN(size.x, size.z) * 0.5);
Vector3 pos = aabb.position;
pos += size / 2.0;
Transform t;
t.origin = pos;
mdr->add_collision_shape(t, shape);
} else if (collider_type == MeshDataResource::COLLIDER_TYPE_APPROXIMATED_SPHERE) {
Ref<ArrayMesh> m;
m.instance();
m->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mdr->get_array());
Ref<SphereShape> shape;
shape.instance();
AABB aabb = m->get_aabb();
Vector3 size = aabb.get_size();
shape->set_radius(MIN(size.x, MIN(size.y, size.z)) * 0.5);
Vector3 mid = aabb.get_size() / 2.0;
Transform t;
t.origin = aabb.position + mid;
mdr->add_collision_shape(t, shape);
}
return mdr;
}
Vector<Array> MDRImportPluginBase::split_mesh_bones(Ref<ArrayMesh> mesh) {
Array arr = mesh->surface_get_arrays(0);
PoolVector<int> barr = arr[VS::ARRAY_BONES];
Vector<Array> resarrs;
Vector<int> bone_ids;
for (int i = 0; i < barr.size(); ++i) {
int bi = barr[i];
if (bone_ids.find(bi) == -1) {
bone_ids.push_back(bi);
}
}
for (int i = 0; i < bone_ids.size(); ++i) {
int bi = bone_ids[i];
Array carr = slice_mesh_bone(arr, bi);
if (carr.size() == VS::ARRAY_MAX) {
PoolVector<Vector3> vcarr = carr[VS::ARRAY_VERTEX];
if (vcarr.size() != 0)
resarrs.push_back(slice_mesh_bone(carr, bi));
}
}
return resarrs;
}
Array MDRImportPluginBase::slice_mesh_bone(const Array &arr, int bone_idx) {
Array resarrs;
resarrs.resize(VS::ARRAY_MAX);
PoolVector<Vector3> varr = arr[VS::ARRAY_VERTEX];
PoolVector<Vector3> narr = arr[VS::ARRAY_NORMAL];
PoolVector<float> tarr = arr[VS::ARRAY_TANGENT];
PoolVector<Color> carr = arr[VS::ARRAY_COLOR];
PoolVector<Vector2> uvarr = arr[VS::ARRAY_TEX_UV];
PoolVector<Vector2> uv2arr = arr[VS::ARRAY_TEX_UV2];
PoolVector<int> barr = arr[VS::ARRAY_BONES];
PoolVector<float> warr = arr[VS::ARRAY_WEIGHTS];
PoolVector<int> iarr = arr[VS::ARRAY_INDEX];
PoolVector<Vector3> rvarr;
PoolVector<Vector3> rnarr;
PoolVector<float> rtarr;
PoolVector<Color> rcarr;
PoolVector<Vector2> ruvarr;
PoolVector<Vector2> ruv2arr;
PoolVector<int> rbarr;
PoolVector<float> rwarr;
PoolVector<int> riarr;
Vector<int> curr_bone_indices;
for (int i = 0; i < barr.size(); i += 4) {
int b0 = barr[i + 0];
//int b1 = barr[i + 1];
//int b2 = barr[i + 2];
//int b3 = barr[i + 3];
if (b0 == bone_idx) { // || b1 == bone_idx || b2 == bone_idx || b3 == bone_idx) {
curr_bone_indices.push_back(i / 4);
}
}
for (int i = 0; i < curr_bone_indices.size(); ++i) {
int indx = curr_bone_indices[i];
rvarr.push_back(varr[indx]);
if (narr.size() > 0)
rnarr.push_back(narr[indx]);
if (tarr.size() > 0) {
int ii = indx * 4;
tarr.push_back(tarr[ii]);
tarr.push_back(tarr[ii + 1]);
tarr.push_back(tarr[ii + 2]);
tarr.push_back(tarr[ii + 3]);
}
if (carr.size() > 0)
rcarr.push_back(carr[indx]);
if (uvarr.size() > 0)
ruvarr.push_back(uvarr[indx]);
if (uv2arr.size() > 0)
ruv2arr.push_back(uv2arr[indx]);
if (barr.size() > 0) {
int ii = indx * 4;
rbarr.push_back(barr[ii]);
rbarr.push_back(0);
rbarr.push_back(0);
rbarr.push_back(0);
//rbarr.set(ii + 1, barr[indx + 1]);
//rbarr.set(ii + 2, barr[indx + 2]);
//rbarr.set(ii + 3, barr[indx + 3]);
}
if (warr.size() > 0) {
int ii = indx * 4;
rwarr.push_back(warr[ii]);
rwarr.push_back(0);
rwarr.push_back(0);
rwarr.push_back(0);
//rwarr.set(ii + 1, warr[indx + 1]);
//rwarr.set(ii + 2, warr[indx + 2]);
//rwarr.set(ii + 3, warr[indx + 3]);
}
}
for (int i = 0; i < curr_bone_indices.size(); ++i) {
int old_indx = curr_bone_indices[i];
int new_indx = i;
for (int j = 0; j < i; ++j) {
if (curr_bone_indices[j] == old_indx) {
new_indx = j;
break;
}
}
riarr.push_back(new_indx);
}
resarrs[VS::ARRAY_VERTEX] = rvarr;
if (rnarr.size() > 0)
resarrs[VS::ARRAY_NORMAL] = rnarr;
if (rtarr.size() > 0)
resarrs[VS::ARRAY_TANGENT] = rtarr;
if (rcarr.size() > 0)
resarrs[VS::ARRAY_COLOR] = rcarr;
if (ruvarr.size() > 0)
resarrs[VS::ARRAY_TEX_UV] = ruvarr;
if (ruv2arr.size() > 0)
resarrs[VS::ARRAY_TEX_UV2] = ruv2arr;
if (rbarr.size() > 0)
resarrs[VS::ARRAY_BONES] = rbarr;
if (rwarr.size() > 0)
resarrs[VS::ARRAY_WEIGHTS] = rwarr;
resarrs[VS::ARRAY_INDEX] = riarr;
return resarrs;
}
Array MDRImportPluginBase::apply_transforms(Array &array, const Map<StringName, Variant> &p_options) {
Vector3 offset = p_options["offset"];
Vector3 rotation = p_options["rotation"];
Vector3 scale = p_options["scale"];
ERR_FAIL_COND_V(array.size() < VS::ARRAY_MAX, array);
Transform transform = Transform(Basis(rotation).scaled(scale), offset);
PoolVector3Array verts = array.get(Mesh::ARRAY_VERTEX);

View File

@ -58,6 +58,7 @@ public:
MDR_IMPORT_TIME_SINGLE = 0,
MDR_IMPORT_TIME_SINGLE_MERGED,
MDR_IMPORT_TIME_MULTIPLE,
MDR_IMPORT_TIME_SINGLE_WITH_SEPARATED_BONES,
};
public:
@ -68,9 +69,13 @@ public:
int get_mesh_count(Node *n);
Error process_node_single(Node *n, 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);
Error process_node_single_separated_bones(Node *n, 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);
Error process_node_multi(Node *n, 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, Ref<MeshDataResourceCollection> coll);
Ref<MeshDataResource> get_mesh(MeshInstance *mi, const Map<StringName, Variant> &p_options, MeshDataResource::ColliderType collider_type, Vector3 scale);
Ref<MeshDataResource> get_mesh_arrays(Array &arrs, const Map<StringName, Variant> &p_options, MeshDataResource::ColliderType collider_type, Vector3 scale);
Vector<Array> split_mesh_bones(Ref<ArrayMesh> mesh);
Array slice_mesh_bone(const Array &array, int bone_idx);
Array apply_transforms(Array &array, const Map<StringName, Variant> &p_options);
Ref<Shape> scale_shape(Ref<Shape> shape, const Vector3 &scale);