20 void MeshLoaderGltf::loadMesh(
const std::filesystem::path &filePath, std::vector<Vertex> &vertices, std::vector<uint32_t> &indices,
21 std::vector<std::unique_ptr<TextureLoadData>>& textureLoadData) {
22 tinygltf::Model model;
23 tinygltf::TinyGLTF loader;
25 if (filePath.generic_string().length() == 0) {
26 throw std::runtime_error(std::string(
"missing file path to mesh with filepath: ") + filePath.generic_string());
29 if (!exists(filePath)) {
30 throw::std::runtime_error(std::string(
"Path does not exist! ") + filePath.generic_string() + std::string(
" from this directory: ") + std::filesystem::current_path().generic_string());
34 model =
getModel(filePath, model, loader);
37 std::unordered_map<int, int> textureMap;
39 for (
auto& mesh : model.meshes) {
40 PLOGI <<
"Loading " << mesh.primitives.size() <<
"primitives";
41 for (
auto& primitive : mesh.primitives) {
42 if (primitive.mode != TINYGLTF_MODE_TRIANGLES) {
43 PLOGE <<
"Non-Triangles found! Skipping!";
47 for (
auto attribute : primitive.attributes) {
48 PLOGI << attribute.first;
52 auto positionIterator = primitive.attributes.find(
"POSITION");
53 if (positionIterator == primitive.attributes.end()) {
54 PLOGE <<
"POSITION attribute not found! Skipping primitive.";
58 const tinygltf::Accessor& positionAccessor = model.accessors[positionIterator->second];
59 const tinygltf::BufferView& positionView = model.bufferViews[positionAccessor.bufferView];
60 const tinygltf::Buffer& positionBuffer = model.buffers[positionView.buffer];
61 const float* positions =
reinterpret_cast<const float*
>(&(positionBuffer.data[positionView.byteOffset + positionAccessor.byteOffset]));
64 auto normalIterator = primitive.attributes.find(
"NORMAL");
65 if (normalIterator == primitive.attributes.end()) {
66 PLOGE <<
"NORMAL attribute not found! Skipping primitive.";
70 const tinygltf::Accessor& normalAccessor = model.accessors[normalIterator->second];
71 const tinygltf::BufferView& normalView = model.bufferViews[normalAccessor.bufferView];
72 const tinygltf::Buffer& normalBuffer = model.buffers[normalView.buffer];
73 const float* normals =
reinterpret_cast<const float*
>(&(normalBuffer.data[normalView.byteOffset + normalAccessor.byteOffset]));
76 auto textureCoordinateIterator = primitive.attributes.find(
"TEXCOORD_0");
77 if (textureCoordinateIterator == primitive.attributes.end()) {
78 PLOGE <<
"TEXCOORD_0 attribute not found! Skipping primitive.";
82 const tinygltf::Accessor& textureCoordinateAccessor = model.accessors[textureCoordinateIterator->second];
83 const tinygltf::BufferView& textureCoordinateView = model.bufferViews[textureCoordinateAccessor.bufferView];
84 const tinygltf::Buffer& textureCoordinateBuffer = model.buffers[textureCoordinateView.buffer];
85 const float* textureCoordinates =
reinterpret_cast<const float*
>(&(textureCoordinateBuffer.data[textureCoordinateView.byteOffset + textureCoordinateAccessor.byteOffset]));
88 if (primitive.material >= 0 && primitive.material < model.materials.size()){
89 const tinygltf::Material& material = model.materials[primitive.material];
92 if (material.pbrMetallicRoughness.baseColorTexture.index >= 0 &&
93 material.pbrMetallicRoughness.baseColorTexture.index < model.textures.size()
96 int textureIndex = material.pbrMetallicRoughness.baseColorTexture.index;
98 const tinygltf::Texture& texture = model.textures[textureIndex];
99 if (texture.source < 0 || texture.source >= model.images.size()) {
100 PLOGE <<
"Invalid textureData source index: " << texture.source;
104 const tinygltf::Image& img = model.images[texture.source];
106 if (img.image.empty()) {
107 PLOGE <<
"Image data is empty for textureData: " << filePath.generic_string();
111 std::unique_ptr<TextureLoadData> textureData = std::make_unique<TextureLoadData>(img.image, img.width, img.height, img.component);
112 PLOGI <<
"Loaded textureData: " << filePath.generic_string() <<
" (" << textureData->width <<
"x" << textureData->height <<
")";
115 textureLoadData.push_back(std::move(textureData));
116 textureMap[textureIndex] = textureLoadData.size() - 1;
130 const tinygltf::Accessor& indicesAccessor = model.accessors[primitive.indices];
131 const tinygltf::BufferView& indicesView = model.bufferViews[indicesAccessor.bufferView];
132 const tinygltf::Buffer& indicesBuffer = model.buffers[indicesView.buffer];
133 const void* indicesPointer = &(indicesBuffer.data[indicesView.byteOffset + indicesAccessor.byteOffset]);
136 std::vector<uint32_t> convertedIndices;
137 if (indicesAccessor.componentType == TINYGLTF_COMPONENT_TYPE_SHORT) {
138 const uint16_t* indices_16 =
static_cast<const uint16_t*
>(indicesPointer);
139 convertedIndices.reserve(indicesAccessor.count);
140 for (
size_t i = 0; i < indicesAccessor.count; i++) {
141 convertedIndices.push_back(
static_cast<uint32_t
>(indices_16[i]));
143 }
else if (indicesAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) {
144 const uint16_t* indices_16 =
static_cast<const uint16_t*
>(indicesPointer);
145 convertedIndices.reserve(indicesAccessor.count);
146 for (
size_t i = 0; i < indicesAccessor.count; i++) {
147 convertedIndices.push_back(
static_cast<uint32_t
>(indices_16[i]));
149 }
else if (indicesAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
150 const uint32_t* indices_32 =
static_cast<const uint32_t*
>(indicesPointer);
151 convertedIndices.assign(indices_32, indices_32 + indicesAccessor.count);
153 PLOGE <<
"Unsupported index component type. Skipping primitive. Index type: " << indicesAccessor.componentType;
158 size_t vertexCount = positionAccessor.count;
159 for (
size_t i = 0; i < vertexCount; i++) {
165 vertices.push_back(vertex);
168 indices.insert(indices.end(), convertedIndices.begin(), convertedIndices.end());
169 PLOGD <<
"Loaded " << indices.size() <<
" indices";
176 tinygltf::TinyGLTF &loader)
const {
180 bool loadingSuccess =
false;
181 if (filePath.has_extension() && filePath.extension().generic_string() ==
".glb" ) {
182 PLOGD <<
"Loading a .glb file from " << filePath.generic_string();
183 loadingSuccess = loader.LoadBinaryFromFile(&model, &err, &warn, filePath.generic_string());
184 }
else if (filePath.has_extension() && filePath.extension().generic_string() ==
"gltf" ) {
185 PLOGD <<
"Loading a .gltf file from " << filePath.generic_string();
186 loadingSuccess = loader.LoadASCIIFromFile(&model, &err, &warn, filePath.generic_string());
190 PLOGW <<
"Loading gltf model: " << warn;
191 throw std::runtime_error(
"Warnings while loading a 3d model");
195 PLOGE <<
"Error while loading gltf model: " << err;
196 throw std::runtime_error(
"Error while loading mesh");
199 if (!loadingSuccess) {
200 PLOGE <<
"Failed to load model";
201 throw std::runtime_error(std::string(
"Failed to load model from path: ") + filePath.generic_string());
std::unique_ptr< TextureLoadData > loadImage(const std::filesystem::path &path)