mirror of
https://git.mirrors.martin98.com/https://github.com/google/draco
synced 2025-08-12 06:39:05 +08:00
Merging changes from our private repo:
1. More optimized selection of prediction schemes for different compression levels on the encoder side. 2. Improved robustness to tampered input data (.drc) 3. Added support for strognly typed vectors of bools 4. Support for logging and squared lenght to our VectorND class 5. Added support for partially defined indices in .OBJ files 6. Added support for loading of normal vectors in .PLY files
This commit is contained in:
parent
8c0911dcb0
commit
8374e14042
@ -16,6 +16,36 @@
|
|||||||
|
|
||||||
namespace draco {
|
namespace draco {
|
||||||
|
|
||||||
|
PredictionSchemeMethod SelectPredictionMethod(
|
||||||
|
int att_id, const PointCloudEncoder *encoder) {
|
||||||
|
if (encoder->options()->GetSpeed() >= 10) {
|
||||||
|
return PREDICTION_NONE; // No prediction when the fastest speed is
|
||||||
|
// requested.
|
||||||
|
}
|
||||||
|
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
|
||||||
|
// Use speed setting to select the best encoding method.
|
||||||
|
const PointAttribute *const att = encoder->point_cloud()->attribute(att_id);
|
||||||
|
if (att->attribute_type() == GeometryAttribute::TEX_COORD) {
|
||||||
|
if (encoder->options()->GetSpeed() < 4) {
|
||||||
|
// Use texture coordinate prediction for speeds 0, 1, 2, 3.
|
||||||
|
return MESH_PREDICTION_TEX_COORDS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Handle other attribute types.
|
||||||
|
if (encoder->options()->GetSpeed() >= 8) {
|
||||||
|
return PREDICTION_DIFFERENCE;
|
||||||
|
}
|
||||||
|
if (encoder->options()->GetSpeed() >= 2) {
|
||||||
|
// Parallelogram prediction is used for speeds 2 - 7.
|
||||||
|
return MESH_PREDICTION_PARALLELOGRAM;
|
||||||
|
}
|
||||||
|
// Multi-parallelogram is used for speeds 0, 1.
|
||||||
|
return MESH_PREDICTION_MULTI_PARALLELOGRAM;
|
||||||
|
}
|
||||||
|
// Default option is delta coding.
|
||||||
|
return PREDICTION_DIFFERENCE;
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the preferred prediction scheme based on the encoder options.
|
// Returns the preferred prediction scheme based on the encoder options.
|
||||||
PredictionSchemeMethod GetPredictionMethodFromOptions(
|
PredictionSchemeMethod GetPredictionMethodFromOptions(
|
||||||
int att_id, const EncoderOptions &options) {
|
int att_id, const EncoderOptions &options) {
|
||||||
|
@ -23,6 +23,11 @@
|
|||||||
|
|
||||||
namespace draco {
|
namespace draco {
|
||||||
|
|
||||||
|
// Selects a prediction method based on the input geometry type and based on the
|
||||||
|
// encoder options.
|
||||||
|
PredictionSchemeMethod SelectPredictionMethod(int att_id,
|
||||||
|
const PointCloudEncoder *encoder);
|
||||||
|
|
||||||
// Creates a prediction scheme for a given encoder and given prediction method.
|
// Creates a prediction scheme for a given encoder and given prediction method.
|
||||||
// The prediction schemes are automatically initialized with encoder specific
|
// The prediction schemes are automatically initialized with encoder specific
|
||||||
// data if needed.
|
// data if needed.
|
||||||
@ -34,23 +39,9 @@ CreatePredictionSchemeForEncoder(PredictionSchemeMethod method, int att_id,
|
|||||||
const TransformT &transform) {
|
const TransformT &transform) {
|
||||||
const PointAttribute *const att = encoder->point_cloud()->attribute(att_id);
|
const PointAttribute *const att = encoder->point_cloud()->attribute(att_id);
|
||||||
if (method == PREDICTION_UNDEFINED) {
|
if (method == PREDICTION_UNDEFINED) {
|
||||||
if (encoder->options()->GetSpeed() >= 10) {
|
method = SelectPredictionMethod(att_id, encoder);
|
||||||
return nullptr; // No prediction when the fastest speed is requested.
|
if (method == PREDICTION_NONE)
|
||||||
}
|
return nullptr; // No prediction is used.
|
||||||
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
|
|
||||||
// Use speed setting to select the best encoding method.
|
|
||||||
if (encoder->options()->GetSpeed() >= 8) {
|
|
||||||
method = PREDICTION_DIFFERENCE;
|
|
||||||
} else if (encoder->options()->GetSpeed() >= 5) {
|
|
||||||
method = MESH_PREDICTION_PARALLELOGRAM;
|
|
||||||
} else {
|
|
||||||
if (att->attribute_type() == GeometryAttribute::TEX_COORD) {
|
|
||||||
method = MESH_PREDICTION_TEX_COORDS;
|
|
||||||
} else {
|
|
||||||
method = MESH_PREDICTION_MULTI_PARALLELOGRAM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
|
if (encoder->GetGeometryType() == TRIANGULAR_MESH) {
|
||||||
// Cast the encoder to mesh encoder. This is not necessarily safe if there
|
// Cast the encoder to mesh encoder. This is not necessarily safe if there
|
||||||
|
@ -36,7 +36,8 @@ bool SequentialAttributeDecoder::InitializeStandalone(
|
|||||||
|
|
||||||
bool SequentialAttributeDecoder::Decode(
|
bool SequentialAttributeDecoder::Decode(
|
||||||
const std::vector<PointIndex> &point_ids, DecoderBuffer *in_buffer) {
|
const std::vector<PointIndex> &point_ids, DecoderBuffer *in_buffer) {
|
||||||
attribute_->Reset(point_ids.size());
|
if (!attribute_->Reset(point_ids.size()))
|
||||||
|
return false;
|
||||||
if (!DecodeValues(point_ids, in_buffer))
|
if (!DecodeValues(point_ids, in_buffer))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
@ -97,9 +97,8 @@ bool SequentialIntegerAttributeEncoder::EncodeValues(
|
|||||||
reinterpret_cast<uint32_t *>(values_.data()));
|
reinterpret_cast<uint32_t *>(values_.data()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encoder() == nullptr ||
|
if (encoder() == nullptr || encoder()->options()->GetGlobalBool(
|
||||||
encoder()->options()->GetGlobalBool("use_built_in_attribute_compression",
|
"use_built_in_attribute_compression", true)) {
|
||||||
true)) {
|
|
||||||
out_buffer->Encode(static_cast<uint8_t>(1));
|
out_buffer->Encode(static_cast<uint8_t>(1));
|
||||||
EncodeSymbols(reinterpret_cast<uint32_t *>(values_.data()),
|
EncodeSymbols(reinterpret_cast<uint32_t *>(values_.data()),
|
||||||
point_ids.size() * num_components, num_components,
|
point_ids.size() * num_components, num_components,
|
||||||
|
@ -18,7 +18,10 @@ namespace draco {
|
|||||||
|
|
||||||
DataBuffer::DataBuffer() {}
|
DataBuffer::DataBuffer() {}
|
||||||
|
|
||||||
void DataBuffer::Update(const void *data, int64_t size) {
|
bool DataBuffer::Update(const void *data, int64_t size) {
|
||||||
|
if (size < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
// If no data is provided, just resize the buffer.
|
// If no data is provided, just resize the buffer.
|
||||||
data_.resize(size);
|
data_.resize(size);
|
||||||
@ -27,19 +30,25 @@ void DataBuffer::Update(const void *data, int64_t size) {
|
|||||||
data_.assign(byte_data, byte_data + size);
|
data_.assign(byte_data, byte_data + size);
|
||||||
}
|
}
|
||||||
descriptor_.buffer_update_count++;
|
descriptor_.buffer_update_count++;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataBuffer::Update(const void *data, int64_t size, int64_t offset) {
|
bool DataBuffer::Update(const void *data, int64_t size, int64_t offset) {
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
|
if (size + offset < 0)
|
||||||
|
return false;
|
||||||
// If no data is provided, just resize the buffer.
|
// If no data is provided, just resize the buffer.
|
||||||
data_.resize(size + offset);
|
data_.resize(size + offset);
|
||||||
} else {
|
} else {
|
||||||
|
if (size < 0)
|
||||||
|
return false;
|
||||||
if (size + offset > static_cast<int64_t>(data_.size()))
|
if (size + offset > static_cast<int64_t>(data_.size()))
|
||||||
data_.resize(size + offset);
|
data_.resize(size + offset);
|
||||||
const uint8_t *const byte_data = static_cast<const uint8_t *>(data);
|
const uint8_t *const byte_data = static_cast<const uint8_t *>(data);
|
||||||
std::copy(byte_data, byte_data + size, data_.data() + offset);
|
std::copy(byte_data, byte_data + size, data_.data() + offset);
|
||||||
}
|
}
|
||||||
descriptor_.buffer_update_count++;
|
descriptor_.buffer_update_count++;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataBuffer::WriteDataToStream(std::ostream &stream) {
|
void DataBuffer::WriteDataToStream(std::ostream &stream) {
|
||||||
|
@ -36,10 +36,10 @@ struct DataBufferDescriptor {
|
|||||||
class DataBuffer {
|
class DataBuffer {
|
||||||
public:
|
public:
|
||||||
DataBuffer();
|
DataBuffer();
|
||||||
void Update(const void *data, int64_t size);
|
bool Update(const void *data, int64_t size);
|
||||||
// TODO(zhafang): The two update functions should be combined. I will
|
// TODO(zhafang): The two update functions should be combined. I will
|
||||||
// leave for now in case it breaks any geometry compression tools.
|
// leave for now in case it breaks any geometry compression tools.
|
||||||
void Update(const void *data, int64_t size, int64_t offset);
|
bool Update(const void *data, int64_t size, int64_t offset);
|
||||||
void WriteDataToStream(std::ostream &stream);
|
void WriteDataToStream(std::ostream &stream);
|
||||||
// Reads data from the buffer. Potentially unsafe, called needs to ensure
|
// Reads data from the buffer. Potentially unsafe, called needs to ensure
|
||||||
// the accessed memory is valid.
|
// the accessed memory is valid.
|
||||||
|
@ -30,6 +30,9 @@ namespace draco {
|
|||||||
template <class IndexTypeT, class ValueTypeT>
|
template <class IndexTypeT, class ValueTypeT>
|
||||||
class IndexTypeVector {
|
class IndexTypeVector {
|
||||||
public:
|
public:
|
||||||
|
typedef typename std::vector<ValueTypeT>::const_reference const_reference;
|
||||||
|
typedef typename std::vector<ValueTypeT>::reference reference;
|
||||||
|
|
||||||
IndexTypeVector() {}
|
IndexTypeVector() {}
|
||||||
explicit IndexTypeVector(size_t size) : vector_(size) {}
|
explicit IndexTypeVector(size_t size) : vector_(size) {}
|
||||||
IndexTypeVector(size_t size, const ValueTypeT &val) : vector_(size, val) {}
|
IndexTypeVector(size_t size, const ValueTypeT &val) : vector_(size, val) {}
|
||||||
@ -45,16 +48,16 @@ class IndexTypeVector {
|
|||||||
void push_back(const ValueTypeT &val) { vector_.push_back(val); }
|
void push_back(const ValueTypeT &val) { vector_.push_back(val); }
|
||||||
void push_back(ValueTypeT &&val) { vector_.push_back(std::move(val)); }
|
void push_back(ValueTypeT &&val) { vector_.push_back(std::move(val)); }
|
||||||
|
|
||||||
inline ValueTypeT &operator[](const IndexTypeT &index) {
|
inline reference operator[](const IndexTypeT &index) {
|
||||||
return vector_[index.value()];
|
return vector_[index.value()];
|
||||||
}
|
}
|
||||||
inline const ValueTypeT &operator[](const IndexTypeT &index) const {
|
inline const_reference operator[](const IndexTypeT &index) const {
|
||||||
return vector_[index.value()];
|
return vector_[index.value()];
|
||||||
}
|
}
|
||||||
inline ValueTypeT &at(const IndexTypeT &index) {
|
inline reference at(const IndexTypeT &index) {
|
||||||
return vector_[index.value()];
|
return vector_[index.value()];
|
||||||
}
|
}
|
||||||
inline const ValueTypeT &at(const IndexTypeT &index) const {
|
inline const_reference at(const IndexTypeT &index) const {
|
||||||
return vector_[index.value()];
|
return vector_[index.value()];
|
||||||
}
|
}
|
||||||
const ValueTypeT *data() const { return vector_.data(); }
|
const ValueTypeT *data() const { return vector_.data(); }
|
||||||
|
@ -24,41 +24,43 @@ namespace draco {
|
|||||||
// D-dimensional vector class with basic operations.
|
// D-dimensional vector class with basic operations.
|
||||||
template <class CoeffT, int dimension_t>
|
template <class CoeffT, int dimension_t>
|
||||||
class VectorD {
|
class VectorD {
|
||||||
typedef VectorD<CoeffT, dimension_t> Self;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef VectorD<CoeffT, dimension_t> Self;
|
||||||
|
typedef CoeffT CoefficientType;
|
||||||
|
static constexpr int dimension = dimension_t;
|
||||||
|
|
||||||
VectorD() {
|
VectorD() {
|
||||||
for (int i = 0; i < dimension_t; ++i)
|
for (int i = 0; i < dimension_t; ++i)
|
||||||
(*this)[i] = CoeffT(0);
|
(*this)[i] = CoeffT(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The following constructor does not compile in opt mode, which for now led
|
// The following constructor does not compile in opt mode, which for now led
|
||||||
// to the further down, which is not ideal.
|
// to the constructors further down, which is not ideal.
|
||||||
// TODO(hemmer): fix constructor below and remove others.
|
// TODO(hemmer): fix constructor below and remove others.
|
||||||
// template <typename... Args>
|
// template <typename... Args>
|
||||||
// explicit VectorD(Args... args) : v_({args...}) {}
|
// explicit VectorD(Args... args) : v_({args...}) {}
|
||||||
|
|
||||||
VectorD(const CoeffT &c0, const CoeffT &c1) : v_({{c0, c1}}) {
|
VectorD(const CoeffT &c0, const CoeffT &c1) : v_({{c0, c1}}) {
|
||||||
CHECK(dimension_t == 2);
|
CHECK_EQ(dimension_t, 2);
|
||||||
v_[0] = c0;
|
v_[0] = c0;
|
||||||
v_[1] = c1;
|
v_[1] = c1;
|
||||||
}
|
}
|
||||||
|
|
||||||
VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2)
|
VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2)
|
||||||
: v_({{c0, c1, c2}}) {
|
: v_({{c0, c1, c2}}) {
|
||||||
CHECK(dimension_t == 3);
|
CHECK_EQ(dimension_t, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2,
|
VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2,
|
||||||
const CoeffT &c3)
|
const CoeffT &c3)
|
||||||
: v_({{c0, c1, c2, c3}}) {
|
: v_({{c0, c1, c2, c3}}) {
|
||||||
CHECK(dimension_t == 4);
|
CHECK_EQ(dimension_t, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2,
|
VectorD(const CoeffT &c0, const CoeffT &c1, const CoeffT &c2,
|
||||||
const CoeffT &c3, const CoeffT &c4)
|
const CoeffT &c3, const CoeffT &c4)
|
||||||
: v_({{c0, c1, c2, c3, c4}}) {
|
: v_({{c0, c1, c2, c3, c4}}) {
|
||||||
CHECK(dimension_t == 5);
|
CHECK_EQ(dimension_t, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
VectorD(const Self &o) {
|
VectorD(const Self &o) {
|
||||||
@ -160,6 +162,25 @@ VectorD<CoeffT, dimension_t> operator*(const CoeffT &o,
|
|||||||
return v * o;
|
return v * o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculates the squared distance between two points.
|
||||||
|
template <class CoeffT, int dimension_t>
|
||||||
|
CoeffT SquaredDistance(const VectorD<CoeffT, dimension_t> v1,
|
||||||
|
const VectorD<CoeffT, dimension_t> v2) {
|
||||||
|
CoeffT difference;
|
||||||
|
CoeffT squared_distance = 0;
|
||||||
|
// Check each index seperately so difference is never negative and underflow
|
||||||
|
// is avoided for unsigned types.
|
||||||
|
for (int i = 0; i < dimension_t; ++i) {
|
||||||
|
if (v1[i] >= v2[i]) {
|
||||||
|
difference = v1[i] - v2[i];
|
||||||
|
} else {
|
||||||
|
difference = v2[i] - v1[i];
|
||||||
|
}
|
||||||
|
squared_distance += (difference * difference);
|
||||||
|
}
|
||||||
|
return squared_distance;
|
||||||
|
}
|
||||||
|
|
||||||
typedef VectorD<float, 2> Vector2f;
|
typedef VectorD<float, 2> Vector2f;
|
||||||
typedef VectorD<float, 3> Vector3f;
|
typedef VectorD<float, 3> Vector3f;
|
||||||
typedef VectorD<float, 4> Vector4f;
|
typedef VectorD<float, 4> Vector4f;
|
||||||
@ -172,4 +193,15 @@ typedef VectorD<uint32_t, 5> Vector5ui;
|
|||||||
|
|
||||||
} // namespace draco
|
} // namespace draco
|
||||||
|
|
||||||
|
template <typename Char, typename CharTraits, class CoeffT, int dimension_t>
|
||||||
|
inline ::std::basic_ostream<Char, CharTraits> &operator<<(
|
||||||
|
::std::basic_ostream<Char, CharTraits> &out,
|
||||||
|
const draco::VectorD<CoeffT, dimension_t> &vec) {
|
||||||
|
for (int i = 0; i < dimension_t - 1; ++i) {
|
||||||
|
out << vec[i] << " ";
|
||||||
|
}
|
||||||
|
out << vec[dimension_t - 1];
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // DRACO_CORE_VECTOR_D_H_
|
#endif // DRACO_CORE_VECTOR_D_H_
|
||||||
|
@ -18,10 +18,26 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using draco::Vector3f;
|
typedef draco::Vector2f Vector2f;
|
||||||
|
typedef draco::Vector3f Vector3f;
|
||||||
|
typedef draco::Vector4f Vector4f;
|
||||||
|
typedef draco::Vector5f Vector5f;
|
||||||
|
typedef draco::Vector2ui Vector2ui;
|
||||||
|
typedef draco::Vector3ui Vector3ui;
|
||||||
|
typedef draco::Vector4ui Vector4ui;
|
||||||
|
typedef draco::Vector5ui Vector5ui;
|
||||||
|
|
||||||
class VectorDTest : public ::testing::Test {
|
class VectorDTest : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
|
template <class CoeffT, int dimension_t>
|
||||||
|
void TestSquaredDistance(const draco::VectorD<CoeffT, dimension_t> v1,
|
||||||
|
const draco::VectorD<CoeffT, dimension_t> v2,
|
||||||
|
const CoeffT result) {
|
||||||
|
CoeffT squared_distance = SquaredDistance(v1, v2);
|
||||||
|
ASSERT_EQ(squared_distance, result);
|
||||||
|
squared_distance = SquaredDistance(v2, v1);
|
||||||
|
ASSERT_EQ(squared_distance, result);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(VectorDTest, TestOperators) {
|
TEST_F(VectorDTest, TestOperators) {
|
||||||
@ -69,4 +85,54 @@ TEST_F(VectorDTest, TestOperators) {
|
|||||||
ASSERT_EQ(v.Dot(v), 14);
|
ASSERT_EQ(v.Dot(v), 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(VectorDTest, TestSquaredDistance) {
|
||||||
|
// Test Vector2f: float, 2D.
|
||||||
|
Vector2f v1_2f(5.5, 10.5);
|
||||||
|
Vector2f v2_2f(3.5, 15.5);
|
||||||
|
float result_f = 29;
|
||||||
|
TestSquaredDistance(v1_2f, v2_2f, result_f);
|
||||||
|
|
||||||
|
// Test Vector3f: float, 3D.
|
||||||
|
Vector3f v1_3f(5.5, 10.5, 2.3);
|
||||||
|
Vector3f v2_3f(3.5, 15.5, 0);
|
||||||
|
result_f = 34.29;
|
||||||
|
TestSquaredDistance(v1_3f, v2_3f, result_f);
|
||||||
|
|
||||||
|
// Test Vector4f: float, 4D.
|
||||||
|
Vector4f v1_4f(5.5, 10.5, 2.3, 7.2);
|
||||||
|
Vector4f v2_4f(3.5, 15.5, 0, 9.9);
|
||||||
|
result_f = 41.58;
|
||||||
|
TestSquaredDistance(v1_4f, v2_4f, result_f);
|
||||||
|
|
||||||
|
// Test Vector5f: float, 5D.
|
||||||
|
Vector5f v1_5f(5.5, 10.5, 2.3, 7.2, 1.0);
|
||||||
|
Vector5f v2_5f(3.5, 15.5, 0, 9.9, 0.2);
|
||||||
|
result_f = 42.22;
|
||||||
|
TestSquaredDistance(v1_5f, v2_5f, result_f);
|
||||||
|
|
||||||
|
// Test Vector 2ui: uint32_t, 2D.
|
||||||
|
Vector2ui v1_2ui(5, 10);
|
||||||
|
Vector2ui v2_2ui(3, 15);
|
||||||
|
uint32_t result_ui = 29;
|
||||||
|
TestSquaredDistance(v1_2ui, v2_2ui, result_ui);
|
||||||
|
|
||||||
|
// Test Vector 3ui: uint32_t, 3D.
|
||||||
|
Vector3ui v1_3ui(5, 10, 2);
|
||||||
|
Vector3ui v2_3ui(3, 15, 0);
|
||||||
|
result_ui = 33;
|
||||||
|
TestSquaredDistance(v1_3ui, v2_3ui, result_ui);
|
||||||
|
|
||||||
|
// Test Vector 4ui: uint32_t, 4D.
|
||||||
|
Vector4ui v1_4ui(5, 10, 2, 7);
|
||||||
|
Vector4ui v2_4ui(3, 15, 0, 9);
|
||||||
|
result_ui = 37;
|
||||||
|
TestSquaredDistance(v1_4ui, v2_4ui, result_ui);
|
||||||
|
|
||||||
|
// Test Vector 5ui: uint32_t, 5D.
|
||||||
|
Vector5ui v1_5ui(5, 10, 2, 7, 1);
|
||||||
|
Vector5ui v2_5ui(3, 15, 0, 9, 12);
|
||||||
|
result_ui = 158;
|
||||||
|
TestSquaredDistance(v1_5ui, v2_5ui, result_ui);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -311,22 +311,38 @@ bool ObjDecoder::ParseFace(bool *error) {
|
|||||||
->SetPointMapEntry(vert_id, AttributeValueIndex(indices[0] - 1));
|
->SetPointMapEntry(vert_id, AttributeValueIndex(indices[0] - 1));
|
||||||
} else if (indices[0] < 0) {
|
} else if (indices[0] < 0) {
|
||||||
out_point_cloud_->attribute(pos_att_id_)
|
out_point_cloud_->attribute(pos_att_id_)
|
||||||
->SetPointMapEntry(vert_id, AttributeValueIndex(num_positions_ + indices[0]));
|
->SetPointMapEntry(
|
||||||
|
vert_id, AttributeValueIndex(num_positions_ + indices[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indices[1] > 0) {
|
if (indices[1] > 0) {
|
||||||
out_point_cloud_->attribute(tex_att_id_)
|
out_point_cloud_->attribute(tex_att_id_)
|
||||||
->SetPointMapEntry(vert_id, AttributeValueIndex(indices[1] - 1));
|
->SetPointMapEntry(vert_id, AttributeValueIndex(indices[1] - 1));
|
||||||
} else if (indices[1] < 0) {
|
} else if (indices[1] < 0) {
|
||||||
out_point_cloud_->attribute(tex_att_id_)
|
out_point_cloud_->attribute(tex_att_id_)
|
||||||
->SetPointMapEntry(vert_id, AttributeValueIndex(num_tex_coords_ + indices[1]));
|
->SetPointMapEntry(
|
||||||
|
vert_id, AttributeValueIndex(num_tex_coords_ + indices[1]));
|
||||||
|
} else if (tex_att_id_ >= 0) {
|
||||||
|
// Texture index not provided but expected. Insert 0 entry as the
|
||||||
|
// default value.
|
||||||
|
out_point_cloud_->attribute(tex_att_id_)
|
||||||
|
->SetPointMapEntry(vert_id, AttributeValueIndex(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indices[2] > 0) {
|
if (indices[2] > 0) {
|
||||||
out_point_cloud_->attribute(norm_att_id_)
|
out_point_cloud_->attribute(norm_att_id_)
|
||||||
->SetPointMapEntry(vert_id, AttributeValueIndex(indices[2] - 1));
|
->SetPointMapEntry(vert_id, AttributeValueIndex(indices[2] - 1));
|
||||||
} else if (indices[2] < 0) {
|
} else if (indices[2] < 0) {
|
||||||
out_point_cloud_->attribute(norm_att_id_)
|
out_point_cloud_->attribute(norm_att_id_)
|
||||||
->SetPointMapEntry(vert_id, AttributeValueIndex(num_normals_ + indices[2]));
|
->SetPointMapEntry(vert_id,
|
||||||
|
AttributeValueIndex(num_normals_ + indices[2]));
|
||||||
|
} else if (norm_att_id_ >= 0) {
|
||||||
|
// Normal index not provided but expected. Insert 0 entry as the default
|
||||||
|
// value.
|
||||||
|
out_point_cloud_->attribute(norm_att_id_)
|
||||||
|
->SetPointMapEntry(vert_id, AttributeValueIndex(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (material_att_id_ >= 0) {
|
if (material_att_id_ >= 0) {
|
||||||
out_point_cloud_->attribute(material_att_id_)
|
out_point_cloud_->attribute(material_att_id_)
|
||||||
->SetPointMapEntry(vert_id, AttributeValueIndex(last_material_id_));
|
->SetPointMapEntry(vert_id, AttributeValueIndex(last_material_id_));
|
||||||
|
@ -48,5 +48,10 @@ TEST_F(ObjDecoderTest, ExtraVertexOBJ) {
|
|||||||
test_decoding(file_name);
|
test_decoding(file_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ObjDecoderTest, ParialAttributesOBJ) {
|
||||||
|
const std::string file_name = "cube_att_partial.obj";
|
||||||
|
test_decoding(file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace draco
|
} // namespace draco
|
||||||
|
@ -95,7 +95,7 @@ bool ObjEncoder::EncodePositions() {
|
|||||||
return false;
|
return false;
|
||||||
buffer()->Encode("v ", 2);
|
buffer()->Encode("v ", 2);
|
||||||
EncodeFloatList(&value[0], 3);
|
EncodeFloatList(&value[0], 3);
|
||||||
buffer()->Encode("\r\n", 2);
|
buffer()->Encode("\n", 1);
|
||||||
}
|
}
|
||||||
pos_att_ = att;
|
pos_att_ = att;
|
||||||
return true;
|
return true;
|
||||||
@ -112,7 +112,7 @@ bool ObjEncoder::EncodeTextureCoordinates() {
|
|||||||
return false;
|
return false;
|
||||||
buffer()->Encode("vt ", 3);
|
buffer()->Encode("vt ", 3);
|
||||||
EncodeFloatList(&value[0], 2);
|
EncodeFloatList(&value[0], 2);
|
||||||
buffer()->Encode("\r\n", 2);
|
buffer()->Encode("\n", 1);
|
||||||
}
|
}
|
||||||
tex_coord_att_ = att;
|
tex_coord_att_ = att;
|
||||||
return true;
|
return true;
|
||||||
@ -129,7 +129,7 @@ bool ObjEncoder::EncodeNormals() {
|
|||||||
return false;
|
return false;
|
||||||
buffer()->Encode("vn ", 3);
|
buffer()->Encode("vn ", 3);
|
||||||
EncodeFloatList(&value[0], 3);
|
EncodeFloatList(&value[0], 3);
|
||||||
buffer()->Encode("\r\n", 2);
|
buffer()->Encode("\n", 1);
|
||||||
}
|
}
|
||||||
normal_att_ = att;
|
normal_att_ = att;
|
||||||
return true;
|
return true;
|
||||||
@ -142,7 +142,7 @@ bool ObjEncoder::EncodeFaces() {
|
|||||||
if (!EncodeFaceCorner(i, j))
|
if (!EncodeFaceCorner(i, j))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
buffer()->Encode("\r\n", 2);
|
buffer()->Encode("\n", 1);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -132,6 +132,11 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) {
|
|||||||
// Decode vertex positions.
|
// Decode vertex positions.
|
||||||
{
|
{
|
||||||
// TODO(ostava): For now assume the position types are float32.
|
// TODO(ostava): For now assume the position types are float32.
|
||||||
|
if (x_prop->data_type() != DT_FLOAT32 ||
|
||||||
|
y_prop->data_type() != DT_FLOAT32 ||
|
||||||
|
z_prop->data_type() != DT_FLOAT32) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
PlyPropertyReader<float> x_reader(x_prop);
|
PlyPropertyReader<float> x_reader(x_prop);
|
||||||
PlyPropertyReader<float> y_reader(y_prop);
|
PlyPropertyReader<float> y_reader(y_prop);
|
||||||
PlyPropertyReader<float> z_reader(z_prop);
|
PlyPropertyReader<float> z_reader(z_prop);
|
||||||
@ -149,6 +154,33 @@ bool PlyDecoder::DecodeVertexData(const PlyElement *vertex_element) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decode normals if present.
|
||||||
|
const PlyProperty *const n_x_prop = vertex_element->GetPropertyByName("nx");
|
||||||
|
const PlyProperty *const n_y_prop = vertex_element->GetPropertyByName("ny");
|
||||||
|
const PlyProperty *const n_z_prop = vertex_element->GetPropertyByName("nz");
|
||||||
|
if (n_x_prop != nullptr && n_y_prop != nullptr && n_z_prop != nullptr) {
|
||||||
|
// For now, all normal properties must be set and of type float32
|
||||||
|
if (n_x_prop->data_type() == DT_FLOAT32 &&
|
||||||
|
n_y_prop->data_type() == DT_FLOAT32 &&
|
||||||
|
n_z_prop->data_type() == DT_FLOAT32) {
|
||||||
|
PlyPropertyReader<float> x_reader(n_x_prop);
|
||||||
|
PlyPropertyReader<float> y_reader(n_y_prop);
|
||||||
|
PlyPropertyReader<float> z_reader(n_z_prop);
|
||||||
|
GeometryAttribute va;
|
||||||
|
va.Init(GeometryAttribute::NORMAL, nullptr, 3, DT_FLOAT32, false,
|
||||||
|
sizeof(float) * 3, 0);
|
||||||
|
const int att_id = out_point_cloud_->AddAttribute(va, true, num_vertices);
|
||||||
|
for (PointIndex::ValueType i = 0; i < num_vertices; ++i) {
|
||||||
|
std::array<float, 3> val;
|
||||||
|
val[0] = x_reader.ReadValue(i);
|
||||||
|
val[1] = y_reader.ReadValue(i);
|
||||||
|
val[2] = z_reader.ReadValue(i);
|
||||||
|
out_point_cloud_->attribute(att_id)->SetAttributeValue(
|
||||||
|
AttributeValueIndex(i), &val[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Decode color data if present.
|
// Decode color data if present.
|
||||||
int num_colors = 0;
|
int num_colors = 0;
|
||||||
const PlyProperty *const r_prop = vertex_element->GetPropertyByName("red");
|
const PlyProperty *const r_prop = vertex_element->GetPropertyByName("red");
|
||||||
|
@ -32,10 +32,13 @@ class PlyDecoderTest : public ::testing::Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void test_decoding_method(const std::string &file_name, int num_faces,
|
void test_decoding_method(const std::string &file_name, int num_faces,
|
||||||
uint32_t num_points) {
|
uint32_t num_points,
|
||||||
const std::unique_ptr<Mesh> mesh(DecodePly<Mesh>(file_name));
|
std::unique_ptr<Mesh> *out_mesh) {
|
||||||
|
std::unique_ptr<Mesh> mesh(DecodePly<Mesh>(file_name));
|
||||||
ASSERT_NE(mesh, nullptr) << "Failed to load test model " << file_name;
|
ASSERT_NE(mesh, nullptr) << "Failed to load test model " << file_name;
|
||||||
ASSERT_EQ(mesh->num_faces(), num_faces);
|
ASSERT_EQ(mesh->num_faces(), num_faces);
|
||||||
|
if (out_mesh)
|
||||||
|
*out_mesh = std::move(mesh);
|
||||||
|
|
||||||
const std::unique_ptr<PointCloud> pc(DecodePly<PointCloud>(file_name));
|
const std::unique_ptr<PointCloud> pc(DecodePly<PointCloud>(file_name));
|
||||||
ASSERT_NE(pc, nullptr) << "Failed to load test model " << file_name;
|
ASSERT_NE(pc, nullptr) << "Failed to load test model " << file_name;
|
||||||
@ -45,7 +48,18 @@ class PlyDecoderTest : public ::testing::Test {
|
|||||||
|
|
||||||
TEST_F(PlyDecoderTest, TestPlyDecoding) {
|
TEST_F(PlyDecoderTest, TestPlyDecoding) {
|
||||||
const std::string file_name = "test_pos_color.ply";
|
const std::string file_name = "test_pos_color.ply";
|
||||||
test_decoding_method(file_name, 224, 114);
|
test_decoding_method(file_name, 224, 114, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(PlyDecoderTest, TestPlyNormals) {
|
||||||
|
const std::string file_name = "cube_att.ply";
|
||||||
|
std::unique_ptr<Mesh> mesh;
|
||||||
|
test_decoding_method(file_name, 12, 3 * 8, &mesh);
|
||||||
|
ASSERT_NE(mesh, nullptr);
|
||||||
|
const int att_id = mesh->GetNamedAttributeId(GeometryAttribute::NORMAL);
|
||||||
|
ASSERT_GE(att_id, 0);
|
||||||
|
const PointAttribute *const att = mesh->attribute(att_id);
|
||||||
|
ASSERT_EQ(att->size(), 6); // 6 unique normal values.
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace draco
|
} // namespace draco
|
||||||
|
@ -75,7 +75,8 @@ THREE.DRACOLoader.prototype = {
|
|||||||
/*
|
/*
|
||||||
* Example on how to retrieve mesh and attributes.
|
* Example on how to retrieve mesh and attributes.
|
||||||
*/
|
*/
|
||||||
let numFaces, numPoints, numVertexCoordinates, numTextureCoordinates, numAttributes;
|
let numFaces, numPoints;
|
||||||
|
let numVertexCoordinates, numTextureCoordinates, numAttributes;
|
||||||
// For output basic geometry information.
|
// For output basic geometry information.
|
||||||
let geometryInfoStr;
|
let geometryInfoStr;
|
||||||
if (geometryType == DracoModule.TRIANGULAR_MESH) {
|
if (geometryType == DracoModule.TRIANGULAR_MESH) {
|
||||||
@ -137,9 +138,11 @@ THREE.DRACOLoader.prototype = {
|
|||||||
let textCoordAttributeData;
|
let textCoordAttributeData;
|
||||||
if (texCoordAttId != -1) {
|
if (texCoordAttId != -1) {
|
||||||
geometryInfoStr += "\nLoaded texture coordinate attribute.\n";
|
geometryInfoStr += "\nLoaded texture coordinate attribute.\n";
|
||||||
const texCoordAttribute = wrapper.GetAttribute(dracoGeometry, texCoordAttId);
|
const texCoordAttribute = wrapper.GetAttribute(dracoGeometry,
|
||||||
|
texCoordAttId);
|
||||||
textCoordAttributeData = new DracoModule.DracoFloat32Array();
|
textCoordAttributeData = new DracoModule.DracoFloat32Array();
|
||||||
wrapper.GetAttributeFloatForAllPoints(dracoGeometry, texCoordAttribute,
|
wrapper.GetAttributeFloatForAllPoints(dracoGeometry,
|
||||||
|
texCoordAttribute,
|
||||||
textCoordAttributeData);
|
textCoordAttributeData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,15 +32,17 @@ PointAttribute::PointAttribute(const GeometryAttribute &att)
|
|||||||
num_unique_entries_(0),
|
num_unique_entries_(0),
|
||||||
identity_mapping_(false) {}
|
identity_mapping_(false) {}
|
||||||
|
|
||||||
void PointAttribute::Reset(size_t num_attribute_values) {
|
bool PointAttribute::Reset(size_t num_attribute_values) {
|
||||||
if (attribute_buffer_ == nullptr) {
|
if (attribute_buffer_ == nullptr) {
|
||||||
attribute_buffer_ = std::unique_ptr<DataBuffer>(new DataBuffer());
|
attribute_buffer_ = std::unique_ptr<DataBuffer>(new DataBuffer());
|
||||||
}
|
}
|
||||||
const int64_t entry_size = DataTypeLength(data_type()) * components_count();
|
const int64_t entry_size = DataTypeLength(data_type()) * components_count();
|
||||||
attribute_buffer_->Update(nullptr, num_attribute_values * entry_size);
|
if (!attribute_buffer_->Update(nullptr, num_attribute_values * entry_size))
|
||||||
|
return false;
|
||||||
// Assign the new buffer to the parent attribute.
|
// Assign the new buffer to the parent attribute.
|
||||||
ResetBuffer(attribute_buffer_.get(), entry_size, 0);
|
ResetBuffer(attribute_buffer_.get(), entry_size, 0);
|
||||||
num_unique_entries_ = num_attribute_values;
|
num_unique_entries_ = num_attribute_values;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValueIndex::ValueType PointAttribute::DeduplicateValues(
|
AttributeValueIndex::ValueType PointAttribute::DeduplicateValues(
|
||||||
|
@ -39,7 +39,7 @@ class PointAttribute : public GeometryAttribute {
|
|||||||
PointAttribute &operator=(PointAttribute &&attribute) = default;
|
PointAttribute &operator=(PointAttribute &&attribute) = default;
|
||||||
|
|
||||||
// Prepares the attribute storage for the specified number of entries.
|
// Prepares the attribute storage for the specified number of entries.
|
||||||
void Reset(size_t num_attribute_values);
|
bool Reset(size_t num_attribute_values);
|
||||||
|
|
||||||
size_t size() const { return num_unique_entries_; }
|
size_t size() const { return num_unique_entries_; }
|
||||||
AttributeValueIndex mapped_index(PointIndex point_index) const {
|
AttributeValueIndex mapped_index(PointIndex point_index) const {
|
||||||
|
50
testdata/cube_att.ply
vendored
Normal file
50
testdata/cube_att.ply
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
ply
|
||||||
|
format ascii 1.0
|
||||||
|
comment VCGLIB generated
|
||||||
|
element vertex 24
|
||||||
|
property float x
|
||||||
|
property float y
|
||||||
|
property float z
|
||||||
|
property float nx
|
||||||
|
property float ny
|
||||||
|
property float nz
|
||||||
|
element face 12
|
||||||
|
property list uchar int vertex_indices
|
||||||
|
property list uchar float texcoord
|
||||||
|
end_header
|
||||||
|
0 0 0 -1 0 0
|
||||||
|
0 0 1 0 0 1
|
||||||
|
0 1 0 0 1 0
|
||||||
|
0 1 1 0 1 0
|
||||||
|
1 0 0 0 -1 0
|
||||||
|
1 0 1 0 -1 0
|
||||||
|
1 1 0 1 0 0
|
||||||
|
1 1 1 1 0 0
|
||||||
|
0 0 0 0 -1 0
|
||||||
|
0 0 0 0 0 -1
|
||||||
|
1 1 0 0 1 0
|
||||||
|
1 1 0 0 0 -1
|
||||||
|
1 0 0 1 0 0
|
||||||
|
1 0 0 0 0 -1
|
||||||
|
0 1 0 -1 0 0
|
||||||
|
0 1 0 0 0 -1
|
||||||
|
0 1 1 0 0 1
|
||||||
|
0 1 1 -1 0 0
|
||||||
|
0 0 1 0 -1 0
|
||||||
|
0 0 1 -1 0 0
|
||||||
|
1 1 1 0 0 1
|
||||||
|
1 1 1 0 1 0
|
||||||
|
1 0 1 0 0 1
|
||||||
|
1 0 1 1 0 0
|
||||||
|
3 9 11 13 6 1 1 0 0 0 1
|
||||||
|
3 9 15 11 6 1 1 1 0 0 0
|
||||||
|
3 0 17 14 6 0 1 1 0 0 0
|
||||||
|
3 0 19 17 6 0 1 1 1 1 0
|
||||||
|
3 2 21 10 6 0 0 1 1 1 0
|
||||||
|
3 2 3 21 6 0 0 0 1 1 1
|
||||||
|
3 12 6 7 6 1 1 1 0 0 0
|
||||||
|
3 12 7 23 6 1 1 0 0 0 1
|
||||||
|
3 8 4 5 6 0 1 1 1 1 0
|
||||||
|
3 8 5 18 6 0 1 1 0 0 0
|
||||||
|
3 1 22 20 6 0 1 1 1 1 0
|
||||||
|
3 1 20 16 6 0 1 1 0 0 0
|
35
testdata/cube_att_partial.obj
vendored
Normal file
35
testdata/cube_att_partial.obj
vendored
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Attributes are only partially specified on the faces.
|
||||||
|
|
||||||
|
v 0.0 0.0 0.0
|
||||||
|
v 0.0 0.0 1.0
|
||||||
|
v 0.0 1.0 0.0
|
||||||
|
v 0.0 1.0 1.0
|
||||||
|
v 1.0 0.0 0.0
|
||||||
|
v 1.0 0.0 1.0
|
||||||
|
v 1.0 1.0 0.0
|
||||||
|
v 1.0 1.0 1.0
|
||||||
|
|
||||||
|
vn 0.0 0.0 1.0
|
||||||
|
vn 0.0 0.0 -1.0
|
||||||
|
vn 0.0 1.0 0.0
|
||||||
|
vn 0.0 -1.0 0.0
|
||||||
|
vn 1.0 0.0 0.0
|
||||||
|
vn -1.0 0.0 0.0
|
||||||
|
|
||||||
|
vt 0.0 0.0
|
||||||
|
vt 0.0 1.0
|
||||||
|
vt 1.0 0.0
|
||||||
|
vt 1.0 1.0
|
||||||
|
|
||||||
|
f 1/4 7/1 5/2
|
||||||
|
f 1/4/2 3/3/2 7/1/2
|
||||||
|
f 1/2 4/3 3/1
|
||||||
|
f 1//6 2//6 4//6
|
||||||
|
f 3/1/3 8/4/3 7/3/3
|
||||||
|
f 3/1/3 4/2/3 8/4/3
|
||||||
|
f 5//5 7//5 8//5
|
||||||
|
f 5/4/5 8/1/5 6/2/5
|
||||||
|
f 1/2/4 5/4/4 6/3/4
|
||||||
|
f 1/2/4 6/3/4 2/1/4
|
||||||
|
f 2 6 8
|
||||||
|
f 2 8 4
|
Loading…
x
Reference in New Issue
Block a user