diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fb4560..74192d7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -61,6 +61,7 @@ find_package(imgui CONFIG REQUIRED) find_package(Stb REQUIRED) find_package(tinyobjloader CONFIG REQUIRED) find_package(CURL REQUIRED) +find_package(Ktx CONFIG REQUIRED) if (!ANDROID) find_package(RapidJSON CONFIG REQUIRED) diff --git a/assets/models/basketballopt.glb b/assets/models/basketballopt.glb new file mode 100644 index 0000000..4f087ba Binary files /dev/null and b/assets/models/basketballopt.glb differ diff --git a/assets/shaders/common/ColorFunc.glsl b/assets/shaders/common/ColorFunc.glsl index 4480a58..40a2053 100644 --- a/assets/shaders/common/ColorFunc.glsl +++ b/assets/shaders/common/ColorFunc.glsl @@ -113,9 +113,9 @@ vec3 uintToColor(uint id) { // sRGB to linear approximation, see http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html vec4 srgbToLinear(in vec4 sRgb) { - //return vec4(pow(sRgb.xyz, vec3(2.2f)), sRgb.w); - vec3 rgb = sRgb.xyz * (sRgb.xyz * (sRgb.xyz * 0.305306011F + 0.682171111F) + 0.012522878F); - return vec4(rgb, sRgb.a); + //return vec4(pow(sRgb.xyz, vec3(1.0f / 2.2f)), sRgb.w); + //vec3 rgb = sRgb.xyz * (sRgb.xyz * (sRgb.xyz * 0.305306011F + 0.682171111F) + 0.012522878F); + return vec4(sRgb.rgb, sRgb.a); } #define ColorFunc_glsl diff --git a/src/Assets/Model.cpp b/src/Assets/Model.cpp index c053bee..19c8e11 100644 --- a/src/Assets/Model.cpp +++ b/src/Assets/Model.cpp @@ -37,6 +37,8 @@ #define TINYGLTF_NO_INCLUDE_RAPIDJSON #endif +#define TINYGLTF_NO_STB_IMAGE +//#define TINYGLTF_NO_STB_IMAGE_WRITE #define STB_IMAGE_WRITE_IMPLEMENTATION #include #include @@ -231,10 +233,13 @@ namespace Assets } } + static std::string currSceneName = "default"; + bool LoadImageData(tinygltf::Image * image, const int image_idx, std::string * err, std::string * warn, int req_width, int req_height, const unsigned char * bytes, int size, void * user_data ) { + image->as_is = true; return true; } @@ -249,31 +254,65 @@ namespace Assets tinygltf::TinyGLTF gltfLoader; std::string err; std::string warn; + std::filesystem::path filepath = filename; + + + // load all textures + std::vector textureIdMap; + currSceneName = filepath.filename().string(); + gltfLoader.SetImagesAsIs(true); gltfLoader.SetImageLoader(LoadImageData, nullptr); if(!gltfLoader.LoadBinaryFromFile(&model, &err, &warn, filename) ) { return; } - - // load all textures - std::vector textureIdMap; - std::filesystem::path filepath = filename; - - for ( uint32_t i = 0; i < model.images.size(); ++i ) + // delayed texture creation + textureIdMap.resize(model.images.size(), -1); + auto lambdaLoadTexture = [&textureIdMap, &model](int texture, bool srgb) { - tinygltf::Image& image = model.images[i]; - - std::string texname = image.name.empty() ? fmt::format("tex_{}", i): image.name; - // 假设,这里的image id和外面的textures id是一样的 - uint32_t texIdx = GlobalTexturePool::LoadTexture( - filepath.filename().string() + "_" + texname, model.buffers[0].data.data() + model.bufferViews[image.bufferView].byteOffset, - model.bufferViews[image.bufferView].byteLength, Vulkan::SamplerConfig()); + if (texture != -1) + { + int imageIdx = model.textures[texture].source; + if (imageIdx == -1) imageIdx = texture; - textureIdMap.push_back(texIdx); - } + if (textureIdMap[imageIdx] != -1) + { + return; + } + + // create texture + auto& image = model.images[imageIdx]; + std::string texname = image.name.empty() ? fmt::format("tex_{}", imageIdx) : image.name; + + uint32_t texIdx = GlobalTexturePool::LoadTexture( + currSceneName + texname, model.images[imageIdx].mimeType, + model.buffers[0].data.data() + model.bufferViews[image.bufferView].byteOffset, + model.bufferViews[image.bufferView].byteLength, srgb); + + textureIdMap[imageIdx] = texIdx; + } + }; + auto lambdaGetTexture = [&textureIdMap, &model](int texture) + { + if (texture != -1) + { + int imageIdx = model.textures[texture].source; + if (imageIdx == -1) imageIdx = texture; + return textureIdMap[imageIdx]; + } + return -1; + }; + + for (tinygltf::Material& mat : model.materials) + { + lambdaLoadTexture(mat.pbrMetallicRoughness.baseColorTexture.index, true); + lambdaLoadTexture(mat.pbrMetallicRoughness.metallicRoughnessTexture.index, false); + lambdaLoadTexture(mat.normalTexture.index, false); + } + // load all materials for (tinygltf::Material& mat : model.materials) { @@ -290,23 +329,11 @@ namespace Assets m.RefractionIndex = 1.46f; m.RefractionIndex2 = 1.46f; - int texture = mat.pbrMetallicRoughness.baseColorTexture.index; - if(texture != -1) - { - m.DiffuseTextureId = textureIdMap[ model.textures[texture].source ]; - } - int mraTexture = mat.pbrMetallicRoughness.metallicRoughnessTexture.index; - if(mraTexture != -1) - { - m.MRATextureId = textureIdMap[ model.textures[mraTexture].source ]; - m.Fuzziness = 1.0; - } - int normalTexture = mat.normalTexture.index; - if(normalTexture != -1) - { - m.NormalTextureId = textureIdMap[ model.textures[normalTexture].source ]; - m.NormalTextureScale = static_cast(mat.normalTexture.scale); - } + m.DiffuseTextureId = lambdaGetTexture( mat.pbrMetallicRoughness.baseColorTexture.index ); + m.MRATextureId = lambdaGetTexture(mat.pbrMetallicRoughness.metallicRoughnessTexture.index); + + m.NormalTextureId = lambdaGetTexture(mat.normalTexture.index); + m.NormalTextureScale = static_cast(mat.normalTexture.scale); glm::vec3 emissiveColor = mat.emissiveFactor.empty() ? glm::vec3(0) diff --git a/src/Assets/Texture.cpp b/src/Assets/Texture.cpp index cdc5575..5c863f0 100644 --- a/src/Assets/Texture.cpp +++ b/src/Assets/Texture.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "Options.hpp" #include "Runtime/TaskCoordinator.hpp" @@ -22,34 +23,32 @@ namespace Assets float elapsed; std::array outputInfo; }; - + uint32_t GlobalTexturePool::LoadTexture(const std::string& filename, const Vulkan::SamplerConfig& samplerConfig) { std::vector data; Utilities::Package::FPackageFileSystem::GetInstance().LoadFile(filename, data); - return GetInstance()->RequestNewTextureMemAsync(filename, false, data.data(), data.size()); + return GetInstance()->RequestNewTextureMemAsync(filename, "texture/default", false, data.data(), data.size(), + false); } - uint32_t GlobalTexturePool::LoadTexture(const std::string& texname, const unsigned char* data, size_t bytelength, const Vulkan::SamplerConfig& samplerConfig) + uint32_t GlobalTexturePool::LoadTexture(const std::string& texname, const std::string& mime, + const unsigned char* data, size_t bytelength, bool srgb) { - return GetInstance()->RequestNewTextureMemAsync(texname, false, data, bytelength); + return GetInstance()->RequestNewTextureMemAsync(texname, mime, false, data, bytelength, srgb); } uint32_t GlobalTexturePool::LoadHDRTexture(const std::string& filename, const Vulkan::SamplerConfig& samplerConfig) { std::vector data; Utilities::Package::FPackageFileSystem::GetInstance().LoadFile(filename, data); - return GetInstance()->RequestNewTextureMemAsync(filename, true, data.data(), data.size()); - } - - void GlobalTexturePool::UpdateHDRTexture(uint32_t idx, const std::string& filename, const Vulkan::SamplerConfig& samplerConfig) - { - GetInstance()->RequestUpdateTextureFileAsync(idx, filename, true); + return GetInstance()->RequestNewTextureMemAsync(filename, "texture/default", true, data.data(), data.size(), + false); } TextureImage* GlobalTexturePool::GetTextureImage(uint32_t idx) { - if(GetInstance()->textureImages_.size() > idx) + if (GetInstance()->textureImages_.size() > idx) { return GetInstance()->textureImages_[idx].get(); } @@ -59,30 +58,32 @@ namespace Assets TextureImage* GlobalTexturePool::GetTextureImageByName(const std::string& name) { uint32_t id = GetTextureIndexByName(name); - if( id != -1 ) + if (id != -1) { - return GetInstance()->textureImages_[id].get(); + return GetInstance()->textureImages_[id].get(); } return nullptr; } uint32_t GlobalTexturePool::GetTextureIndexByName(const std::string& name) { - if( GetInstance()->textureNameMap_.find(name) != GetInstance()->textureNameMap_.end() ) + if (GetInstance()->textureNameMap_.find(name) != GetInstance()->textureNameMap_.end()) { return GetInstance()->textureNameMap_[name]; } return -1; } - GlobalTexturePool::GlobalTexturePool(const Vulkan::Device& device, Vulkan::CommandPool& command_pool, Vulkan::CommandPool& command_pool_mt) : + GlobalTexturePool::GlobalTexturePool(const Vulkan::Device& device, Vulkan::CommandPool& command_pool, + Vulkan::CommandPool& command_pool_mt) : device_(device), commandPool_(command_pool), mainThreadCommandPool_(command_pool_mt) { static const uint32_t k_bindless_texture_binding = 0; // The maximum number of bindless resources is limited by the device. - static const uint32_t k_max_bindless_resources = std::min(65535u, device.DeviceProperties().limits.maxPerStageDescriptorSamplers); + static const uint32_t k_max_bindless_resources = std::min( + 65535u, device.DeviceProperties().limits.maxPerStageDescriptorSamplers); // Create bindless descriptor pool VkDescriptorPoolSize pool_sizes_bindless[] = @@ -102,7 +103,8 @@ namespace Assets "create global descriptor pool"); // create set layout - VkDescriptorBindingFlags bindless_flags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; + VkDescriptorBindingFlags bindless_flags = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT | + VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT; VkDescriptorSetLayoutBinding vk_binding; vk_binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; @@ -117,7 +119,9 @@ namespace Assets layout_info.pBindings = &vk_binding; layout_info.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT; - VkDescriptorSetLayoutBindingFlagsCreateInfoEXT extended_info{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT, nullptr}; + VkDescriptorSetLayoutBindingFlagsCreateInfoEXT extended_info{ + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT, nullptr + }; extended_info.bindingCount = 1; extended_info.pBindingFlags = &bindless_flags; @@ -131,7 +135,9 @@ namespace Assets alloc_info.descriptorSetCount = 1; alloc_info.pSetLayouts = &layout_; - VkDescriptorSetVariableDescriptorCountAllocateInfoEXT count_info{VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT}; + VkDescriptorSetVariableDescriptorCountAllocateInfoEXT count_info{ + VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT + }; uint32_t max_binding = k_max_bindless_resources - 1; count_info.descriptorSetCount = 1; // This number is the max allocatable count @@ -192,52 +198,9 @@ namespace Assets } return -1; } - - void GlobalTexturePool::RequestUpdateTextureFileAsync(uint32_t textureIdx, const std::string& filename, bool hdr) - { - TaskCoordinator::GetInstance()->AddTask([this, filename, hdr, textureIdx](ResTask& task) - { - TextureTaskContext taskContext {}; - const auto timer = std::chrono::high_resolution_clock::now(); - - // Load the texture in normal host memory. - int width, height, channels; - void* pixels = nullptr; - if(hdr) - { - pixels = stbi_loadf(filename.c_str(), &width, &height, &channels, STBI_rgb_alpha); - } - else - { - pixels = stbi_load(filename.c_str(), &width, &height, &channels, STBI_rgb_alpha); - } - - if (!pixels) - { - Throw(std::runtime_error("failed to load texture image '" + filename + "'")); - } - - // thread reset may cause crash, created the new texture here, but reset in later main thread phase - taskContext.transferPtr = new TextureImage(commandPool_, width, height, hdr, static_cast((void*)pixels)); - stbi_image_free(pixels); - taskContext.textureId = textureIdx; - taskContext.elapsed = std::chrono::duration(std::chrono::high_resolution_clock::now() - timer).count(); - std::string info = fmt::format("reloaded {} ({} x {} x {}) in {:.2f}ms", filename, width, height, channels, taskContext.elapsed * 1000.f); - std::copy(info.begin(), info.end(), taskContext.outputInfo.data()); - task.SetContext( taskContext ); - }, [this](ResTask& task) - { - TextureTaskContext taskContext {}; - task.GetContext( taskContext ); - - textureImages_[taskContext.textureId].reset(taskContext.transferPtr); - BindTexture(taskContext.textureId, *(textureImages_[taskContext.textureId])); - - fmt::print("{}\n", taskContext.outputInfo.data()); - }, 0); - } - uint32_t GlobalTexturePool::RequestNewTextureMemAsync(const std::string& texname, bool hdr, const unsigned char* data, size_t bytelength) + uint32_t GlobalTexturePool::RequestNewTextureMemAsync(const std::string& texname, const std::string& mime, bool hdr, + const unsigned char* data, size_t bytelength, bool srgb) { if (textureNameMap_.find(texname) != textureNameMap_.end()) { @@ -249,47 +212,141 @@ namespace Assets uint8_t* copyedData = new uint8_t[bytelength]; memcpy(copyedData, data, bytelength); - TaskCoordinator::GetInstance()->AddTask([this, hdr, texname, copyedData, bytelength, newTextureIdx](ResTask& task) - { - TextureTaskContext taskContext {}; - const auto timer = std::chrono::high_resolution_clock::now(); - - // Load the texture in normal host memory. - int width, height, channels; - void* pixels = nullptr; - - if(hdr) + TaskCoordinator::GetInstance()->AddTask( + [this, hdr, srgb, texname, mime, copyedData, bytelength, newTextureIdx](ResTask& task) { - pixels = stbi_loadf_from_memory(copyedData, static_cast(bytelength), &width, &height, &channels, STBI_rgb_alpha); - } - else + TextureTaskContext taskContext{}; + const auto timer = std::chrono::high_resolution_clock::now(); + + // Load the texture in normal host memory. + int width, height, channels; + uint8_t* stbdata = nullptr; + uint8_t* pixels = nullptr; + uint32_t size = 0; + uint32_t miplevel = 1; + VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; + + ktxTexture2* kTexture = nullptr; + ktx_error_code_e result; + if (mime.find("ktx") != std::string::npos) + { + result = ktxTexture2_CreateFromMemory(copyedData, bytelength, KTX_TEXTURE_CREATE_CHECK_GLTF_BASISU_BIT, &kTexture); + if (KTX_SUCCESS != result) Throw(std::runtime_error("failed to load ktx2 texture image ")); + result = ktxTexture2_TranscodeBasis(kTexture, KTX_TTF_BC7_RGBA, 0); + if (KTX_SUCCESS != result) Throw(std::runtime_error("failed to load ktx2 texture image ")); + pixels = ktxTexture_GetData(ktxTexture(kTexture)); + + ktx_size_t offset; + ktxTexture_GetImageOffset(ktxTexture(kTexture), 0, 0, 0, &offset); + pixels += offset; + size = static_cast(ktxTexture_GetImageSize(ktxTexture(kTexture), 0)); + + format = static_cast(kTexture->vkFormat); + width = kTexture->baseWidth; + height = kTexture->baseHeight; + miplevel = 1; + } + else + { + if (hdr) + { + // ktx now don't support hdr, use stbi import + stbdata = reinterpret_cast(stbi_loadf_from_memory(copyedData, static_cast(bytelength), &width, &height, &channels, STBI_rgb_alpha)); + pixels = stbdata; + format = VK_FORMAT_R32G32B32A32_SFLOAT; + size = width * height * 4 * sizeof(float); + } + else + { + // ldr texture, try cache fist + std::filesystem::path cachePath = Utilities::FileHelper::GetPlatformFilePath("cache"); + std::filesystem::create_directories(cachePath); + + // hash the texname + std::hash hasher; + std::string hashname = fmt::format("{:x}", hasher(texname)); + std::string cacheFileName = (cachePath / fmt::format("{}.ktx", hashname)).string(); + if (!std::filesystem::exists(cacheFileName)) + { + // load from stbi and compress to ktx and cache + stbdata = stbi_load_from_memory(copyedData, static_cast(bytelength), &width, &height, &channels, STBI_rgb_alpha); + format = srgb ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM; + size = width * height * 4 * sizeof(uint8_t); + + ktxTextureCreateInfo createInfo = { + 0, + static_cast(format), + 0, + static_cast(width), + static_cast(height), + 1, 2, 1, 1, 1,KTX_FALSE,KTX_FALSE + }; + + result = ktxTexture2_Create(&createInfo, KTX_TEXTURE_CREATE_ALLOC_STORAGE, &kTexture); + if (result != KTX_SUCCESS) Throw(std::runtime_error("failed to create ktx2 image ")); + + std::memcpy(ktxTexture_GetData(ktxTexture(kTexture)), stbdata, size); + + ktxBasisParams params = {}; + params.structSize = sizeof(params); + params.uastc = KTX_TRUE; + params.compressionLevel = 2; + params.qualityLevel = 128; + params.threadCount = 12; + result = ktxTexture2_CompressBasisEx(kTexture, ¶ms); + if (KTX_SUCCESS != result) Throw(std::runtime_error("failed to compress ktx2 image ")); + // save to cache + ktxTexture_WriteToNamedFile(ktxTexture(kTexture), (cachePath / fmt::format("{}.ktx", hashname)).string().c_str()); + } + else + { + result = ktxTexture2_CreateFromNamedFile(cacheFileName.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, &kTexture); + if (result != KTX_SUCCESS) Throw(std::runtime_error("failed to load ktx2 image ")); + } + + // next + result = ktxTexture2_TranscodeBasis(kTexture, KTX_TTF_BC7_RGBA, 0); + if (result != KTX_SUCCESS) Throw(std::runtime_error("failed to transcode ktx2 image ")); + + pixels = ktxTexture_GetData(ktxTexture(kTexture)); + ktx_size_t offset; + ktxTexture_GetImageOffset(ktxTexture(kTexture), 0, 0, 0, &offset); + pixels += offset; + size = static_cast(ktxTexture_GetImageSize(ktxTexture(kTexture), 0)); + + format = srgb ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK; + width = kTexture->baseWidth; + height = kTexture->baseHeight; + miplevel = 1; + } + } + + // create texture image + textureImages_[newTextureIdx] = std::make_unique( + commandPool_, width, height, miplevel, format, pixels, size); + BindTexture(newTextureIdx, *(textureImages_[newTextureIdx])); + + // clean up + if (stbdata) stbi_image_free(stbdata); + if (kTexture) + ktxTexture_Destroy(ktxTexture(kTexture)); + + // transfer + taskContext.textureId = newTextureIdx; + taskContext.elapsed = std::chrono::duration( + std::chrono::high_resolution_clock::now() - timer).count(); + std::string info = fmt::format("loaded {} ({} x {} x {}) in {:.2f}ms", texname, width, height, miplevel, + taskContext.elapsed * 1000.f); + std::copy(info.begin(), info.end(), taskContext.outputInfo.data()); + task.SetContext(taskContext); + }, [this, copyedData](ResTask& task) { - pixels = stbi_load_from_memory(copyedData, static_cast(bytelength), &width, &height, &channels, STBI_rgb_alpha); - } - - if (!pixels) - { - Throw(std::runtime_error("failed to load texture image ")); - } - - // create texture image - textureImages_[newTextureIdx] = std::make_unique(commandPool_, width, height, hdr, static_cast((void*)pixels)); - BindTexture(newTextureIdx, *(textureImages_[newTextureIdx])); - stbi_image_free(pixels); - - taskContext.textureId = newTextureIdx; - taskContext.elapsed = std::chrono::duration(std::chrono::high_resolution_clock::now() - timer).count(); - std::string info = fmt::format("loaded {} ({} x {} x {}) in {:.2f}ms", texname, width, height, channels, taskContext.elapsed * 1000.f); - std::copy(info.begin(), info.end(), taskContext.outputInfo.data()); - task.SetContext( taskContext ); - }, [this, copyedData](ResTask& task) - { - TextureTaskContext taskContext {}; - task.GetContext( taskContext ); - textureImages_[taskContext.textureId]->MainThreadPostLoading(mainThreadCommandPool_); - if(!GOption->Benchmark) fmt::print("{}\n", taskContext.outputInfo.data()); - delete[] copyedData; - }, 0); + TextureTaskContext taskContext{}; + task.GetContext(taskContext); + textureImages_[taskContext.textureId]->MainThreadPostLoading(mainThreadCommandPool_); + if (!GOption->Benchmark) fmt::print("{}\n", taskContext.outputInfo.data()); + delete[] copyedData; + }, 0); // cache in namemap textureNameMap_[texname] = newTextureIdx; diff --git a/src/Assets/Texture.hpp b/src/Assets/Texture.hpp index e6d363f..2c87f0d 100644 --- a/src/Assets/Texture.hpp +++ b/src/Assets/Texture.hpp @@ -27,19 +27,16 @@ namespace Assets void BindTexture(uint32_t textureIdx, const TextureImage& textureImage); uint32_t TryGetTexureIndex(const std::string& textureName) const; uint32_t RequestNewTextureFileAsync(const std::string& filename, bool hdr); - void RequestUpdateTextureFileAsync(uint32_t textureIdx, const std::string& filename, bool hdr); - uint32_t RequestNewTextureMemAsync(const std::string& texname, bool hdr, const unsigned char* data, size_t bytelength); - + uint32_t RequestNewTextureMemAsync(const std::string& texname, const std::string& mime, bool hdr, const unsigned char* data, size_t bytelength, bool srgb); + uint32_t TotalTextures() const {return static_cast(textureImages_.size());} const std::unordered_map& TotalTextureMap() {return textureNameMap_;} static GlobalTexturePool* GetInstance() {return instance_;} - static uint32_t LoadTexture(const std::string& texname, const unsigned char* data, size_t bytelength, const Vulkan::SamplerConfig& samplerConfig); + static uint32_t LoadTexture(const std::string& texname, const std::string& mime, const unsigned char* data, size_t bytelength, bool srgb); static uint32_t LoadTexture(const std::string& filename, const Vulkan::SamplerConfig& samplerConfig); static uint32_t LoadHDRTexture(const std::string& filename, const Vulkan::SamplerConfig& samplerConfig); - static void UpdateHDRTexture(uint32_t idx, const std::string& filename, const Vulkan::SamplerConfig& samplerConfig); - static TextureImage* GetTextureImage(uint32_t idx); static TextureImage* GetTextureImageByName(const std::string& name); static uint32_t GetTextureIndexByName(const std::string& name); diff --git a/src/Assets/TextureImage.cpp b/src/Assets/TextureImage.cpp index a9c7722..9336ef9 100644 --- a/src/Assets/TextureImage.cpp +++ b/src/Assets/TextureImage.cpp @@ -3,16 +3,15 @@ #include "Vulkan/Buffer.hpp" #include "Vulkan/CommandPool.hpp" #include "Vulkan/ImageView.hpp" -#include "Vulkan/Image.hpp" #include "Vulkan/Sampler.hpp" #include namespace Assets { -TextureImage::TextureImage(Vulkan::CommandPool& commandPool, size_t width, size_t height, bool hdr, const unsigned char* data) +TextureImage::TextureImage(Vulkan::CommandPool& commandPool, size_t width, size_t height, uint32_t miplevel, VkFormat format, const unsigned char* data, uint32_t size) { // Create a host staging buffer and copy the image into it. - const VkDeviceSize imageSize = width * height * (hdr ? 16 : 4); + const VkDeviceSize imageSize = size; const auto& device = commandPool.Device(); auto stagingBuffer = std::make_unique(device, imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT); @@ -23,7 +22,7 @@ TextureImage::TextureImage(Vulkan::CommandPool& commandPool, size_t width, size_ stagingBufferMemory.Unmap(); // Create the device side image, memory, view and sampler. - image_.reset(new Vulkan::Image(device, VkExtent2D{ static_cast(width), static_cast(height) }, hdr ? VK_FORMAT_R32G32B32A32_SFLOAT : VK_FORMAT_R8G8B8A8_UNORM)); + image_.reset(new Vulkan::Image(device, VkExtent2D{ static_cast(width), static_cast(height) }, miplevel, format)); imageMemory_.reset(new Vulkan::DeviceMemory(image_->AllocateMemory(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT))); imageView_.reset(new Vulkan::ImageView(device, image_->Handle(), image_->Format(), VK_IMAGE_ASPECT_COLOR_BIT)); sampler_.reset(new Vulkan::Sampler(device, Vulkan::SamplerConfig())); diff --git a/src/Assets/TextureImage.hpp b/src/Assets/TextureImage.hpp index d0e8160..f85554f 100644 --- a/src/Assets/TextureImage.hpp +++ b/src/Assets/TextureImage.hpp @@ -1,5 +1,6 @@ #pragma once +#include "Vulkan/Image.hpp" #include namespace Vulkan @@ -24,7 +25,7 @@ namespace Assets TextureImage& operator = (const TextureImage&) = delete; TextureImage& operator = (TextureImage&&) = delete; - TextureImage(Vulkan::CommandPool& commandPool, size_t width, size_t height, bool hdr, const unsigned char* data); + TextureImage(Vulkan::CommandPool& commandPool, size_t width, size_t height, uint32_t miplevel, VkFormat format, const unsigned char* data, uint32_t size); ~TextureImage(); const Vulkan::ImageView& ImageView() const { return *imageView_; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9135179..a45fb60 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -127,8 +127,7 @@ foreach(target IN LISTS AllTargets) # preprocessor definitions target_compile_definitions(${target} PUBLIC IMGUI_DEFINE_MATH_OPERATORS) target_compile_definitions(${target} PUBLIC MA_NO_ENCODING MA_NO_FLAC) - target_link_libraries(${target} PRIVATE fmt::fmt CURL::libcurl Boost::boost Boost::exception Boost::program_options glm::glm imgui::imgui tinyobjloader::tinyobjloader draco::draco ${Vulkan_LIBRARIES} ${extra_libs}) - + target_link_libraries(${target} PRIVATE KTX::ktx fmt::fmt CURL::libcurl Boost::boost Boost::exception Boost::program_options glm::glm imgui::imgui tinyobjloader::tinyobjloader draco::draco ${Vulkan_LIBRARIES} ${extra_libs}) # link engine if ( ${target} STREQUAL gkNextEngine ) target_compile_definitions(${target} PRIVATE ENGINE_EXPORTS) diff --git a/src/MagicaLego/MagicaLegoGameInstance.cpp b/src/MagicaLego/MagicaLegoGameInstance.cpp index d62b852..22744d9 100644 --- a/src/MagicaLego/MagicaLegoGameInstance.cpp +++ b/src/MagicaLego/MagicaLegoGameInstance.cpp @@ -283,6 +283,7 @@ void MagicaLegoGameInstance::OnSceneLoaded() } glm::vec3 location = glm::vec3((x - 10.25) * 0.96f, 0.0f, (z - 9.5) * 0.96f); auto newNode = Assets::Node::CreateNode(NodeName, location, glm::quat(1,0,0,0), glm::vec3(1), modelId, basementInstanceId_, false); + newNode->SetMaterial( GetEngine().GetScene().GetModel(modelId)->Materials() ); GetEngine().GetScene().Nodes().push_back(newNode); } } @@ -503,7 +504,7 @@ void MagicaLegoGameInstance::AddBasicBlock(std::string blockName, std::string ty std::string fileName = fmt::format("assets/textures/thumb/thumb_{}_{}.jpg", type, name); std::vector outData; GetEngine().GetPakSystem().LoadFile(fileName, outData); - Assets::GlobalTexturePool::LoadTexture(fileName, outData.data(), outData.size(), Vulkan::SamplerConfig()); + Assets::GlobalTexturePool::LoadTexture(fileName, "jpg", outData.data(), outData.size(), false ); #endif } } @@ -775,6 +776,7 @@ void MagicaLegoGameInstance::RebuildScene(std::unordered_map newNode = Assets::Node::CreateNode("blockInst", GetRenderLocationFromBlockLocation(Block.second.location), glm::quat(orientation), glm::vec3(1), BasicBlock->modelId_, instanceId, newhash != Block.first); + newNode->SetMaterial( GetEngine().GetScene().GetModel(BasicBlock->modelId_)->Materials() ); newNode->SetVisible(true); GetEngine().GetScene().Nodes().push_back(newNode); diff --git a/src/Runtime/Engine.cpp b/src/Runtime/Engine.cpp index 4cbb26f..671ffa1 100644 --- a/src/Runtime/Engine.cpp +++ b/src/Runtime/Engine.cpp @@ -751,7 +751,7 @@ void NextEngine::OnRendererDeviceSet() Assets::GlobalTexturePool::LoadHDRTexture("assets/textures/umhlanga_sunrise_1k.hdr", Vulkan::SamplerConfig()); Assets::GlobalTexturePool::LoadHDRTexture("assets/textures/shanghai_bund_1k.hdr", Vulkan::SamplerConfig()); - if(GOption->HDRIfile != "") Assets::GlobalTexturePool::UpdateHDRTexture(0, GOption->HDRIfile.c_str(), Vulkan::SamplerConfig()); + //if(GOption->HDRIfile != "") Assets::GlobalTexturePool::UpdateHDRTexture(0, GOption->HDRIfile.c_str(), Vulkan::SamplerConfig()); scene_.reset(new Assets::Scene(renderer_->CommandPool(), renderer_->supportRayTracing_)); renderer_->SetScene(scene_); diff --git a/src/Vulkan/DepthBuffer.cpp b/src/Vulkan/DepthBuffer.cpp index 518f4a6..c51bf59 100644 --- a/src/Vulkan/DepthBuffer.cpp +++ b/src/Vulkan/DepthBuffer.cpp @@ -47,7 +47,7 @@ namespace Vulkan { { const auto& device = commandPool.Device(); - image_.reset(new Image(device, extent, format_, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)); + image_.reset(new Image(device, extent, 1, format_, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)); imageMemory_.reset(new DeviceMemory(image_->AllocateMemory(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT))); imageView_.reset(new class ImageView(device, image_->Handle(), format_, VK_IMAGE_ASPECT_DEPTH_BIT)); diff --git a/src/Vulkan/Image.cpp b/src/Vulkan/Image.cpp index 8102807..d1d8c63 100644 --- a/src/Vulkan/Image.cpp +++ b/src/Vulkan/Image.cpp @@ -7,14 +7,15 @@ namespace Vulkan { -Image::Image(const class Device& device, const VkExtent2D extent, const VkFormat format) : - Image(device, extent, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, false) +Image::Image(const class Device& device, const VkExtent2D extent, uint32_t miplevel, const VkFormat format) : + Image(device, extent, miplevel, format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, false) { } Image::Image( const class Device& device, const VkExtent2D extent, + const uint32_t miplevel, const VkFormat format, const VkImageTiling tiling, const VkImageUsageFlags usage, @@ -31,7 +32,7 @@ Image::Image( imageInfo.extent.width = extent.width; imageInfo.extent.height = extent.height; imageInfo.extent.depth = 1; - imageInfo.mipLevels = 1; + imageInfo.mipLevels = miplevel; imageInfo.arrayLayers = 1; imageInfo.format = format; imageInfo.tiling = tiling; diff --git a/src/Vulkan/Image.hpp b/src/Vulkan/Image.hpp index e587cab..4175cef 100644 --- a/src/Vulkan/Image.hpp +++ b/src/Vulkan/Image.hpp @@ -17,8 +17,8 @@ namespace Vulkan Image& operator = (const Image&) = delete; Image& operator = (Image&&) = delete; - Image(const Device& device, VkExtent2D extent, VkFormat format); - Image(const Device& device, VkExtent2D extent, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, bool useForExternal = false); + Image(const Device& device, VkExtent2D extent, uint32_t miplevel, VkFormat format); + Image(const Device& device, VkExtent2D extent, uint32_t miplevel, VkFormat format,VkImageTiling tiling, VkImageUsageFlags usage, bool useForExternal = false); Image(Image&& other) noexcept; ~Image(); diff --git a/src/Vulkan/RenderImage.cpp b/src/Vulkan/RenderImage.cpp index 336a947..6de9553 100644 --- a/src/Vulkan/RenderImage.cpp +++ b/src/Vulkan/RenderImage.cpp @@ -18,7 +18,7 @@ namespace Vulkan { bool external, const char* debugName) { - image_.reset(new Image(device, extent, format, tiling, usage, external)); + image_.reset(new Image(device, extent, 1, format, tiling, usage, external)); imageMemory_.reset( new DeviceMemory(image_->AllocateMemory(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, external))); imageView_.reset(new ImageView(device, image_->Handle(), format, VK_IMAGE_ASPECT_COLOR_BIT)); diff --git a/src/Vulkan/VulkanBaseRenderer.cpp b/src/Vulkan/VulkanBaseRenderer.cpp index d22fa83..28c6585 100644 --- a/src/Vulkan/VulkanBaseRenderer.cpp +++ b/src/Vulkan/VulkanBaseRenderer.cpp @@ -411,7 +411,7 @@ namespace Vulkan fence = nullptr; - screenShotImage_.reset(new Image(*device_, swapChain_->Extent(), swapChain_->Format(), VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_DST_BIT)); + screenShotImage_.reset(new Image(*device_, swapChain_->Extent(), 1, swapChain_->Format(), VK_IMAGE_TILING_LINEAR, VK_IMAGE_USAGE_TRANSFER_DST_BIT)); screenShotImageMemory_.reset(new DeviceMemory(screenShotImage_->AllocateMemory(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT))); rtEditorViewport_.reset(new RenderImage(*device_, {1280, 720}, swapChain_->Format(), VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT)); diff --git a/vcpkg_android.bat b/vcpkg_android.bat index e99bb1b..a26d2b5 100644 --- a/vcpkg_android.bat +++ b/vcpkg_android.bat @@ -31,6 +31,8 @@ copy /Y %PROJROOT%\android\custom-triplets\arm64-android.cmake %CD%\triplets\arm curl:arm64-android ^ draco:arm64-android ^ fmt:arm64-android ^ + meshoptimizer:arm64-android ^ + ktx:arm64-android ^ cpp-base64:arm64-android || goto :error cd .. diff --git a/vcpkg_android.sh b/vcpkg_android.sh index 126b349..c820f4a 100755 --- a/vcpkg_android.sh +++ b/vcpkg_android.sh @@ -30,4 +30,6 @@ cp -f ../../android/custom-triplets/arm64-android.cmake ./triplets/arm64-android tinygltf:arm64-android \ draco:arm64-android \ fmt:arm64-android \ + meshoptimizer:arm64-android \ + ktx:arm64-android \ cpp-base64:arm64-android diff --git a/vcpkg_linux.sh b/vcpkg_linux.sh index cbd83e1..6c73516 100755 --- a/vcpkg_linux.sh +++ b/vcpkg_linux.sh @@ -29,4 +29,6 @@ git checkout 2024.08.23 draco:x64-linux \ rapidjson:x64-linux \ fmt:x64-linux \ + meshoptimizer:x64-linux \ + ktx:x64-linux \ cpp-base64:x64-linux diff --git a/vcpkg_macos.sh b/vcpkg_macos.sh index 20a00b3..7a1f272 100755 --- a/vcpkg_macos.sh +++ b/vcpkg_macos.sh @@ -28,4 +28,6 @@ fi draco:x64-osx \ rapidjson:x64-osx \ fmt:x64-osx \ + meshoptimizer:x64-osx \ + ktx:x64-osx \ cpp-base64:x64-osx diff --git a/vcpkg_mingw.sh b/vcpkg_mingw.sh index 295d298..5ef6e48 100644 --- a/vcpkg_mingw.sh +++ b/vcpkg_mingw.sh @@ -30,4 +30,6 @@ git checkout 2024.08.23 draco:x64-mingw-static \ rapidjson:x64-mingw-static \ fmt:x64-mingw-static \ + meshoptimizer:x64-mingw-static \ + ktx:x64-mingw-static \ cpp-base64:x64-mingw-static diff --git a/vcpkg_windows.bat b/vcpkg_windows.bat index 3f825fe..8b130ec 100644 --- a/vcpkg_windows.bat +++ b/vcpkg_windows.bat @@ -34,6 +34,8 @@ vcpkg.exe install --recurse ^ draco:x64-windows-static ^ rapidjson:x64-windows-static ^ fmt:x64-windows-static ^ + meshoptimizer:x64-windows-static ^ + ktx:x64-windows-static ^ cpp-base64:x64-windows-static || goto :error IF "%1" == "avif" (