diff --git a/.vscode/launch.json b/.vscode/launch.json index 3991930..a1f2b9a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,7 +8,7 @@ "name": "Launch", "type": "lldb", "request": "launch", - "program": "${workspaceRoot}/", + "program": "${workspaceRoot}/build/bin/PlumageRender.exe", "args": [], "cwd": "${workspaceRoot}" } diff --git a/3rdparty/stb/stb_image.h b/3rdparty/stb/stb_image.h index 9eedabe..d0aaf2a 100644 Binary files a/3rdparty/stb/stb_image.h and b/3rdparty/stb/stb_image.h differ diff --git a/3rdparty/stb/stb_image_write.h b/3rdparty/stb/stb_image_write.h index e4b32ed..151eaca 100644 --- a/3rdparty/stb/stb_image_write.h +++ b/3rdparty/stb/stb_image_write.h @@ -773,7 +773,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f #ifdef __STDC_LIB_EXT1__ len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else - len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + len = snprintf(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #endif s->func(s->context, buffer, len); diff --git a/3rdparty/tinygltf/README.md b/3rdparty/tinygltf/README.md index 2d9143d..ddf175b 100644 --- a/3rdparty/tinygltf/README.md +++ b/3rdparty/tinygltf/README.md @@ -2,25 +2,36 @@ `TinyGLTF` is a header only C++11 glTF 2.0 https://github.com/KhronosGroup/glTF library. -`TinyGLTF` uses Niels Lohmann's json library(https://github.com/nlohmann/json), so now it requires C++11 compiler. -If you are looking for old, C++03 version, please use `devel-picojson` branch. +`TinyGLTF` uses Niels Lohmann's json library (https://github.com/nlohmann/json), so now it requires C++11 compiler. +(Also, you can use RadpidJSON as an JSON backend) +If you are looking for old, C++03 version, please use `devel-picojson` branch (but not maintained anymore). ## Status +Currently TinyGLTF is stable and maintenance mode. No drastic changes and feature additions planned. + - v2.9.0 Various fixes and improvements. Filesystem callback API change. + - v2.8.0 Add URICallbacks for custom URI handling in Buffer and Image. PR#397 + - v2.7.0 Change WriteImageDataFunction user callback function signature. PR#393 + - v2.6.0 Support serializing sparse accessor(Thanks to @fynv). + - v2.5.0 Add SetPreserveImageChannels() option to load image data as is. - v2.4.0 Experimental RapidJSON support. Experimental C++14 support(C++14 may give better performance) - v2.3.0 Modified Material representation according to glTF 2.0 schema(and introduced TextureInfo class) - v2.2.0 release(Support loading 16bit PNG. Sparse accessor support) - - v2.1.0 release(Draco support) + - v2.1.0 release(Draco decoding support) - v2.0.0 release(22 Aug, 2018)! +### Branches + +* `sajson` : Use sajson to parse JSON. Parsing only but faster compile time(2x reduction compared to json.hpp and RapidJson), but not well maintained. + ## Builds -[![Build Status](https://travis-ci.org/syoyo/tinygltf.svg?branch=devel)](https://travis-ci.org/syoyo/tinygltf) - -[![Build status](https://ci.appveyor.com/api/projects/status/warngenu9wjjhlm8?svg=true)](https://ci.appveyor.com/project/syoyo/tinygltf) +![C/C++ CI](https://github.com/syoyo/tinygltf/workflows/C/C++%20CI/badge.svg) ## Features +Probably mostly feature-complete. Last missing feature is Draco encoding: https://github.com/syoyo/tinygltf/issues/207 + * Written in portable C++. C++-11 with STL dependency only. * [x] macOS + clang(LLVM) * [x] iOS + clang @@ -71,6 +82,13 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number * [glview](examples/glview) : Simple glTF geometry viewer. * [validator](examples/validator) : Simple glTF validator with JSON schema. * [basic](examples/basic) : Basic glTF viewer with texturing support. +* [build-gltf](examples/build-gltf) : Build simple glTF scene from a scratch. + +### WASI/WASM build + +Users who want to run TinyGLTF securely and safely(e.g. need to handle malcious glTF file to serve online glTF conver), +I recommend to build TinyGLTF for WASM target. +WASI build example is located in [wasm](wasm) . ## Projects using TinyGLTF @@ -83,11 +101,16 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number * [QuickLook GLTF](https://github.com/toshiks/glTF-quicklook) - quicklook plugin for macos. Also SceneKit wrapper for tinygltf. * [GlslViewer](https://github.com/patriciogonzalezvivo/glslViewer) - live GLSL coding for MacOS and Linux * [Vulkan-Samples](https://github.com/KhronosGroup/Vulkan-Samples) - The Vulkan Samples is collection of resources to help you develop optimized Vulkan applications. +* [TDME2](https://github.com/andreasdr/tdme2) - TDME2 - ThreeDeeMiniEngine2 is a lightweight 3D engine including tools suited for 3D game development using C++11 +* [SanityEngine](https://github.com/DethRaid/SanityEngine) - A C++/D3D12 renderer focused on the personal and professional development of its developer +* [Open3D](http://www.open3d.org/) - A Modern Library for 3D Data Processing +* [Supernova Engine](https://github.com/supernovaengine/supernova) - Game engine for 2D and 3D projects with Lua or C++ in data oriented design. +* [Wicked Engine](https://github.com/turanszkij/WickedEngine) - 3D engine with modern graphics * Your projects here! (Please send PR) ## TODOs -* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing. +* [ ] Robust URI decoding/encoding. https://github.com/syoyo/tinygltf/issues/369 * [ ] Mesh Compression/decompression(Open3DGC, etc) * [x] Load Draco compressed mesh * [ ] Save Draco compressed mesh @@ -98,6 +121,10 @@ In extension(`ExtensionMap`), JSON number value is parsed as int or float(number * [ ] 16bit PNG support in Serialization * [ ] Write example and tests for `animation` and `skin` +### Optional + +* [ ] Write C++ code generator which emits C++ code from JSON schema for robust parsing? + ## Licenses TinyGLTF is licensed under MIT license. @@ -130,9 +157,10 @@ Model model; TinyGLTF loader; std::string err; std::string warn; +std::string filename = "input.gltf"; -bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, argv[1]); -//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, argv[1]); // for binary glTF(.glb) +bool ret = loader.LoadASCIIFromFile(&model, &err, &warn, filename); +//bool ret = loader.LoadBinaryFromFile(&model, &err, &warn, filename); // for binary glTF(.glb) if (!warn.empty()) { printf("Warn: %s\n", warn.c_str()); @@ -143,11 +171,14 @@ if (!err.empty()) { } if (!ret) { - printf("Failed to parse glTF\n"); - return -1; + printf("Failed to parse glTF: %s\n", filename.c_str()); } ``` +#### Loader options + +* `TinyGLTF::SetPreserveimageChannels(bool onoff)`. `true` to preserve image channels as stored in image file for loaded image. `false` by default for backward compatibility(image channels are widen to `RGBA` 4 channels). Effective only when using builtin image loader(STB image loader). + ## Compile options * `TINYGLTF_NOEXCEPTION` : Disable C++ exception in JSON parsing. You can use `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION` and `TINYGLTF_NOEXCEPTION` to fully remove C++ exception codes when compiling TinyGLTF. @@ -157,12 +188,32 @@ if (!ret) { * `TINYGLTF_ANDROID_LOAD_FROM_ASSETS`: Load all files from packaged app assets instead of the regular file system. **Note:** You must pass a valid asset manager from your android app to `tinygltf::asset_manager` beforehand. * `TINYGLTF_ENABLE_DRACO`: Enable Draco compression. User must provide include path and link correspnding libraries in your project file. * `TINYGLTF_NO_INCLUDE_JSON `: Disable including `json.hpp` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`. +* `TINYGLTF_NO_INCLUDE_RAPIDJSON `: Disable including RapidJson's header files from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`. * `TINYGLTF_NO_INCLUDE_STB_IMAGE `: Disable including `stb_image.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`. * `TINYGLTF_NO_INCLUDE_STB_IMAGE_WRITE `: Disable including `stb_image_write.h` from within `tiny_gltf.h` because it has been already included before or you want to include it using custom path before including `tiny_gltf.h`. -* `TINYGLTF_USE_RAPIDJSON` : Use RapidJSON as a JSON parser/serializer. RapidJSON files are not included in TinyGLTF repo. Please set an include path to RapidJSON if you enable this featrure. -* `TINYGLTF_USE_CPP14` : Use C++14 feature(requires C++14 compiler). This may give better performance than C++11. +* `TINYGLTF_USE_RAPIDJSON` : Use RapidJSON as a JSON parser/serializer. RapidJSON files are not included in TinyGLTF repo. Please set an include path to RapidJSON if you enable this feature. +## CMake options + +You can add tinygltf using `add_subdirectory` feature. +If you add tinygltf to your project using `add_subdirectory`, it would be better to set `TINYGLTF_HEADER_ONLY` on(just add an include path to tinygltf) and `TINYGLTF_INSTALL` off(Which does not install tinygltf files). + +``` +// Your project's CMakeLists.txt +... + +set(TINYGLTF_HEADER_ONLY ON CACHE INTERNAL "" FORCE) +set(TINYGLTF_INSTALL OFF CACHE INTERNAL "" FORCE) +add_subdirectory(/path/to/tinygltf) +``` + +NOTE: Using tinygltf as a submodule doesn't automatically add the headers to your include path (as standard for many libraries). To get this functionality, add the following to the CMakeLists.txt file from above: + +``` +target_include_directories(${PROJECT_NAME} PRIVATE "/path/to/tinygltf") +``` + ### Saving gltTF 2.0 model * Buffers. @@ -182,7 +233,7 @@ if (!ret) { #### Setup -Python 2.6 or 2.7 required. +Python required. Git clone https://github.com/KhronosGroup/glTF-Sample-Models to your local dir. #### Run parsing test diff --git a/3rdparty/tinygltf/json.hpp b/3rdparty/tinygltf/json.hpp index c9af0be..87475ab 100644 Binary files a/3rdparty/tinygltf/json.hpp and b/3rdparty/tinygltf/json.hpp differ diff --git a/3rdparty/tinygltf/stb_image.h b/3rdparty/tinygltf/stb_image.h deleted file mode 100644 index 8b71060..0000000 Binary files a/3rdparty/tinygltf/stb_image.h and /dev/null differ diff --git a/3rdparty/tinygltf/tiny_gltf.h b/3rdparty/tinygltf/tiny_gltf.h index 710e9d9..7e62630 100644 Binary files a/3rdparty/tinygltf/tiny_gltf.h and b/3rdparty/tinygltf/tiny_gltf.h differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 521fab3..0ad268d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,9 +64,6 @@ if(WIN32) ${GLTF_MODEL_LOADER} ${VULKAN_BASE} ${PBR} - - "render/renderFoundation.h" - "render/renderFoundation.cpp" ) target_link_libraries(${RenderName} base ${Vulkan_LIBRARY} ${WINLIBS}) endif() diff --git a/src/base/VulkanDevice.cpp b/src/base/VulkanDevice.cpp index 5a6670d..89968ea 100644 --- a/src/base/VulkanDevice.cpp +++ b/src/base/VulkanDevice.cpp @@ -43,6 +43,80 @@ VulkanDevice::~VulkanDevice() } } +/// @brief 据分配的物理设备创建逻辑设备,同时获取默认队列族索引 +/// @param enabledFeatures 在创建设备时启用某些功能 +/// @param enabledExtensions 在创建设备时启用某些扩展 +/// @param requestedQueueTypes 指定要从设备请求的队列类型 +/// @return 逻辑设备是否成功创建 +VkResult VulkanDevice::createLogicalDevice(VkPhysicalDeviceFeatures enabledFeatures, std::vector enabledExtensions, VkQueueFlags requestedQueueTypes) +{ + std::vector queueCreateInfos{}; + const float defaultQueuePriority(0.0f); + // Graphics queue + if (requestedQueueTypes & VK_QUEUE_GRAPHICS_BIT) + { + m_queueFamilyIndices.graphics = getQueueFamilyIndex(VK_QUEUE_GRAPHICS_BIT); + VkDeviceQueueCreateInfo queueInfo{}; + queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueInfo.queueFamilyIndex = m_queueFamilyIndices.graphics; + queueInfo.queueCount = 1; + queueInfo.pQueuePriorities = &defaultQueuePriority; + queueCreateInfos.push_back(queueInfo); + } + else + { + m_queueFamilyIndices.graphics = 0; + } + + // Dedicated compute queue + if (requestedQueueTypes & VK_QUEUE_COMPUTE_BIT) + { + m_queueFamilyIndices.compute = getQueueFamilyIndex(VK_QUEUE_COMPUTE_BIT); + if (m_queueFamilyIndices.compute != m_queueFamilyIndices.graphics) + { + // If compute family index differs, we need an additional queue create info for the compute queue + VkDeviceQueueCreateInfo queueInfo{}; + queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueInfo.queueFamilyIndex = m_queueFamilyIndices.compute; + queueInfo.queueCount = 1; + queueInfo.pQueuePriorities = &defaultQueuePriority; + queueCreateInfos.push_back(queueInfo); + } + } + else + { + m_queueFamilyIndices.compute = m_queueFamilyIndices.graphics; + } + + // Create the logical device representation + std::vector deviceExtensions(enabledExtensions); + deviceExtensions.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + + VkDeviceCreateInfo deviceCreateInfo = {}; + deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceCreateInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); + ; + deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data(); + deviceCreateInfo.pEnabledFeatures = &enabledFeatures; + + if (deviceExtensions.size() > 0) + { + deviceCreateInfo.enabledExtensionCount = (uint32_t)deviceExtensions.size(); + deviceCreateInfo.ppEnabledExtensionNames = deviceExtensions.data(); + } + + VkResult result = vkCreateDevice(m_physicalDevice, &deviceCreateInfo, nullptr, &m_logicalDevice); + + if (result == VK_SUCCESS) + { + m_commandPool = createCommandPool(m_queueFamilyIndices.graphics); + } + + m_enabledFeatures = enabledFeatures; + + return result; +} + VkDevice VulkanDevice::getLogicalDevice() { return m_logicalDevice; diff --git a/src/base/VulkanTools.h b/src/base/VulkanTools.h index de4f15f..06c9660 100644 --- a/src/base/VulkanTools.h +++ b/src/base/VulkanTools.h @@ -4,7 +4,6 @@ #include "VulkanInitializers.hpp" #include "vulkan/vulkan.h" - #include #include #include diff --git a/src/gltf/glTFMainModel.cpp b/src/gltf/glTFMainModel.cpp index 5d47b4a..569c490 100644 --- a/src/gltf/glTFMainModel.cpp +++ b/src/gltf/glTFMainModel.cpp @@ -1,6 +1,18 @@ #include "glTFMainModel.h" +#include "glTFMaterial.h" +#include "glTFNode.h" #include + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" +#include "stb_image_write.h" + +#define TINYGLTF_IMPLEMENTATION +#define TINYGLTF_NO_INCLUDE_STB_IMAGE +#include + #include +#include GLTFLOADER_NAMESPACE_BEGIN @@ -1071,4 +1083,34 @@ glTFNode *glTFMainModel::nodeFromIndex(uint32_t index) return nodeFound; } +std::vector glTFMainModel::getNodes() +{ + return m_nodes; +} + +std::vector glTFMainModel::getMaterials() +{ + return m_materials; +} + +std::vector glTFMainModel::getAnimations() +{ + return m_animations; +} + +std::vector glTFMainModel::getExtensions() +{ + return m_extensions; +} + +std::vector glTFMainModel::getLinearNodes() +{ + return m_linearNodes; +} + +glm::mat4 glTFMainModel::getAABB() +{ + return m_aabb; +} + GLTFLOADER_NAMESPACE_END diff --git a/src/gltf/glTFMainModel.h b/src/gltf/glTFMainModel.h index 1cbb029..a6bd4d8 100644 --- a/src/gltf/glTFMainModel.h +++ b/src/gltf/glTFMainModel.h @@ -1,9 +1,8 @@ #ifndef GLTFMAINMODEL_H #define GLTFMAINMODEL_H -#ifndef TINYGLTF_NO_STB_IMAGE_WRITE -#define TINYGLTF_NO_STB_IMAGE_WRITE -#endif +#include "glTFMaterial.h" +#include "glm/detail/type_mat.hpp" #include "glTFModel_Marco.h" #include "glTFModel_common.h" @@ -15,8 +14,6 @@ #include "glTFSkin.h" #include "glTFTexture.h" -#include - #include #include #include @@ -67,6 +64,13 @@ public: glTFNode *findNode(glTFNode *parent, uint32_t index); glTFNode *nodeFromIndex(uint32_t index); + std::vector getNodes(); + std::vector getLinearNodes(); + std::vector getMaterials(); + std::vector getAnimations(); + std::vector getExtensions(); + glm::mat4 getAABB(); + private: VulkanBase::VulkanDevice *m_device; diff --git a/src/gltf/glTFModel.h b/src/gltf/glTFModel.h index 6fae447..34c1a1d 100644 --- a/src/gltf/glTFModel.h +++ b/src/gltf/glTFModel.h @@ -20,12 +20,6 @@ #include #include - -#ifndef TINYGLTF_NO_STB_IMAGE_WRITE -#define TINYGLTF_NO_STB_IMAGE_WRITE -#endif // - - #ifdef VK_USE_PLATFORM_ANDROID_KHR #define TINYGLTF_ANDROID_LOAD_FROM_ASSETS #endif diff --git a/src/gltf/glTFTexture.cpp b/src/gltf/glTFTexture.cpp index 068b33f..b2952d4 100644 --- a/src/gltf/glTFTexture.cpp +++ b/src/gltf/glTFTexture.cpp @@ -13,258 +13,266 @@ glTFTexture::~glTFTexture() void glTFTexture::updateDescriptor() { - m_descriptor.sampler = m_sampler; - m_descriptor.imageView = m_view; - m_descriptor.imageLayout = m_imageLayout; + m_descriptor.sampler = m_sampler; + m_descriptor.imageView = m_view; + m_descriptor.imageLayout = m_imageLayout; +} + +VkDescriptorImageInfo glTFTexture::getDescriptor() +{ + return m_descriptor; } void glTFTexture::destroy() { - VkDevice logicalDevice = m_device->getLogicalDevice(); - vkDestroyImageView(logicalDevice, m_view, nullptr); - vkDestroyImage(logicalDevice, m_image, nullptr); - vkFreeMemory(logicalDevice, m_deviceMemory, nullptr); - vkDestroySampler(logicalDevice, m_sampler, nullptr); - + VkDevice logicalDevice = m_device->getLogicalDevice(); + vkDestroyImageView(logicalDevice, m_view, nullptr); + vkDestroyImage(logicalDevice, m_image, nullptr); + vkFreeMemory(logicalDevice, m_deviceMemory, nullptr); + vkDestroySampler(logicalDevice, m_sampler, nullptr); } -void glTFTexture::fromglTfImage(tinygltf::Image& gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice* device, VkQueue copyQueue) +void glTFTexture::fromglTfImage(tinygltf::Image &gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice *device, VkQueue copyQueue) { - VkDevice logicalDevice = device->getLogicalDevice(); - unsigned char* buffer = nullptr; - VkDeviceSize bufferSize = 0; - bool deleteBuffer = false; - if (gltfimage.component == 3) { - /// 即使创建为24bit的rgb,硬件上依旧是rgba,因此填充alpha值,但带宽压力上升25% - /// 可选todo:采用计算着色器将rgb写入uniform buffer - bufferSize = gltfimage.width * gltfimage.height * 4; - buffer = new unsigned char[bufferSize]; - unsigned char* rgba = buffer; - unsigned char* rgb = &gltfimage.image[0]; - for (int32_t i = 0; i < gltfimage.width * gltfimage.height; ++i) { - for (int32_t j = 0; j < 3; ++j) { - rgba[j] = rgb[j]; - } - rgba += 4; - rgb += 3; - } - deleteBuffer = true; - } - else { - buffer = &gltfimage.image[0]; - bufferSize = gltfimage.image.size(); - } + VkDevice logicalDevice = device->getLogicalDevice(); + unsigned char *buffer = nullptr; + VkDeviceSize bufferSize = 0; + bool deleteBuffer = false; + if (gltfimage.component == 3) + { + /// 即使创建为24bit的rgb,硬件上依旧是rgba,因此填充alpha值,但带宽压力上升25% + /// 可选todo:采用计算着色器将rgb写入uniform buffer + bufferSize = gltfimage.width * gltfimage.height * 4; + buffer = new unsigned char[bufferSize]; + unsigned char *rgba = buffer; + unsigned char *rgb = &gltfimage.image[0]; + for (int32_t i = 0; i < gltfimage.width * gltfimage.height; ++i) + { + for (int32_t j = 0; j < 3; ++j) + { + rgba[j] = rgb[j]; + } + rgba += 4; + rgb += 3; + } + deleteBuffer = true; + } + else + { + buffer = &gltfimage.image[0]; + bufferSize = gltfimage.image.size(); + } - VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; + VkFormat format = VK_FORMAT_R8G8B8A8_UNORM; - VkFormatProperties formatProperties; + VkFormatProperties formatProperties; - m_width = gltfimage.width; - m_height = gltfimage.height; - m_mipLevels = static_cast(floor(log2(std::max(m_width, m_height))) + 1.0); + m_width = gltfimage.width; + m_height = gltfimage.height; + m_mipLevels = static_cast(floor(log2(std::max(m_width, m_height))) + 1.0); - vkGetPhysicalDeviceFormatProperties(device->getPhysicalDevice(), format, &formatProperties); - assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT); - assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT); - /// 分配存放缓冲区的设备内存 - VkMemoryAllocateInfo memAllocInfo{}; - memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - VkMemoryRequirements memReqs{}; + vkGetPhysicalDeviceFormatProperties(device->getPhysicalDevice(), format, &formatProperties); + assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_SRC_BIT); + assert(formatProperties.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT); + /// 分配存放缓冲区的设备内存 + VkMemoryAllocateInfo memAllocInfo{}; + memAllocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + VkMemoryRequirements memReqs{}; - VkBuffer stagingBuffer; - VkDeviceMemory stagingMemory; + VkBuffer stagingBuffer; + VkDeviceMemory stagingMemory; - VkBufferCreateInfo bufferCreateInfo{}; - bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferCreateInfo.size = bufferSize; - bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer)); - vkGetBufferMemoryRequirements(logicalDevice, stagingBuffer, &memReqs); - memAllocInfo.allocationSize = memReqs.size; - memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory)); - VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, stagingBuffer, stagingMemory, 0)); - // 向设备内存中写入缓冲区 - uint8_t* data; - VK_CHECK_RESULT(vkMapMemory(logicalDevice, stagingMemory, 0, memReqs.size, 0, (void**)&data)); - memcpy(data, buffer, bufferSize); - vkUnmapMemory(logicalDevice, stagingMemory); - /// 创建图片类型设备内存 - VkImageCreateInfo imageCreateInfo{}; - imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - imageCreateInfo.format = format; - imageCreateInfo.mipLevels = m_mipLevels; - imageCreateInfo.arrayLayers = 1; - imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageCreateInfo.extent = { m_width, m_height, 1 }; - imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &m_image)); - vkGetImageMemoryRequirements(logicalDevice, m_image, &memReqs); - memAllocInfo.allocationSize = memReqs.size; - memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &m_deviceMemory)); - VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, m_image, m_deviceMemory, 0)); - /// 分配复制命令缓冲区 - VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + VkBufferCreateInfo bufferCreateInfo{}; + bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferCreateInfo.size = bufferSize; + bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + VK_CHECK_RESULT(vkCreateBuffer(logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer)); + vkGetBufferMemoryRequirements(logicalDevice, stagingBuffer, &memReqs); + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &stagingMemory)); + VK_CHECK_RESULT(vkBindBufferMemory(logicalDevice, stagingBuffer, stagingMemory, 0)); + // 向设备内存中写入缓冲区 + uint8_t *data; + VK_CHECK_RESULT(vkMapMemory(logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data)); + memcpy(data, buffer, bufferSize); + vkUnmapMemory(logicalDevice, stagingMemory); + /// 创建图片类型设备内存 + VkImageCreateInfo imageCreateInfo{}; + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.format = format; + imageCreateInfo.mipLevels = m_mipLevels; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCreateInfo.extent = {m_width, m_height, 1}; + imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + VK_CHECK_RESULT(vkCreateImage(logicalDevice, &imageCreateInfo, nullptr, &m_image)); + vkGetImageMemoryRequirements(logicalDevice, m_image, &memReqs); + memAllocInfo.allocationSize = memReqs.size; + memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + VK_CHECK_RESULT(vkAllocateMemory(logicalDevice, &memAllocInfo, nullptr, &m_deviceMemory)); + VK_CHECK_RESULT(vkBindImageMemory(logicalDevice, m_image, m_deviceMemory, 0)); + /// 分配复制命令缓冲区 + VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - VkImageSubresourceRange subresourceRange = {}; - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subresourceRange.levelCount = 1; - subresourceRange.layerCount = 1; + VkImageSubresourceRange subresourceRange = {}; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.levelCount = 1; + subresourceRange.layerCount = 1; - { - /// 插入barrier,强制管线等待上方指令完成 - VkImageMemoryBarrier imageMemoryBarrier{}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imageMemoryBarrier.srcAccessMask = 0; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - imageMemoryBarrier.image = m_image; - imageMemoryBarrier.subresourceRange = subresourceRange; - vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); - } + { + /// 插入barrier,强制管线等待上方指令完成 + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.image = m_image; + imageMemoryBarrier.subresourceRange = subresourceRange; + vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + } - VkBufferImageCopy bufferCopyRegion = {}; - bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - bufferCopyRegion.imageSubresource.mipLevel = 0; - bufferCopyRegion.imageSubresource.baseArrayLayer = 0; - bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent.width = m_width; - bufferCopyRegion.imageExtent.height = m_height; - bufferCopyRegion.imageExtent.depth = 1; + VkBufferImageCopy bufferCopyRegion = {}; + bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + bufferCopyRegion.imageSubresource.mipLevel = 0; + bufferCopyRegion.imageSubresource.baseArrayLayer = 0; + bufferCopyRegion.imageSubresource.layerCount = 1; + bufferCopyRegion.imageExtent.width = m_width; + bufferCopyRegion.imageExtent.height = m_height; + bufferCopyRegion.imageExtent.depth = 1; - vkCmdCopyBufferToImage(copyCmd, stagingBuffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); + vkCmdCopyBufferToImage(copyCmd, stagingBuffer, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &bufferCopyRegion); - { - /// 插入barrier,管线等待copy操作完成 - VkImageMemoryBarrier imageMemoryBarrier{}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - imageMemoryBarrier.image = m_image; - imageMemoryBarrier.subresourceRange = subresourceRange; - vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); - } - /// 提交到命令队列 - device->flushCommandBuffer(copyCmd, copyQueue, true); - /// 销毁图片buffer存储的设备内存 - vkFreeMemory(logicalDevice, stagingMemory, nullptr); - /// 销毁图片buffer存储的设备缓冲区 - vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr); + { + /// 插入barrier,管线等待copy操作完成 + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + imageMemoryBarrier.image = m_image; + imageMemoryBarrier.subresourceRange = subresourceRange; + vkCmdPipelineBarrier(copyCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + } + /// 提交到命令队列 + device->flushCommandBuffer(copyCmd, copyQueue, true); + /// 销毁图片buffer存储的设备内存 + vkFreeMemory(logicalDevice, stagingMemory, nullptr); + /// 销毁图片buffer存储的设备缓冲区 + vkDestroyBuffer(logicalDevice, stagingBuffer, nullptr); - // 生成mip-map链 (glTF 使用 jpg 和 png 格式, 需要当场生成mip-map) - VkCommandBuffer blitCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - for (uint32_t i = 1; i < m_mipLevels; i++) { - VkImageBlit imageBlit{}; + // 生成mip-map链 (glTF 使用 jpg 和 png 格式, 需要当场生成mip-map) + VkCommandBuffer blitCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); + for (uint32_t i = 1; i < m_mipLevels; i++) + { + VkImageBlit imageBlit{}; - imageBlit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageBlit.srcSubresource.layerCount = 1; - imageBlit.srcSubresource.mipLevel = i - 1; - imageBlit.srcOffsets[1].x = int32_t(m_width >> (i - 1)); - imageBlit.srcOffsets[1].y = int32_t(m_height >> (i - 1)); - imageBlit.srcOffsets[1].z = 1; + imageBlit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageBlit.srcSubresource.layerCount = 1; + imageBlit.srcSubresource.mipLevel = i - 1; + imageBlit.srcOffsets[1].x = int32_t(m_width >> (i - 1)); + imageBlit.srcOffsets[1].y = int32_t(m_height >> (i - 1)); + imageBlit.srcOffsets[1].z = 1; - imageBlit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageBlit.dstSubresource.layerCount = 1; - imageBlit.dstSubresource.mipLevel = i; - imageBlit.dstOffsets[1].x = int32_t(m_width >> i); - imageBlit.dstOffsets[1].y = int32_t(m_height >> i); - imageBlit.dstOffsets[1].z = 1; + imageBlit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageBlit.dstSubresource.layerCount = 1; + imageBlit.dstSubresource.mipLevel = i; + imageBlit.dstOffsets[1].x = int32_t(m_width >> i); + imageBlit.dstOffsets[1].y = int32_t(m_height >> i); + imageBlit.dstOffsets[1].z = 1; - VkImageSubresourceRange mipSubRange = {}; - mipSubRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - mipSubRange.baseMipLevel = i; - mipSubRange.levelCount = 1; - mipSubRange.layerCount = 1; + VkImageSubresourceRange mipSubRange = {}; + mipSubRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + mipSubRange.baseMipLevel = i; + mipSubRange.levelCount = 1; + mipSubRange.layerCount = 1; - { - VkImageMemoryBarrier imageMemoryBarrier{}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imageMemoryBarrier.srcAccessMask = 0; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - imageMemoryBarrier.image = m_image; - imageMemoryBarrier.subresourceRange = mipSubRange; - vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); - } + { + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.srcAccessMask = 0; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.image = m_image; + imageMemoryBarrier.subresourceRange = mipSubRange; + vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + } - vkCmdBlitImage(blitCmd, m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageBlit, VK_FILTER_LINEAR); + vkCmdBlitImage(blitCmd, m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageBlit, VK_FILTER_LINEAR); - { - VkImageMemoryBarrier imageMemoryBarrier{}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - imageMemoryBarrier.image = m_image; - imageMemoryBarrier.subresourceRange = mipSubRange; - vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); - } - } + { + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + imageMemoryBarrier.image = m_image; + imageMemoryBarrier.subresourceRange = mipSubRange; + vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + } + } - subresourceRange.levelCount = m_mipLevels; - m_imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + subresourceRange.levelCount = m_mipLevels; + m_imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - { - VkImageMemoryBarrier imageMemoryBarrier{}; - imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - imageMemoryBarrier.image = m_image; - imageMemoryBarrier.subresourceRange = subresourceRange; - vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); - } + { + VkImageMemoryBarrier imageMemoryBarrier{}; + imageMemoryBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + imageMemoryBarrier.image = m_image; + imageMemoryBarrier.subresourceRange = subresourceRange; + vkCmdPipelineBarrier(blitCmd, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); + } - m_device->flushCommandBuffer(blitCmd, copyQueue, true); + m_device->flushCommandBuffer(blitCmd, copyQueue, true); - /// 创建贴图采样器 - VkSamplerCreateInfo samplerInfo{}; - samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerInfo.magFilter = textureSampler.getMaxFilter(); - samplerInfo.minFilter = textureSampler.getMinFilter(); - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerInfo.addressModeU = textureSampler.getAddressModeU(); - samplerInfo.addressModeV = textureSampler.getAddressModeV(); - samplerInfo.addressModeW = textureSampler.getAddressModeW(); - samplerInfo.compareOp = VK_COMPARE_OP_NEVER; - samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - samplerInfo.maxAnisotropy = 1.0; - samplerInfo.anisotropyEnable = VK_FALSE; - samplerInfo.maxLod = (float)m_mipLevels; - samplerInfo.maxAnisotropy = 8.0f; - samplerInfo.anisotropyEnable = VK_TRUE; - VK_CHECK_RESULT(vkCreateSampler(logicalDevice, &samplerInfo, nullptr, &m_sampler)); + /// 创建贴图采样器 + VkSamplerCreateInfo samplerInfo{}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = textureSampler.getMaxFilter(); + samplerInfo.minFilter = textureSampler.getMinFilter(); + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.addressModeU = textureSampler.getAddressModeU(); + samplerInfo.addressModeV = textureSampler.getAddressModeV(); + samplerInfo.addressModeW = textureSampler.getAddressModeW(); + samplerInfo.compareOp = VK_COMPARE_OP_NEVER; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; + samplerInfo.maxAnisotropy = 1.0; + samplerInfo.anisotropyEnable = VK_FALSE; + samplerInfo.maxLod = (float)m_mipLevels; + samplerInfo.maxAnisotropy = 8.0f; + samplerInfo.anisotropyEnable = VK_TRUE; + VK_CHECK_RESULT(vkCreateSampler(logicalDevice, &samplerInfo, nullptr, &m_sampler)); - /// 创建图片的数据视图,用于读写图片 - VkImageViewCreateInfo viewInfo{}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = m_image; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = format; - viewInfo.components = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A }; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.layerCount = 1; - viewInfo.subresourceRange.levelCount = m_mipLevels; - VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewInfo, nullptr, &m_view)); + /// 创建图片的数据视图,用于读写图片 + VkImageViewCreateInfo viewInfo{}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = m_image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = format; + viewInfo.components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B, VK_COMPONENT_SWIZZLE_A}; + viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + viewInfo.subresourceRange.layerCount = 1; + viewInfo.subresourceRange.levelCount = m_mipLevels; + VK_CHECK_RESULT(vkCreateImageView(logicalDevice, &viewInfo, nullptr, &m_view)); - updateDescriptor(); - - if (deleteBuffer) - delete[] buffer; + updateDescriptor(); + if (deleteBuffer) + delete[] buffer; } GLTFLOADER_NAMESPACE_END \ No newline at end of file diff --git a/src/gltf/glTFTexture.h b/src/gltf/glTFTexture.h index ae93278..d0c9f4f 100644 --- a/src/gltf/glTFTexture.h +++ b/src/gltf/glTFTexture.h @@ -5,6 +5,7 @@ #include "VulkanDevice.h" #include "VulkanTextureSampler.h" +#include "vulkan/vulkan_core.h" #include @@ -23,6 +24,8 @@ public: void fromglTfImage(tinygltf::Image &gltfimage, VulkanBase::VulkanTextureSampler textureSampler, VulkanBase::VulkanDevice *device, VkQueue copyQueue); + VkDescriptorImageInfo getDescriptor(); + private: VulkanBase::VulkanDevice *m_device; VkImage m_image; diff --git a/src/render/IndexStagingBuffer.h b/src/render/IndexStagingBuffer.h index f3dabde..a459f3f 100644 --- a/src/render/IndexStagingBuffer.h +++ b/src/render/IndexStagingBuffer.h @@ -1,5 +1,5 @@ #pragma once -#include "RenderStagingBuffer.h" +#include "renderStagingBuffer.h" class IndexStagingBuffer : public RenderStagingBuffer { public: diff --git a/src/render/RenderPushBlock.cpp b/src/render/RenderPushBlock.cpp index 6be630f..f366aa5 100644 --- a/src/render/RenderPushBlock.cpp +++ b/src/render/RenderPushBlock.cpp @@ -1,5 +1,12 @@ #include "RenderPushBlock.h" +RenderPushBlock::RenderPushBlock() +{ +} +RenderPushBlock::~RenderPushBlock() +{ +} + // Getter method definitions const glm::mat4 &RenderPushBlock::getMvp() const { diff --git a/src/render/VertexStagingBuffer.h b/src/render/VertexStagingBuffer.h index c61f657..c8bb1bb 100644 --- a/src/render/VertexStagingBuffer.h +++ b/src/render/VertexStagingBuffer.h @@ -1,5 +1,5 @@ #pragma once -#include "renderStagingBuffer.h" +#include "RenderStagingBuffer.h" class VertexStagingBuffer : public RenderStagingBuffer { public: diff --git a/src/render/render.cpp b/src/render/render.cpp index 9267a79..41fcc9f 100644 --- a/src/render/render.cpp +++ b/src/render/render.cpp @@ -1,34 +1,30 @@ -#pragma once - + #include "render.h" - #include "PbrBaseTexture.h" #include "PbrTextureCoordSet.h" +#include "glTFAnimation.h" #include "glTFMainModel.h" +#include "glTFMesh.h" +#include "glTFModel_common.h" #include "PushConstBlockMaterial.h" #include "ShaderLoader.h" #include "VulkanTexture.h" #include "glTFMaterial.h" + +#include "glTFNode.h" #include "glTFPrimitive.h" -#include "glTFSkin.h" + #include "glTFTexture.h" #include "glm/gtc/matrix_transform.hpp" #include "renderUniformBufferSet.h" +#include "vulkan/vulkan_core.h" #include #include #include -#ifndef STB_IMAGE_IMPLEMENTATION -#define STB_IMAGE_IMPLEMENTATION -#endif - -#ifndef TINYGLTF_NO_STB_IMAGE_WRITE -#define TINYGLTF_NO_STB_IMAGE_WRITE -#endif - // #include "VulkanUtils.hpp" // #include "assetLoader.h" @@ -270,22 +266,23 @@ void PlumageRender::buildCommandBuffers() } boundPipeline = VK_NULL_HANDLE; + std::vector modelNodes = model.getNodes(); // Opaque primitives first - for (auto node : model.nodes) + for (auto node : modelNodes) { - renderNode(node, i, glTFModel::Material::ALPHAMODE_OPAQUE); + renderNode(node, i, glTFLoader::ALPHAMODE_OPAQUE); } // Alpha masked primitives - for (auto node : model.nodes) + for (auto node : modelNodes) { - renderNode(node, i, glTFModel::Material::ALPHAMODE_MASK); + renderNode(node, i, glTFLoader::ALPHAMODE_MASK); } // Transparent primitives // TODO: Correct depth sorting - for (auto node : model.nodes) + for (auto node : modelNodes) { - renderNode(node, i, glTFModel::Material::ALPHAMODE_BLEND); + renderNode(node, i, glTFLoader::ALPHAMODE_BLEND); } // User interface @@ -381,12 +378,14 @@ void PlumageRender::loadAssets() loadEnvironment(envMapFile.c_str()); } -void PlumageRender::setupNodeDescriptorSet(glTFModel::Node *node) +void PlumageRender::setupNodeDescriptorSet(glTFLoader::glTFNode *node) { /* This sample uses separate descriptor sets (and layouts) for the matrices and materials (textures) */ - if (node->mesh) + glTFLoader::glTFMesh *mesh = node->getMesh(); + + if (mesh) { VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -394,19 +393,21 @@ void PlumageRender::setupNodeDescriptorSet(glTFModel::Node *node) VkDescriptorSetLayout nodeDescriptorSetLayout = m_descriptorSetLayoutList.getNode(); descriptorSetAllocInfo.pSetLayouts = &nodeDescriptorSetLayout; descriptorSetAllocInfo.descriptorSetCount = 1; - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &node->mesh->uniformBuffer.descriptorSet)); + VkDescriptorSet descriptorSet = mesh->getUniformBuffer().descriptorSet; + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &descriptorSet)); VkWriteDescriptorSet writeDescriptorSet{}; writeDescriptorSet.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptorSet.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; writeDescriptorSet.descriptorCount = 1; - writeDescriptorSet.dstSet = node->mesh->uniformBuffer.descriptorSet; + writeDescriptorSet.dstSet = mesh->getUniformBuffer().descriptorSet; writeDescriptorSet.dstBinding = 0; - writeDescriptorSet.pBufferInfo = &node->mesh->uniformBuffer.descriptor; + VkDescriptorBufferInfo descriptor = mesh->getUniformBuffer().descriptor; + writeDescriptorSet.pBufferInfo = &descriptor; vkUpdateDescriptorSets(device, 1, &writeDescriptorSet, 0, nullptr); } - for (auto &child : node->children) + for (auto &child : node->getChildren()) { setupNodeDescriptorSet(child); } @@ -424,17 +425,21 @@ void PlumageRender::setupDescriptors() // Environment samplers (radiance, irradiance, brdflut) imageSamplerCount += 3; - std::vector modellist = {&m_sceneModel.getSkyBox(), &m_sceneModel.getScene()}; + std::vector modellist = {&m_sceneModel.getSkyBox(), &m_sceneModel.getScene()}; for (auto &model : modellist) { - for (auto &material : model->materials) + std::vector materials = model->getMaterials(); + for (auto &material : materials) { imageSamplerCount += 5; materialCount++; } - for (auto node : model->linearNodes) + + std::vector linearNodes = model->getLinearNodes(); + + for (auto node : linearNodes) { - if (node->mesh) + if (node->getMesh()) { meshCount++; } @@ -542,7 +547,7 @@ void PlumageRender::setupDescriptors() VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &materialDescriptorSetLayout)); // Per-Material descriptor sets - for (auto &material : m_sceneModel.getScene().materials) + for (auto &material : m_sceneModel.getScene().getMaterials()) { VkDescriptorSetAllocateInfo descriptorSetAllocInfo{}; descriptorSetAllocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; @@ -550,36 +555,70 @@ void PlumageRender::setupDescriptors() VkDescriptorSetLayout materialDescriptorSetLayout = m_descriptorSetLayoutList.getMaterial(); descriptorSetAllocInfo.pSetLayouts = &materialDescriptorSetLayout; descriptorSetAllocInfo.descriptorSetCount = 1; - VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &material.descriptorSet)); + VkDescriptorSet materialDescriptorSet = material.getDescriptorSet(); + VK_CHECK_RESULT(vkAllocateDescriptorSets(device, &descriptorSetAllocInfo, &materialDescriptorSet)); VkDescriptorImageInfo emptyTexDescriptor = m_sceneTextures.getEmpty().descriptor; - std::vector imageDescriptors = { - emptyTexDescriptor, - emptyTexDescriptor, - material.normalTexture ? material.normalTexture->descriptor : emptyTexDescriptor, - material.occlusionTexture ? material.occlusionTexture->descriptor : emptyTexDescriptor, - material.emissiveTexture ? material.emissiveTexture->descriptor : emptyTexDescriptor}; + std::vector imageDescriptors(5); + imageDescriptors[0] = emptyTexDescriptor; + imageDescriptors[1] = emptyTexDescriptor; - if (material.pbrWorkflows.metallicRoughness) + // 法线贴图 + glTFLoader::glTFTexture *normalTexture = material.getPbrBaseTexture()->getNormalTexture(); + if (normalTexture) { - if (material.baseColorTexture) - { - imageDescriptors[0] = material.baseColorTexture->descriptor; - } - if (material.metallicRoughnessTexture) - { - imageDescriptors[1] = material.metallicRoughnessTexture->descriptor; - } + imageDescriptors[2] = normalTexture->getDescriptor(); + } + else + { + imageDescriptors[2] = emptyTexDescriptor; } - if (material.pbrWorkflows.specularGlossiness) + glTFLoader::glTFTexture *occlusionTexture = material.getPbrBaseTexture()->getOcclusionTexture(); + // 遮蔽贴图 + if (occlusionTexture) { - if (material.extension.diffuseTexture) + imageDescriptors[3] = occlusionTexture->getDescriptor(); + } + else + { + imageDescriptors[3] = emptyTexDescriptor; + } + glTFLoader::glTFTexture *emissiveTexture = material.getPbrBaseTexture()->getEmissiveTexture(); + // 自发光贴图 + if (emissiveTexture) + { + imageDescriptors[4] = emissiveTexture->getDescriptor(); + } + else + { + imageDescriptors[4] = emptyTexDescriptor; + } + bool metallicRoughness = material.getPbrWorkFlow()->getMetallicRoughness(); + if (metallicRoughness) + { + glTFLoader::glTFTexture *baseColorTexture = material.getPbrBaseTexture()->getBaseColorTexture(); + if (baseColorTexture) { - imageDescriptors[0] = material.extension.diffuseTexture->descriptor; + imageDescriptors[0] = baseColorTexture->getDescriptor(); } - if (material.extension.specularGlossinessTexture) + glTFLoader::glTFTexture *metallicRoughnessTexture = material.getPbrBaseTexture()->getMetalicRoughnessTexture(); + if (metallicRoughnessTexture) { - imageDescriptors[1] = material.extension.specularGlossinessTexture->descriptor; + imageDescriptors[1] = metallicRoughnessTexture->getDescriptor(); + } + } + bool specularGlossiness = material.getPbrWorkFlow()->getSpecularGlossiness(); + if (specularGlossiness) + { + glTFLoader::glTFTexture *diffuseTexture = material.getTextureExtension()->getDiffuseTexture(); + if (diffuseTexture) + { + imageDescriptors[0] = diffuseTexture->getDescriptor(); + } + glTFLoader::glTFTexture *specularGlossinessTexture = material.getTextureExtension()->getSpecularGlossinessTexture(); + if (specularGlossinessTexture) + { + imageDescriptors[1] = specularGlossinessTexture->getDescriptor(); } } @@ -589,7 +628,7 @@ void PlumageRender::setupDescriptors() writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; writeDescriptorSets[i].descriptorCount = 1; - writeDescriptorSets[i].dstSet = material.descriptorSet; + writeDescriptorSets[i].dstSet = material.getDescriptorSet(); writeDescriptorSets[i].dstBinding = static_cast(i); writeDescriptorSets[i].pImageInfo = &imageDescriptors[i]; } @@ -610,7 +649,7 @@ void PlumageRender::setupDescriptors() VK_CHECK_RESULT(vkCreateDescriptorSetLayout(device, &descriptorSetLayoutCI, nullptr, &nodeDescriptorSetLayout)); // Per-Node descriptor set - for (auto &node : m_sceneModel.getScene().nodes) + for (auto &node : m_sceneModel.getScene().getNodes()) { setupNodeDescriptorSet(node); } @@ -723,7 +762,7 @@ void PlumageRender::preparePipelines() VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCI, nullptr, &pipelineLayout)); // Vertex bindings an attributes - VkVertexInputBindingDescription vertexInputBinding = {0, sizeof(glTFModel::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX}; + VkVertexInputBindingDescription vertexInputBinding = {0, sizeof(glTFLoader::Vertex), VK_VERTEX_INPUT_RATE_VERTEX}; std::vector vertexInputAttributes = { {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}, {1, 0, VK_FORMAT_R32G32B32_SFLOAT, sizeof(float) * 3}, @@ -1116,7 +1155,7 @@ void PlumageRender::generateCubemaps() dynamicStateCI.dynamicStateCount = static_cast(dynamicStateEnables.size()); // Vertex input state - VkVertexInputBindingDescription vertexInputBinding = {0, sizeof(glTFModel::Model::Vertex), VK_VERTEX_INPUT_RATE_VERTEX}; + VkVertexInputBindingDescription vertexInputBinding = {0, sizeof(glTFLoader::Vertex), VK_VERTEX_INPUT_RATE_VERTEX}; VkVertexInputAttributeDescription vertexInputAttribute = {0, 0, VK_FORMAT_R32G32B32_SFLOAT, 0}; VkPipelineVertexInputStateCreateInfo vertexInputStateCI{}; @@ -1644,13 +1683,13 @@ void PlumageRender::updateUniformBuffers() // Scene m_shaderDataScene.setProjection(camera.matrices.perspective); m_shaderDataScene.setView(camera.matrices.view); - glTFModel::Model &models = m_sceneModel.getScene(); - - float modelSize = std::max(models.aabb[0][0], std::max(models.aabb[1][1], models.aabb[2][2])); + glTFLoader::glTFMainModel &models = m_sceneModel.getScene(); + glm::mat4 aabb = models.getAABB(); + float modelSize = std::max(aabb[0][0], std::max(aabb[1][1], aabb[2][2])); // Center and scale model float scale = (1.0f / modelSize) * 0.5f; - glm::vec3 translate = -glm::vec3(models.aabb[3][0], models.aabb[3][1], models.aabb[3][2]); - translate += -0.5f * glm::vec3(models.aabb[0][0], models.aabb[1][1], models.aabb[2][2]); + glm::vec3 translate = -glm::vec3(aabb[3][0], aabb[3][1], aabb[3][2]); + translate += -0.5f * glm::vec3(aabb[0][0], aabb[1][1], aabb[2][2]); // camera.setPosition(glm::vec3(0, 0, -modelSize - 2)); @@ -2196,12 +2235,14 @@ void PlumageRender::render() modelrot -= 360.0f; } } - if ((animate) && (m_sceneModel.getScene().animations.size() > 0)) + std::vector animations = m_sceneModel.getScene().getAnimations(); + if ((animate) && (animations.size())) { animationTimer += frameTimer; - if (animationTimer > m_sceneModel.getScene().animations[animationIndex].end) + glTFLoader::glTFAnimation currentAnimation = animations.at(animationIndex); + if (animationTimer > currentAnimation.getEnd()) { - animationTimer -= m_sceneModel.getScene().animations[animationIndex].end; + animationTimer -= currentAnimation.getEnd(); } m_sceneModel.getScene().updateAnimation(animationIndex, animationTimer); } @@ -2357,7 +2398,8 @@ void PlumageRender::updateUIOverlay() } if (gui->beginMenu(m_localizationStrings.getMenuAnimation())) { - if (m_sceneModel.getScene().animations.size() > 0) + std::vector animations = m_sceneModel.getScene().getAnimations(); + if (animations.size()) { if (gui->beginMenu(m_localizationStrings.getMenuAnimationActivation())) { @@ -2367,9 +2409,9 @@ void PlumageRender::updateUIOverlay() if (gui->beginMenu(m_localizationStrings.getMenuAnimationAnimationSequence())) { std::vector animationNames; - for (auto animation : m_sceneModel.getScene().animations) + for (auto animation : animations) { - animationNames.push_back(animation.name); + animationNames.push_back(animation.getName()); } gui->combo(m_localizationStrings.getAnimationSeq(), &animationIndex, animationNames); gui->endMenu(); diff --git a/src/render/render.h b/src/render/render.h index 930be68..640d2e4 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -6,6 +6,7 @@ #include "RenderPipelineList.h" #include "RenderSceneTextures.h" #include "glTFMaterial.h" +#include "glTFNode.h" #include "glTFSkin.h" #include "renderShaderData.h" #if defined(_WIN32) @@ -36,7 +37,7 @@ #include #include "VulkanExampleBase.h" -#include "glTFModel.h" + #include "ui.hpp" #include #include @@ -56,7 +57,7 @@ #include "RenderPipelineList.h" #include "RenderSceneTextures.h" #include "SceneUBOMatrices.h" -#include "ShaderLoader.h" + #include "SkyboxUBOMatrices.h" #include "VertexStagingBuffer.h" #include "renderEffectState.h" @@ -191,7 +192,7 @@ public: void loadEnvironment(std::string filename); void buildCommandBuffers(); void loadAssets(); - void setupNodeDescriptorSet(glTFModel::Node *node); + void setupNodeDescriptorSet(glTFLoader::glTFNode *node); void setupDescriptors(); void preparePipelines(); // void tonemappingPipelin(); diff --git a/src/render/renderStagingBuffer.cpp b/src/render/renderStagingBuffer.cpp index a71dc47..e767811 100644 --- a/src/render/renderStagingBuffer.cpp +++ b/src/render/renderStagingBuffer.cpp @@ -1,4 +1,4 @@ -#include "renderStagingBuffer.h" +#include "RenderStagingBuffer.h" // Getter method definitions VkBuffer RenderStagingBuffer::getBuffer() const