Google Draco 源码解析

Draco 源码执行过程分析

可结合源码对比查看

(一)、压缩格网信息
position顶点信息 、normal法线信息、TexCoord纹理信息、face 面

声明数组获取数据--》声明draco网格(unique_ptr<draco::Mesh> dracomesh)--》向draco网格添加面

定义面的索引信息--》向draco网格设置面的个数--》声明网格面--》将面的索引信息循环存储到网格面--》根据网格面数据设置draco网格SetFace

定义position顶点数组信息--》计算获取到顶点数--》计算每个顶点的步长--》声明压缩属性并初始化属性--》使用网格的AddAttribute()方法添加网格属性--》声明点属性并赋值为根据属性ID获取的网格属性--》将position顶点数组信息循环存储到网格里

法线、纹理同上

创建压缩encoder--》设置压缩参数--》声明压缩所以后存储的对象EncoderBuffer dracobuffer--》使用encoder压缩中的EncodeMeshToBuffer方法参数为(dracomesh,dracobuffer)。

使用Draco压缩库进行几何编码的高级助手类--》重置创建编码器选项--》编码缓冲--》设置编码后点数--》设置编码后面数

********编码缓冲*******
EncodeToBuffer(EncoderBuffer *out_buffer)方法
判断point_cloud_是否为null为null时提示无效输入几何学。--》判断mesh网格是否为null,为null执行EncodePointCloudToBuffer(*point_cloud_, out_buffer);不为则执行EncodeMeshToBuffer(*mesh_, out_buffer);

注:判断数据中是否有多个面:
如果有面,则进行Mesh to File的过程
若不存在面,则只进行PointCloud to File的过程
两个函数都会返回一个bool变量,来表示是否成功。PointCloud是n维空间中的点的集合,PointCloud的相关信息在 …/point_cloud/point_cloud.h 中,而Mesh是PointCloud的继承类,Mesh只是比PointCloud多了Face数据:
…/mesh/mesh.h

********EncodeMeshToBuffer()*******
定义所有网格编码器的基类--》根据提供的选项选择编码方法 MeshEdgebreakerEncoder()或MeshSequentialEncoder()--》利用encoder->SetMesh(const Mesh &m)来对encoder内部的一些数据进行了初始化(把Mesh和CloudPoint信息在Encoder里也存了一下)
…/compression/mesh/mesh_encoder.cc
void MeshEncoder::SetMesh(const Mesh &m) {
  mesh_ = &m;
  SetPointCloud(m);
}
…/compression/point_cloud/point_cloud_encoder.cc
void PointCloudEncoder::SetPointCloud(const PointCloud &pc) {
  point_cloud_ = &pc;
}
因为Mesh是PointCloud的继承,所以可以直接把Mesh数据传进SetPointCloud函数。
--》Encode(const EncoderOptions &options,EncoderBuffer *out_buffer)--》设置编码后点数--》设置编码后面数

********Encode()*******
 options_ = &options; (赋值编码选项) buffer_ = out_buffer;(这个缓冲区保存最终编码的数据。)--》清除以前运行的内存属性--》判断point_cloud_是否为null返回无效输入几何学。--》执行EncodeHeader、EncodeMetadata、InitializeEncoder、具体对EncodeEncoderData、EncodeGeometryData、EncodePointAttributes进行了编码

EncoderHeader()将encoder的一些基本信息写入buffer,以便今后decode
这些信息包括:”DRACO”字符串标识、major version、minor version、encoder type(point cloud, mesh, …)、selected encoding method (edgebreaker, etc…)、保留标识
然后用encoder->Encode根据option对数据进行编码,写入buffer

InitializeEncoder()功能是:可以由派生类实现,以执行编码器的任何自定义初始化。在Encode()方法中调用。

EncodeEncoderData()功能是:应该用于编码任何特定于编码器的数据。
不过这两个都是预留接口,设置了虚函数但没有实现,直接返回true

EncoderGeometryData()会把mesh 的 connectivity进行编码并存入buffer,根据encoder的不同,编码connectivity的方式会分为sequential encoding 和 edgebreaker encoding。

