From 3f6d9a3a75e2615866f8ed2cd0015fabea6490b7 Mon Sep 17 00:00:00 2001 From: ladevieq Date: Mon, 6 Sep 2021 22:55:51 +0200 Subject: Load gltf materials + diffuse and specular brdf --- src/gltf.cpp | 133 +++++++++++++++++++++++++++++++++++++++++++++++----- src/main.cpp | 12 +++-- src/scene.cpp | 14 +++--- src/vk-context.cpp | 1 + src/vk-renderer.cpp | 53 +++++++++++++++++---- 5 files changed, 183 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/gltf.cpp b/src/gltf.cpp index 66147dc..bfd7522 100644 --- a/src/gltf.cpp +++ b/src/gltf.cpp @@ -3,11 +3,14 @@ #include #include +#define STB_IMAGE_IMPLEMENTATION +#include "thirdparty/stb_image.h" + #include "utils.hpp" const vec3 scale (0.00800000037997961); -node gltf::load(std::filesystem::path &path, std::string &filename) { +node gltf::load(std::filesystem::path &path, std::string &filename, vkrenderer &renderer) { std::fstream f(path / filename); json gltf_json; @@ -24,8 +27,8 @@ node gltf::load(std::filesystem::path &path, std::string &filename) { buffer_index++; } - // auto materials = load_materials(gltf_json); - std::vector materials; + auto textures = load_textures(gltf_json, path, renderer); + auto materials = load_materials(gltf_json, textures); auto meshes = load_meshes(gltf_json, buffers_content, materials); @@ -77,7 +80,68 @@ std::vector gltf::load_meshes(json &gltf_json, std::vector gltf::load_materials(json &gltf_json) { +std::vector gltf::load_textures(json &gltf_json, std::filesystem::path &path, vkrenderer &renderer) { + auto &gltf_images = gltf_json["images"]; + auto images_count = gltf_images.size(); + std::vector images { images_count }; + + for (size_t image_index = 0; image_index < images_count; image_index++) { + auto &gltf_image = gltf_images[image_index]; + int x,y,n; + auto filepath = (path / gltf_image["uri"].get()).string(); + unsigned char *data = stbi_load(filepath.c_str(), &x, &y, &n, 4); + VkExtent3D size { + .width = static_cast(x), + .height = static_cast(y), + .depth = 1 + }; + auto img = renderer.api.create_image(size, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + renderer.update_image(img, data, x * y * 4); + + stbi_image_free(data); + + images[image_index] = std::move(img); + } + + renderer.api.update_descriptor_images(images, VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE); + + auto &gltf_samplers = gltf_json["samplers"]; + auto samplers_count = gltf_samplers.size(); + std::vector samplers { samplers_count }; + + for (size_t sampler_index = 0; sampler_index < samplers_count; sampler_index++) { + samplers[sampler_index] = renderer.api.create_sampler(VK_FILTER_LINEAR, VK_SAMPLER_ADDRESS_MODE_REPEAT); + } + + renderer.api.update_descriptor_samplers(samplers); + + auto &gltf_textures = gltf_json["textures"]; + auto textures_count = gltf_textures.size(); + std::vector textures { textures_count }; + + for (size_t texture_index = 0; texture_index < textures_count; texture_index++) { + auto gltf_texture = gltf_textures[texture_index]; + + auto image_index = gltf_texture["source"].get(); + auto &image = images[image_index]; + + uint32_t sampler_id = 0; + if (gltf_texture.contains("sampler")) { + auto sampler_index = gltf_texture["sampler"].get(); + auto &sampler = samplers[sampler_index]; + sampler_id = sampler.bindless_index; + } + + textures[texture_index] = texture { + .image_id = image.bindless_sampled_index, + .sampler_id = sampler_id + }; + } + + return std::move(textures); +} + +std::vector gltf::load_materials(json &gltf_json, std::vector &textures) { auto &gltf_materials = gltf_json["materials"]; auto materials_count = gltf_materials.size(); std::vector materials { materials_count }; @@ -86,13 +150,38 @@ std::vector gltf::load_materials(json &gltf_json) { auto& gltf_material = gltf_materials[material_index]; auto& material = materials[material_index]; - auto base_color = gltf_material["baseColorFactor"]; - material.base_color.v[0] = base_color[0]; - material.base_color.v[1] = base_color[1]; - material.base_color.v[2] = base_color[2]; - material.base_color.v[3] = base_color[3]; - material.metalness = gltf_material["matellicFactor"].get(); - material.roughness = gltf_material["roughnessFactor"].get(); + if (gltf_material.contains("pbrMetallicRoughness")) { + auto &pbr_params = gltf_material["pbrMetallicRoughness"]; + + if (pbr_params.contains("baseColorFactor")) { + auto &base_color = pbr_params["baseColorFactor"]; + material.base_color.v[0] = base_color[0].get(); + material.base_color.v[1] = base_color[1].get(); + material.base_color.v[2] = base_color[2].get(); + material.base_color.v[3] = base_color[3].get(); + } else + material.base_color = vec3(1.f); + + if (pbr_params.contains("baseColorTexture")) { + auto base_color_index = pbr_params["baseColorTexture"]["index"].get(); + material.base_color_texture = textures[base_color_index]; + } + + if (pbr_params.contains("metallicFactor")) + material.metalness = pbr_params["metallicFactor"].get(); + else + material.metalness = 1.0; + + if (pbr_params.contains("roughnessFactor")) + material.roughness = pbr_params["roughnessFactor"].get(); + else + material.roughness = 1.0; + + if (pbr_params.contains("metallicRoughnessTexture")) { + auto metallic_roughness_index = pbr_params["metallicRoughnessTexture"]["index"].get(); + material.metallic_roughness_texture = textures[metallic_roughness_index]; + } + } } return std::move(materials); @@ -159,7 +248,27 @@ mesh_part gltf::load_primitive(json &gltf_json, json &primitive, std::vector()]; + { + auto uvs_accessor_index = primitive["attributes"]["TEXCOORD_0"].get(); + auto uvs_view_index = accessors[uvs_accessor_index]["bufferView"].get(); + auto &uvs_view = gltf_json["bufferViews"][uvs_view_index]; + + auto uvs_buffer_index = uvs_view["buffer"].get(); + auto uvs_offset = uvs_view["byteOffset"].get(); + auto uvs_length = uvs_view["byteLength"].get(); + + auto &uvs_buffer = buffers_content[uvs_buffer_index]; + float* uvs_start = (float*)(uvs_buffer.data() + uvs_offset); + + size_t uvs_count = uvs_length / (sizeof(float) * 2); + part.uvs.resize(uvs_count); + + for (size_t i = 0; i < uvs_count; i++) { + part.uvs[i] = vec3(uvs_start[i * 2], uvs_start[i * 2 + 1], 0.0); + } + } + + part.mat = materials[primitive["material"].get()]; return std::move(part); } diff --git a/src/main.cpp b/src/main.cpp index c47aaeb..287b0eb 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -60,17 +60,23 @@ int main() { auto aperture = 0.1; auto focus_distance = 10; auto cam = camera(position, target, v_fov, (float)width / (float)height, aperture, focus_distance); - auto main_scene = scene(cam, width, height); - auto can_render = true; - vkrenderer renderer { wnd, sizeof(main_scene.meta), sizeof(main_scene.triangles[0]) * main_scene.triangles.size(), sizeof(main_scene.packed_nodes[0]) * main_scene.packed_nodes.size() }; + + vkrenderer renderer { wnd }; + auto main_scene = scene(cam, width, height, renderer); // vkrenderer renderer { wnd, sizeof(main_scene.meta), sizeof(main_scene.spheres[0]) * main_scene.spheres.size(), sizeof(main_scene.packed_nodes[0]) * main_scene.packed_nodes.size() }; + renderer.create_scene_buffer(sizeof(main_scene.meta)); + renderer.create_geometry_buffer(sizeof(main_scene.triangles[0]) * main_scene.triangles.size()); + renderer.create_bvh_buffer(sizeof(main_scene.packed_nodes[0]) * main_scene.packed_nodes.size()); + // Upload scene content std::memcpy(renderer.scene_buffer_ptr(), &main_scene.meta, sizeof(main_scene.meta)); renderer.update_geometry_buffer(main_scene.triangles.data()); // renderer.update_geometry_buffer(main_scene.spheres.data()); renderer.update_bvh_buffer(main_scene.packed_nodes.data()); + auto can_render = true; + ImGuiIO& io = ImGui::GetIO(); io.DisplaySize.x = (float)width; io.DisplaySize.y = (float)height; diff --git a/src/scene.cpp b/src/scene.cpp index a94c603..d162b3a 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -55,16 +55,16 @@ // spheres_count = spheres.size(); // } -scene::scene(camera cam, uint32_t width, uint32_t height) +scene::scene(camera cam, uint32_t width, uint32_t height, vkrenderer &renderer) :meta(cam, width, height){ auto bistro_interior_path = std::filesystem::path("../models/BistroInterior"); auto bistro_interior_filename = std::string("BistroInterior.gltf"); - auto root_node = gltf::load(bistro_interior_path, bistro_interior_filename); + auto root_node = gltf::load(bistro_interior_path, bistro_interior_filename, renderer); // auto sponza_path = std::filesystem::path("../models/sponza"); // auto sponza_filename = std::string("Sponza.gltf"); - // auto root_node = gltf::load(sponza_path, sponza_filename); + // auto root_node = gltf::load(sponza_path, sponza_filename, renderer); std::queue nodes_to_load {}; nodes_to_load.push(root_node); @@ -80,11 +80,11 @@ scene::scene(camera cam, uint32_t width, uint32_t height) auto i2 = mesh_part.indices[i + 1]; auto i3 = mesh_part.indices[i + 2]; - auto v1 = vertex { .position = mesh_part.positions[i1], .normal = mesh_part.normals[i1] }; - auto v2 = vertex { .position = mesh_part.positions[i2], .normal = mesh_part.normals[i2] }; - auto v3 = vertex { .position = mesh_part.positions[i3], .normal = mesh_part.normals[i3] }; + auto v1 = vertex { .position = mesh_part.positions[i1], .normal = mesh_part.normals[i1], .uv = mesh_part.uvs[i1] }; + auto v2 = vertex { .position = mesh_part.positions[i2], .normal = mesh_part.normals[i2], .uv = mesh_part.uvs[i2] }; + auto v3 = vertex { .position = mesh_part.positions[i3], .normal = mesh_part.normals[i3], .uv = mesh_part.uvs[i3] }; - triangles.emplace_back(v1, v2, v3); + triangles.emplace_back(v1, v2, v3, mesh_part.mat); } } } diff --git a/src/vk-context.cpp b/src/vk-context.cpp index 2f909ff..d68dca9 100644 --- a/src/vk-context.cpp +++ b/src/vk-context.cpp @@ -118,6 +118,7 @@ void vkcontext::create_device() { physical_device_12_features.bufferDeviceAddress = VK_TRUE; physical_device_12_features.runtimeDescriptorArray = VK_TRUE; physical_device_12_features.shaderStorageImageArrayNonUniformIndexing = VK_TRUE; + physical_device_12_features.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; physical_device_12_features.descriptorBindingPartiallyBound = VK_TRUE; physical_device_12_features.descriptorBindingPartiallyBound = VK_TRUE; physical_device_12_features.descriptorBindingUpdateUnusedWhilePending = VK_TRUE; diff --git a/src/vk-renderer.cpp b/src/vk-renderer.cpp index 68debc8..4ac1cd0 100644 --- a/src/vk-renderer.cpp +++ b/src/vk-renderer.cpp @@ -28,7 +28,7 @@ struct UiTransforms { float translate_x, translate_y; }; -vkrenderer::vkrenderer(window& wnd, size_t scene_buffer_size, size_t geometry_buffer_size, size_t bvh_buffer_size) { +vkrenderer::vkrenderer(window& wnd) { platform_surface = api.create_surface(wnd); swapchain = api.create_swapchain( platform_surface, @@ -55,10 +55,6 @@ vkrenderer::vkrenderer(window& wnd, size_t scene_buffer_size, size_t geometry_bu execution_semaphores = api.create_semaphores(virtual_frames_count); acquire_semaphores = api.create_semaphores(virtual_frames_count); - scene_buffer = api.create_buffer(scene_buffer_size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU); - geometry_buffer = api.create_buffer(geometry_buffer_size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY); - bvh_buffer = api.create_buffer(bvh_buffer_size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY); - std::vector attachments_format { swapchain.surface_format.format }; render_pass = api.create_render_pass(attachments_format, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); @@ -87,7 +83,7 @@ vkrenderer::vkrenderer(window& wnd, size_t scene_buffer_size, size_t geometry_bu .height = (uint32_t)atlas_height, .depth = 1, }; - auto staging_buffer = api.create_buffer(atlas_width * atlas_height * sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + staging_buffer = api.create_buffer(4096 * 4096 * 4 * sizeof(uint32_t), VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); std::memcpy(staging_buffer.alloc_info.pMappedData, pixels, atlas_width * atlas_height * sizeof(uint32_t)); ui_texture = api.create_image(atlas_size, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT); @@ -115,8 +111,6 @@ vkrenderer::vkrenderer(window& wnd, size_t scene_buffer_size, size_t geometry_bu VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) - api.destroy_buffer(staging_buffer); - std::vector images = { accumulation_images[0], accumulation_images[1], @@ -152,6 +146,7 @@ vkrenderer::~vkrenderer() { api.destroy_buffer(scene_buffer); api.destroy_buffer(geometry_buffer); api.destroy_buffer(bvh_buffer); + api.destroy_buffer(staging_buffer); api.destroy_fences(submission_fences); api.destroy_semaphores(execution_semaphores); api.destroy_semaphores(acquire_semaphores); @@ -411,6 +406,18 @@ void vkrenderer::handle_swapchain_result(VkResult function_result) { } +void vkrenderer::create_scene_buffer(size_t size) { + scene_buffer = api.create_buffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, VMA_MEMORY_USAGE_CPU_TO_GPU); +} + +void vkrenderer::create_geometry_buffer(size_t size) { + geometry_buffer = api.create_buffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY); +} + +void vkrenderer::create_bvh_buffer(size_t size) { + bvh_buffer = api.create_buffer(size, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VMA_MEMORY_USAGE_GPU_ONLY); +} + // TODO: Integrate into the API so that we no longer have to wait for the fence void vkrenderer::update_geometry_buffer(void* data) { VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) @@ -453,3 +460,33 @@ void vkrenderer::update_bvh_buffer(void* data) { api.destroy_buffer(staging_buffer); } + +void vkrenderer::update_image(image img, void* data, size_t size) { + if (staging_buffer.size < size) { + api.destroy_buffer(staging_buffer); + + staging_buffer = api.create_buffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY); + } + + std::memcpy(staging_buffer.alloc_info.pMappedData, data, size); + + VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) + VKRESULT(vkResetFences(api.context.device, 1, &submission_fences[virtual_frame_index])) + + auto cmd_buf = command_buffers[virtual_frame_index]; + api.start_record(cmd_buf); + + api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_MEMORY_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, img); + + api.copy_buffer(cmd_buf, staging_buffer, img); + + api.image_barrier(cmd_buf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_GENERAL, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, 0, img); + + api.end_record(cmd_buf); + + + api.submit(cmd_buf, VK_NULL_HANDLE, VK_NULL_HANDLE, submission_fences[virtual_frame_index]); + + VKRESULT(vkWaitForFences(api.context.device, 1, &submission_fences[virtual_frame_index], VK_TRUE, UINT64_MAX)) + +} -- cgit v1.3