Vulkan Schnee 0.0.1
High-performance rendering engine
Loading...
Searching...
No Matches
GltfMeshLoader.cpp
Go to the documentation of this file.
2#include "tiny_gltf.h"
3#include <filesystem>
4#include <optional>
5#include <plog/Log.h>
6
10
11namespace EngineCore {
12 void MeshLoaderGltf::useDefaultTexture(std::vector<std::unique_ptr<TextureLoadData>> &textureLoadData) {
13 TextureLoader textureLoader = TextureLoader();
14
15 for (int i = 0; i < Mesh::getTextureCount(); i++) {
16 textureLoadData.push_back(textureLoader.loadImage("textures/DefaultGrid.png"));
17 }
18 }
19
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;
24
25 if (filePath.generic_string().length() == 0) {
26 throw std::runtime_error(std::string("missing file path to mesh with filepath: ") + filePath.generic_string());
27 }
28
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());
31 return;
32 }
33
34 model = getModel(filePath, model, loader);
35
36 // Load textures first to avoid duplicates
37 std::unordered_map<int, int> textureMap; // Maps texture index to texture vector index
38
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!";
44 continue;
45 }
46
47 for (auto attribute : primitive.attributes) {
48 PLOGI << attribute.first;
49 }
50
51 // access position of the vertices
52 auto positionIterator = primitive.attributes.find("POSITION");
53 if (positionIterator == primitive.attributes.end()) {
54 PLOGE << "POSITION attribute not found! Skipping primitive.";
55 continue;
56 }
57
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]));
62
63 // access NORMAL
64 auto normalIterator = primitive.attributes.find("NORMAL");
65 if (normalIterator == primitive.attributes.end()) {
66 PLOGE << "NORMAL attribute not found! Skipping primitive.";
67 continue;
68 }
69
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]));
74
75 // Texture coordinate
76 auto textureCoordinateIterator = primitive.attributes.find("TEXCOORD_0");
77 if (textureCoordinateIterator == primitive.attributes.end()) {
78 PLOGE << "TEXCOORD_0 attribute not found! Skipping primitive.";
79 continue;
80 }
81
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]));
86
87 // textures
88 if (primitive.material >= 0 && primitive.material < model.materials.size()){
89 const tinygltf::Material& material = model.materials[primitive.material];
90
91 // base color
92 if (material.pbrMetallicRoughness.baseColorTexture.index >= 0 &&
93 material.pbrMetallicRoughness.baseColorTexture.index < model.textures.size()
94 )
95 {
96 int textureIndex = material.pbrMetallicRoughness.baseColorTexture.index;
97
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;
101 continue;
102 }
103
104 const tinygltf::Image& img = model.images[texture.source];
105
106 if (img.image.empty()) {
107 PLOGE << "Image data is empty for textureData: " << filePath.generic_string();
108 continue;
109 }
110
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 << ")";
113
114 // Store the textureData
115 textureLoadData.push_back(std::move(textureData));
116 textureMap[textureIndex] = textureLoadData.size() - 1;
117
118 }
119 else {
120 useDefaultTexture(textureLoadData);
121 }
122 }
123 else {
124 // default texture if main texture is missing
125 useDefaultTexture(textureLoadData);
126
127 }
128
129 // indices
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]);
134
135 // convert indices to uint32_t
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]));
142 }
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]));
148 }
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);
152 } else {
153 PLOGE << "Unsupported index component type. Skipping primitive. Index type: " << indicesAccessor.componentType;
154 continue;
155 }
156
157 // Populate the vertices array
158 size_t vertexCount = positionAccessor.count;
159 for (size_t i = 0; i < vertexCount; i++) {
160 Vertex vertex{};
161 vertex.position = glm::vec4(getVec3FromMemory(positions, i), 0.0f);
162 vertex.textureCoordinate = getVec2FromMemory(textureCoordinates, i);
163 vertex.normal = glm::vec4(getVec3FromMemory(normals, i), 0.0f);
164
165 vertices.push_back(vertex);
166 }
167
168 indices.insert(indices.end(), convertedIndices.begin(), convertedIndices.end());
169 PLOGD << "Loaded " << indices.size() << " indices";
170 }
171 }
172 }
173
174 tinygltf::Model &
175 MeshLoaderGltf::getModel(const std::filesystem::path &filePath, tinygltf::Model &model,
176 tinygltf::TinyGLTF &loader) const {
177 std::string err;
178 std::string warn;
179
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());
187 }
188
189 if (!warn.empty()) {
190 PLOGW << "Loading gltf model: " << warn;
191 throw std::runtime_error("Warnings while loading a 3d model");
192 }
193
194 if (!err.empty()) {
195 PLOGE << "Error while loading gltf model: " << err;
196 throw std::runtime_error("Error while loading mesh");
197 }
198
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());
202 }
203 return model;
204 }
205
206 glm::vec3 MeshLoaderGltf::getVec3FromMemory(const float *memory, size_t accessIndex, const bool invert_x, const bool invert_y, const bool invert_z) {
207 assert(memory != nullptr);
208 return glm::vec3((invert_x ? -1 : 1) * memory[accessIndex * 3 + 0],
209 (invert_y ? -1 : 1) * memory[accessIndex * 3 + 1],
210 (invert_z ? -1 : 1) * memory[accessIndex * 3 + 2]);
211 }
212
213 glm::vec2 MeshLoaderGltf::getVec2FromMemory(const float *memory, size_t accessIndex) {
214 assert(memory != nullptr);
215 return glm::vec2(memory[accessIndex * 2 + 0], memory[accessIndex * 2 + 1]);
216 }
217}
void loadMesh(const std::filesystem::path &filePath, std::vector< Vertex > &vertices, std::vector< uint32_t > &indices, std::vector< std::unique_ptr< TextureLoadData > > &textureLoadData) override
void useDefaultTexture(std::vector< std::unique_ptr< TextureLoadData > > &textureLoadData)
glm::vec2 getVec2FromMemory(const float *memory, size_t accessIndex)
tinygltf::Model & getModel(const std::filesystem::path &filePath, tinygltf::Model &model, tinygltf::TinyGLTF &loader) const
glm::vec3 getVec3FromMemory(const float *memory, size_t accessIndex, bool invert_x=false, bool invert_y=false, bool invert_z=false)
static uint32_t getTextureCount()
Definition Mesh.cpp:170
std::unique_ptr< TextureLoadData > loadImage(const std::filesystem::path &path)
Log category system implementation.
The fundamental building block of all meshes in this engine.
Definition Vertex.h:15
glm::vec4 normal
Definition Vertex.h:20
glm::vec4 position
Definition Vertex.h:19
glm::vec2 textureCoordinate
Definition Vertex.h:22