一、前言

网上的教程均为搭配opengl使用,如果单纯想读取模型数据,资料就比较少了。先放出相关链接:

1、gltf规范文档:glTF™ 2.0 Specification (khronos.org)

2、gltf在线模型查看器 :glTF Viewer (donmccurdy.com)

3、gltf>tinygltf:GitHub – syoyo/gltf>tinygltf: Header only C++11 tiny glTF 2.0 library

4、vulkan使用gltf>tinygltf官方示例:GitHub – SaschaWillems/Vulkan-glTF-PBR: Physical based rendering with Vulkan using glTF 2.0 models

 二、使用

1、初始化

首先引入头文件:

#define TINYGLTF_IMPLEMENTATION
#include <tiny_gltf.h>

再加载文件,注意glb格式和gltf格式调用的函数不同:

gltf>tinygltf::Model model;
gltf>tinygltf::TinyGLTF loader;
std::string err;
std::string warn;bool load_ok;
if(is_glb)load_ok = loader.LoadBinaryFromFile(&model, &err, &warn, std::string{ path_name });
elseload_ok = loader.LoadASCIIFromFile(&model, &err, &warn, std::string{ path_name });if (!warn.empty()) log_warn("{}", warn);if (!err.empty())log_err("{}", err);if (!load_ok)
{log_err("解析gltf格式失败:{}", err);return {};
}

二、读取材质

其中 mo_material是我们自定义的结构,用于接收读取到的数据。由于之前的光照模型是 Blinn-Phong,而现在更通用的是pbr,以下代码可能不适用你的需求。

之所以我将纹理导出、因为我要进行二次处理,生成自定义的模型格式。你可以不保存到文件,而是直接使用。

通过查看 gltf>tinygltf::PbrMetallicRoughness类型的定义,可以知道提供哪些纹理和材质数据。

//------------------获取材质-------------------
mo_material.resize(model.materials.size());
for (size_t i = 0; i < model.materials.size(); ++i)
{gltf>tinygltf::Material& m = model.materials[i];log_info("材质:{},{}", i, m.name);gltf>tinygltf::PbrMetallicRoughness& pbr = m.pbrMetallicRoughness;ModelObjectMaterial& material = mo_material[i];material._materialName = m.name;material._material._diffuseAlbedo = { (float)pbr.baseColorFactor[0],(float)pbr.baseColorFactor[1],(float)pbr.baseColorFactor[2], 1.0f };material._material._fresnelR0 = { (float)pbr.metallicFactor, (float)pbr.metallicFactor, (float)pbr.metallicFactor };material._material._roughness = (float)pbr.roughnessFactor;// 纹理导出auto fn_texture = [&](int index, std::string_view tag) {if (index == -1)return std::string{};gltf>tinygltf::Image& img = model.images[index];if (!img.uri.empty())return img.uri;std::string path_name = fmt::format("{}{}{}#{}.png",File::PathTemp(), res_name, tag, i);stbi_write_png(CodeCvt::Utf8ToMultiByte(path_name).c_str(),img.width, img.height,4, img.image.data(), 0);return path_name;};material._pathTexDiffuse = fn_texture(pbr.baseColorTexture.index, "");material._pathTexNormal = fn_texture(m.normalTexture.index, "_normal");
}

我的做法是按材质合并网格(不知道会不会影响骨骼动画,后面再说),你也可以简单处理,按 gltf>tinygltf::Primitive为单位为绘制。prim里不直接存数据,而是通过 Accessor访问,然后通过 Accessor取得 BufferView,然后通过 BufferView取得真正的顶点数据。

注意数据首地址为 buf.data.data() + buf_view.byteOffset + accessor.byteOffset,单个顶点偏移为 int byte_stride = accessor.ByteStride(buf_view)。

