• 正文概述
  • glTF介绍
    DCC生成的模型往往不能直接被渲染引擎使用,比如包含冗余数据、缺失场景数据、缺少动画状态机、压缩率不足等。许多引擎拥有一个Asset Pipeline,负责将不同DCC导出的各类数据转化为引擎可以直接使用的资源文件,比如UE的Cooking操作
    glTF是一种表示3D场景的模型格式,它的目标就是尽可能保留3D场景相关的数据(使用json描述场景),为渲染引擎提供无需解码的模型数据(使用二进制存储buffer和image)
    文本类型
    glTF有二进制(.glb)和ASCII文本格式(.gltf)
    一般而言,文本格式的glTF并不包含二进制内容(buffer和image),而是仅有一个uri链接,指向真正存储这些二进制数据的文件,这些数据已经被处理成GPU便于访问的格式
    “buffer01”: { “byteLength”: 12352, “type”: “arraybuffer”, “uri”: “buffer01.bin” }
    “image01”: { “uri”: “image01.png” }
    正是因为glTF这种描述和存储分离的特点,我们可以用很小的文件就能得到场景的描述,当我们需要使用到某个buffer或image时再懒加载这个资源,于是很适合Web项目。现在很多基于WebGL的渲染器都使用glTF格式
    值得注意的是,对于一些小模型,我们也可以将这些二进制嵌入到json中
    “buffers” : [ { “uri” : “data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=”, “byteLength” : 44 } ],
    json结构
     
    glTF/GLB格式入门

    添加图片注释,不超过 140 字(可选)
     
    scene
    scene是解析一个glTF的入口,一个glTF可以包含多个scene
    一个scene中会有一个nodes,nodes是一个数组,指向多个node
    一个node中会有mesh等元素
    mesh
    一个meshes包含多个primitives(图元),每个图元中有一个attributes(属性)和indices
    attributes中包含着模型的顶点数据(vertices),比如POSITION、NORMAL、TEXCOORD_0
    “meshes” : [ { “primitives” : [ { “attributes” : { “POSITION” : 1 }, “indices” : 0 } ] } ],
    accessor
    accessor(访问器),这是对资源的一种抽象封装,它存储了bufferView的结构,以及访问方法
    对于mesh、skin、animation等数据,我们要通过accessor来访问。accessor中有一个bufferView,bufferView又指向存储真正二进制数据的buffer
    “accessors” : [ { “bufferView” : 0, “byteOffset” : 0, “componentType” : 5123, “count” : 3, “type” : “SCALAR”, “max” : [ 2 ], “min” : [ 0 ] }, { “bufferView” : 1, “byteOffset” : 0, “componentType” : 5126, “count” : 3, “type” : “VEC3”, “max” : [ 1.0, 1.0, 0.0 ], “min” : [ 0.0, 0.0, 0.0 ] } ],
    buffer
    A buffer defines a block of raw, unstructured data with no inherent meaning
    为了便于渲染API的使用,glTF里的buffer是单纯的二进制,因此在解析时一定要明确读取的步长、类型
    bufferView
    A bufferView describes a “chunk” or a “slice” of the whole, raw buffer data
    bufferView将一个完整的巨大的二进制内容切割为一个个小片,可以实现一个buffer存储多种类型的数据,还可以实现字节对齐等功能
    一个简单的读mesh示例
    这里我使用tinygltf库来加载glTF,这是一个基于cmake的纯头文件库
    举一个简单的glTF读取mesh的例子,仅读取index buffer和vertex buffer(只有POSITION和TEXCOORD_0)
    class GltfLoader { public: GltfLoader(std::string model_path); ~GltfLoader(); std::vector<Index> loaded_index_buffer; std::vector<Vertex> loaded_vertex_buffer; private: tinygltf::Model m_gltf_model; tinygltf::TinyGLTF m_loader_context; };
    GltfLoader::GltfLoader(std::string model_path) { std::string gltf_load_error; std::string gltf_load_warning; bool gltf_load_result = m_loader_context.LoadASCIIFromFile(&m_gltf_model, &gltf_load_error, &gltf_load_warning, model_path); if (gltf_load_result) { // load mesh for (auto& mesh : m_gltf_model.meshes) { for (auto& primitive : mesh.primitives) { // vertex int vertex_count = 0; std::vector<Vertex> local_vertex_buffer; // position if (primitive.attributes.find(“POSITION”) != primitive.attributes.end()) { const int accessor_index = primitive.attributes.at(“POSITION”); const tinygltf::Accessor& accessor = m_gltf_model.accessors[accessor_index]; const tinygltf::BufferView& buffer_view = m_gltf_model.bufferViews[accessor.bufferView]; const tinygltf::Buffer& buffer = m_gltf_model.buffers[buffer_view.buffer]; const float* data_ptr = reinterpret_cast<const float*>(&buffer.data[buffer_view.byteOffset + accessor.byteOffset]); const int position_byte_stride = 3; vertex_count = accessor.count; for (int i = 0; i < vertex_count; i++) { Vertex local_vertex; local_vertex.pos = glm::vec3(data_ptr[i * position_byte_stride], data_ptr[i * position_byte_stride + 1], data_ptr[i * position_byte_stride + 2]); local_vertex_buffer.push_back(local_vertex); } } // uv if (primitive.attributes.find(“TEXCOORD_0”) != primitive.attributes.end()) { const int accessor_index = primitive.attributes.at(“TEXCOORD_0”); const tinygltf::Accessor& accessor = m_gltf_model.accessors[accessor_index]; const tinygltf::BufferView& buffer_view = m_gltf_model.bufferViews[accessor.bufferView]; const tinygltf::Buffer& buffer = m_gltf_model.buffers[buffer_view.buffer]; const float* data_ptr = reinterpret_cast<const float*>(&buffer.data[buffer_view.byteOffset + accessor.byteOffset]); const int uv_byte_stride = accessor.ByteStride(buffer_view) ? (accessor.ByteStride(buffer_view) / sizeof(float)) : tinygltf::GetNumComponentsInType(TINYGLTF_TYPE_VEC2); for (int i = 0; i < vertex_count; i++) { local_vertex_buffer[i].texture_coord = glm::vec2(data_ptr[i * uv_byte_stride], data_ptr[i * uv_byte_stride + 1]); } } // append local vertex buffer to loaded vertex buffer for (int i = 0; i < vertex_count; i++) { loaded_vertex_buffer.push_back(local_vertex_buffer[i]); } // index if (primitive.indices >= 0) { const tinygltf::Accessor& accessor = m_gltf_model.accessors[primitive.indices]; const tinygltf::BufferView& buffer_view = m_gltf_model.bufferViews[accessor.bufferView]; const tinygltf::Buffer& buffer = m_gltf_model.buffers[buffer_view.buffer]; const void* dataPtr = &(buffer.data[buffer_view.byteOffset + accessor.byteOffset]); const int elements_count = accessor.count; // MARK: the component type is very important, common is TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT switch (accessor.componentType) { case TINYGLTF_PARAMETER_TYPE_UNSIGNED_INT: { const uint32_t* buf = static_cast<const uint32_t*>(dataPtr); for (int i = 0; i < elements_count; i++) { Index local_index; local_index.index = buf[i]; loaded_index_buffer.push_back(local_index); } break; } case TINYGLTF_PARAMETER_TYPE_UNSIGNED_SHORT: { const uint16_t* buf = static_cast<const uint16_t*>(dataPtr); for (int i = 0; i < elements_count; i++) { Index local_index; local_index.index = buf[i]; loaded_index_buffer.push_back(local_index); } break; } case TINYGLTF_PARAMETER_TYPE_UNSIGNED_BYTE: { const uint8_t* buf = static_cast<const uint8_t*>(dataPtr); for (int i = 0; i < elements_count; i++) { Index local_index; local_index.index = buf[i]; loaded_index_buffer.push_back(local_index); } break; } default: std::cerr << “Index component type ” << accessor.componentType << ” not supported!” << std::endl; return; } } } } // TODO: load children // TODO: load transform, material, texture, skin, skeleton, animtion, blendshape } }
    1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
    2. 分享目的仅供大家学习和交流,请不要用于商业用途!
    3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入!
    4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
    5. 如有链接无法下载、失效或广告,请联系管理员处理!
    6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
    7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员!
    8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载
    声明如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性

    GLB下载网 - GLB/GLTF模型与格式资源免费下载,支持在线浏览与转换 » glTF/GLB格式入门

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载要提取码
    百度网盘提取码都是gltf。
    分享过期和重复下载怎么办
    分享过期请使用备份下载,重复下载是不另扣费的,请放心下载。
    模型和平台不兼容怎么办
    可以用网站在线编辑功能,修改模型属性,大小,方向,坐标,中心,透明等问题,然后重新导出既可https://glbxz.com/38636.html
    开通VIP 享更多特权,建议使用 QQ 登录