GLB/GLTF模型文件结构及Cesium加载部分问题
GLB/GLTF 文件结构
1.概述
Gltf 模型:glTF 是一种通用的 3D 模型格式,其本身是一个 JSON 文件,描述了 3D 模型的几何形状、材质和动画等信息。
文件结构: GLTF 文件通常包含一个 JSON 文件,描述模型的结构,以及二进制(或外部)文件,包含实际的二进制数据,如几何信息、纹理等。
扩展: GLTF 支持添加扩展,以支持更高级的功能,例如动画、物理模拟等。
Glb 模型: glb 格式是其 gltf 模型的二进制形式,它把 GLTF 的 JSON 结构和二进制数据打包到一个二进制文件中,通过这种方式,GLB 可以更高效地加载和传输。
特点: GLB 是一个二进制格式,相对于 GLTF 来说,它更紧凑,加载速度更快。
文件结构: GLB 文件包含一个二进制 JSON 块和一个或多个二进制块,其中包含模型的二进制数据。这种结构有助于加快加载速度。
扩展: 与 GLTF 一样,GLB 也支持扩展,允许添加额外的功能。
2.可加载编辑的平台软件
| 软件/网站 | 优点 | 概述 |
|---|---|---|
| Blender | 可编辑、修改模型各种参数 | 参数类型多,可细调模型 |
| 3D 查看器 | Windows 自带,可查看 | 无法编辑,可直接在微软商店免费下载 |
| 模型网 (threejs 提供的编辑器) | 在线编辑,兼容性强 | https://glbxz.com/glbxz/editor/index.html 导出的 GLB 模型为通用类型,会改变一定 Json 结构字段 |
注:Cesium 加载 glb 模型及以上平台均有一定兼容性问题,可能出现一个模型在以上平台出现部分可加载、部分不可加载的现象(血的教训),多试几个说不定就可以了
3. GLB/GLTF 文件 Json 部分剖析
- asset:关于GLTF文件的整体信息。
- version: 表示GLTF版本,通常为字符串 "2.0"。
- generator: 表示生成该GLTF文件的工具或软件。
- accessors(存取器): 包括了用于访问模型数据的描述,如几何顶点的位置、法线、纹理坐标等。
- bufferView: 指定数据的缓冲区视图。
- componentType: 指定每个组件的数据类型(如5126表示浮点数)。
- count: 表示访问器包含的元素数量。
- type: 表示访问器中每个元素的类型。
- max 和 min: 表示元素的最大和最小值。
- buffers(缓冲区): 包括二进制数据,实际存储了模型的几何、纹理和其他信息。
- uri: 包含二进制数据的缓冲区的URI,可以是Base64编码的数据或外部文件的URI。
- byteLength: 缓冲区的字节长度。
- bufferViews(缓冲区视图): 描述了如何从缓冲区中查找数据。每个缓冲区视图关联到一个存取器。
- buffer: 指定数据所在的缓冲区。
- byteOffset: 指定数据在缓冲区中的偏移量。
- byteLength: 指定数据的字节长度。
- target: 指定数据的用途,如34963表示用于ARRAY_BUFFER。
- materials(材质): 包括了用于渲染模型的材质定义,如颜色、纹理等。
- meshes(网格): 描述了模型的几何、材质和其他属性,通常包括了几何和材质的 ID 引用。
- primitives: 包含一个或多个基元,每个基元定义了一个网格表面。
- attributes: 包含网格的各种属性,如位置、法线、纹理坐标等。
- indices: 表示网格的索引。
- material: 表示使用的材质的索引。
- nodes(节点): 用于组织场景中的对象和模型。节点可以包括转换信息、网格引用、材质引用等。
- mesh: 表示节点包含的网格的索引。
- rotation、scale、translation:分别用于指定节点的旋转、缩放和平移信息。
- matrix:表示节点的变换矩阵,通常用于指定节点的平移、旋转和缩放。
- scene(场景): 指定了主要渲染场景中的根节点。这个节点引用了场景中所有对象的节点。
- nodes: 表示场景中的节点数组,每个节点由索引标识。
- skins(皮肤): 用于骨骼动画,包括骨骼、关节和权重信息。
- textures(纹理): 包括了渲染模型时使用的纹理图像的定义。注:Cesium 中,加载模型的 matrix 矩阵可以被修改,但 translation 偏移参数无直接的 API 修改;若有 GLB/GLTF 模型加载后不报错不显示,可以考虑是否为 translation 偏移参数的问题(血的教训),这个参数会影响模型在 Cesium 中加载 Glb 模型;
- 在GLTF(GLB)文件中,节点的变换信息通常由一个4x4的矩阵(matrix)来表示。
- 这个矩阵包含了旋转、缩放和平移的信息。如果同时存在rotation、scale和translation属性,这些属性可以用来构建这个矩阵。Cesium 加载 Glb/Gltf 代码(网上很多)
let origin = Cesium.Cartesian3.fromDegrees(116.755, 23.4702, 100); // 设置位置
let heading = Cesium.Math.toRadians(0); // 相机的方向,默认朝北,表示物体绕垂直轴(通常是地球表面上的北方向)旋转的角度
let pitch = 7.8; // 相机的俯仰角度,默认是朝下,表示物体绕横轴(从左到右的轴)的旋转角度,单位为弧度
let roll = 105.1; // 相机的滚动角度,默认是0,表示物体绕其自身轴的旋转角度,单位为弧度。
let hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
let orientation = Cesium.Transforms.headingPitchRollQuaternion(origin, hpr);
let entity = viewer.entities.add({
position: origin,
// 默认情况下,模型是直立的并面向东。
orientation: orientation,
model: {
show: true,
uri: url, //public路径下存储,本地加载用uri
scale: 3.0, // 缩放比例
minimumPixelSize: 128, // 最小像素大小
maximumScale: 20000, // 模型的最大比例尺大小。 minimumPixelSize的上限
},
});Python 修改 Glb 模型 json 参数(仅作测试,感谢 GPT)
import struct
import json
def read_glb(file_path):
with open(file_path, 'rb') as f:
# 读取文件头部
header = f.read(12)
magic, version, length = struct.unpack('<4sII', header)
# 读取 JSON 部分
json_chunk_header = f.read(8)
json_length, json_type = struct.unpack('<I4s', json_chunk_header)
json_data = f.read(json_length)
json_obj = json.loads(json_data.decode())
# 读取二进制数据部分
binary_chunk_header = f.read(8)
binary_length, binary_type = struct.unpack('<I4s', binary_chunk_header)
binary_data = f.read(binary_length)
return json_obj, binary_data
def modify_translation(json_obj, translation):
# 修改 translation 数据
if 'nodes' in json_obj:
node = json_obj['nodes'][0]
if 'translation' in node:
node['translation'] = translation
def write_glb(json_obj, binary_data, output_file):
# 将修改后的 JSON 数据和二进制数据写入新的 GLB 文件
json_str = json.dumps(json_obj).encode()
json_length = len(json_str)
binary_length = len(binary_data)
with open(output_file, 'wb') as f:
# 写入文件头部
f.write(struct.pack('<4sII', b'glTF', 2, json_length + 20 + binary_length))
# 写入 JSON 部分
f.write(struct.pack('<I4s', json_length, b'JSON'))
f.write(json_str)
# 写入二进制数据部分
f.write(struct.pack('<I4s', binary_length, b'BIN\x00'))
f.write(binary_data)
if __name__ == "__main__":
input_file = './glb/img_0000000001.glb'
output_file = './glb/point_res.glb'
# 读取 GLB 文件
json_obj, binary_data = read_glb(input_file)
# 修改 translation
translation = [0, 0, 0]
modify_translation(json_obj, translation)
# 写入修改后的 GLB 文件
write_glb(json_obj, binary_data, output_file)参考博客
- gltf 模型变换:https://zhuanlan.zhihu.com/p/65266340
- Cesium 矩阵变换:https://blog.csdn.net/debbie_luo1211571826/article/details/130994363
- glTF 教程:https://github.com/KhronosGroup/glTF-Tutorials/tree/master/gltfTutorial
