From 9ed211d1ca084b25d1780da3bde19e9da64d4a4a Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Sat, 5 Oct 2024 23:40:53 -0700 Subject: glTF loader start working --- .gitignore | 2 + assets/Box/Box.gltf | 142 +++++++++++++++++++++++++++++++++++++++++++++++ src/app.cpp | 13 +++++ src/gltf_loader.cpp | 78 +++++++++++++++++++++----- src/gltf_loader.h | 10 ++-- src/render_assets.h | 8 ++- src/vulkan_swapchain.cpp | 4 ++ 7 files changed, 236 insertions(+), 21 deletions(-) create mode 100644 assets/Box/Box.gltf diff --git a/.gitignore b/.gitignore index 125e2ae..ab3b6de 100644 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,5 @@ cmake-build-release/ imgui.ini e.log +assets/Avocado +assets/Sponza diff --git a/assets/Box/Box.gltf b/assets/Box/Box.gltf new file mode 100644 index 0000000..7f603f0 --- /dev/null +++ b/assets/Box/Box.gltf @@ -0,0 +1,142 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.800000011920929, + 0.0, + 0.0, + 1.0 + ], + "metallicFactor": 0.0 + }, + "name": "Red" + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 648, + "uri": "Box0.bin" + } + ] +} diff --git a/src/app.cpp b/src/app.cpp index 11a219d..2fd7c31 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1,4 +1,6 @@ #include "imgui.h" +#include "render_assets.h" +#include "gltf_loader.h" #include "vulkan_swapchain.h" #include "imgui_impl_vulkan.h" @@ -22,10 +24,15 @@ int main(int argc, char** argv) { argparse::ArgumentParser program("Iris Renderer"); program.add_argument("width") .help("display width of the window") + .default_value(1920) .scan<'i', int>(); program.add_argument("height") .help("display height of the window") + .default_value(1080) .scan<'i', int>(); + program.add_argument("scene") + .help("path to the scene file") + .default_value("assets/Box/Box.gltf"); try { program.parse_args(argc, argv); @@ -37,6 +44,7 @@ int main(int argc, char** argv) { int window_width = program.get("width"); int window_height = program.get("height"); + std::string scene_path = program.get("scene"); if (!glfwInit()) { const char* description = nullptr; @@ -72,6 +80,11 @@ int main(int argc, char** argv) { .flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT, .usage = VMA_MEMORY_USAGE_AUTO, }); + iris::Scene scene; + if (!load_gltf(scene_path, scene)) { + spdlog::critical("Failed to load glTF file"); + abort(); + } // end load debug image auto swapchain = iris::Swapchain(window, device, window_width, window_height); diff --git a/src/gltf_loader.cpp b/src/gltf_loader.cpp index bf64740..684fa7f 100644 --- a/src/gltf_loader.cpp +++ b/src/gltf_loader.cpp @@ -1,4 +1,5 @@ #include "gltf_loader.h" +#include "render_assets.h" #include "spdlog/spdlog.h" #include @@ -75,15 +76,26 @@ bool load_gltf(const std::string_view path, iris::Scene &scene) { model.scenes.size(), model.lights.size()); + for (const auto &mesh : model.meshes) { - iris::Mesh iris_mesh { - .name = mesh.name, - .vertices = {}, - .normals = {}, - .texcoords = {}, - .indices = {}, - }; + auto mesh_primitive_counter = 0u; + const std::string mesh_name = mesh.name == "" ? "mesh" : mesh.name; + + // TODO: A Mesh in glTF can have multiple primitives, each with its own set of attributes + // But our current abstract doesn't support multiple primitives within a mesh, so we load + // each primitive as a separate mesh instead. This is a temporary solution and should be fixed. for (const auto &primitive : mesh.primitives) { + std::string name = mesh_name + "_" + std::to_string(mesh_primitive_counter++); + spdlog::info("loading mesh primitive: {}", name); + iris::Mesh iris_mesh { + .name = mesh.name, + .vertices = {}, + .normals = {}, + .texcoords = {}, + .indices = {}, + .material_index = primitive.material, + }; + const auto &index_accessor = model.accessors[primitive.indices]; const auto &index_buffer_view = model.bufferViews[index_accessor.bufferView]; const auto &index_buffer = model.buffers[index_buffer_view.buffer]; @@ -144,15 +156,14 @@ bool load_gltf(const std::string_view path, iris::Scene &scene) { return *typed_data; }; - // TODO: support other types. Currently only float3 is supported - if (accessor.type != TINYGLTF_TYPE_VEC3 || accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) { - spdlog::error("Unsupported POSITION type: {}, {}", accessor.type, accessor.componentType); - return false; - } - // spdlog::info("attribute: {}, count: {}", attrib_name, accessor.count); if (attrib_name == "POSITION") { spdlog::info("loading POSITION, count {}", accessor.count); + // TODO: support other types. Currently only float3 is supported + if (accessor.type != TINYGLTF_TYPE_VEC3 || accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) { + spdlog::error("Field {} type unsupported: {}, {}", attrib_name, accessor.type, accessor.componentType); + continue; + } iris_mesh.p_min = glm::vec3(accessor.minValues[0], accessor.minValues[1], accessor.minValues[2]); iris_mesh.p_max = glm::vec3(accessor.maxValues[0], accessor.maxValues[1], accessor.maxValues[2]); for (size_t i = 0; i < accessor.count; i++) { @@ -160,26 +171,65 @@ bool load_gltf(const std::string_view path, iris::Scene &scene) { } } else if (attrib_name == "NORMAL") { spdlog::info("loading NORMAL, count {}", accessor.count); + // TODO: support other types. Currently only float3 is supported + if (accessor.type != TINYGLTF_TYPE_VEC3 || accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) { + spdlog::error("Field {} type unsupported: {}, {}", attrib_name, accessor.type, accessor.componentType); + continue; + } for (size_t i = 0; i < accessor.count; i++) { iris_mesh.normals.push_back(extract_data.operator()()); } } else if (attrib_name == "TEXCOORD_0") { spdlog::info("loading TEXCOORD_0, count {}", accessor.count); + // TODO: support other types. Currently only float2 is supported + if (accessor.type != TINYGLTF_TYPE_VEC2 || accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) { + spdlog::error("Field {} type unsupported: {}, {}", attrib_name, accessor.type, accessor.componentType); + continue; + } for (size_t i = 0; i < accessor.count; i++) { iris_mesh.texcoords.push_back(extract_data.operator()()); } + } else if (attrib_name == "TANGENT") { + spdlog::info("loading TANGENT, count {}", accessor.count); + // TODO: support other types. Currently only float4 is supported + if (accessor.type != TINYGLTF_TYPE_VEC4 || accessor.componentType != TINYGLTF_COMPONENT_TYPE_FLOAT) { + spdlog::error("Field {} type unsupported: {}, {}", attrib_name, accessor.type, accessor.componentType); + continue; + } + for (size_t i = 0; i < accessor.count; i++) { + iris_mesh.tangents.push_back(extract_data.operator()()); + } } else { spdlog::warn("Unsupported attribute: {}", attrib_name); } } + break; } // TODO add support for other modes default: spdlog::error("Unsupported primitive mode: {}", primitive.mode); return false; } + scene.meshes.push_back(iris_mesh); } - scene.meshes.push_back(iris_mesh); + } + + for (const tinygltf::Material &material : model.materials) { + const std::string material_name = material.name == "" ? "material" : material.name; + const auto &pbr = material.pbrMetallicRoughness; + iris::Material iris_material { + .name = material_name, + .base_color = glm::vec4( + pbr.baseColorFactor[0], + pbr.baseColorFactor[1], + pbr.baseColorFactor[2], + pbr.baseColorFactor[3]), + .metallic = float(pbr.metallicFactor), + .roughness = float(pbr.roughnessFactor), + }; + + // TODO: load texture information, skip for now + spdlog::info("Material: {}", material_name); } // TODO load materials and textures diff --git a/src/gltf_loader.h b/src/gltf_loader.h index c239bb2..4b3190b 100644 --- a/src/gltf_loader.h +++ b/src/gltf_loader.h @@ -1,11 +1,9 @@ -#pragma once +#ifndef GLTF_LOADER_H +#define GLTF_LOADER_H #include #include "render_assets.h" - -#define TINYGLTF_IMPLEMENTATION -#define STB_IMAGE_IMPLEMENTATION -#define STB_IMAGE_WRITE_IMPLEMENTATION #include "tiny_gltf.h" -bool load_gltf(const std::string_view path, iris::Scene &scene); \ No newline at end of file +bool load_gltf(const std::string_view path, iris::Scene &scene); +#endif \ No newline at end of file diff --git a/src/render_assets.h b/src/render_assets.h index 8c28ead..113084a 100644 --- a/src/render_assets.h +++ b/src/render_assets.h @@ -12,7 +12,10 @@ struct Mesh { std::vector vertices; std::vector normals; std::vector texcoords; + // Note: w component is a sign, 1.0 or -1.0 + std::vector tangents; std::vector indices; + int32_t material_index; // AABB glm::vec3 p_min; @@ -20,7 +23,10 @@ struct Mesh { }; struct Material { - + std::string name; + glm::vec4 base_color; + float metallic; + float roughness; }; struct Texture { diff --git a/src/vulkan_swapchain.cpp b/src/vulkan_swapchain.cpp index 4e08049..b93b8a9 100644 --- a/src/vulkan_swapchain.cpp +++ b/src/vulkan_swapchain.cpp @@ -1,5 +1,9 @@ #include "vulkan_swapchain.h" +#define TINYGLTF_IMPLEMENTATION +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "tiny_gltf.h" #include "GLFW/glfw3.h" #include "imgui.h" #include "imgui_impl_glfw.h" -- cgit v1.2.3-70-g09d2