注意我这里没有过多的 assert的检查,这里的代码还需要尝试更多模型,才能具有可靠性。

		for (gltf>tinygltf::Mesh& mesh : model.meshes){for (gltf>tinygltf::Primitive& prim : mesh.primitives){PrimData& prim_data = map_material[prim.material];size_t vertex_offset = prim_data._allVertex.size();// 索引{gltf>tinygltf::Accessor accessor = model.accessors[prim.indices];gltf>tinygltf::BufferView buf_view = model.bufferViews[accessor.bufferView];gltf>tinygltf::Buffer& buf = model.buffers[buf_view.buffer];int byte_stride = accessor.ByteStride(buf_view);unsigned char* p = buf.data.data() + buf_view.byteOffset + accessor.byteOffset;assert(byte_stride == 4);for (size_t i = 0; i < accessor.count; ++i){uint32_t index = *(uint32_t*)p; prim_data._allIndex.push_back(vertex_offset + index);p += byte_stride;}}// 位置auto iter_pos = prim.attributes.find("POSITION");if(iter_pos != prim.attributes.end()){gltf>tinygltf::Accessor accessor = model.accessors[iter_pos->second];gltf>tinygltf::BufferView buf_view = model.bufferViews[accessor.bufferView];gltf>tinygltf::Buffer& buf = model.buffers[buf_view.buffer];prim_data._allVertex.resize(vertex_offset + accessor.count);int byte_stride = accessor.ByteStride(buf_view);unsigned char* p = buf.data.data() + buf_view.byteOffset + accessor.byteOffset;for (size_t i = 0; i < accessor.count; ++i){Vertex& v = prim_data._allVertex[vertex_offset + i];v._pos = *(Position3*)p;p += byte_stride;}}// uvauto iter_uv = prim.attributes.find("TEXCOORD_0");if (iter_uv != prim.attributes.end()){gltf>tinygltf::Accessor accessor = model.accessors[iter_uv->second];gltf>tinygltf::BufferView buf_view = model.bufferViews[accessor.bufferView];gltf>tinygltf::Buffer& buf = model.buffers[buf_view.buffer];int byte_stride = accessor.ByteStride(buf_view);unsigned char* p = buf.data.data() + buf_view.byteOffset + accessor.byteOffset;for (size_t i = 0; i < accessor.count; ++i){Vertex& v = prim_data._allVertex[vertex_offset + i];v._uv = *(Position2*)p;p += byte_stride;}}// normalauto iter_normal = prim.attributes.find("NORMAL");if (iter_normal != prim.attributes.end()){gltf>tinygltf::Accessor accessor = model.accessors[iter_normal->second];gltf>tinygltf::BufferView buf_view = model.bufferViews[accessor.bufferView];gltf>tinygltf::Buffer& buf = model.buffers[buf_view.buffer];int byte_stride = accessor.ByteStride(buf_view);unsigned char* p = buf.data.data() + buf_view.byteOffset + accessor.byteOffset;for (size_t i = 0; i < accessor.count; ++i){Vertex& v = prim_data._allVertex[vertex_offset + i];v._normal = *(Position3*)p;p += byte_stride;}}// TANGENTauto iter_tangent = prim.attributes.find("TANGENT");if (iter_tangent != prim.attributes.end()){gltf>tinygltf::Accessor accessor = model.accessors[iter_tangent->second];gltf>tinygltf::BufferView buf_view = model.bufferViews[accessor.bufferView];gltf>tinygltf::Buffer& buf = model.buffers[buf_view.buffer];int byte_stride = accessor.ByteStride(buf_view);unsigned char* p = buf.data.data() + buf_view.byteOffset + accessor.byteOffset;for (size_t i = 0; i < accessor.count; ++i){Vertex& v = prim_data._allVertex[vertex_offset + i];v._tangent = *(Position3*)p;p += byte_stride;}}}}

三、截图

这里没有处理骨骼动画和光照,不过对于学习 gltf>tinygltf的基本用法,应该是足够了!

项目地址:dl: C++ drawing library (gitee.com)

 

 

1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,请不要用于商业用途!
3. 如果你也有好源码或者教程,可以到用户中心发布,分享有积分奖励和额外收入!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,默认解压密码为"gltf",如遇到无法解压的请联系管理员!
8. 因为资源和程序源码均为可复制品,所以不支持任何理由的退款兑现,请斟酌后支付下载
声明如果标题没有注明"已测试"或者"测试可用"等字样的资源源码均未经过站长测试.特别注意没有标注的源码不保证任何可用性

GLB下载网(glbxz.com)gltf文件下载-glb格式下载-模型制作 » 【C++】tinygltf基本使用方法

常见问题FAQ

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

提供最优质的资源集合

加入VIP
开通VIP 享更多特权,建议使用 QQ 登录
×