Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 89 additions & 60 deletions en/15_GLTF_KTX2_Migration.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vertex, uint32_t> 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<uint32_t>(vertices.size());

for (size_t i = 0; i < posAccessor.count; i++)
{
Vertex vertex{};

// Get position
const float* pos = reinterpret_cast<const float*>(&posBuffer.data[posBufferView.byteOffset + posAccessor.byteOffset + i * 12]);
vertex.pos = {pos[0], pos[1], pos[2]};
const float *pos = reinterpret_cast<const float *>(&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<const float*>(&texCoordBuffer->data[texCoordBufferView->byteOffset + texCoordAccessor->byteOffset + i * 8]);
vertex.texCoord = {texCoord[0], 1.0f - texCoord[1]};
} else {
if (hasTexCoords)
{
const float *texCoord = reinterpret_cast<const float *>(&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<uint32_t>(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<const uint16_t*>(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<const uint16_t *>(indexData + i * indexStride);
}
} else if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) {
const uint32_t* indices32 = reinterpret_cast<const uint32_t*>(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<const uint32_t *>(indexData + i * indexStride);
}
} else if (indexAccessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) {
const uint8_t* indices8 = reinterpret_cast<const uint8_t*>(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<const uint8_t *>(indexData + i * indexStride);
}

indices.push_back(baseVertex + index);
}
}
}
Expand Down
Loading