diff --git a/en/15_GLTF_KTX2_Migration.adoc b/en/15_GLTF_KTX2_Migration.adoc index 098c6c79..e552deea 100644 --- a/en/15_GLTF_KTX2_Migration.adoc +++ b/en/15_GLTF_KTX2_Migration.adoc @@ -141,102 +141,131 @@ Now, let's modify our `loadModel()` function to use tinygltf instead of tinyobjl [,c{pp}] ---- -void loadModel() { +void loadModel() +{ // Use tinygltf to load the model instead of tinyobjloader - tinygltf::Model model; + tinygltf::Model model; tinygltf::TinyGLTF loader; - std::string err; - std::string warn; + std::string err; + std::string warn; - bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, MODEL_PATH); + bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, MODEL_PATH); - if (!warn.empty()) { + if (!warn.empty()) + { std::cout << "glTF warning: " << warn << std::endl; } - if (!err.empty()) { + if (!err.empty()) + { std::cout << "glTF error: " << err << std::endl; } - if (!ret) { + if (!ret) + { throw std::runtime_error("Failed to load glTF model"); } - // Process all meshes in the model - std::unordered_map uniqueVertices{}; + vertices.clear(); + indices.clear(); - for (const auto& mesh : model.meshes) { - for (const auto& primitive : mesh.primitives) { + // Process all meshes in the model + for (const auto &mesh : model.meshes) + { + for (const auto &primitive : mesh.primitives) + { // Get indices - const tinygltf::Accessor& indexAccessor = model.accessors[primitive.indices]; - const tinygltf::BufferView& indexBufferView = model.bufferViews[indexAccessor.bufferView]; - const tinygltf::Buffer& indexBuffer = model.buffers[indexBufferView.buffer]; + const tinygltf::Accessor &indexAccessor = model.accessors[primitive.indices]; + const tinygltf::BufferView &indexBufferView = model.bufferViews[indexAccessor.bufferView]; + const tinygltf::Buffer &indexBuffer = model.buffers[indexBufferView.buffer]; // Get vertex positions - const tinygltf::Accessor& posAccessor = model.accessors[primitive.attributes.at("POSITION")]; - const tinygltf::BufferView& posBufferView = model.bufferViews[posAccessor.bufferView]; - const tinygltf::Buffer& posBuffer = model.buffers[posBufferView.buffer]; + const tinygltf::Accessor &posAccessor = model.accessors[primitive.attributes.at("POSITION")]; + const tinygltf::BufferView &posBufferView = model.bufferViews[posAccessor.bufferView]; + const tinygltf::Buffer &posBuffer = model.buffers[posBufferView.buffer]; // Get texture coordinates if available - bool hasTexCoords = primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end(); - const tinygltf::Accessor* texCoordAccessor = nullptr; - const tinygltf::BufferView* texCoordBufferView = nullptr; - const tinygltf::Buffer* texCoordBuffer = nullptr; - - if (hasTexCoords) { - texCoordAccessor = &model.accessors[primitive.attributes.at("TEXCOORD_0")]; + bool hasTexCoords = primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end(); + const tinygltf::Accessor *texCoordAccessor = nullptr; + const tinygltf::BufferView *texCoordBufferView = nullptr; + const tinygltf::Buffer *texCoordBuffer = nullptr; + + if (hasTexCoords) + { + texCoordAccessor = &model.accessors[primitive.attributes.at("TEXCOORD_0")]; texCoordBufferView = &model.bufferViews[texCoordAccessor->bufferView]; - texCoordBuffer = &model.buffers[texCoordBufferView->buffer]; + texCoordBuffer = &model.buffers[texCoordBufferView->buffer]; } - // Process vertices - for (size_t i = 0; i < posAccessor.count; i++) { + uint32_t baseVertex = static_cast(vertices.size()); + + for (size_t i = 0; i < posAccessor.count; i++) + { Vertex vertex{}; - // Get position - const float* pos = reinterpret_cast(&posBuffer.data[posBufferView.byteOffset + posAccessor.byteOffset + i * 12]); - vertex.pos = {pos[0], pos[1], pos[2]}; + const float *pos = reinterpret_cast(&posBuffer.data[posBufferView.byteOffset + posAccessor.byteOffset + i * 12]); + // glTF uses a right-handed coordinate system with Y-up + // Vulkan uses a right-handed coordinate system with Y-down + // We need to flip the Y coordinate + vertex.pos = {pos[0], -pos[1], pos[2]}; - // Get texture coordinates if available - if (hasTexCoords) { - const float* texCoord = reinterpret_cast(&texCoordBuffer->data[texCoordBufferView->byteOffset + texCoordAccessor->byteOffset + i * 8]); - vertex.texCoord = {texCoord[0], 1.0f - texCoord[1]}; - } else { + if (hasTexCoords) + { + const float *texCoord = reinterpret_cast(&texCoordBuffer->data[texCoordBufferView->byteOffset + texCoordAccessor->byteOffset + i * 8]); + vertex.texCoord = {texCoord[0], texCoord[1]}; + } + else + { vertex.texCoord = {0.0f, 0.0f}; } - // Set default color vertex.color = {1.0f, 1.0f, 1.0f}; - // Add vertex if unique - if (!uniqueVertices.contains(vertex)) { - uniqueVertices[vertex] = static_cast(vertices.size()); - vertices.push_back(vertex); - } + vertices.push_back(vertex); + } + + const unsigned char *indexData = &indexBuffer.data[indexBufferView.byteOffset + indexAccessor.byteOffset]; + size_t indexCount = indexAccessor.count; + size_t indexStride = 0; + + // Determine index stride based on component type + if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) + { + indexStride = sizeof(uint16_t); + } + else if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) + { + indexStride = sizeof(uint32_t); + } + else if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) + { + indexStride = sizeof(uint8_t); } + else + { + throw std::runtime_error("Unsupported index component type"); + } + + indices.reserve(indices.size() + indexCount); - // Process indices - const unsigned char* indexData = &indexBuffer.data[indexBufferView.byteOffset + indexAccessor.byteOffset]; + for (size_t i = 0; i < indexCount; i++) + { + uint32_t index = 0; - // Handle different index component types - if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) { - const uint16_t* indices16 = reinterpret_cast(indexData); - for (size_t i = 0; i < indexAccessor.count; i++) { - Vertex vertex = vertices[indices16[i]]; - indices.push_back(uniqueVertices[vertex]); + if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) + { + index = *reinterpret_cast(indexData + i * indexStride); } - } else if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) { - const uint32_t* indices32 = reinterpret_cast(indexData); - for (size_t i = 0; i < indexAccessor.count; i++) { - Vertex vertex = vertices[indices32[i]]; - indices.push_back(uniqueVertices[vertex]); + else if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) + { + index = *reinterpret_cast(indexData + i * indexStride); } - } else if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) { - const uint8_t* indices8 = reinterpret_cast(indexData); - for (size_t i = 0; i < indexAccessor.count; i++) { - Vertex vertex = vertices[indices8[i]]; - indices.push_back(uniqueVertices[vertex]); + else if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) + { + index = *reinterpret_cast(indexData + i * indexStride); } + + indices.push_back(baseVertex + index); } } }