mirror of
https://git.mirrors.martin98.com/https://github.com/google/draco
synced 2025-06-04 11:25:44 +08:00
A couple of more bug fixes to be included in the 1.5.7 release.
This commit is contained in:
parent
dcce9d0b3a
commit
c4ec84680d
@ -34,12 +34,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
namespace draco {
|
namespace draco {
|
||||||
|
|
||||||
#ifndef DISALLOW_COPY_AND_ASSIGN
|
|
||||||
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
|
||||||
TypeName(const TypeName &) = delete; \
|
|
||||||
void operator=(const TypeName &) = delete;
|
|
||||||
#endif // DISALLOW_COPY_AND_ASSIGN
|
|
||||||
|
|
||||||
#ifndef FALLTHROUGH_INTENDED
|
#ifndef FALLTHROUGH_INTENDED
|
||||||
#if defined(__clang__) && defined(__has_warning)
|
#if defined(__clang__) && defined(__has_warning)
|
||||||
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
|
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
|
||||||
@ -67,6 +61,12 @@ namespace draco {
|
|||||||
|
|
||||||
} // namespace draco
|
} // namespace draco
|
||||||
|
|
||||||
|
#ifndef DISALLOW_COPY_AND_ASSIGN
|
||||||
|
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
|
||||||
|
TypeName(const TypeName &) = delete; \
|
||||||
|
void operator=(const TypeName &) = delete;
|
||||||
|
#endif // DISALLOW_COPY_AND_ASSIGN
|
||||||
|
|
||||||
#ifdef DRACO_DEBUG
|
#ifdef DRACO_DEBUG
|
||||||
#define DRACO_DCHECK(x) (assert(x));
|
#define DRACO_DCHECK(x) (assert(x));
|
||||||
#define DRACO_DCHECK_EQ(a, b) assert((a) == (b));
|
#define DRACO_DCHECK_EQ(a, b) assert((a) == (b));
|
||||||
|
@ -313,7 +313,7 @@ Status CopyDataFromBufferView(const tinygltf::Model &model, int buffer_view_id,
|
|||||||
const uint8_t *const data_start = buffer.data.data() + buffer_view.byteOffset;
|
const uint8_t *const data_start = buffer.data.data() + buffer_view.byteOffset;
|
||||||
|
|
||||||
data->resize(buffer_view.byteLength);
|
data->resize(buffer_view.byteLength);
|
||||||
memcpy(&(*data)[0], data_start, buffer_view.byteLength);
|
memcpy(data->data(), data_start, buffer_view.byteLength);
|
||||||
return OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1268,6 +1268,31 @@ TEST(GltfDecoderTest, DecodeMeshWithMeshFeaturesWithStructuralMetadata) {
|
|||||||
GltfTestHelper::CheckBoxMetaStructuralMetadata(*mesh, use_case);
|
GltfTestHelper::CheckBoxMetaStructuralMetadata(*mesh, use_case);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(GltfDecoderTest, DecodeMeshWithStructuralMetadataWithEmptyStringBuffer) {
|
||||||
|
// Checks that the decoder correctly handles 0-length buffers. An example case
|
||||||
|
// where this could happen is an EXT_structural_metadata extension with a
|
||||||
|
// buffer containing an empty string.
|
||||||
|
const auto path =
|
||||||
|
GetTestFileFullPath("ZeroLengthBufferView/ZeroLengthBufferView.gltf");
|
||||||
|
GltfTestHelper::UseCase use_case;
|
||||||
|
use_case.has_mesh_features = true;
|
||||||
|
use_case.has_structural_metadata = true;
|
||||||
|
|
||||||
|
draco::GltfDecoder decoder;
|
||||||
|
DRACO_ASSIGN_OR_ASSERT(auto mesh, decoder.DecodeFromFile(path));
|
||||||
|
ASSERT_NE(mesh, nullptr);
|
||||||
|
ASSERT_EQ(mesh->GetStructuralMetadata().NumPropertyTables(), 1);
|
||||||
|
ASSERT_EQ(mesh->GetStructuralMetadata().GetPropertyTable(0).GetCount(), 1);
|
||||||
|
ASSERT_EQ(mesh->GetStructuralMetadata().GetPropertyTable(0).NumProperties(),
|
||||||
|
1);
|
||||||
|
ASSERT_EQ(mesh->GetStructuralMetadata()
|
||||||
|
.GetPropertyTable(0)
|
||||||
|
.GetProperty(0)
|
||||||
|
.GetData()
|
||||||
|
.data.size(),
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(GltfDecoderTest, DecodeMeshWithMeshFeaturesWithDracoCompression) {
|
TEST(GltfDecoderTest, DecodeMeshWithMeshFeaturesWithDracoCompression) {
|
||||||
// Checks decoding of a simple glTF with mesh features compressed with Draco
|
// Checks decoding of a simple glTF with mesh features compressed with Draco
|
||||||
// as draco::Mesh.
|
// as draco::Mesh.
|
||||||
|
@ -387,10 +387,8 @@ class GltfAsset {
|
|||||||
std::unordered_map<int, int> *feature_id_name_indices);
|
std::unordered_map<int, int> *feature_id_name_indices);
|
||||||
|
|
||||||
// Iterate through the materials that are associated with |mesh| and add them
|
// Iterate through the materials that are associated with |mesh| and add them
|
||||||
// to the asset. Returns true if |mesh| does not contain any materials or all
|
// to the asset.
|
||||||
// the materials are supported. Returns false if |mesh| contains materials
|
void AddMaterials(const Mesh &mesh);
|
||||||
// that are not supported.
|
|
||||||
bool AddMaterials(const Mesh &mesh);
|
|
||||||
|
|
||||||
// Checks whether a given Draco |attribute| has data of expected |data_type|
|
// Checks whether a given Draco |attribute| has data of expected |data_type|
|
||||||
// and whether the data has one of expected |num_components|. Returns true
|
// and whether the data has one of expected |num_components|. Returns true
|
||||||
@ -428,10 +426,8 @@ class GltfAsset {
|
|||||||
Status AddSceneNode(const Scene &scene, SceneNodeIndex scene_node_index);
|
Status AddSceneNode(const Scene &scene, SceneNodeIndex scene_node_index);
|
||||||
|
|
||||||
// Iterate through the materials that are associated with |scene| and add them
|
// Iterate through the materials that are associated with |scene| and add them
|
||||||
// to the asset. Returns true if |scene| does not contain any materials or all
|
// to the asset.
|
||||||
// the materials are supported. Returns false if |scene| contains materials
|
void AddMaterials(const Scene &scene);
|
||||||
// that are not supported.
|
|
||||||
bool AddMaterials(const Scene &scene);
|
|
||||||
|
|
||||||
// Iterate through the animations that are associated with |scene| and add
|
// Iterate through the animations that are associated with |scene| and add
|
||||||
// them to the asset. Returns OkStatus() if |scene| does not contain any
|
// them to the asset. Returns OkStatus() if |scene| does not contain any
|
||||||
@ -736,9 +732,7 @@ bool GltfAsset::AddDracoMesh(const Mesh &mesh) {
|
|||||||
if (scene_index < 0) {
|
if (scene_index < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!AddMaterials(mesh)) {
|
AddMaterials(mesh);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GltfMesh gltf_mesh;
|
GltfMesh gltf_mesh;
|
||||||
meshes_.push_back(gltf_mesh);
|
meshes_.push_back(gltf_mesh);
|
||||||
@ -1286,10 +1280,13 @@ int GltfAsset::AddDracoNormals(const Mesh &mesh, int num_encoded_points) {
|
|||||||
int GltfAsset::AddDracoColors(const Mesh &mesh, int num_encoded_points) {
|
int GltfAsset::AddDracoColors(const Mesh &mesh, int num_encoded_points) {
|
||||||
const PointAttribute *const att =
|
const PointAttribute *const att =
|
||||||
mesh.GetNamedAttribute(GeometryAttribute::COLOR);
|
mesh.GetNamedAttribute(GeometryAttribute::COLOR);
|
||||||
// TODO(b/200302561): Add support for DT_UINT16 with COLOR.
|
if (!CheckDracoAttribute(att, {DT_UINT8, DT_UINT16, DT_FLOAT32}, {3, 4})) {
|
||||||
if (!CheckDracoAttribute(att, {DT_UINT8, DT_FLOAT32}, {3, 4})) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
if (att->data_type() == DT_UINT16) {
|
||||||
|
return AddAttribute<uint16_t>(*att, mesh.num_points(), num_encoded_points,
|
||||||
|
mesh.IsCompressionEnabled());
|
||||||
|
}
|
||||||
if (att->data_type() == DT_FLOAT32) {
|
if (att->data_type() == DT_FLOAT32) {
|
||||||
return AddAttribute<float>(*att, mesh.num_points(), num_encoded_points,
|
return AddAttribute<float>(*att, mesh.num_points(), num_encoded_points,
|
||||||
mesh.IsCompressionEnabled());
|
mesh.IsCompressionEnabled());
|
||||||
@ -1460,12 +1457,10 @@ std::vector<std::pair<std::string, int>> GltfAsset::AddDracoGenerics(
|
|||||||
return attrs;
|
return attrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GltfAsset::AddMaterials(const Mesh &mesh) {
|
void GltfAsset::AddMaterials(const Mesh &mesh) {
|
||||||
if (mesh.GetMaterialLibrary().NumMaterials() == 0) {
|
if (mesh.GetMaterialLibrary().NumMaterials()) {
|
||||||
return true;
|
material_library_.Copy(mesh.GetMaterialLibrary());
|
||||||
}
|
}
|
||||||
material_library_.Copy(mesh.GetMaterialLibrary());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GltfAsset::CheckDracoAttribute(const PointAttribute *attribute,
|
bool GltfAsset::CheckDracoAttribute(const PointAttribute *attribute,
|
||||||
@ -1589,9 +1584,7 @@ Status GltfAsset::AddScene(const Scene &scene) {
|
|||||||
if (scene_index < 0) {
|
if (scene_index < 0) {
|
||||||
return Status(Status::DRACO_ERROR, "Error creating a new scene.");
|
return Status(Status::DRACO_ERROR, "Error creating a new scene.");
|
||||||
}
|
}
|
||||||
if (!AddMaterials(scene)) {
|
AddMaterials(scene);
|
||||||
return Status(Status::DRACO_ERROR, "Error adding materials to the scene.");
|
|
||||||
}
|
|
||||||
AddStructuralMetadata(scene);
|
AddStructuralMetadata(scene);
|
||||||
|
|
||||||
// Initialize base mesh transforms that may be needed when the base meshes are
|
// Initialize base mesh transforms that may be needed when the base meshes are
|
||||||
@ -1695,12 +1688,10 @@ Status GltfAsset::AddSceneNode(const Scene &scene,
|
|||||||
return OkStatus();
|
return OkStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GltfAsset::AddMaterials(const Scene &scene) {
|
void GltfAsset::AddMaterials(const Scene &scene) {
|
||||||
if (scene.GetMaterialLibrary().NumMaterials() == 0) {
|
if (scene.GetMaterialLibrary().NumMaterials()) {
|
||||||
return true;
|
material_library_.Copy(scene.GetMaterialLibrary());
|
||||||
}
|
}
|
||||||
material_library_.Copy(scene.GetMaterialLibrary());
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Status GltfAsset::AddAnimations(const Scene &scene) {
|
Status GltfAsset::AddAnimations(const Scene &scene) {
|
||||||
|
@ -407,7 +407,8 @@ bool ObjEncoder::EncodeFaceCorner(PointIndex vert_index) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ObjEncoder::EncodeFloat(float val) {
|
void ObjEncoder::EncodeFloat(float val) {
|
||||||
snprintf(num_buffer_, sizeof(num_buffer_), "%f", val);
|
// Use %F instead of %f to make the floating point non-locale aware.
|
||||||
|
snprintf(num_buffer_, sizeof(num_buffer_), "%F", val);
|
||||||
buffer()->Encode(num_buffer_, strlen(num_buffer_));
|
buffer()->Encode(num_buffer_, strlen(num_buffer_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,8 +32,15 @@ class StlEncoderTest : public ::testing::Test {
|
|||||||
ASSERT_EQ(mesh0->num_faces(), mesh1->num_faces());
|
ASSERT_EQ(mesh0->num_faces(), mesh1->num_faces());
|
||||||
ASSERT_EQ(mesh0->num_attributes(), mesh1->num_attributes());
|
ASSERT_EQ(mesh0->num_attributes(), mesh1->num_attributes());
|
||||||
for (size_t att_id = 0; att_id < mesh0->num_attributes(); ++att_id) {
|
for (size_t att_id = 0; att_id < mesh0->num_attributes(); ++att_id) {
|
||||||
ASSERT_EQ(mesh0->attribute(att_id)->size(),
|
ASSERT_EQ(mesh0->attribute(att_id)->attribute_type(),
|
||||||
mesh1->attribute(att_id)->size());
|
mesh1->attribute(att_id)->attribute_type());
|
||||||
|
// Normals are recomputed during STL encoding and they may not
|
||||||
|
// correspond to the source ones.
|
||||||
|
if (mesh0->attribute(att_id)->attribute_type() !=
|
||||||
|
GeometryAttribute::NORMAL) {
|
||||||
|
ASSERT_EQ(mesh0->attribute(att_id)->size(),
|
||||||
|
mesh1->attribute(att_id)->size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ class MeshSplitterInternal {
|
|||||||
struct WorkData : public MeshSplitter::WorkData {
|
struct WorkData : public MeshSplitter::WorkData {
|
||||||
// TriangleSoupMeshBuilder or PointCloudBuilder.
|
// TriangleSoupMeshBuilder or PointCloudBuilder.
|
||||||
std::vector<BuilderT> builders;
|
std::vector<BuilderT> builders;
|
||||||
|
std::vector<int> *att_id_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Computes number of elements (faces or points) for each sub-mesh.
|
// Computes number of elements (faces or points) for each sub-mesh.
|
||||||
@ -112,7 +113,8 @@ StatusOr<MeshSplitter::MeshVector> MeshSplitter::SplitMeshInternal(
|
|||||||
// Create the sub-meshes.
|
// Create the sub-meshes.
|
||||||
work_data.builders.resize(num_out_meshes);
|
work_data.builders.resize(num_out_meshes);
|
||||||
// Map between attribute ids of the input and output meshes.
|
// Map between attribute ids of the input and output meshes.
|
||||||
work_data.att_id_map.resize(mesh.num_attributes(), -1);
|
att_id_map_.resize(mesh.num_attributes(), -1);
|
||||||
|
work_data.att_id_map = &att_id_map_;
|
||||||
const int ignored_att_id =
|
const int ignored_att_id =
|
||||||
(!preserve_split_attribute ? split_attribute_id : -1);
|
(!preserve_split_attribute ? split_attribute_id : -1);
|
||||||
for (int mi = 0; mi < num_out_meshes; ++mi) {
|
for (int mi = 0; mi < num_out_meshes; ++mi) {
|
||||||
@ -185,10 +187,10 @@ void MeshSplitterInternal<BuilderT>::InitializeBuilder(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const GeometryAttribute *const src_att = mesh.attribute(ai);
|
const GeometryAttribute *const src_att = mesh.attribute(ai);
|
||||||
work_data->att_id_map[ai] = work_data->builders[b_index].AddAttribute(
|
(*work_data->att_id_map)[ai] = work_data->builders[b_index].AddAttribute(
|
||||||
src_att->attribute_type(), src_att->num_components(),
|
src_att->attribute_type(), src_att->num_components(),
|
||||||
src_att->data_type(), src_att->normalized());
|
src_att->data_type(), src_att->normalized());
|
||||||
work_data->builders[b_index].SetAttributeName(work_data->att_id_map[ai],
|
work_data->builders[b_index].SetAttributeName(work_data->att_id_map->at(ai),
|
||||||
src_att->name());
|
src_att->name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -228,7 +230,7 @@ void AddElementToBuilder(
|
|||||||
const auto &face = mesh.face(source_i);
|
const auto &face = mesh.face(source_i);
|
||||||
for (int ai = 0; ai < mesh.num_attributes(); ++ai) {
|
for (int ai = 0; ai < mesh.num_attributes(); ++ai) {
|
||||||
const PointAttribute *const src_att = mesh.attribute(ai);
|
const PointAttribute *const src_att = mesh.attribute(ai);
|
||||||
const int target_att_id = work_data->att_id_map[ai];
|
const int target_att_id = work_data->att_id_map->at(ai);
|
||||||
if (target_att_id == -1) {
|
if (target_att_id == -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -245,7 +247,7 @@ void AddElementToBuilder(
|
|||||||
MeshSplitterInternal<PointCloudBuilder>::WorkData *work_data) {
|
MeshSplitterInternal<PointCloudBuilder>::WorkData *work_data) {
|
||||||
for (int ai = 0; ai < mesh.num_attributes(); ++ai) {
|
for (int ai = 0; ai < mesh.num_attributes(); ++ai) {
|
||||||
const PointAttribute *const src_att = mesh.attribute(ai);
|
const PointAttribute *const src_att = mesh.attribute(ai);
|
||||||
const int target_att_id = work_data->att_id_map[ai];
|
const int target_att_id = work_data->att_id_map->at(ai);
|
||||||
if (target_att_id == -1) {
|
if (target_att_id == -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -391,7 +393,7 @@ StatusOr<MeshSplitter::MeshVector> MeshSplitter::FinalizeMeshes(
|
|||||||
|
|
||||||
// Copy over attribute unique ids.
|
// Copy over attribute unique ids.
|
||||||
for (int att_id = 0; att_id < mesh.num_attributes(); ++att_id) {
|
for (int att_id = 0; att_id < mesh.num_attributes(); ++att_id) {
|
||||||
const int mapped_att_id = work_data.att_id_map[att_id];
|
const int mapped_att_id = att_id_map_[att_id];
|
||||||
if (mapped_att_id == -1) {
|
if (mapped_att_id == -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -431,6 +433,14 @@ StatusOr<MeshSplitter::MeshVector> MeshSplitter::FinalizeMeshes(
|
|||||||
// Create a copy of source mesh features.
|
// Create a copy of source mesh features.
|
||||||
std::unique_ptr<MeshFeatures> mf(new MeshFeatures());
|
std::unique_ptr<MeshFeatures> mf(new MeshFeatures());
|
||||||
mf->Copy(mesh.GetMeshFeatures(mfi));
|
mf->Copy(mesh.GetMeshFeatures(mfi));
|
||||||
|
|
||||||
|
// Update mesh features attribute index if used.
|
||||||
|
if (mf->GetAttributeIndex() != -1) {
|
||||||
|
const int new_mf_attribute_index =
|
||||||
|
att_id_map_[mf->GetAttributeIndex()];
|
||||||
|
mf->SetAttributeIndex(new_mf_attribute_index);
|
||||||
|
}
|
||||||
|
|
||||||
const MeshFeaturesIndex new_mfi =
|
const MeshFeaturesIndex new_mfi =
|
||||||
out_meshes[mi]->AddMeshFeatures(std::move(mf));
|
out_meshes[mi]->AddMeshFeatures(std::move(mf));
|
||||||
if (work_data.split_by_materials && !preserve_materials_) {
|
if (work_data.split_by_materials && !preserve_materials_) {
|
||||||
@ -548,7 +558,8 @@ StatusOr<MeshSplitter::MeshVector> MeshSplitter::SplitMeshToComponents(
|
|||||||
typename MeshSplitterInternal<TriangleSoupMeshBuilder>::WorkData work_data;
|
typename MeshSplitterInternal<TriangleSoupMeshBuilder>::WorkData work_data;
|
||||||
work_data.builders.resize(num_out_meshes);
|
work_data.builders.resize(num_out_meshes);
|
||||||
work_data.num_sub_mesh_elements.resize(num_out_meshes, 0);
|
work_data.num_sub_mesh_elements.resize(num_out_meshes, 0);
|
||||||
work_data.att_id_map.resize(mesh.num_attributes(), -1);
|
att_id_map_.resize(mesh.num_attributes(), -1);
|
||||||
|
work_data.att_id_map = &att_id_map_;
|
||||||
for (int mi = 0; mi < num_out_meshes; ++mi) {
|
for (int mi = 0; mi < num_out_meshes; ++mi) {
|
||||||
const int num_faces = connected_components.NumConnectedComponentFaces(mi);
|
const int num_faces = connected_components.NumConnectedComponentFaces(mi);
|
||||||
work_data.num_sub_mesh_elements[mi] = num_faces;
|
work_data.num_sub_mesh_elements[mi] = num_faces;
|
||||||
@ -572,5 +583,9 @@ StatusOr<MeshSplitter::MeshVector> MeshSplitter::SplitMeshToComponents(
|
|||||||
return FinalizeMeshes(mesh, work_data, std::move(out_meshes));
|
return FinalizeMeshes(mesh, work_data, std::move(out_meshes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MeshSplitter::GetSplitMeshAttributeIndex(int source_mesh_att_index) const {
|
||||||
|
return att_id_map_[source_mesh_att_index];
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace draco
|
} // namespace draco
|
||||||
#endif // DRACO_TRANSCODER_SUPPORTED
|
#endif // DRACO_TRANSCODER_SUPPORTED
|
||||||
|
@ -98,10 +98,13 @@ class MeshSplitter {
|
|||||||
StatusOr<MeshVector> SplitMeshToComponents(
|
StatusOr<MeshVector> SplitMeshToComponents(
|
||||||
const Mesh &mesh, const MeshConnectedComponents &connected_components);
|
const Mesh &mesh, const MeshConnectedComponents &connected_components);
|
||||||
|
|
||||||
|
// Returns attribute index on each split mesh that corresponds to the
|
||||||
|
// |source_mesh_att_index| of the source Mesh.
|
||||||
|
// Must be called after SplitMesh() or SplitMeshToComponents().
|
||||||
|
int GetSplitMeshAttributeIndex(int source_mesh_att_index) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct WorkData {
|
struct WorkData {
|
||||||
// Map between attribute ids of the input and output meshes.
|
|
||||||
std::vector<int> att_id_map;
|
|
||||||
std::vector<int> num_sub_mesh_elements;
|
std::vector<int> num_sub_mesh_elements;
|
||||||
bool split_by_materials = false;
|
bool split_by_materials = false;
|
||||||
};
|
};
|
||||||
@ -120,6 +123,9 @@ class MeshSplitter {
|
|||||||
bool preserve_structural_metadata_;
|
bool preserve_structural_metadata_;
|
||||||
bool deduplicate_vertices_;
|
bool deduplicate_vertices_;
|
||||||
|
|
||||||
|
// Map between attribute ids of the input and output meshes.
|
||||||
|
std::vector<int> att_id_map_;
|
||||||
|
|
||||||
template <typename BuilderT>
|
template <typename BuilderT>
|
||||||
friend class MeshSplitterInternal;
|
friend class MeshSplitterInternal;
|
||||||
};
|
};
|
||||||
|
@ -317,6 +317,17 @@ StatusOr<std::unique_ptr<Scene>> SceneUtils::MeshToScene(
|
|||||||
// Copy over mesh features that were associated with the |material_index|.
|
// Copy over mesh features that were associated with the |material_index|.
|
||||||
Mesh &scene_mesh = scene->GetMesh(mesh_index);
|
Mesh &scene_mesh = scene->GetMesh(mesh_index);
|
||||||
Mesh::CopyMeshFeaturesForMaterial(*mesh, &scene_mesh, material_index);
|
Mesh::CopyMeshFeaturesForMaterial(*mesh, &scene_mesh, material_index);
|
||||||
|
|
||||||
|
// Update mesh features attribute indices if needed.
|
||||||
|
for (MeshFeaturesIndex mfi(0); mfi < scene_mesh.NumMeshFeatures();
|
||||||
|
++mfi) {
|
||||||
|
auto &mesh_features = scene_mesh.GetMeshFeatures(mfi);
|
||||||
|
if (mesh_features.GetAttributeIndex() != -1) {
|
||||||
|
mesh_features.SetAttributeIndex(splitter.GetSplitMeshAttributeIndex(
|
||||||
|
mesh_features.GetAttributeIndex()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UpdateMeshFeaturesTexturesOnMesh(old_texture_to_index_map,
|
UpdateMeshFeaturesTexturesOnMesh(old_texture_to_index_map,
|
||||||
&scene->GetNonMaterialTextureLibrary(),
|
&scene->GetNonMaterialTextureLibrary(),
|
||||||
&scene_mesh);
|
&scene_mesh);
|
||||||
|
@ -403,6 +403,39 @@ TEST(SceneUtilsTest, TestMeshToSceneMultipleMeshFeatures) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(SceneUtilsTest, TestMeshToSceneMeshFeaturesWithAttributes) {
|
||||||
|
// Tests that converting a mesh into scene properly updates mesh features
|
||||||
|
// attribute indices.
|
||||||
|
auto mesh =
|
||||||
|
draco::ReadMeshFromTestFile("CesiumMilkTruck/glTF/CesiumMilkTruck.gltf");
|
||||||
|
ASSERT_NE(mesh, nullptr);
|
||||||
|
|
||||||
|
// Add a new dummy mesh features and mesh features attribute to the mesh.
|
||||||
|
std::unique_ptr<draco::PointAttribute> mf_att(new draco::PointAttribute());
|
||||||
|
mf_att->Init(draco::GeometryAttribute::GENERIC, 1, draco::DT_FLOAT32, false,
|
||||||
|
mesh->num_points());
|
||||||
|
const int mf_att_id = mesh->AddAttribute(std::move(mf_att));
|
||||||
|
std::unique_ptr<draco::MeshFeatures> mf(new draco::MeshFeatures());
|
||||||
|
mf->SetAttributeIndex(mf_att_id);
|
||||||
|
mesh->AddMeshFeatures(std::move(mf));
|
||||||
|
|
||||||
|
// Convert the mesh into a scene.
|
||||||
|
DRACO_ASSIGN_OR_ASSERT(const std::unique_ptr<draco::Scene> scene_from_mesh,
|
||||||
|
draco::SceneUtils::MeshToScene(std::move(mesh)));
|
||||||
|
ASSERT_NE(scene_from_mesh, nullptr);
|
||||||
|
|
||||||
|
// Ensure the attribute indices on the meshes from scene are decremented by
|
||||||
|
// one because the material attribute was removed.
|
||||||
|
ASSERT_EQ(scene_from_mesh->NumMeshes(), 4);
|
||||||
|
for (draco::MeshIndex mi(0); mi < scene_from_mesh->NumMeshes(); ++mi) {
|
||||||
|
for (draco::MeshFeaturesIndex mfi(0);
|
||||||
|
mfi < scene_from_mesh->GetMesh(mi).NumMeshFeatures(); ++mfi) {
|
||||||
|
const auto &mf = scene_from_mesh->GetMesh(mi).GetMeshFeatures(mfi);
|
||||||
|
ASSERT_EQ(mf.GetAttributeIndex(), mf_att_id - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST(SceneUtilsTest, TestMeshToSceneStructuralMetadata) {
|
TEST(SceneUtilsTest, TestMeshToSceneStructuralMetadata) {
|
||||||
const std::string filename = "cube_att.obj";
|
const std::string filename = "cube_att.obj";
|
||||||
std::unique_ptr<draco::Mesh> mesh = draco::ReadMeshFromTestFile(filename);
|
std::unique_ptr<draco::Mesh> mesh = draco::ReadMeshFromTestFile(filename);
|
||||||
|
BIN
testdata/ZeroLengthBufferView/ZeroLengthBufferView.bin
vendored
Normal file
BIN
testdata/ZeroLengthBufferView/ZeroLengthBufferView.bin
vendored
Normal file
Binary file not shown.
130
testdata/ZeroLengthBufferView/ZeroLengthBufferView.gltf
vendored
Normal file
130
testdata/ZeroLengthBufferView/ZeroLengthBufferView.gltf
vendored
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
{
|
||||||
|
"asset": {
|
||||||
|
"generator": "by_hand",
|
||||||
|
"version": "2.0"
|
||||||
|
},
|
||||||
|
"scenes": [
|
||||||
|
{
|
||||||
|
"nodes": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scene": 0,
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"mesh": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes": [
|
||||||
|
{
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"POSITION": 1
|
||||||
|
},
|
||||||
|
"indices": 0,
|
||||||
|
"mode": 4,
|
||||||
|
"material": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"materials": [
|
||||||
|
{
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorFactor": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"metallicFactor": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"accessors": [
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"componentType": 5121,
|
||||||
|
"count": 6,
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 4,
|
||||||
|
"max": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extensions": {
|
||||||
|
"EXT_structural_metadata": {
|
||||||
|
"schema": {
|
||||||
|
"classes": {
|
||||||
|
"class": {
|
||||||
|
"properties": {
|
||||||
|
"entity_id": {
|
||||||
|
"type": "STRING"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"propertyTables": [
|
||||||
|
{
|
||||||
|
"class": "class",
|
||||||
|
"count": 1,
|
||||||
|
"properties": {
|
||||||
|
"entity_id": {
|
||||||
|
"values": 2,
|
||||||
|
"stringOffsetType": "UINT8",
|
||||||
|
"stringOffsets": 3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"propertyAttributes": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bufferViews": [
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 0,
|
||||||
|
"byteLength": 8
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 8,
|
||||||
|
"byteLength": 48
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 56,
|
||||||
|
"byteLength": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteOffset": 56,
|
||||||
|
"byteLength": 4
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers": [
|
||||||
|
{
|
||||||
|
"byteLength": 60,
|
||||||
|
"uri": "ZeroLengthBufferView.bin"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extensionsUsed": [
|
||||||
|
"EXT_structural_metadata"
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user