EncodePointAttributes()功能是对顶点坐标等信息压缩编码,关于每个属性的点特定数据。一般情况下,存储在点云中的多个点可以共享相同的属性值,这个类提供了点id和属性值id之间必要的映射。

********EncodePointAttributes()********

GenerateAttributesEncoders()生成属性器--》Encode()对属性编码器的数量进行编码。--》初始化所有编码器--》RearrangeAttributesEncoders()重新排列属性--》EncodeAttributesEncoderIdentifier()对创建相应的属性解码器所需的任何数据进行编码。--》EncodeAttributesEncoderData()还要编码任何属性编码器数据(例如关于已编码属性的信息)。---》EncodeAllAttributes() 最后,使用提供的属性编码器对所有属性进行编码。

********EncodeAllAttributes()********
EncodeAttributes() 将属性数据编码到目标缓冲区。

********EncodeAttributes()********
TransformAttributesToPortableFormat() 将输入属性数据转换为应进行无损编码的形式(转换本身可能是有损的)。--》
EncodePortableAttributes(out_buffer) 编码可移动属性 --》
EncodeDataNeededByPortableTransforms(out_buffer) 在对属性进行编码后,对可移植转换所需的数据进行编码。这对应于数据将被解码器解码的顺序。

********EncodePortableAttributes(out_buffer)********
EncodeValues()方法 输入值的无损编码

   ********EncodeValues()********
初始化一般量化数据--》预案的方法--》预测计划--》便携式属性数据--》encoded_data 保存我们储存的可移动数据--》预测计划--》设置符号编码压缩级别--》编码符号--》编码预测数据

初始化一般量化数据--》……--》EncodeSymbols()

   ********EncodeSymbols() 编码符号********

 ComputeBitLengths 计算比特长度--》tagged_scheme_total_bits 标记方案总位数(使用标记模式存储符号所需的大约位数。)--》raw_scheme_total_bits 原始方案总位数(  使用原始方案存储符号所需的大约比特数。)--》max_value_bit_length最大位长(可以使用原始方案编码的单个条目值的最大位长。)--》比较 标记方案总位数和原始方案总位数的大小(根据总位数大小选择熵编码方法)或者 比较最大位长与kMaxRawEncodingBitLength(固定值18)的大小--》当标记方案总位数小于原始方案总位数的大小或者最大位长大于k最大原始编码位长度的大小时使用EncodeTaggedSymbols()熵编码方法 ,否则使用EncodeRawSymbols()熵编码方法

********EncodeTaggedSymbols() 熵编码********
frequencies带标记位长频率--》将每个条目的频率设置为零。--》根据输入数据计算频率。--》创建一个额外的缓冲区来存储原始值。--》开始编码位标记。--》还可以开始对值进行编码。--》判断是否需要反向编码 (for循环索引不同)--》EndEncoding()结束编码位标记。--》EndBitEncoding()结束对值进行编码--》将值附加到目标缓冲区的末尾。

********EncodeRawSymbols() 熵编码********
symbol_bits符号位默认为0--》如果num_unique_symbols值大于0则符号位获取MostSignificantBit()最重要位--》计算unique_symbols_bit_length唯一符号位长判断如果大于k最大原始编码位长度则返回False(不支持超过2^18个唯一符号的编码。)--》获取压缩级别取默认值7--》若options选项不为空且设置了符号编码压缩级则取设置的符号编码压缩级--》比较compression_level压缩级别修改unique_symbols_bit_length唯一符号位长--》将unique_symbols_bit_length设置为一个有效的范围。--》EncodeRawSymbolsInternal()根据最大符号位长度使用适当的符号编码器。

    ********EncodeRawSymbolsInternal() 符号编码器********
frequencies 计算每个条目值的频率。--》创建符号编码器--》开始编码--》编码所有值 判断是否反向编码(for循环索引不同)--》结束编码

*********TransformAttributeToPortableFormat()********

TransformAttributeToPortableFormat()将属性转换为可移植格式

********EncodeDataNeededByPortableTransforms(out_buffer)********


