Draco encode过程代码分析 - 探究其数据编码方式
Introduction
Draco是谷歌在2017年1月发布的一个3D图形开源压缩库,提供了多种算法进行压缩和解压缩。
对于encoder过程,Draco整体思路是将网格的连接信息和几何信息进行分别编码并进行存储。
其中,连接信息使用了edgebreaker等算法进行了编码压缩,几何信息对数据进行量化、预测压缩、熵编码。其中熵编码采用了rANS算法。
不过和原先预想的不同,Draco并未建立一张静态查询表,而是利用算法动态地生成。
本文从encoder入口开始,一层一层分析其代码,试图弄清其数据编码方式。
github源码: https://github.com/google/draco
encoder 过程
encode 过程入口
…/tools/draco_encoder.cc: int main()
int main(int argc, char **argv) {
Options options;
const int argc_check = argc - 1;
for (int i = 1; i < argc; ++i) {
if (!strcmp("-h", argv[i]) || !strcmp("-?", argv[i])) {
Usage();
return 0;
} else if (!strcmp("-i", argv[i]) && i < argc_check) {
options.input = argv[++i];
} else if (!strcmp("-o", argv[i]) && i < argc_check) {
options.output = argv[++i];
} else if (!strcmp("-point_cloud", argv[i])) {
options.is_point_cloud = true;
} else if (!strcmp("-qp", argv[i]) && i < argc_check) {
options.pos_quantization_bits = StringToInt(argv[++i]);
if (options.pos_quantization_bits > 31) {
printf(
"Error: The maximum number of quantization bits for the position "
"attribute is 31.\n");
return -1;
}
} else if (!strcmp("-qt", argv[i]) && i < argc_check) {
options.tex_coords_quantization_bits = StringToInt(argv[++i]);
if (options.tex_coords_quantization_bits > 31) {
printf(
"Error: The maximum number of quantization bits for the texture "
"coordinate attribute is 31.\n");
return -1;
}
} else if (!strcmp("-qn", argv[i]) && i < argc_check) {
options.normals_quantization_bits = StringToInt(argv[++i]);
if (options.normals_quantization_bits > 31) {
printf(
"Error: The maximum number of quantization bits for the normal "
"attribute is 31.\n");
return -1;
}
} else if (!strcmp("-cl", argv[i]) && i < argc_check) {
options.compression_level = StringToInt(argv[++i]);
}
}
if (argc < 3 || options.input.empty()) {
Usage();
return -1;
}
std::unique_ptr<draco::PointCloud> pc;
draco::Mesh *mesh = nullptr;
if (!options.is_point_cloud) {
std::unique_ptr<draco::Mesh> in_mesh =
draco::ReadMeshFromFile(options.input);
if (!in_mesh) {
printf("Failed loading the input mesh.\n");
return -1;
}
mesh = in_mesh.get();
pc = std::move(in_mesh);
} else {
pc = draco::ReadPointCloudFromFile(options.input);
if (!pc) {
printf("Failed loading the input point cloud.\n");
return -1;
}
}
// Setup encoder options.
draco::EncoderOptions encoder_options = draco::CreateDefaultEncoderOptions();
if (options.pos_quantization_bits > 0) {
draco::SetNamedAttributeQuantization(&encoder_options, *pc.get(),
draco::GeometryAttribute::POSITION,
options.pos_quantization_bits);
}
if (options.tex_coords_quantization_bits > 0) {
draco::SetNamedAttributeQuantization(&encoder_options, *pc.get(),
draco::GeometryAttribute::TEX_COORD,
options.tex_coords_quantization_bits);
}
if (options.normals_quantization_bits > 0) {
draco::SetNamedAttributeQuantization(&encoder_options, *pc.get(),
draco::GeometryAttribute::NORMAL,
options.normals_quantization_bits);
}
// Convert compression level to speed (that 0 = slowest, 10 = fastest).
const int speed = 10 - options.compression_level;
draco::SetSpeedOptions(&encoder_options, speed, speed);
if (options.output.empty()) {
// Create a default output file by attaching .drc to the input file name.
options.output = options.input + ".drc";
}
PrintOptions(*pc.get(), options);
int ret = -1;
if (mesh && mesh->num_faces() > 0)
ret = EncodeMeshToFile(*mesh, encoder_options, options.output);
else
ret = EncodePointCloudToFile(*pc.get(), encoder_options, options.output);
if (ret != -1 && options.compression_level < 10) {
printf(
"For better compression, increase the compression level '-cl' (up to "
"10).\n\n");
}
return ret;
}
这一部分前大半都是在处理命令,核心代码就是最后两行:
if (mesh && mesh->num_faces() > 0)
ret = EncodeMeshToFile(*mesh, encoder_options, options.output);
else
ret = EncodePointCloudToFile(*pc.get(), encoder_options, options.output);
这里先做判断,判断数据中是否有多个面:
- 如果有面,则进行Mesh to File的过程
- 若不存在面,则只进行PointCloud to File的过程
其中,两个函数都会一个bool变量,来表示是否成功
>
PointCloud是n维空间中的点的集合,PointCloud的相关信息在 …/point_cloud/point_cloud.h 中,内容较多,暂不贴出
而Mesh是PointCloud的继承类,Mesh只是比PointCloud多了Face数据:
…/mesh/mesh.h
class Mesh : public PointCloud {
public:
typedef std::