Optimized Mesh Merging

Changes from PoolVector to LocalVector and pre-reserving vectors rather than push_back.
This commit is contained in:
lawnjelly 2022-05-31 19:26:21 +01:00 committed by Relintai
parent a55cfb671b
commit 693c503213
3 changed files with 139 additions and 62 deletions

View File

@ -32,6 +32,7 @@
#include "core/error_macros.h" #include "core/error_macros.h"
#include "core/os/memory.h" #include "core/os/memory.h"
#include "core/pool_vector.h"
#include "core/sort_array.h" #include "core/sort_array.h"
#include "core/vector.h" #include "core/vector.h"
@ -239,6 +240,17 @@ public:
return ret; return ret;
} }
operator PoolVector<T>() const {
PoolVector<T> pl;
if (size()) {
pl.resize(size());
typename PoolVector<T>::Write w = pl.write();
T *dest = w.ptr();
memcpy(dest, data, sizeof(T) * count);
}
return pl;
}
Vector<uint8_t> to_byte_array() const { //useful to pass stuff to gpu or variant Vector<uint8_t> to_byte_array() const { //useful to pass stuff to gpu or variant
Vector<uint8_t> ret; Vector<uint8_t> ret;
ret.resize(count * sizeof(T)); ret.resize(count * sizeof(T));
@ -254,6 +266,19 @@ public:
data[i] = p_from.data[i]; data[i] = p_from.data[i];
} }
} }
LocalVector(const Vector<T> &p_from) {
resize(p_from.size());
for (U i = 0; i < count; i++) {
data[i] = p_from[i];
}
}
LocalVector(const PoolVector<T> &p_from) {
resize(p_from.size());
typename PoolVector<T>::Read r = p_from.read();
for (U i = 0; i < count; i++) {
data[i] = r[i];
}
}
inline LocalVector &operator=(const LocalVector &p_from) { inline LocalVector &operator=(const LocalVector &p_from) {
resize(p_from.size()); resize(p_from.size());
for (U i = 0; i < p_from.count; i++) { for (U i = 0; i < p_from.count; i++) {
@ -268,6 +293,14 @@ public:
} }
return *this; return *this;
} }
inline LocalVector &operator=(const PoolVector<T> &p_from) {
resize(p_from.size());
typename PoolVector<T>::Read r = p_from.read();
for (U i = 0; i < count; i++) {
data[i] = r[i];
}
return *this;
}
_FORCE_INLINE_ ~LocalVector() { _FORCE_INLINE_ ~LocalVector() {
if (data) { if (data) {

View File

@ -949,7 +949,7 @@ bool MeshInstance::_is_mergeable_with(const MeshInstance &p_other) const {
return true; return true;
} }
void MeshInstance::_merge_into_mesh_data(const MeshInstance &p_mi, const Transform &p_dest_tr_inv, int p_surface_id, PoolVector<Vector3> &r_verts, PoolVector<Vector3> &r_norms, PoolVector<real_t> &r_tangents, PoolVector<Color> &r_colors, PoolVector<Vector2> &r_uvs, PoolVector<Vector2> &r_uv2s, PoolVector<int> &r_inds) { void MeshInstance::_merge_into_mesh_data(const MeshInstance &p_mi, const Transform &p_dest_tr_inv, int p_surface_id, LocalVector<Vector3> &r_verts, LocalVector<Vector3> &r_norms, LocalVector<real_t> &r_tangents, LocalVector<Color> &r_colors, LocalVector<Vector2> &r_uvs, LocalVector<Vector2> &r_uv2s, LocalVector<int> &r_inds) {
_merge_log("\t\t\tmesh data from " + p_mi.get_name()); _merge_log("\t\t\tmesh data from " + p_mi.get_name());
// get the mesh verts in local space // get the mesh verts in local space
@ -961,13 +961,18 @@ void MeshInstance::_merge_into_mesh_data(const MeshInstance &p_mi, const Transfo
Array arrays = rmesh->surface_get_arrays(p_surface_id); Array arrays = rmesh->surface_get_arrays(p_surface_id);
PoolVector<Vector3> verts = arrays[VS::ARRAY_VERTEX]; LocalVector<Vector3> verts = PoolVector<Vector3>(arrays[VS::ARRAY_VERTEX]);
PoolVector<Vector3> normals = arrays[VS::ARRAY_NORMAL]; if (!verts.size()) {
PoolVector<real_t> tangents = arrays[VS::ARRAY_TANGENT]; // early out if there are no vertices, no point in doing anything else
PoolVector<Color> colors = arrays[VS::ARRAY_COLOR]; return;
PoolVector<Vector2> uvs = arrays[VS::ARRAY_TEX_UV]; }
PoolVector<Vector2> uv2s = arrays[VS::ARRAY_TEX_UV2];
PoolVector<int> indices = arrays[VS::ARRAY_INDEX]; LocalVector<Vector3> normals = PoolVector<Vector3>(arrays[VS::ARRAY_NORMAL]);
LocalVector<real_t> tangents = PoolVector<real_t>(arrays[VS::ARRAY_TANGENT]);
LocalVector<Color> colors = PoolVector<Color>(arrays[VS::ARRAY_COLOR]);
LocalVector<Vector2> uvs = PoolVector<Vector2>(arrays[VS::ARRAY_TEX_UV]);
LocalVector<Vector2> uv2s = PoolVector<Vector2>(arrays[VS::ARRAY_TEX_UV2]);
LocalVector<int> indices = PoolVector<int>(arrays[VS::ARRAY_INDEX]);
// The attributes present must match the first mesh for the attributes // The attributes present must match the first mesh for the attributes
// to remain in sync. Here we reject meshes with different attributes. // to remain in sync. Here we reject meshes with different attributes.
@ -1004,7 +1009,7 @@ void MeshInstance::_merge_into_mesh_data(const MeshInstance &p_mi, const Transfo
} }
// the first index of this mesh is offset from the verts we already have stored in the merged mesh // the first index of this mesh is offset from the verts we already have stored in the merged mesh
int first_index = r_verts.size(); int starting_index = r_verts.size();
// transform verts to world space // transform verts to world space
Transform tr = p_mi.get_global_transform(); Transform tr = p_mi.get_global_transform();
@ -1018,78 +1023,117 @@ void MeshInstance::_merge_into_mesh_data(const MeshInstance &p_mi, const Transfo
Basis normal_basis = tr.basis.inverse(); Basis normal_basis = tr.basis.inverse();
normal_basis.transpose(); normal_basis.transpose();
for (int n = 0; n < verts.size(); n++) { int num_verts = verts.size();
Vector3 pt_world = tr.xform(verts[n]);
r_verts.push_back(pt_world);
if (normals.size()) { // verts
DEV_ASSERT(num_verts > 0);
int first_vert = r_verts.size();
r_verts.resize(first_vert + num_verts);
Vector3 *dest_verts = &r_verts[first_vert];
for (int n = 0; n < num_verts; n++) {
Vector3 pt_world = tr.xform(verts[n]);
*dest_verts++ = pt_world;
}
// normals
if (normals.size()) {
int first_norm = r_norms.size();
r_norms.resize(first_norm + num_verts);
Vector3 *dest_norms = &r_norms[first_norm];
for (int n = 0; n < num_verts; n++) {
Vector3 pt_norm = normal_basis.xform(normals[n]); Vector3 pt_norm = normal_basis.xform(normals[n]);
pt_norm.normalize(); pt_norm.normalize();
r_norms.push_back(pt_norm); *dest_norms++ = pt_norm;
} }
}
if (tangents.size()) { // tangents
if (tangents.size()) {
int first_tang = r_tangents.size();
r_tangents.resize(first_tang + (num_verts * 4));
real_t *dest_tangents = &r_tangents[first_tang];
for (int n = 0; n < num_verts; n++) {
int tstart = n * 4; int tstart = n * 4;
Vector3 pt_tangent = Vector3(tangents[tstart], tangents[tstart + 1], tangents[tstart + 2]); Vector3 pt_tangent = Vector3(tangents[tstart], tangents[tstart + 1], tangents[tstart + 2]);
real_t fourth = tangents[tstart + 3]; real_t fourth = tangents[tstart + 3];
pt_tangent = normal_basis.xform(pt_tangent); pt_tangent = normal_basis.xform(pt_tangent);
pt_tangent.normalize(); pt_tangent.normalize();
r_tangents.push_back(pt_tangent.x); *dest_tangents++ = pt_tangent.x;
r_tangents.push_back(pt_tangent.y); *dest_tangents++ = pt_tangent.y;
r_tangents.push_back(pt_tangent.z); *dest_tangents++ = pt_tangent.z;
r_tangents.push_back(fourth); *dest_tangents++ = fourth;
} }
}
if (colors.size()) { // colors
r_colors.push_back(colors[n]); if (colors.size()) {
int first_col = r_colors.size();
r_colors.resize(first_col + num_verts);
Color *dest_colors = &r_colors[first_col];
for (int n = 0; n < num_verts; n++) {
*dest_colors++ = colors[n];
} }
}
if (uvs.size()) { // uvs
r_uvs.push_back(uvs[n]); if (uvs.size()) {
int first_uv = r_uvs.size();
r_uvs.resize(first_uv + num_verts);
Vector2 *dest_uvs = &r_uvs[first_uv];
for (int n = 0; n < num_verts; n++) {
*dest_uvs++ = uvs[n];
} }
}
if (uv2s.size()) { // uv2s
r_uv2s.push_back(uv2s[n]); if (uv2s.size()) {
int first_uv2 = r_uv2s.size();
r_uv2s.resize(first_uv2 + num_verts);
Vector2 *dest_uv2s = &r_uv2s[first_uv2];
for (int n = 0; n < num_verts; n++) {
*dest_uv2s++ = uv2s[n];
} }
} }
// indices // indices
for (int n = 0; n < indices.size(); n++) { if (indices.size()) {
int ind = indices[n] + first_index; int first_ind = r_inds.size();
r_inds.push_back(ind); r_inds.resize(first_ind + indices.size());
int *dest_inds = &r_inds[first_ind];
for (unsigned int n = 0; n < indices.size(); n++) {
int ind = indices[n] + starting_index;
*dest_inds++ = ind;
}
} }
} }
bool MeshInstance::_ensure_indices_valid(PoolVector<int> &r_indices, const PoolVector<Vector3> &p_verts) const { bool MeshInstance::_ensure_indices_valid(LocalVector<int> &r_indices, const PoolVector<Vector3> &p_verts) const {
// no indices? create some // no indices? create some
if (!r_indices.size()) { if (!r_indices.size()) {
_merge_log("\t\t\t\tindices are blank, creating..."); _merge_log("\t\t\t\tindices are blank, creating...");
// indices are blank!! let's create some, assuming the mesh is using triangles // indices are blank!! let's create some, assuming the mesh is using triangles
r_indices.resize(p_verts.size()); r_indices.resize(p_verts.size());
PoolVector<int>::Write write = r_indices.write();
int *pi = write.ptr();
// this is assuming each triangle vertex is unique // this is assuming each triangle vertex is unique
for (int n = 0; n < p_verts.size(); n++) { for (unsigned int n = 0; n < r_indices.size(); n++) {
*pi = n; r_indices[n] = n;
pi++;
} }
} }
if (!_check_for_valid_indices(r_indices, p_verts, nullptr)) { if (!_check_for_valid_indices(r_indices, p_verts, nullptr)) {
LocalVector<int, int32_t> new_inds; LocalVector<int> new_inds;
_check_for_valid_indices(r_indices, p_verts, &new_inds); _check_for_valid_indices(r_indices, p_verts, &new_inds);
// copy the new indices // copy the new indices
r_indices.resize(new_inds.size()); r_indices = new_inds;
PoolVector<int>::Write write = r_indices.write();
int *pi = write.ptr();
for (int n = 0; n < new_inds.size(); n++) {
pi[n] = new_inds[n];
}
return false; return false;
} }
@ -1098,7 +1142,7 @@ bool MeshInstance::_ensure_indices_valid(PoolVector<int> &r_indices, const PoolV
} }
// check for invalid tris, or make a list of the valid triangles, depending on whether r_inds is set // check for invalid tris, or make a list of the valid triangles, depending on whether r_inds is set
bool MeshInstance::_check_for_valid_indices(const PoolVector<int> &p_inds, const PoolVector<Vector3> &p_verts, LocalVector<int, int32_t> *r_inds) const { bool MeshInstance::_check_for_valid_indices(const LocalVector<int> &p_inds, const PoolVector<Vector3> &p_verts, LocalVector<int> *r_inds) const {
int nTris = p_inds.size(); int nTris = p_inds.size();
nTris /= 3; nTris /= 3;
int indCount = 0; int indCount = 0;
@ -1220,13 +1264,13 @@ bool MeshInstance::_merge_meshes(Vector<MeshInstance *> p_list, bool p_use_globa
} }
for (int s = 0; s < first->get_mesh()->get_surface_count(); s++) { for (int s = 0; s < first->get_mesh()->get_surface_count(); s++) {
PoolVector<Vector3> verts; LocalVector<Vector3> verts;
PoolVector<Vector3> normals; LocalVector<Vector3> normals;
PoolVector<real_t> tangents; LocalVector<real_t> tangents;
PoolVector<Color> colors; LocalVector<Color> colors;
PoolVector<Vector2> uvs; LocalVector<Vector2> uvs;
PoolVector<Vector2> uv2s; LocalVector<Vector2> uv2s;
PoolVector<int> inds; LocalVector<int> inds;
for (int n = 0; n < p_list.size(); n++) { for (int n = 0; n < p_list.size(); n++) {
// Ignore if the mesh is incompatible // Ignore if the mesh is incompatible
@ -1242,9 +1286,9 @@ bool MeshInstance::_merge_meshes(Vector<MeshInstance *> p_list, bool p_use_globa
} }
// sanity check on the indices // sanity check on the indices
for (int n = 0; n < inds.size(); n++) { for (unsigned int n = 0; n < inds.size(); n++) {
int i = inds[n]; int i = inds[n];
if (i >= verts.size()) { if ((unsigned int)i >= verts.size()) {
WARN_PRINT_ONCE("Mesh index out of range, invalid mesh, aborting"); WARN_PRINT_ONCE("Mesh index out of range, invalid mesh, aborting");
return false; return false;
} }
@ -1252,23 +1296,23 @@ bool MeshInstance::_merge_meshes(Vector<MeshInstance *> p_list, bool p_use_globa
Array arr; Array arr;
arr.resize(Mesh::ARRAY_MAX); arr.resize(Mesh::ARRAY_MAX);
arr[Mesh::ARRAY_VERTEX] = verts; arr[Mesh::ARRAY_VERTEX] = PoolVector<Vector3>(verts);
if (normals.size()) { if (normals.size()) {
arr[Mesh::ARRAY_NORMAL] = normals; arr[Mesh::ARRAY_NORMAL] = PoolVector<Vector3>(normals);
} }
if (tangents.size()) { if (tangents.size()) {
arr[Mesh::ARRAY_TANGENT] = tangents; arr[Mesh::ARRAY_TANGENT] = PoolVector<real_t>(tangents);
} }
if (colors.size()) { if (colors.size()) {
arr[Mesh::ARRAY_COLOR] = colors; arr[Mesh::ARRAY_COLOR] = PoolVector<Color>(colors);
} }
if (uvs.size()) { if (uvs.size()) {
arr[Mesh::ARRAY_TEX_UV] = uvs; arr[Mesh::ARRAY_TEX_UV] = PoolVector<Vector2>(uvs);
} }
if (uv2s.size()) { if (uv2s.size()) {
arr[Mesh::ARRAY_TEX_UV2] = uv2s; arr[Mesh::ARRAY_TEX_UV2] = PoolVector<Vector2>(uv2s);
} }
arr[Mesh::ARRAY_INDEX] = inds; arr[Mesh::ARRAY_INDEX] = PoolVector<int>(inds);
am->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr, Array(), Mesh::ARRAY_COMPRESS_DEFAULT); am->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arr, Array(), Mesh::ARRAY_COMPRESS_DEFAULT);
} // for s through surfaces } // for s through surfaces

View File

@ -100,9 +100,9 @@ private:
// merging // merging
bool _merge_meshes(Vector<MeshInstance *> p_list, bool p_use_global_space, bool p_check_compatibility); bool _merge_meshes(Vector<MeshInstance *> p_list, bool p_use_global_space, bool p_check_compatibility);
bool _is_mergeable_with(const MeshInstance &p_other) const; bool _is_mergeable_with(const MeshInstance &p_other) const;
void _merge_into_mesh_data(const MeshInstance &p_mi, const Transform &p_dest_tr_inv, int p_surface_id, PoolVector<Vector3> &r_verts, PoolVector<Vector3> &r_norms, PoolVector<real_t> &r_tangents, PoolVector<Color> &r_colors, PoolVector<Vector2> &r_uvs, PoolVector<Vector2> &r_uv2s, PoolVector<int> &r_inds); void _merge_into_mesh_data(const MeshInstance &p_mi, const Transform &p_dest_tr_inv, int p_surface_id, LocalVector<Vector3> &r_verts, LocalVector<Vector3> &r_norms, LocalVector<real_t> &r_tangents, LocalVector<Color> &r_colors, LocalVector<Vector2> &r_uvs, LocalVector<Vector2> &r_uv2s, LocalVector<int> &r_inds);
bool _ensure_indices_valid(PoolVector<int> &r_indices, const PoolVector<Vector3> &p_verts) const; bool _ensure_indices_valid(LocalVector<int> &r_indices, const PoolVector<Vector3> &p_verts) const;
bool _check_for_valid_indices(const PoolVector<int> &p_inds, const PoolVector<Vector3> &p_verts, LocalVector<int, int32_t> *r_inds) const; bool _check_for_valid_indices(const LocalVector<int> &p_inds, const PoolVector<Vector3> &p_verts, LocalVector<int> *r_inds) const;
bool _triangle_is_degenerate(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c, real_t p_epsilon) const; bool _triangle_is_degenerate(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c, real_t p_epsilon) const;
void _merge_log(String p_string) const; void _merge_log(String p_string) const;