(二)、压缩点信息
position顶点信息 、normal法线信息、color颜色信息、noise噪声信息

定义position 、normal、color、noise vector数组数据--》声明定义dracoPointCloud点云--》设置要压缩的点数--》获取顶点数、组件数、每个顶点的步长--》创建压缩属性并初始化--》将压缩属性对象、点数添加到dracoPointCloud点云中--》根据添加到点云返回的ID获取添加的属性对象--》将顶点数据添加到压缩属性att中--》定义压缩对象--》设置压缩参数--》设置压缩方法--》EncodePointCloudToBuffer()压缩点法线颜色噪声

*********EncodePointCloudToBuffer()*********
使用Draco压缩库进行几何编码的高级助手类--》重置创建编码器选项--》EncodeToBuffer()编码缓冲--》EncodePointCloudToBuffer() 编码--》encoder定义点云编码的基类--》获取编码方法--》设置编码器--》利用encoder->SetPointCloud(pc)来对encoder内部的一些数据进行了初始化(把CloudPoint信息在Encoder存一下)--》Encode()编码

*********Encode()*********
options_ = &options; (赋值编码选项) buffer_ = out_buffer;(这个缓冲区保存最终编码的数据。)--》清除以前运行的内存属性--》判断point_cloud_是否为null返回无效输入几何学。--》执行EncodeHeader、EncodeMetadata、InitializeEncoder、具体对EncodeEncoderData、EncodeGeometryData、EncodePointAttributes进行了编码

EncoderHeader()将encoder的一些基本信息写入buffer,以便今后decode
这些信息包括:”DRACO”字符串标识、major version、minor version、encoder type(point cloud, mesh, …)、selected encoding method (edgebreaker, etc…)、保留标识
然后用encoder->Encode根据option对数据进行编码,写入buffer

InitializeEncoder()功能是:可以由派生类实现,以执行编码器的任何自定义初始化。在Encode()方法中调用。

EncodeEncoderData()功能是:应该用于编码任何特定于编码器的数据。
不过这两个都是预留接口,设置了虚函数但没有实现,直接返回true

EncoderGeometryData()会把mesh 的 connectivity进行编码并存入buffer,根据encoder的不同,编码connectivity的方式会分为sequential encoding 和 edgebreaker encoding。

EncodePointAttributes()功能是对顶点坐标等信息压缩编码,关于每个属性的点特定数据。一般情况下,存储在点云中的多个点可以共享相同的属性值,这个类提供了点id和属性值id之间必要的映射。

********EncodePointAttributes()********

GenerateAttributesEncoders()生成属性器--》Encode()对属性编码器的数量进行编码。--》初始化所有编码器--》RearrangeAttributesEncoders()重新排列属性--》EncodeAttributesEncoderIdentifier()对创建相应的属性解码器所需的任何数据进行编码。--》EncodeAttributesEncoderData()还要编码任何属性编码器数据(例如关于已编码属性的信息)。---》EncodeAllAttributes() 最后,使用提供的属性编码器对所有属性进行编码。

********EncodeAllAttributes()********
EncodeAttributes() 将属性数据编码到目标缓冲区。

********EncodeAttributes()********
TransformAttributesToPortableFormat() 将输入属性数据转换为应进行无损编码的形式(转换本身可能是有损的)。--》
EncodePortableAttributes(out_buffer) 编码可移动属性 --》
EncodeDataNeededByPortableTransforms(out_buffer) 在对属性进行编码后,对可移植转换所需的数据进行编码。这对应于数据将被解码器解码的顺序。

*********EncodePortableAttributes(out_buffer) *********
使用kd树编码算法对数据进行编码,将compression_level的最大值限制为6,因为目前没有这样做为更高的压缩级别提供可行的算法。--》获取压缩级别--》创建编码--》获取点数、组件数--》创建点向量--》复制数据到点向量--》复制源属性到矢量--》计算kd树编码所需的最大比特长度。--》根据压缩等级使用对应动态整数点Kd树编码器--》执行点解码--》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落魄的佩奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值