forked from google/draco
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mesh.h
332 lines (285 loc) · 12.9 KB
/
mesh.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
// 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.
//
#ifndef DRACO_MESH_MESH_H_
#define DRACO_MESH_MESH_H_
#include <memory>
#include <unordered_map>
#include "draco/attributes/geometry_indices.h"
#include "draco/core/hash_utils.h"
#include "draco/core/macros.h"
#include "draco/core/status.h"
#include "draco/draco_features.h"
#ifdef DRACO_TRANSCODER_SUPPORTED
#include "draco/compression/draco_compression_options.h"
#include "draco/material/material_library.h"
#include "draco/mesh/mesh_features.h"
#include "draco/mesh/mesh_indices.h"
#include "draco/metadata/structural_metadata.h"
#endif
#include "draco/point_cloud/point_cloud.h"
namespace draco {
// List of different variants of mesh attributes.
enum MeshAttributeElementType {
// All corners attached to a vertex share the same attribute value. A typical
// example are the vertex positions and often vertex colors.
MESH_VERTEX_ATTRIBUTE = 0,
// The most general attribute where every corner of the mesh can have a
// different attribute value. Often used for texture coordinates or normals.
MESH_CORNER_ATTRIBUTE,
// All corners of a single face share the same value.
MESH_FACE_ATTRIBUTE
};
// Mesh class can be used to represent general triangular meshes. Internally,
// Mesh is just an extended PointCloud with extra connectivity data that defines
// what points are connected together in triangles.
class Mesh : public PointCloud {
public:
typedef std::array<PointIndex, 3> Face;
Mesh();
#ifdef DRACO_TRANSCODER_SUPPORTED
// Copies all data from the |src| mesh.
void Copy(const Mesh &src);
#endif
void AddFace(const Face &face) { faces_.push_back(face); }
void SetFace(FaceIndex face_id, const Face &face) {
if (face_id >= static_cast<uint32_t>(faces_.size())) {
faces_.resize(face_id.value() + 1, Face());
}
faces_[face_id] = face;
}
// Sets the total number of faces. Creates new empty faces or deletes
// existing ones if necessary.
void SetNumFaces(size_t num_faces) { faces_.resize(num_faces, Face()); }
FaceIndex::ValueType num_faces() const {
return static_cast<uint32_t>(faces_.size());
}
const Face &face(FaceIndex face_id) const {
DRACO_DCHECK_LE(0, face_id.value());
DRACO_DCHECK_LT(face_id.value(), static_cast<int>(faces_.size()));
return faces_[face_id];
}
void SetAttribute(int att_id, std::unique_ptr<PointAttribute> pa) override {
PointCloud::SetAttribute(att_id, std::move(pa));
if (static_cast<int>(attribute_data_.size()) <= att_id) {
attribute_data_.resize(att_id + 1);
}
}
void DeleteAttribute(int att_id) override {
PointCloud::DeleteAttribute(att_id);
if (att_id >= 0 && att_id < static_cast<int>(attribute_data_.size())) {
attribute_data_.erase(attribute_data_.begin() + att_id);
}
}
#ifdef DRACO_TRANSCODER_SUPPORTED
// Adds a point attribute |att| to the mesh and returns the index of the
// newly inserted attribute. Attribute connectivity data is specified in
// |corner_to_value| array that contains mapping between face corners and
// attribute value indices.
// The purpose of this function is to allow users to add attributes with
// arbitrary connectivity to an existing mesh. New points will be
// automatically created if needed.
int32_t AddAttributeWithConnectivity(
std::unique_ptr<PointAttribute> att,
const IndexTypeVector<CornerIndex, AttributeValueIndex> &corner_to_value);
// Adds a point attribute |att| to the mesh and returns the index of the
// newly inserted attribute. The inserted attribute must have the same
// connectivity as the position attribute of the mesh (that is, the attribute
// values are defined per-vertex). Each attribute value entry in |att|
// corresponds to the corresponding attribute value entry in the position
// attribute (AttributeValueIndex in both attributes refer to the same
// spatial vertex).
// Returns -1 in case of error.
int32_t AddPerVertexAttribute(std::unique_ptr<PointAttribute> att);
// Removes points that are not mapped to any face of the mesh. All attribute
// values are going to be removed as well.
void RemoveIsolatedPoints();
// Adds a point attribute |att| to the mesh and returns the index of the
// newly inserted attribute. Attribute values are mapped 1:1 to face indices.
// Returns -1 in case of error.
int32_t AddPerFaceAttribute(std::unique_ptr<PointAttribute> att);
#endif // DRACO_TRANSCODER_SUPPORTED
MeshAttributeElementType GetAttributeElementType(int att_id) const {
return attribute_data_[att_id].element_type;
}
void SetAttributeElementType(int att_id, MeshAttributeElementType et) {
attribute_data_[att_id].element_type = et;
}
// Returns the point id of for a corner |ci|.
inline PointIndex CornerToPointId(int ci) const {
if (ci < 0 || static_cast<uint32_t>(ci) == kInvalidCornerIndex.value()) {
return kInvalidPointIndex;
}
return this->face(FaceIndex(ci / 3))[ci % 3];
}
// Returns the point id of a corner |ci|.
inline PointIndex CornerToPointId(CornerIndex ci) const {
return this->CornerToPointId(ci.value());
}
struct AttributeData {
AttributeData() : element_type(MESH_CORNER_ATTRIBUTE) {}
MeshAttributeElementType element_type;
};
#ifdef DRACO_TRANSCODER_SUPPORTED
void SetName(const std::string &name) { name_ = name; }
const std::string &GetName() const { return name_; }
const MaterialLibrary &GetMaterialLibrary() const {
return material_library_;
}
MaterialLibrary &GetMaterialLibrary() { return material_library_; }
// Removes all materials that are not referenced by any face of the mesh.
// Optional argument |remove_unused_material_indices| can be used to control
// whether unusued material indices are removed as well (default = true).
// If material indices are not removed, the unused material indices will
// point to empty (default) materials.
void RemoveUnusedMaterials();
void RemoveUnusedMaterials(bool remove_unused_material_indices);
// Enables or disables Draco geometry compression for this mesh.
void SetCompressionEnabled(bool enabled) { compression_enabled_ = enabled; }
bool IsCompressionEnabled() const { return compression_enabled_; }
// Sets |options| that configure Draco geometry compression. This does not
// enable or disable compression.
void SetCompressionOptions(const DracoCompressionOptions &options) {
compression_options_ = options;
}
const DracoCompressionOptions &GetCompressionOptions() const {
return compression_options_;
}
DracoCompressionOptions &GetCompressionOptions() {
return compression_options_;
}
// Library that contains non-material textures.
const TextureLibrary &GetNonMaterialTextureLibrary() const {
return non_material_texture_library_;
}
TextureLibrary &GetNonMaterialTextureLibrary() {
return non_material_texture_library_;
}
// Mesh feature ID sets as defined by EXT_mesh_features glTF extension.
MeshFeaturesIndex AddMeshFeatures(
std::unique_ptr<MeshFeatures> mesh_features) {
mesh_features_.push_back(std::move(mesh_features));
mesh_features_material_mask_.push_back({});
return MeshFeaturesIndex(mesh_features_.size() - 1);
}
int NumMeshFeatures() const { return mesh_features_.size(); }
const MeshFeatures &GetMeshFeatures(MeshFeaturesIndex index) const {
return *mesh_features_[index];
}
MeshFeatures &GetMeshFeatures(MeshFeaturesIndex index) {
return *mesh_features_[index];
}
void RemoveMeshFeatures(MeshFeaturesIndex index) {
mesh_features_.erase(mesh_features_.begin() + index.value());
mesh_features_material_mask_.erase(mesh_features_material_mask_.begin() +
index.value());
}
// Restricts given mesh features to faces mapped to a material with
// |material_index|. Note that single mesh features can be restricted to
// multiple materials.
void AddMeshFeaturesMaterialMask(MeshFeaturesIndex index,
int material_index) {
mesh_features_material_mask_[index].push_back(material_index);
}
size_t NumMeshFeaturesMaterialMasks(MeshFeaturesIndex index) const {
return mesh_features_material_mask_[index].size();
}
int GetMeshFeaturesMaterialMask(MeshFeaturesIndex index,
int mask_index) const {
return mesh_features_material_mask_[index][mask_index];
}
// Updates mesh features texture pointer to point to a new |texture_library|.
// The current texture pointer is used to determine the texture index in the
// new texture library via a given |texture_to_index_map|.
static void UpdateMeshFeaturesTexturePointer(
const std::unordered_map<const Texture *, int> &texture_to_index_map,
TextureLibrary *texture_library, MeshFeatures *mesh_features);
// Copies over mesh features from |source_mesh| and stores them in
// |target_mesh| as long as the mesh features material mask is valid for
// given |material_index|.
static void CopyMeshFeaturesForMaterial(const Mesh &source_mesh,
Mesh *target_mesh,
int material_index);
// Structural metadata.
const StructuralMetadata &GetStructuralMetadata() const {
return structural_metadata_;
}
StructuralMetadata &GetStructuralMetadata() { return structural_metadata_; }
#endif // DRACO_TRANSCODER_SUPPORTED
protected:
#ifdef DRACO_ATTRIBUTE_INDICES_DEDUPLICATION_SUPPORTED
// Extends the point deduplication to face corners. This method is called from
// the PointCloud::DeduplicatePointIds() and it remaps all point ids stored in
// |faces_| to the new deduplicated point ids using the map |id_map|.
void ApplyPointIdDeduplication(
const IndexTypeVector<PointIndex, PointIndex> &id_map,
const std::vector<PointIndex> &unique_point_ids) override;
#endif
// Exposes |faces_|. Use |faces_| at your own risk. DO NOT store the
// reference: the |faces_| object is destroyed with the mesh.
IndexTypeVector<FaceIndex, Face> &faces() { return faces_; }
private:
// Mesh specific per-attribute data.
std::vector<AttributeData> attribute_data_;
// Vertex indices valid for all attributes. Each attribute has its own map
// that converts vertex indices into attribute indices.
IndexTypeVector<FaceIndex, Face> faces_;
#ifdef DRACO_TRANSCODER_SUPPORTED
// Mesh name.
std::string name_;
// Materials applied to to this mesh.
MaterialLibrary material_library_;
// Compression options for this mesh.
// TODO(vytyaz): Store encoded bitstream that this mesh compresses into.
bool compression_enabled_;
DracoCompressionOptions compression_options_;
// Sets of feature IDs as defined by EXT_mesh_features glTF extension.
IndexTypeVector<MeshFeaturesIndex, std::unique_ptr<MeshFeatures>>
mesh_features_;
// When the Mesh contains multiple materials, |mesh_features_material_mask_|
// can be used to limit specific MeshFeaturesIndex to a vector of material
// indices. If for a given mesh feature index, the material indices are empty,
// the corresponding mesh features are applied to the entire mesh.
IndexTypeVector<MeshFeaturesIndex, std::vector<int>>
mesh_features_material_mask_;
// Texture library for storing non-material textures used by this mesh, e.g.,
// textures containing mesh feature IDs of EXT_mesh_features glTF extension.
// If the mesh is part of the scene then the textures are stored in the scene.
// Note that mesh features contain pointers to non-material textures. It is
// responsibility of class user to update these pointers when updating the
// textures. See Mesh::Copy() for example.
TextureLibrary non_material_texture_library_;
// Structural metadata defined by the EXT_structural_metadata glTF extension.
StructuralMetadata structural_metadata_;
#endif // DRACO_TRANSCODER_SUPPORTED
friend struct MeshHasher;
};
// Functor for computing a hash from data stored within a mesh.
// Note that this can be quite slow. Two meshes will have the same hash only
// when they have exactly the same connectivity and attribute values.
struct MeshHasher {
size_t operator()(const Mesh &mesh) const {
PointCloudHasher pc_hasher;
size_t hash = pc_hasher(mesh);
// Hash faces.
for (FaceIndex i(0); i < static_cast<uint32_t>(mesh.faces_.size()); ++i) {
for (int j = 0; j < 3; ++j) {
hash = HashCombine(mesh.faces_[i][j].value(), hash);
}
}
return hash;
}
};
} // namespace draco
#endif // DRACO_MESH_MESH_H_