Added remove_doubles, and remove_doubles_hashed methods to VoxelMesher, the hashed version is actually about 40-ish percent faster usually, but if hash might occur with it. The TransvoxelMesher now automatically simplifies it's meshes after a buffer is added, using the hashed version (to see in practice how common hash collisions are).

This commit is contained in:
Relintai 2020-03-09 00:17:50 +01:00
parent a22be7208c
commit 9154009250
3 changed files with 106 additions and 1 deletions

View File

@ -395,6 +395,8 @@ void VoxelMesherTransvoxel::_add_chunk(Node *p_chunk) {
}
}
}
remove_doubles_hashed();
}
Vector3 VoxelMesherTransvoxel::corner_id_to_vertex(int corner_id) const {

View File

@ -282,6 +282,104 @@ void VoxelMesher::generate_normals(bool p_flip) {
}
}
void VoxelMesher::remove_doubles() {
if (_vertices.size() == 0)
return;
//print_error("before " + String::num(_vertices.size()));
for (int i = 0; i < _vertices.size(); ++i) {
Vertex vert = _vertices[i];
PoolVector<int> indices;
for (int j = i + 1; j < _vertices.size(); ++j) {
if (_vertices[j] == vert) {
indices.push_back(j);
}
}
for (int j = 0; j < indices.size(); ++j) {
int index = indices[j];
_vertices.remove(index);
//make all indices that were bigger than the one we replaced one lower
for (int k = 0; k < _indices.size(); ++k) {
int indx = _indices[k];
if (indx == index) {
_indices.set(k, i);
} else if (indx > index) {
_indices.set(k, --indx);
}
}
for (int k = j + 1; k < indices.size(); ++k) {
int val = indices[k];
if (val > index) {
indices.set(k, --val);
}
}
}
}
//print_error("after " + String::num(_vertices.size())+ " " + String::num(duration.count()));
}
//lot faster that normal remove_doubles, but false positives can happen curtesy of hash collisions
void VoxelMesher::remove_doubles_hashed() {
if (_vertices.size() == 0)
return;
//print_error("before " + String::num(_vertices.size()));
PoolVector<uint32_t> hashes;
hashes.resize(_vertices.size());
for (int i = 0; i < _vertices.size(); ++i) {
hashes.set(i, VertexHasher::hash(_vertices[i]));
}
for (int i = 0; i < hashes.size(); ++i) {
uint32_t hash = hashes[i];
PoolVector<int> indices;
for (int j = i + 1; j < hashes.size(); ++j) {
if (hashes[j] == hash) {
indices.push_back(j);
}
}
for (int j = 0; j < indices.size(); ++j) {
int index = indices[j];
hashes.remove(index);
_vertices.remove(index);
//make all indices that were bigger than the one we replaced one lower
for (int k = 0; k < _indices.size(); ++k) {
int indx = _indices[k];
if (indx == index) {
_indices.set(k, i);
} else if (indx > index) {
_indices.set(k, --indx);
}
}
for (int k = j + 1; k < indices.size(); ++k) {
int val = indices[k];
if (val > index) {
indices.set(k, --val);
}
}
}
}
//print_error("after " + String::num(_vertices.size()) + " " + String::num(duration.count()));
}
void VoxelMesher::reset() {
_vertices.resize(0);
_indices.resize(0);
@ -1055,4 +1153,7 @@ void VoxelMesher::_bind_methods() {
ClassDB::bind_method(D_METHOD("build_collider"), &VoxelMesher::build_collider);
ClassDB::bind_method(D_METHOD("generate_normals", "flip"), &VoxelMesher::generate_normals, DEFVAL(false));
ClassDB::bind_method(D_METHOD("remove_doubles"), &VoxelMesher::remove_doubles);
ClassDB::bind_method(D_METHOD("remove_doubles_hashed"), &VoxelMesher::remove_doubles_hashed);
}

View File

@ -138,6 +138,8 @@ public:
void build_mesh_into(RID mesh);
void generate_normals(bool p_flip = false);
void remove_doubles();
void remove_doubles_hashed();
PoolVector<Vector3> get_vertices() const;
void set_vertices(const PoolVector<Vector3> &values);