Added remove_doubles and remove_doubles_interpolate_normals methods to the MeshUtils singleton.

This commit is contained in:
Relintai 2021-07-19 17:58:50 +02:00
parent 6725a4906c
commit 29c5cc9a75
2 changed files with 292 additions and 0 deletions

View File

@ -130,6 +130,291 @@ Array MeshUtils::bake_mesh_array_uv(Array arr, Ref<Texture> tex, float mul_color
return arr;
}
//If normals are present they need to match too to be removed
Array MeshUtils::remove_doubles(Array arr) const {
ERR_FAIL_COND_V(arr.size() != VisualServer::ARRAY_MAX, arr);
PoolVector3Array verts = arr[VisualServer::ARRAY_VERTEX];
PoolVector3Array normals = arr[VisualServer::ARRAY_NORMAL];
PoolVector2Array uvs = arr[VisualServer::ARRAY_TEX_UV];
PoolColorArray colors = arr[VisualServer::ARRAY_COLOR];
PoolIntArray indices = arr[VisualServer::ARRAY_INDEX];
PoolIntArray bones = arr[VisualServer::ARRAY_BONES];
PoolRealArray weights = arr[VisualServer::ARRAY_WEIGHTS];
ERR_FAIL_COND_V(normals.size() != 0 && normals.size() != verts.size(), Array());
ERR_FAIL_COND_V(uvs.size() != 0 && normals.size() != verts.size(), Array());
ERR_FAIL_COND_V(colors.size() != 0 && normals.size() != verts.size(), Array());
ERR_FAIL_COND_V(bones.size() != 0 && bones.size() != (verts.size() * 4), Array());
ERR_FAIL_COND_V(weights.size() != 0 && weights.size() != (verts.size() * 4), Array());
ERR_FAIL_COND_V(bones.size() != weights.size(), Array());
Vector3 v;
Vector3 normal;
Vector2 uv;
Color color;
PoolIntArray bone;
bone.resize(4);
PoolRealArray weight;
weight.resize(4);
int i = 0;
while (i < verts.size()) {
v = verts[i];
if (normals.size() != 0) {
normal = normals[i];
}
if (uvs.size() != 0) {
uv = uvs[i];
}
if (colors.size() != 0) {
color = colors[i];
}
if (bones.size() != 0) {
int indx = i * 4;
for (int l = 0; l < 4; ++l) {
bone.set(l, bones[indx + l]);
weight.set(l, weights[indx + l]);
}
}
Array equals;
for (int j = i + 1; j < verts.size(); ++j) {
Vector3 vc = verts[j];
if (normals.size() != 0) {
if (!normals[j].is_equal_approx(normal)) {
continue;
}
}
if (uvs.size() != 0) {
if (!uvs[j].is_equal_approx(uv)) {
continue;
}
}
if (colors.size() != 0) {
if (!colors[j].is_equal_approx(color)) {
continue;
}
}
if (bones.size() != 0) {
int indx = i * 4;
for (int l = 0; l < 4; ++l) {
if (bones[indx + l] != bone[l]) {
continue;
}
if (!Math::is_equal_approx(weights[indx + l], weight[l])) {
continue;
}
}
}
if (vc.is_equal_approx(v)) {
equals.push_back(j);
}
}
for (int k = 0; k < equals.size(); ++k) {
int rem = equals[k];
int remk = rem - k;
verts.remove(remk);
if (normals.size() > 0) {
normals.remove(remk);
}
if (uvs.size() > 0) {
uvs.remove(remk);
}
if (colors.size() > 0) {
colors.remove(remk);
}
if (bones.size() > 0) {
int bindex = remk * 4;
for (int l = 0; l < 4; ++l) {
bones.remove(bindex);
weights.remove(bindex);
}
}
for (int j = 0; j < indices.size(); ++j) {
int indx = indices[j];
if (indx == remk)
indices.set(j, i);
else if (indx > remk)
indices.set(j, indx - 1);
}
}
++i;
}
arr[VisualServer::ARRAY_VERTEX] = verts;
arr[VisualServer::ARRAY_NORMAL] = normals;
arr[VisualServer::ARRAY_TEX_UV] = uvs;
arr[VisualServer::ARRAY_COLOR] = colors;
arr[VisualServer::ARRAY_INDEX] = indices;
arr[VisualServer::ARRAY_BONES] = bones;
arr[VisualServer::ARRAY_WEIGHTS] = weights;
return arr;
}
//Normals are always interpolated, merged
Array MeshUtils::remove_doubles_interpolate_normals(Array arr) const {
ERR_FAIL_COND_V(arr.size() != VisualServer::ARRAY_MAX, arr);
PoolVector3Array verts = arr[VisualServer::ARRAY_VERTEX];
PoolVector3Array normals = arr[VisualServer::ARRAY_NORMAL];
PoolVector2Array uvs = arr[VisualServer::ARRAY_TEX_UV];
PoolColorArray colors = arr[VisualServer::ARRAY_COLOR];
PoolIntArray indices = arr[VisualServer::ARRAY_INDEX];
PoolIntArray bones = arr[VisualServer::ARRAY_BONES];
PoolRealArray weights = arr[VisualServer::ARRAY_WEIGHTS];
ERR_FAIL_COND_V(normals.size() != 0 && normals.size() != verts.size(), Array());
ERR_FAIL_COND_V(uvs.size() != 0 && normals.size() != verts.size(), Array());
ERR_FAIL_COND_V(colors.size() != 0 && normals.size() != verts.size(), Array());
ERR_FAIL_COND_V(bones.size() != 0 && bones.size() != (verts.size() * 4), Array());
ERR_FAIL_COND_V(weights.size() != 0 && weights.size() != (verts.size() * 4), Array());
ERR_FAIL_COND_V(bones.size() != weights.size(), Array());
Vector3 v;
Vector2 uv;
Color color;
PoolIntArray bone;
bone.resize(4);
PoolRealArray weight;
weight.resize(4);
int i = 0;
while (i < verts.size()) {
v = verts[i];
if (uvs.size() != 0) {
uv = uvs[i];
}
if (colors.size() != 0) {
color = colors[i];
}
if (bones.size() != 0) {
int indx = i * 4;
for (int l = 0; l < 4; ++l) {
bone.set(l, bones[indx + l]);
weight.set(l, weights[indx + l]);
}
}
Array equals;
for (int j = i + 1; j < verts.size(); ++j) {
Vector3 vc = verts[j];
if (uvs.size() != 0) {
if (!uvs[j].is_equal_approx(uv)) {
continue;
}
}
if (colors.size() != 0) {
if (!colors[j].is_equal_approx(color)) {
continue;
}
}
if (bones.size() != 0) {
int indx = i * 4;
for (int l = 0; l < 4; ++l) {
if (bones[indx + l] != bone[l]) {
continue;
}
if (!Math::is_equal_approx(weights[indx + l], weight[l])) {
continue;
}
}
}
if (vc.is_equal_approx(v)) {
equals.push_back(j);
}
}
Vector3 normal;
for (int k = 0; k < equals.size(); ++k) {
int rem = equals[k];
int remk = rem - k;
verts.remove(remk);
if (normals.size() > 0) {
Vector3 n = normals[remk];
normals.remove(remk);
if (k == 0) {
normal = n;
} else {
normal = normal.linear_interpolate(n, 0.5);
}
}
if (uvs.size() > 0) {
uvs.remove(remk);
}
if (colors.size() > 0) {
colors.remove(remk);
}
if (bones.size() > 0) {
int bindex = remk * 4;
for (int l = 0; l < 4; ++l) {
bones.remove(bindex);
weights.remove(bindex);
}
}
for (int j = 0; j < indices.size(); ++j) {
int indx = indices[j];
if (indx == remk)
indices.set(j, i);
else if (indx > remk)
indices.set(j, indx - 1);
}
}
++i;
}
arr[VisualServer::ARRAY_VERTEX] = verts;
arr[VisualServer::ARRAY_NORMAL] = normals;
arr[VisualServer::ARRAY_TEX_UV] = uvs;
arr[VisualServer::ARRAY_COLOR] = colors;
arr[VisualServer::ARRAY_INDEX] = indices;
arr[VisualServer::ARRAY_BONES] = bones;
arr[VisualServer::ARRAY_WEIGHTS] = weights;
return arr;
}
MeshUtils::MeshUtils() {
_instance = this;
}
@ -141,6 +426,9 @@ MeshUtils::~MeshUtils() {
void MeshUtils::_bind_methods() {
ClassDB::bind_method(D_METHOD("merge_mesh_array", "arr"), &MeshUtils::merge_mesh_array);
ClassDB::bind_method(D_METHOD("bake_mesh_array_uv", "arr", "tex", "mul_color"), &MeshUtils::bake_mesh_array_uv, DEFVAL(0.7));
ClassDB::bind_method(D_METHOD("remove_doubles", "arr"), &MeshUtils::remove_doubles);
ClassDB::bind_method(D_METHOD("remove_doubles_interpolate_normals", "arr"), &MeshUtils::remove_doubles_interpolate_normals);
}
#if GODOT4

View File

@ -47,6 +47,10 @@ public:
Array merge_mesh_array(Array arr) const;
Array bake_mesh_array_uv(Array arr, Ref<Texture> tex, float mul_color = 0.7) const;
//If normals are present they need to match too to be removed
Array remove_doubles(Array arr) const;
//Normals are always interpolated, merged
Array remove_doubles_interpolate_normals(Array arr) const;
MeshUtils();
~MeshUtils();