SLPK bin file unpacked with draco
SLPK bin file unpacked with draco
0.bin
SLPK
Binary 0.bin
The geometry file storage format used earlier, without draco
compression.
- 4 bytes represent the number of vertices
- vertex data
- Normal data
- texture data
- color data
- FeatureId
- FaceRange
Parsing code:
ifstream fin;
fin.open("0.bin", ios::binary);
if (!fin)
{
cout << "open error!" << endl;
return;
}
int vertexCount[1 * 1];
fin.read((char*)vertexCount, sizeof(int) * (1 * 1));//从bin中读取顶点索引数量
for (int i = 0; i < vertexCount[0]; i++)
{
float Position[1 * 3];
fin.read((char*)Position, sizeof(float) * (1 * 3));
}
for (int i = 0; i < vertexCount[0]; i++)
{
float_t Normal[1 * 3];
fin.read((char*)Normal, sizeof(float_t) * (1 * 3));
}
for (int i = 0; i < vertexCount[0]; i++)
{
float_t Uv0[1 * 2];
fin.read((char*)Uv0, sizeof(float_t) * (1 * 2));
}
for (size_t i = 0; i < vertexCount[0]; i++)
{
uint8_t Color_x[1 * 4];
fin.read((char*)Color_x, sizeof(uint8_t) * (1 * 4));
}
uint64_t FeatureId[1 * 1];
fin.read((char*)FeatureId, sizeof(uint64_t) * (1 * 1));
uint32_t FaceRange_start[1 * 1];
fin.read((char*)FaceRange_start, sizeof(uint32_t) * (1 * 1));
uint32_t FaceRange_end[1 * 1];
fin.read((char*)FaceRange_end, sizeof(uint32_t) * (1 * 1));
fin.close();
Example:
1.bin
SLPK
Binary 1.bin
The geometry file storage format currently used, using draco
compression processing.
Just use the drao library to decompress it.
draco decompression example
char* decodeBuffer(char* indata, int insize, int* outsize) {
if (indata == nullptr || insize <= 0) {
*outsize = 0;
return nullptr;
}
std::string dracoGeometry(indata, insize);
draco::DecoderBuffer buffer;
buffer.Init(dracoGeometry.data(), dracoGeometry.size());
std::unique_ptr<draco::PointCloud> pc;
draco::Mesh* mesh;
auto type_statusor = draco::Decoder::GetEncodedGeometryType(&buffer);
if (!type_statusor.ok()) {
*outsize = 0;
return nullptr;
}
const draco::EncodedGeometryType geom_type = type_statusor.value();
if (geom_type == draco::TRIANGULAR_MESH) {
draco::Decoder decoder;
auto statusor = decoder.DecodeMeshFromBuffer(&buffer);
if (!statusor.ok()) {
*outsize = 0;
return nullptr;
}
std::unique_ptr<draco::Mesh> in_mesh = std::move(statusor).value();
if (in_mesh) {
mesh = in_mesh.get();
pc = std::move(in_mesh);
}
}
int realPointNum = mesh->num_points();
int realFaceNum = mesh->num_faces();
std::vector< int32_t> fids;
//std::cout << "Point Num:" << realPointNum << std::endl;
//std::cout << "Face Num:" << realFaceNum << std::endl;
bool use_normal = false, use_uv = false, use_color = false, use_feature_id = false, use_uvregion = false;
std::ostringstream outStr;
outStr.write(reinterpret_cast<char*>(&realPointNum), sizeof(realPointNum));
outStr.write(reinterpret_cast<char*>(&realFaceNum), sizeof(realFaceNum));
const draco::PointAttribute* position_att =
mesh->GetNamedAttribute(draco::GeometryAttribute::POSITION);
const draco::PointAttribute* normal_att =
mesh->GetNamedAttribute(draco::GeometryAttribute::NORMAL);
if (normal_att != nullptr) {
use_normal = true;
}
outStr.write(reinterpret_cast<char*>(&use_normal), sizeof(use_normal));
//UV
const draco::PointAttribute* uv_att =
mesh->GetNamedAttribute(draco::GeometryAttribute::TEX_COORD);
if (uv_att != nullptr) {
use_uv = true;
}
outStr.write(reinterpret_cast<char*>(&use_uv), sizeof(use_uv));
//Color
const draco::PointAttribute* clr_att =
mesh->GetNamedAttribute(draco::GeometryAttribute::COLOR);
if (clr_att != nullptr) {
use_color = true;
}
outStr.write(reinterpret_cast<char*>(&use_color), sizeof(use_color));
int fid_id = mesh->GetAttributeIdByMetadataEntry("i3s-attribute-type", "feature-index");
const draco::PointAttribute* generic_att = mesh->GetAttributeByUniqueId(fid_id);
if (generic_att && (generic_att->num_components() != 1 || generic_att->attribute_type() != draco::GeometryAttribute::Type::GENERIC))
{
generic_att = nullptr;
}
if (generic_att != nullptr) {
use_feature_id = true;
}
outStr.write(reinterpret_cast<char*>(&use_feature_id), sizeof(use_feature_id));
int region_id = mesh->GetAttributeIdByMetadataEntry("i3s-attribute-type", "uv-region");
const draco::PointAttribute* region_att = mesh->GetAttributeByUniqueId(region_id);
if (region_att && (region_att->num_components() != 4 || region_att->attribute_type() != draco::GeometryAttribute::Type::GENERIC))
{
region_att = nullptr;
}
if (region_att != nullptr) {
use_uvregion = true;
}
outStr.write(reinterpret_cast<char*>(&use_uvregion), sizeof(use_uvregion));
double i3sScaleX = 1.0, i3sScaleY = 1.0;
if (position_att != nullptr) {
//std::cout << "vertex count:" << realPointNum << std::endl
auto pos_att = mesh->GetAttributeMetadataByAttributeId(mesh->GetNamedAttributeId(draco::GeometryAttribute::POSITION));
if (pos_att)
{
pos_att->GetEntryDouble("i3s-scale_x", &i3sScaleX);
pos_att->GetEntryDouble("i3s-scale_y", &i3sScaleY);
}
std::array<float, 3>value;
float x, y, z;
for (draco::PointIndex i = draco::PointIndex(0); i < draco::PointIndex(realPointNum); ++i) {
bool ret = position_att->ConvertValue(position_att->mapped_index(i), 3, &value[0]);
if (!ret) {
*outsize = 0;
return nullptr;
}
else {
x = value[0]*i3sScaleX;
y = value[1]*i3sScaleY;
z = value[2];
outStr.write(reinterpret_cast<char*>(&x), sizeof(float));
outStr.write(reinterpret_cast<char*>(&y), sizeof(float));
outStr.write(reinterpret_cast<char*>(&z), sizeof(float));
//std::cout << i << ":" <<x<<"," << y<<"," << z << std::endl;
}
}
}
else {
*outsize = 0;
return nullptr;
}
if (use_normal) {
std::array<float, 3> value;
for (draco::PointIndex i = draco::PointIndex(0); i < draco::PointIndex(realPointNum); ++i)
{
bool ret = normal_att->ConvertValue(normal_att->mapped_index(i), 3, &value[0]);
if (!ret) {
value = {
0 };
outStr.write(reinterpret_cast<char*>(&value[0]), sizeof(float));
outStr.write(reinterpret_cast<char*>(&value[1]), sizeof(float));
outStr.write(reinterpret_cast<char*>(&value[2]), sizeof(float));
}
else {
outStr.write(reinterpret_cast<char*>(&value[0]), sizeof(float));
outStr.write(reinterpret_cast<char*>(&value[1]), sizeof(float));
outStr.write(reinterpret_cast<char*>(&value[2]), sizeof(float));
}
}
}
if (use_uv) {
std::array<float, 2> value;
for (draco::PointIndex i = draco::PointIndex(0); i < draco::PointIndex(realPointNum); ++i)
{
bool ret = uv_att->ConvertValue(uv_att->mapped_index(i), 2, &value[0]);
if (!ret) {
value = {
0 };
outStr.write(reinterpret_cast<char*>(&value[0]), sizeof(float));
outStr.write(reinterpret_cast<char*>(&value[1]), sizeof(float));
}
else {
outStr.write(reinterpret_cast<char*>(&value[0]), sizeof(float));
outStr.write(reinterpret_cast<char*>(&value[1]), sizeof(float));
}
}
}
if (use_color) {
std::array<uint8_t, 4>value;
for (draco::PointIndex i = draco::PointIndex(0); i < draco::PointIndex(realPointNum); ++i)
{
bool ret = clr_att->ConvertValue(clr_att->mapped_index(i), 4, &value[0]);
if (!ret) {
value = {
0 };
outStr.write(reinterpret_cast<char*>(&value[0]), sizeof(uint8_t));
outStr.write(reinterpret_cast<char*>(&value[1]), sizeof(uint8_t));
outStr.write(reinterpret_cast<char*>(&value[2]), sizeof(uint8_t));
outStr.write(reinterpret_cast<char*>(&value[3]), sizeof(uint8_t));
}
else {
outStr.write(reinterpret_cast<char*>(&value[0]), sizeof(uint8_t));
outStr.write(reinterpret_cast<char*>(&value[1]), sizeof(uint8_t));
outStr.write(reinterpret_cast<char*>(&value[2]), sizeof(uint8_t));
outStr.write(reinterpret_cast<char*>(&value[3]), sizeof(uint8_t));
}
}
}
//fid
if (use_feature_id) {
auto att_dmeta = mesh->GetMetadata()->GetAttributeMetadataByUniqueId(generic_att->unique_id());
if (!generic_att || !att_dmeta->GetEntryIntArray("i3s-feature-ids", &fids))
{
}
std::array<uint64_t, 1>value;
for (draco::PointIndex i = draco::PointIndex(0); i < draco::PointIndex(realPointNum); ++i)
{
bool ret = generic_att->ConvertValue(generic_att->mapped_index(i), 1, &value[0]);
if (!ret) {
value = {
0 };
outStr.write(reinterpret_cast<char*>(&value[0]), sizeof(uint64_t));
}
else {
outStr.write(reinterpret_cast<char*>(&value[0]), sizeof(uint64_t));
//std::cout << i << ":" << value[0] << std::endl;
}
}
}
//UVRegion
if (use_uvregion) {
std::array<uint16_t, 4> value;
for (draco::PointIndex i = draco::PointIndex(0); i < draco::PointIndex(realPointNum); ++i)
{
bool ret = region_att->ConvertValue(region_att->mapped_index(i), 4, &value[0]);
if (!ret) {
value = {
0 };
outStr.write(reinterpret_cast<char*>(&value[0]), sizeof(uint16_t));
outStr.write(reinterpret_cast<char*>(&value[1]), sizeof(uint16_t));
outStr.write(reinterpret_cast<char*>(&value[2]), sizeof(uint16_t));
outStr.write(reinterpret_cast<char*>(&value[3]), sizeof(uint16_t));
}
else {
outStr.write(reinterpret_cast<char*>(&value[0]), sizeof(uint16_t));
outStr.write(reinterpret_cast<char*>(&value[1]), sizeof(uint16_t));
outStr.write(reinterpret_cast<char*>(&value[2]), sizeof(uint16_t));
outStr.write(reinterpret_cast<char*>(&value[3]), sizeof(uint16_t));
}
}
}
//index
uint32_t numFaces = mesh->num_faces();
uint32_t numIndices = numFaces * 3;
std::vector<int64_t> my_Indicese;
my_Indicese.resize(numIndices);
for (draco::FaceIndex i(0); i < numFaces; ++i) {
const draco::Mesh::Face& face = mesh->face(i);
int64_t indexV = i.value();
my_Indicese[indexV * 3] = face[0].value();
my_Indicese[indexV * 3 + 1] = face[1].value();
my_Indicese[indexV * 3 + 2] = face[2].value();
}
for (uint32_t i = 0; i < numIndices; ++i) {
outStr.write(reinterpret_cast<char*>(&my_Indicese[i]), sizeof(uint32_t));
}
if (use_feature_id) {
int32_t fc = fids.size();
outStr.write(reinterpret_cast<char*>(&fc), sizeof(int32_t));
for (size_t i = 0; i<fids.size(); i++) {
outStr.write(reinterpret_cast<char*>(&fids[i]), sizeof(int32_t));
}
}
outStr.write(reinterpret_cast<char*>(&i3sScaleX), sizeof(double));
outStr.write(reinterpret_cast<char*>(&i3sScaleY), sizeof(double));
*outsize = outStr.str().size();
char* outdata = new char[*outsize];
memcpy(outdata, outStr.str().data(), *outsize);
return outdata;
}
draco compression example
Compress 3D geometry data draco
.
char* encodeBuffer(char* indata, int insize, int* outsize,bool isGeo, bool hasregion) {
std::string GeometryStr(indata,insize);
std::istringstream inStr(GeometryStr,std::ios::binary);
int realPointNum = 0;
int realFaceNum = 0;
inStr.read(reinterpret_cast<char*>(&realPointNum), sizeof(realPointNum));
inStr.read(reinterpret_cast<char*>(&realFaceNum), sizeof(realFaceNum));
bool use_normal = false, use_uv = false, use_color = false, use_feature_id = false, use_uvregion = false;
inStr.read(reinterpret_cast<char*>(&use_normal), sizeof(use_normal));
inStr.read(reinterpret_cast<char*>(&use_uv), sizeof(use_uv));
inStr.read(reinterpret_cast<char*>(&use_color), sizeof(use_color));
inStr.read(reinterpret_cast<char*>(&use_feature_id), sizeof(use_feature_id));
inStr.read(reinterpret_cast<char*>(&use_uvregion), sizeof(use_uvregion));
std::vector<Point>Points;
Points.resize(realPointNum,{
0.0f});
for (int i = 0; i < realPointNum; i++) {
inStr.read(reinterpret_cast<char*>(&Points[i][0]), sizeof(float));
inStr.read(reinterpret_cast<char*>(&Points[i][1]), sizeof(float));
inStr.read(reinterpret_cast<char*>(&Points[i][2]), sizeof(float));
}
std::vector<Normal>Normals;
if (use_normal) {
Normals.resize(realPointNum, {
0.0f });
for (int i = 0; i < realPointNum; ++i) {
//normal
inStr.read(reinterpret_cast<char*>(&Normals[i][0]), sizeof(float));
inStr.read(reinterpret_cast<char*>(&Normals[i][1]), sizeof(float));
inStr.read(reinterpret_cast<char*>(&Normals[i][2]), sizeof(float));
}
}
std::vector<UV0>UV0s;
if (use_uv) {
UV0s.resize(realPointNum, {
0.0f });
for (int i = 0; i < realPointNum; ++i) {
//uv0
inStr.read(reinterpret_cast<char*>(&UV0s[i][0]), sizeof(float));
inStr.read(reinterpret_cast<char*>(&UV0s[i][1]), sizeof(float));
}
}
std::vector<Color>Colors;
if (use_color) {
Colors.resize(realPointNum, {
0 });
for (int i = 0; i < realPointNum; ++i) {
//colors
inStr.read(reinterpret_cast<char*>(&Colors[i][0]), sizeof(uint8_t));
inStr.read(reinterpret_cast<char*>(&Colors[i][1]), sizeof(uint8_t));
inStr.read(reinterpret_cast<char*>(&Colors[i][2]), sizeof(uint8_t));
inStr.read(reinterpret_cast<char*>(&Colors[i][3]), sizeof(uint8_t));
}
}
std::vector<FeatureId>FeatureIds;
if (use_feature_id) {
FeatureIds.resize(realPointNum, {
0 });
for (int i = 0; i < realPointNum; ++i) {
inStr.read(reinterpret_cast<char*>(&FeatureIds[i][0]), sizeof(uint64_t));
//std::cout << i << ":" << FeatureIds[i][0] << std::endl;
}
}
std::vector<UVRegion>UVRegions;
if (use_uvregion) {
UVRegions.resize(realPointNum, {
0 });
for (int i = 0; i < realPointNum; ++i) {
inStr.read(reinterpret_cast<char*>(&UVRegions[i][0]), sizeof(uint16_t));
inStr.read(reinterpret_cast<char*>(&UVRegions[i][1]), sizeof(uint16_t));
inStr.read(reinterpret_cast<char*>(&UVRegions[i][2]), sizeof(uint16_t));
inStr.read(reinterpret_cast<char*>(&UVRegions[i][3]), sizeof(uint16_t));
}
}
std::vector<Index>Indices;
Indices.resize(realFaceNum * 3, {
0 });
for (uint32_t i = 0; i < realFaceNum * 3; ++i) {
inStr.read(reinterpret_cast<char*>(&Indices[i][0]), sizeof(uint32_t));
}
std::vector< int32_t> fids;
if (use_feature_id) {
int32_t fc = 0;
inStr.read(reinterpret_cast<char*>(&fc), sizeof(int32_t));
fids.resize(fc);
for (int32_t i = 0; i < fc; i++) {
inStr.read(reinterpret_cast<char*>(&fids[i]), sizeof(int32_t));
}
}
double i3sScaleX = 1.0, i3sScaleY = 1.0;
inStr.read(reinterpret_cast<char*>(&i3sScaleX), sizeof(double));
inStr.read(reinterpret_cast<char*>(&i3sScaleY), sizeof(double));
//draco encoder
//std::unique_ptr<draco::Mesh> pMesh(new draco::Mesh());
std::unique_ptr<draco::Mesh> pMesh_osg(new draco::Mesh());
draco::Mesh* pMesh = pMesh_osg.get();
uint64_t lVertNum = realPointNum;
if (lVertNum == 0) {
*outsize = 0;
return nullptr;
}
pMesh->set_num_points(lVertNum);
//position
draco::GeometryAttribute pos_att;
pos_att.Init(draco::GeometryAttribute::POSITION, nullptr, 3, draco::DT_FLOAT32, false,
sizeof(float) * 3, 0);
draco::PointAttribute pPointAttribute(pos_att);
pPointAttribute.SetIdentityMapping();
pPointAttribute.Reset(lVertNum);
//normal
draco::GeometryAttribute norm_att;
norm_att.Init(draco::GeometryAttribute::NORMAL, nullptr, 3, draco::DT_FLOAT32,
false, sizeof(float) * 3, 0);
draco::PointAttribute pNormalAttribute(norm_att);
pNormalAttribute.SetIdentityMapping();
pNormalAttribute.Reset(lVertNum);
//uv
draco::GeometryAttribute tex_coord_att;
tex_coord_att.Init(draco::GeometryAttribute::TEX_COORD, nullptr, 2, draco::DT_FLOAT32,
false, sizeof(float) * 2, 0);
draco::PointAttribute pTexCoordAtt(tex_coord_att);
pTexCoordAtt.SetIdentityMapping();
pTexCoordAtt.Reset(lVertNum);
//color
draco::GeometryAttribute color_att;
color_att.Init(draco::GeometryAttribute::COLOR, nullptr, 4, draco::DT_UINT8,
false, sizeof(uint8_t) * 4, 0);
draco::PointAttribute pColoratt(color_att);
pColoratt.SetIdentityMapping();
pColoratt.Reset(lVertNum);
//FId
draco::GeometryAttribute gen_att;
gen_att.Init(draco::GeometryAttribute::GENERIC, nullptr, 1, draco::DT_UINT32,
false, sizeof(uint32_t) * 1, 0);
draco::PointAttribute pfeature_index_att(gen_att);
pfeature_index_att.SetIdentityMapping();
pfeature_index_att.Reset(lVertNum);
//UVRegion
draco::GeometryAttribute uv_regions;
uv_regions.Init(draco::GeometryAttribute::GENERIC, nullptr, 4, draco::DT_UINT16,
false, sizeof(uint16_t) * 4, 0);
draco::PointAttribute puv_regions_att(uv_regions);
puv_regions_att.SetIdentityMapping();
puv_regions_att.Reset(lVertNum);
float pts[3];
for (uint64_t i = 0; i < lVertNum; i++)
{
pts[0] = Points[i][0]/i3sScaleX;
pts[1] = Points[i][1]/i3sScaleY;
pts[2] = Points[i][2];
//std::cout << i << ":" << pts[0] << "," << pts[1] << "," << pts[2] << std::endl;
pPointAttribute.SetAttributeValue(draco::AttributeValueIndex(i), &pts[0]);
}
const int pos_att_id_ = pMesh->AddAttribute(pPointAttribute, true, 0);
std::unique_ptr<draco::AttributeMetadata> i3s_scale_metadata =
std::unique_ptr<draco::AttributeMetadata>(new draco::AttributeMetadata());
i3s_scale_metadata->AddEntryDouble("i3s-scale_x", i3sScaleX);
i3s_scale_metadata->AddEntryDouble("i3s-scale_y", i3sScaleY);
pMesh->AddAttributeMetadata(pos_att_id_, std::move(i3s_scale_metadata));
int normal_att_id;
if (use_normal) {
for (uint64_t i = 0; i < lVertNum; i++)
{
pNormalAttribute.SetAttributeValue(draco::AttributeValueIndex(i), &Normals[i][0]);
}
normal_att_id= pMesh->AddAttribute(pNormalAttribute, true, 0);
}
//color
int color_att_id;
if (use_color) {
for (uint64_t i = 0; i < lVertNum; ++i) {
pColoratt.SetAttributeValue(draco::AttributeValueIndex(i), &Colors[i][0]);
}
color_att_id = pMesh->AddAttribute(pColoratt, true, 0);
}
//uv
int tex_att_id;
if (use_uv) {
for (uint64_t i = 0; i < lVertNum; i++)
{
pTexCoordAtt.SetAttributeValue(draco::AttributeValueIndex(i), &UV0s[i][0]);
}
tex_att_id = pMesh->AddAttribute(pTexCoordAtt, true, 0);
}
//fid
int feature_index_att_id;
if (use_feature_id) {
uint64_t fi = 0;
for (uint64_t i = 0; i < lVertNum; i++)
{
fi = FeatureIds[i][0];
pfeature_index_att.SetAttributeValue(draco::AttributeValueIndex(i), &fi);
//std::cout << i << ":" << fi << std::endl;
}
feature_index_att_id = pMesh->AddAttribute(pfeature_index_att, true, 0);
std::unique_ptr<draco::AttributeMetadata> fid_meta(new draco::AttributeMetadata());
fid_meta->set_att_unique_id(feature_index_att_id);
fid_meta->AddEntryIntArray("i3s-feature-ids", fids);
fid_meta->AddEntryString("i3s-attribute-type", "feature-index");
pMesh->AddAttributeMetadata(feature_index_att_id, std::move(fid_meta));
}
//uv-region
int uv_regions_att_id;
if (use_uvregion) {
for (uint64_t i = 0; i < lVertNum; i++)
{
puv_regions_att.SetAttributeValue(draco::AttributeValueIndex(i), &UVRegions[i][0]);
}
uv_regions_att_id = pMesh->AddAttribute(puv_regions_att, true, 0);
std::unique_ptr<draco::AttributeMetadata> region_meta(new draco::AttributeMetadata());
region_meta->set_att_unique_id(uv_regions_att_id);
region_meta->AddEntryString("i3s-attribute-type", "uv-region");
pMesh->AddAttributeMetadata(uv_regions_att_id, std::move(region_meta));
}
//idx
for (uint32_t ic = 0; ic * 3 < Indices.size(); ic++)
{
uint32_t iIndex0 = Indices[ic * 3][0];
uint32_t iIndex1 = Indices[ic * 3 + 1][0];
uint32_t iIndex2 = Indices[ic * 3 + 2][0];
draco::Mesh::Face face;
face[0] = iIndex0;
face[1] = iIndex1;
face[2] = iIndex2;
pMesh->AddFace(face);
}
int compression_level =7;//7
const int speed = 10 - compression_level;
draco::Encoder encoder;
encoder.SetAttributeQuantization(draco::GeometryAttribute::POSITION,
14);//14
encoder.SetAttributeQuantization(draco::GeometryAttribute::NORMAL,
10);//10
encoder.SetAttributeQuantization(draco::GeometryAttribute::TEX_COORD,
12);//12
encoder.SetAttributeQuantization(draco::GeometryAttribute::COLOR,
8);//10
encoder.SetAttributeQuantization(draco::GeometryAttribute::GENERIC,
6);//8
encoder.SetSpeedOptions(speed, speed);
draco::EncoderBuffer buffer;
try
{
draco::CycleTimer timer;
timer.Start();
const draco::Status status = encoder.EncodeMeshToBuffer(*pMesh, &buffer);
if (!status.ok()) {
printf("Failed to encode the mesh.\n");
printf("%s\n", status.error_msg());
*outsize = 0;
return nullptr;
}
/*if (indata != nullptr) {
delete[]indata;
indata = nullptr;
}*/
timer.Stop();
}
catch (const std::exception& e)
{
std::cout << "dracoGeo exception:"<<e.what() <<std::endl;
*outsize = 0;
return nullptr;
}
*outsize = buffer.size();
char* outdata = new char[*outsize];
memcpy(outdata, buffer.data(), *outsize);
return outdata;
}