
解析3dTiles数据和提取b3dm模型文件
1.解析json文件

2.解析b3dm模型
(1)b3dm模型文件时二进制文件,其中包含glTF文件:


当使用tiny_gltf库解析glTF时,需要减去(28byte + featuretable的byte + batchTable的byte ):
bool TinyGLTF::ExtractGltfFromMemory(Model *model, std::string *err, std::string *warn, const unsigned char *bytes, unsigned int size, const std::string &base_dir, unsigned int check_sections) { if (size < 28) { if (err) { (*err) = "Too short data size for b3dm Binary."; } return false; } if (bytes[0] == 'b' && bytes[1] == '3' && bytes[2] == 'd' && bytes[3] == 'm') { // ok } else { if (err) { (*err) = "Invalid magic."; } return false; } unsigned int version; // 4 bytes unsigned int byteLength; // 4 bytes unsigned int featureTableJSONByteLength; // 4 bytes unsigned int featureTableBinaryByteLength;// 4 bytes; unsigned int batchTableJSONByteLength; // 4 bytes unsigned int batchTableBinaryByteLength; // 4 bytes; // @todo { Endian swap for big endian machine. } memcpy(&version, bytes + 4, 4); swap4(&version); memcpy(&byteLength, bytes + 8, 4); swap4(&byteLength); memcpy(&featureTableJSONByteLength, bytes + 12, 4); swap4(&featureTableJSONByteLength); memcpy(&featureTableBinaryByteLength, bytes + 16, 4); swap4(&featureTableBinaryByteLength); memcpy(&batchTableJSONByteLength, bytes + 20, 4); swap4(&batchTableJSONByteLength); memcpy(&batchTableBinaryByteLength, bytes + 24, 4); swap4(&batchTableBinaryByteLength); if ((byteLength != size) || (byteLength < 1) ) { if (err) { (*err) = "Invalid b3dm binary."; } return false; } const int byteOffset = 28 + featureTableJSONByteLength + batchTableJSONByteLength; // 解析glTF二进制 bool ret = LoadBinaryFromMemory( model, err, warn, &bytes[byteOffset], byteLength - byteOffset, base_dir, check_sections); if (!ret) { return ret; } return true; }
(2)使用tiny_gltf库只需要3个文件stb_image.h,
stb_image_write.h,
json.hpp和
tiny_gltf.h。
使用时需要注意,在调用#include “tiny_gltf.h”文件中的函数时,需要添加三个宏,如:
// Define these only in *one* .cc file. #define TINYGLTF_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION // #define TINYGLTF_NOEXCEPTION // optional. disable exception handling. #include "tiny_gltf.h" using namespace tinygltf; Model model; TinyGLTF loader; std::string err; std::string warn; bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]); //bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb) if (!warn.empty()) { printf("Warn: %s\n", warn.c_str()); } if (!err.empty()) { printf("Err: %s\n", err.c_str()); } if (!ret) { printf("Failed to parse glTF\n"); return -1; }
3.关于glTF格式详解
{ "scenes" : [ // 只包含了一个场景 { "nodes" : [ 0, 1] } ], "nodes" : [ // 将mesh对象附着到两个不同的node对象,将其渲染了两次 { "mesh" : 0 }, { "mesh" : 0, "translation" : [ 1.0, 0.0, 0.0 ] // 使用translation属性来将mesh对象的渲染位置移动到其它地方 "rotation": [ 0.259, 0.0, 0.0, 0.966 ], // 四元数 "scale": [ 2.0, 1.0, 0.5 ] // x,y和z轴的缩放系数 // 或者只给出一个matrix进行变换 "matrix": [ // 描述了一个缩放(2,1,0.5),绕x轴旋转30度,平移(10,20,30)的matrix属性 2.0, 0.0, 0.0, 0.0, 0.0, 0.866, 0.5, 0.0, 0.0, -0.25, 0.433, 0.0, 10.0, 20.0, 30.0, 1.0 ] } ], "meshes" : [ { "primitives" : [ { "attributes" : { "POSITION" : 1, // 引用了索引为1的accessor对象 "NORMAL" : 2 // "NORMAL"属性引用了索引为2的accessor对象 }, "indices" : 0 } ] } ], "buffers" : [ // 表示了一个没有任何层次结构和意义的二进制数据块 { "uri" : "data:application/octet-stream;base64,AAA为了排版而删除,可以使用英文原文中的代码=", "byteLength" : 80 // 使用了大小为80字节的经过编码的数据URI作为缓冲的数据 } ], "bufferViews" : [ // 一个bufferView对象代表了一个buffer对象的部分数据 { "buffer" : 0, "byteOffset" : 0, "byteLength" : 6, // 引用了索引为0的buffer对象的前6个字节的数据 "target" : 34963 // 表示数据使用方式的常量,ELEMENT_ARRAY_BUFFER }, { "buffer" : 0, "byteOffset" : 8, "byteLength" : 72, // 从偏移值8开始的36个字节的buffer对象的数据 "target" : 34962 // ARRAY_BUFFER } ], "accessors" : [ { // 表示顶点索引数据是unsigned short类型的标量 "bufferView" : 0, // 引用了索引为0的bufferView,这一bufferView对象描述了buffer数据中的顶点索引数据 "byteOffset" : 0, // 指定了accessor所访问数据的开始位置 "componentType" : 5123, // 定义了数据分量的基础类型,5123代表UNSIGNED_SHORT。同short占用2个字节 "count" : 3, // count属性指定了数据元素的数量,对应三角形的3个顶点的索引值 "type" : "SCALAR", "max" : [ 2 ], "min" : [ 0 ] }, { // 这一accessor对象描述了分量类型为float的3D向量数据 "bufferView" : 1, "byteOffset" : 0, // 指定了accessor所访问数据的开始位置 "componentType" : 5126, // 5126代表FLOAT,一个float类型值占4个字节 "count" : 3, // count属性指定了数据元素的数量 "type" : "VEC3", "max" : [ 1.0, 1.0, 0.0 ], // min和max属性定义了3D对象的包围盒 "min" : [ 0.0, 0.0, 0.0 ] }, { "bufferView" : 1, "byteOffset" : 36, "componentType" : 5126, // 5126代表FLOAT "count" : 3, // count属性指定了数据元素的数量 "type" : "VEC3", "max" : [ 0.0, 0.0, 1.0 ], // min和max属性定义了3D对象的包围盒 "min" : [ 0.0, 0.0, 1.0 ] } ], "asset" : { "version" : "2.0" } }
参考资料
1.解析json文件
Reference:
RapidJSON的简单使用示例:
2.解析3dtile-b3dm格式
Reference:
(1)对相关资料做了总结和推荐:

(2)对b3dm二进制结构做了详细的解析:
3dTiles 数据规范详解[4.1] b3dm瓦片二进制数据文件结构 _

(3)官网对Batched3DModel的介绍
3d-tiles/specification/TileFormats/Batched3DModel/

(4)3dtiles官方规范
(5)


(6)3dtiles规范中文版pdf
链接: https://pan.baidu.com/s/1hhbvD_2DXrPCTOs7slsNHA 提取码: ejm7
3.glTF
(1)glTF官方github:
(2)glTF规范:
(3)对glTF格式的详细介绍,教程(glTF官方文档翻译)
(4)博主的github写了一个解析glTF的工具:
(5)解析b3dm模型的库tiny_gltf(项目中用这个库解析)
https://github.com/fanvanzh/3dtiles
(6)tiny_gltf原始项目出处:
(7)glTF模型文件讲解(B站)
【日常 | 学习Vlog | 程序媛乐乐】数字孪生基础 | 三维模型 | What is glTF?
