mirror of
https://git.mirrors.martin98.com/https://github.com/google/draco
synced 2025-06-04 11:25:44 +08:00
185 lines
7.2 KiB
C++
185 lines
7.2 KiB
C++
// Copyright 2016 The Draco Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
#include "mesh/mesh_cleanup.h"
|
|
|
|
namespace draco {
|
|
|
|
bool MeshCleanup::operator()(Mesh *mesh, const MeshCleanupOptions &options) {
|
|
if (!options.remove_degenerated_faces && !options.remove_unused_attributes)
|
|
return true; // Nothing to cleanup.
|
|
const PointAttribute *const pos_att =
|
|
mesh->GetNamedAttribute(GeometryAttribute::POSITION);
|
|
if (pos_att == nullptr)
|
|
return false;
|
|
// Array that is going to store whether a corresponding point is used.
|
|
std::vector<bool> is_point_used;
|
|
if (options.remove_unused_attributes) {
|
|
is_point_used.resize(mesh->num_points(), false);
|
|
}
|
|
|
|
FaceIndex::ValueType num_degenerated_faces = 0;
|
|
PointIndex::ValueType num_new_points = 0;
|
|
// Array for storing position indices on a face.
|
|
std::array<AttributeValueIndex, 3> pos_indices;
|
|
for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
|
|
const Mesh::Face &face = mesh->face(f);
|
|
for (int p = 0; p < 3; ++p) {
|
|
pos_indices[p] = pos_att->mapped_index(face[p]);
|
|
}
|
|
bool is_face_valid = true;
|
|
if (options.remove_degenerated_faces) {
|
|
if (pos_indices[0] == pos_indices[1] ||
|
|
pos_indices[0] == pos_indices[2] ||
|
|
pos_indices[1] == pos_indices[2]) {
|
|
++num_degenerated_faces;
|
|
is_face_valid = false;
|
|
} else if (num_degenerated_faces > 0) {
|
|
// Copy the face to its new location.
|
|
mesh->SetFace(f - num_degenerated_faces, face);
|
|
}
|
|
}
|
|
if (options.remove_unused_attributes && is_face_valid) {
|
|
for (int p = 0; p < 3; ++p) {
|
|
if (!is_point_used[face[p].value()]) {
|
|
is_point_used[face[p].value()] = true;
|
|
++num_new_points;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (num_degenerated_faces > 0) {
|
|
mesh->SetNumFaces(mesh->num_faces() - num_degenerated_faces);
|
|
}
|
|
if (options.remove_unused_attributes) {
|
|
bool points_changed = false;
|
|
const PointIndex::ValueType num_original_points = mesh->num_points();
|
|
// Map from old points to the new ones.
|
|
IndexTypeVector<PointIndex, PointIndex> point_map(num_original_points);
|
|
if (num_new_points < static_cast<int>(mesh->num_points())) {
|
|
// Some of the points were removed. We need to remap the old points to the
|
|
// new ones.
|
|
num_new_points = 0;
|
|
for (PointIndex i(0); i < num_original_points; ++i) {
|
|
if (is_point_used[i.value()]) {
|
|
point_map[i] = num_new_points++;
|
|
} else {
|
|
point_map[i] = -1;
|
|
}
|
|
}
|
|
// Go over faces and update their points.
|
|
for (FaceIndex f(0); f < mesh->num_faces(); ++f) {
|
|
Mesh::Face face = mesh->face(f);
|
|
for (int p = 0; p < 3; ++p) {
|
|
face[p] = point_map[face[p]];
|
|
}
|
|
mesh->SetFace(f, face);
|
|
}
|
|
// Set the new number of points.
|
|
mesh->set_num_points(num_new_points);
|
|
points_changed = true;
|
|
} else {
|
|
// No points were removed. Initialize identity map between the old and new
|
|
// points.
|
|
for (PointIndex i(0); i < num_original_points; ++i) {
|
|
point_map[i] = i;
|
|
}
|
|
}
|
|
|
|
// Update index mapping for attributes.
|
|
IndexTypeVector<AttributeValueIndex, uint8_t> is_att_index_used;
|
|
IndexTypeVector<AttributeValueIndex, AttributeValueIndex> att_index_map;
|
|
for (int a = 0; a < mesh->num_attributes(); ++a) {
|
|
PointAttribute *const att = mesh->attribute(a);
|
|
// First detect which attribute entries are used (included in a point).
|
|
is_att_index_used.assign(att->size(), 0);
|
|
att_index_map.clear();
|
|
AttributeValueIndex::ValueType num_used_entries = 0;
|
|
for (PointIndex i(0); i < num_original_points; ++i) {
|
|
if (point_map[i] != -1) {
|
|
const AttributeValueIndex entry_id = att->mapped_index(i);
|
|
if (!is_att_index_used[entry_id]) {
|
|
is_att_index_used[entry_id] = 1;
|
|
++num_used_entries;
|
|
}
|
|
}
|
|
}
|
|
bool att_indices_changed = false;
|
|
// If there are some unused attribute entries, remap the attribute values
|
|
// in the attribute buffer.
|
|
if (num_used_entries < static_cast<int>(att->size())) {
|
|
att_index_map.resize(att->size());
|
|
num_used_entries = 0;
|
|
for (AttributeValueIndex i(0); i < att->size(); ++i) {
|
|
if (is_att_index_used[i]) {
|
|
att_index_map[i] = num_used_entries;
|
|
if (i > num_used_entries) {
|
|
const uint8_t *const src_add = att->GetAddress(i);
|
|
att->buffer()->Write(
|
|
att->GetBytePos(AttributeValueIndex(num_used_entries)),
|
|
src_add, att->byte_stride());
|
|
}
|
|
++num_used_entries;
|
|
}
|
|
}
|
|
// Update the number of unique entries in the vertex buffer.
|
|
att->Resize(num_used_entries);
|
|
att_indices_changed = true;
|
|
}
|
|
// If either the points or attribute indices have changed, we need to
|
|
// update the attribute index mapping.
|
|
if (points_changed || att_indices_changed) {
|
|
if (att->is_mapping_identity()) {
|
|
// The mapping was identity. It'll remain identity only if the
|
|
// number of point and attribute indices is still the same.
|
|
if (num_used_entries != static_cast<int>(mesh->num_points())) {
|
|
// We need to create an explicit mapping.
|
|
// First we need to initialize the explicit map to the original
|
|
// number of points to recreate the original identity map.
|
|
att->SetExplicitMapping(num_original_points);
|
|
// Set the entries of the explicit map to identity.
|
|
for (PointIndex::ValueType i = 0; i < num_original_points; ++i) {
|
|
att->SetPointMapEntry(PointIndex(i), AttributeValueIndex(i));
|
|
}
|
|
}
|
|
}
|
|
if (!att->is_mapping_identity()) {
|
|
// Explicit mapping between points and local attribute indices.
|
|
for (PointIndex i(0); i < num_original_points; ++i) {
|
|
// The new point id that maps to the currently processed attribute
|
|
// entry.
|
|
const PointIndex new_point_id = point_map[i];
|
|
if (new_point_id < 0)
|
|
continue;
|
|
// Index of the currenlty processed attribut entry in the original
|
|
// mesh.
|
|
const AttributeValueIndex original_entry_index =
|
|
att->mapped_index(i);
|
|
// New index of the same entry after unused entries were removed.
|
|
const AttributeValueIndex new_entry_index =
|
|
att_index_map[original_entry_index];
|
|
att->SetPointMapEntry(new_point_id, new_entry_index);
|
|
}
|
|
// If the number of points changed, we need to set a new explicit map
|
|
// size.
|
|
att->SetExplicitMapping(mesh->num_points());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
} // namespace draco
|