ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Draco 顺序法线属性解码器(SequentialNormalAttributeDecoder)解析:八面体量化法线从比特流到单位向量的完整还原

Draco 顺序法线属性解码器(SequentialNormalAttributeDecoder)解析:八面体量化法线从比特流到单位向量的完整还原 图形学3D渲染【免费下载链接】dracoDraco is a library for compressing and decompressing 3D geometric meshes and point clouds. It is intended to improve the storage and transmission of 3D graphics.项目地址https://gitcode.com/gh_mirrors/draco1/draco点击查看免费下载导读本文基于 Draco 官方规范文档 docs/spec/sequential.normal.attribute.decoder.md 展开围绕SequentialNormalAttributeDecoder这一核心解码器系统讲解 Draco 如何在顺序解码流程中把编码端量化为八面体坐标octahedral coordinates的法线数据还原为可用于渲染的 float32 单位法向量。读完本文你将掌握法线为何要被投影为 2 维八面体坐标、量化位宽如何从比特流中恢复、MostSignificantBit/OctahedralCoordsToUnitVector/QuantizedOctahedralCoordsToUnitVector三个关键算法的逐行语义以及解码器类在源码中的实际调用链与限制条件。一、背景为什么法线要编码成八面体坐标法线向量是 3D 网格中最常见的逐点属性之一通常以 3 个 float32 分量表示约 12 字节/顶点。直接压缩原始 float 数据效率不高Draco 的常规做法是先做属性变换attribute transform把 3 分量单位向量降维为 2 个量化整数再进行后续的预测与熵编码。Draco 采用的正是八面体编码方案。源码 src/draco/compression/attributes/normal_compression_utils.h 的注释给出了权威说明该方案源自 Cigolle et al.14《A Survey of Efficient Representations for Independent Unit Vectors》其核心思想是把一个内切于单位球的正八面体展开unwrap到 2D 平面法线方向由八面体表面上的一个点定义右半球x 0的点直接投影到 x 0 平面形成菱形diamond区域左半球的点则将三角形向外翻转后再投影最终把所有取值平移到非负区间得到一个可量化的 2D 坐标对(s, t)。因此每个单位法向量在编码端只需保存两个整数(s, t)这正是规范文档中TransformAttributesToOriginalFormat_Normal里“每个点读两个量化值、写出三个 float 分量”的原因。从源码结构看编码端的对应实现位于 src/draco/compression/attributes/sequential_normal_attribute_encoder.cc它通过AttributeOctahedronTransform的TransformAttribute把原始法线批量转换为 portable attribute可移植属性。二、解码器总览类结构与适用前提SequentialNormalAttributeDecoder继承自SequentialIntegerAttributeDecoder定义于 src/draco/compression/attributes/sequential_normal_attribute_decoder.h。它与编码器SequentialNormalAttributeEncoder见 sequential_normal_attribute_encoder.cc一一对应适用于顺序sequential属性解码模式下的法线属性。从 sequential_normal_attribute_decoder.cc 的Init实现可以看出它的硬性适用前提不满足则解码失败分量数必须为 3num_components() ! 3直接返回 false数据类型必须是DT_FLOAT32法线最终以 float 输出必须启用DRACO_NORMAL_ENCODING_SUPPORTED宏——在 sequential_attribute_decoders_controller.cc 中只有当该特性开启时SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALS才会被映射到SequentialNormalAttributeDecoder实例。类还重写了GetNumValueComponents()返回值固定为2其注释直白地写道We quantize everything into two componentssequential_normal_attribute_decoder.h——即解码器预期的“整数值”就是每个点的(s, t)量化坐标对。解码流程的三个阶段SequentialNormalAttributeDecoder重写了父类的三个虚方法共同构成完整解码链路阶段方法职责1. 解码整数DecodeIntegerValues从缓冲区解码量化后的(s, t)整数序列2. 解码变换参数DecodeDataNeededByPortableTransform读取八面体变换的量化位宽参数并挂载到 portable attribute3. 还原原始值StoreValues调用InverseTransformAttribute把量化坐标还原为 float 单位向量源码 sequential_normal_attribute_decoder.cc 中阶段 2 有一个值得注意的版本分支当比特流版本≥ 2.0时变换参数在DecodeDataNeededByPortableTransform中从流里解码而当启用DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED且版本 2.0时参数改在DecodeIntegerValues阶段提前解码旧比特流在该阶段还没有 portable attribute但八面体变换恰好不需要读取属性数据。三、核心算法一MostSignificantBit()规范文档给出的伪代码非常简短int MostSignificantBit(n) { msb -1; while (n ! 0) { msb; n 1; } return msb; }它的语义是返回整数n的最高有效位MSB所在位索引。当n 0时返回-1否则每次右移一位、计数加一直到n变为 0。在法线解码场景中它被QuantizedOctahedralCoordsToUnitVector用来从编码端写入的encoded_max_quantized_value反推量化位宽quantization_bits_ MostSignificantBit(encoded_max_quantized_value) 1; max_quantized_value_ (1 quantization_bits_) - 1;即quantization_bits_ floor(log2(encoded_max_quantized_value)) 1。例如当编码端用 10 bit 量化时encoded_max_quantized_value 1023MostSignificantBit(1023) 9加 1 得到10。这与 normal_compression_utils.h 中SetQuantizationBits的一致性要求完全吻合max_quantized_value_ (1 q) - 1q bit 可表示的最大值必为奇数。四、核心算法二OctahedralCoordsToUnitVector()这是整个法线还原的数学核心。规范文档给出的是浮点域版本输入为已缩放dequantized到[0, 1]区间的in_s、in_t。逐段语义如下构造spt s t与smt s - t用于判断点落在八面体展开平面的哪个区域右半球判断当spt ∈ [0.5, 1.5]且smt ∈ [-0.5, 0.5]时点位于中央菱形内直接沿用原坐标对应x 0左半球翻转否则x_sign -1.0并按spt/smt落在四个象限的具体情况把(s, t)沿最近的菱形对角线镜像mirror回中央区域。源码 normal_compression_utils.h 的OctahedralCoordsToUnitVector私有实现用更紧凑的方式表达了同一逻辑先计算x 1 - |y| - |z|再通过x_offset对y、z做镜像坐标映射y 2*s - 1z 2*t - 1x由菱形约束关系Min(2*spt - 1, 3 - 2*spt, 2*smt 1, 1 - 2*smt)乘上符号得到从而把平面点映射回三维八面体表面归一化计算normSquared x² y² z²。若小于1e-6退化情况理论上仅当所有分量为 0 时出现输出零向量否则以d 1/sqrt(normSquared)缩放得到单位向量。这与 normal_compression_utils.h 中的处理完全一致。伪代码中的Min(...)展开形式与源码实现数学等价两者都利用“菱形内点到两条对角线距离”构造 x 分量。五、核心算法三QuantizedOctahedralCoordsToUnitVector()这一层把整数量化坐标直接转换为单位向量是规范文档中TransformAttributesToOriginalFormat_Normal实际调用的入口。伪代码流程encoded_max_quantized_value pred_trasnform_normal_max_q_val[curr_att_dec][curr_att]; quantization_bits_ MostSignificantBit(encoded_max_quantized_value) 1; max_quantized_value_ (1 quantization_bits_) - 1; max_value_ max_quantized_value_ - 1; scale 1.0 / max_value_; OctahedralCoordsToUnitVector(in_s * scale, in_t * scale, out_vector);关键点在于max_value_ max_quantized_value_ - 1而非max_quantized_value_。源码注释解释了原因normal_compression_utils.h参数空间具有周期性(0, 0) (max_value, max_value)因此菱形必须比 q bit 可表示的最大值小 1以保持取值区间为奇数长度、保证坐标空间无歧义缩放系数为1/max_value_把整数坐标映射到[0, 1]浮点区间随后交给上一节的浮点还原算法。在真实实现中该逻辑封装于OctahedronToolBox::QuantizedOctahedralCoordsToUnitVectornormal_compression_utils.h实现为OctahedralCoordsToUnitVector(in_s * dequantization_scale_ - 1.f, in_t * dequantization_scale_ - 1.f, out_vector);其中dequantization_scale_ 2.0 / max_value_由SetQuantizationBits计算。对比规范伪代码可以看出两者等价in * (2/max_value) - 1 in * (1/max_value) * 2 - 1即先缩放到[0,1]再映射到[-1,1]——这正是规范版把y 2s - 1、z 2t - 1内嵌进算法的原因。此外SetQuantizationBits还限定了量化位宽合法范围为2 ≤ q ≤ 30超出即返回 falsenormal_compression_utils.h。六、核心算法四TransformAttributesToOriginalFormat_Normal()这是整个解码过程的收尾函数规范伪代码展示了它如何逐点把 portable attribute 中的量化整数还原成法线数组void TransformAttributesToOriginalFormat_Normal() { quant_val_id 0; portable_attribute_data seq_int_att_dec_original_values[curr_att_dec][curr_att]; num_points att_dec_num_values_to_decode[curr_att_dec][curr_att]; for (i 0; i num_points; i) { s portable_attribute_data[quant_val_id]; t portable_attribute_data[quant_val_id]; QuantizedOctahedralCoordsToUnitVector(s, t, att_val); for (j 0; j 3; j) { normals.push_back(att_val[j]); } } seq_int_att_dec_dequantized_values[curr_att_dec][curr_att] normals; }其要点每个点消费恰好两个整数(s, t)与GetNumValueComponents() 2呼应产出三个 float 分量逐点调用QuantizedOctahedralCoordsToUnitVector最终结果写入“去量化值”数组交由上层作为法线属性输出。在真实源码中这一阶段由StoreValues触发调用链为StoreValues → octahedral_transform_.InverseTransformAttribute(portable, attribute)sequential_normal_attribute_decoder.cc。AttributeOctahedronTransform::InverseTransformAttributeattribute_octahedron_transform.cc先校验目标属性为DT_FLOAT32且 3 分量再以OctahedronToolBox逐点完成同样的转换并memcpy写入目标缓冲区——与规范伪代码一一对应。七、量化参数的编解码与版本兼容量化位宽quantization bits是法线解码唯一需要的外部参数其编解码实现于 src/draco/attributes/attribute_octahedron_transform.cc编码端EncodeParameters把quantization_bits_以uint8_t写入缓冲区attribute_octahedron_transform.cc 对应行编码器在 sequential_normal_attribute_encoder.cc 中通过EncodeDataNeededByPortableTransform调用它解码端DecodeParameters从流中读回一个uint8_t作为位宽attribute_octahedron_transform.cc随后TransferToAttribute把参数写入 portable attribute 的AttributeTransformData供后续InverseTransformAttribute通过InitFromAttribute读取attribute_octahedron_transform.cc。版本兼容要点依据 sequential_normal_attribute_decoder.cc比特流版本≥ 2.0DecodeParameters在DecodeDataNeededByPortableTransform阶段调用需要 portable attribute 已就绪比特流版本 2.0需编译DRACO_BACKWARDS_COMPATIBILITY_SUPPORTED参数解码提前到DecodeIntegerValues此时尚未有 portable attribute因此传入的是原始属性——八面体变换不读取属性数据故仍能正确工作。量化位宽还决定了预测变换的选择。在 sequential_normal_attribute_decoder.h 的CreateIntPredictionScheme中解码器按变换类型选择预测方案PREDICTION_TRANSFORM_NORMAL_OCTAHEDRON旧版需向后兼容宏→PredictionSchemeNormalOctahedronDecodingTransformint32_tPREDICTION_TRANSFORM_NORMAL_OCTAHEDRON_CANONICALIZED现行默认→PredictionSchemeNormalOctahedronCanonicalizedDecodingTransformint32_t。两类预测方案都需要在预测阶段之后把 correction 值映射回标准量化域因此OctahedronToolBox还提供了ModMax、MakePositive等辅助函数normal_compression_utils.h保证预测残差在量化坐标系内的环绕取模正确性。八、解码器在整体架构中的位置SequentialNormalAttributeDecoder只是 Draco 顺序属性解码家族的一员它与兄弟解码器的分工可通过工厂方法SequentialAttributeDecodersController::CreateSequentialDecodersequential_attribute_decoders_controller.cc看清decoder_type对应解码器用途SEQUENTIAL_ATTRIBUTE_ENCODER_GENERICSequentialAttributeDecoder通用属性无变换SEQUENTIAL_ATTRIBUTE_ENCODER_INTEGERSequentialIntegerAttributeDecoder整数属性SEQUENTIAL_ATTRIBUTE_ENCODER_QUANTIZATIONSequentialQuantizationAttributeDecoder通用量化属性SEQUENTIAL_ATTRIBUTE_ENCODER_NORMALSSequentialNormalAttributeDecoder法线八面体量化属性受DRACO_NORMAL_ENCODING_SUPPORTED宏保护在解码主流程中控制器会先对每个属性解码整数portable值再调用TransformAttributeToOriginalFormatsequential_attribute_decoders_controller.cc对法线属性而言最终会走到上述StoreValues → InverseTransformAttribute的还原路径。此外控制器还支持通过解码选项skip_attribute_transformsequential_attribute_decoders_controller.cc跳过逆变换此时输出的是尚未还原的 portable 量化坐标这为需要原始量化数据的下游应用留出了接口。九、配套源码阅读指引想深入理解本主题的读者建议按以下顺序阅读仓库内相关文件规范文档docs/spec/sequential.normal.attribute.decoder.md本文依据解码器实现src/draco/compression/attributes/sequential_normal_attribute_decoder.cc、sequential_normal_attribute_decoder.h编码器对称实现src/draco/compression/attributes/sequential_normal_attribute_encoder.cc八面体变换与工具箱src/draco/attributes/attribute_octahedron_transform.cc、normal_compression_utils.h解码器注册与调度src/draco/compression/attributes/sequential_attribute_decoders_controller.cc规范中的整体顺序解码流程docs/spec/sequential.decoder.md、docs/spec/sequential.integer.attribute.decoder.md需要说明的是本主题描述的是 Draco 内部核心压缩算法的实现细节适用于希望阅读、移植或调试 Draco 法线编解码逻辑的开发者实际使用时普通用户通过官方工具如 src/draco/tools/draco_encoder.cc 与 src/draco/tools/draco_decoder.cc即可透明完成含法线在内的属性压缩与解压无需直接接触本解码器。赞分享图形学3D渲染【免费下载链接】dracoDraco is a library for compressing and decompressing 3D geometric meshes and point clouds. It is intended to improve the storage and transmission of 3D graphics.项目地址https://gitcode.com/gh_mirrors/draco1/draco点击查看免费下载相关推荐ty 如何根据 requires-python 确定目标 Python 版本手动指定 python-version 需要注意什么ty 如何根据 requires python 确定目标 Python 版本手动指定 python version 需要注意什么 ty 是一个用 Rust图形学3D渲染革命性Blender插件管理器深度解析2000插件一键掌控的终极解决方案革命性Blender插件管理器深度解析2000插件一键掌控的终极解决方案 Blender插件管理器是一款开源免费的强大工具专为简化Blender插件管理流图形学3D渲染pyiCloud完全指南如何用Python轻松管理你的iPhone和iCloud数据pyiCloud完全指南如何用Python轻松管理你的iPhone和iCloud数据 pyiCloud是一个强大的Python库让开发者和普通用户能够轻松与后端CLI上一篇免费解锁Wand专业版零成本享受完整游戏修改体验下一篇Cursor Free VIP破解工具3步解决Cursor AI试用限制永久免费使用Pro功能创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表