diff --git a/.gitmodules b/.gitmodules index cc3bf1fcd2e1eb8117cbcc7222b04f7041fea520..ef5fa3cfcc738f2bc8dedb0ec219903e71500f49 100644 --- a/.gitmodules +++ b/.gitmodules @@ -28,3 +28,9 @@ [submodule "modules/upscaling/lib/FidelityFX-FSR"] path = modules/upscaling/lib/FidelityFX-FSR url = https://github.com/GPUOpen-Effects/FidelityFX-FSR.git +[submodule "lib/Vulkan-Headers"] + path = lib/Vulkan-Headers + url = https://github.com/KhronosGroup/Vulkan-Headers.git +[submodule "lib/Vulkan-Hpp"] + path = lib/Vulkan-Hpp + url = https://github.com/KhronosGroup/Vulkan-Hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 121d499fb2cd337c28524b89ecf1ab9d12607bdf..d47706415b6274a135a4c85aa1010fde2e959105 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,7 @@ endif() include(${vkcv_config}/Sources.cmake) message(STATUS "Framework:") +message(" - Includes: [ ${vkcv_includes} ]") message(" - Libraries: [ ${vkcv_libraries} ]") message(" - Flags: [ ${vkcv_flags} ]") diff --git a/config/lib/Vulkan.cmake b/config/lib/Vulkan.cmake index e8fe4aee3a949fa7bf9906558f8a0c558eb47cf2..5100d1b78986a7a4b4b6180b1862046cb8b4fc8c 100644 --- a/config/lib/Vulkan.cmake +++ b/config/lib/Vulkan.cmake @@ -2,7 +2,26 @@ find_package(Vulkan REQUIRED) if (Vulkan_FOUND) - list(APPEND vkcv_includes ${Vulkan_INCLUDE_DIR}) + if (NOT EXISTS ${Vulkan_INCLUDE_DIR}/vulkan/vulkan.h) + use_git_submodule("${vkcv_lib_path}/Vulkan-Headers" vulkan_headers_status) + + if (${vulkan_headers_status}) + list(APPEND vkcv_includes ${vkcv_lib}/Vulkan-Headers/include) + endif() + else() + list(APPEND vkcv_includes ${Vulkan_INCLUDE_DIR}) + endif() + + if (NOT EXISTS ${Vulkan_INCLUDE_DIR}/vulkan/vulkan.hpp) + use_git_submodule("${vkcv_lib_path}/Vulkan-Hpp" vulkan_hpp_status) + + if (${vulkan_hpp_status}) + list(APPEND vkcv_includes ${vkcv_lib}/Vulkan-Hpp) + endif() + else() + list(APPEND vkcv_includes ${Vulkan_INCLUDE_DIR}) + endif() + list(APPEND vkcv_libraries ${Vulkan_LIBRARIES}) message(${vkcv_config_msg} " Vulkan - ") diff --git a/lib/Vulkan-Headers b/lib/Vulkan-Headers new file mode 160000 index 0000000000000000000000000000000000000000..8ba8294c86d0e99fcb457bedbd573dd678ccc9b3 --- /dev/null +++ b/lib/Vulkan-Headers @@ -0,0 +1 @@ +Subproject commit 8ba8294c86d0e99fcb457bedbd573dd678ccc9b3 diff --git a/lib/Vulkan-Hpp b/lib/Vulkan-Hpp new file mode 160000 index 0000000000000000000000000000000000000000..ae1b0c36df0943795cd621a37e7f7bfd00ac958a --- /dev/null +++ b/lib/Vulkan-Hpp @@ -0,0 +1 @@ +Subproject commit ae1b0c36df0943795cd621a37e7f7bfd00ac958a diff --git a/lib/VulkanMemoryAllocator-Hpp b/lib/VulkanMemoryAllocator-Hpp index c6c3c665b6a29ae546bdec60606a3ef0757ea108..da6ea76eecf12a1decc76f58a3e096bcc555bd94 160000 --- a/lib/VulkanMemoryAllocator-Hpp +++ b/lib/VulkanMemoryAllocator-Hpp @@ -1 +1 @@ -Subproject commit c6c3c665b6a29ae546bdec60606a3ef0757ea108 +Subproject commit da6ea76eecf12a1decc76f58a3e096bcc555bd94 diff --git a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp index f3f55f6514a58e776abf226fd80805fbf656a809..110a941ff6703e989174eaf311118b10b41491d4 100644 --- a/modules/asset_loader/src/vkcv/asset/asset_loader.cpp +++ b/modules/asset_loader/src/vkcv/asset/asset_loader.cpp @@ -171,7 +171,7 @@ namespace vkcv::asset { static std::array<float, 16> calculateModelMatrix(const std::array<float, 3>& translation, const std::array<float, 3>& scale, const std::array<float, 4>& rotation, - const std::array<float, 16>& matrix){ + const std::array<float, 16>& matrix) { std::array<float, 16> modelMatrix = { 1,0,0,0, 0,1,0,0, @@ -185,32 +185,55 @@ namespace vkcv::asset { // translation modelMatrix[3] = translation[0]; modelMatrix[7] = translation[1]; - modelMatrix[11] = translation[2]; + modelMatrix[11] = -translation[2]; // flip Z to convert from GLTF to Vulkan // rotation and scale - auto a = rotation[0]; - auto q1 = rotation[1]; - auto q2 = rotation[2]; - auto q3 = rotation[3]; - - modelMatrix[0] = (2 * (a * a + q1 * q1) - 1) * scale[0]; - modelMatrix[1] = (2 * (q1 * q2 - a * q3)) * scale[1]; - modelMatrix[2] = (2 * (q1 * q3 + a * q2)) * scale[2]; - - modelMatrix[4] = (2 * (q1 * q2 + a * q3)) * scale[0]; - modelMatrix[5] = (2 * (a * a + q2 * q2) - 1) * scale[1]; - modelMatrix[6] = (2 * (q2 * q3 - a * q1)) * scale[2]; - - modelMatrix[8] = (2 * (q1 * q3 - a * q2)) * scale[0]; - modelMatrix[9] = (2 * (q2 * q3 + a * q1)) * scale[1]; - modelMatrix[10] = (2 * (a * a + q3 * q3) - 1) * scale[2]; - - // flip y, because GLTF uses y up, but vulkan -y up - modelMatrix[5] *= -1; + auto a = rotation[3]; + auto q1 = rotation[0]; + auto q2 = rotation[1]; + auto q3 = rotation[2]; + + auto s = 2 / (a * a + q1 * q1 + q2 * q2 + q3 * q3); + + auto s1 = scale[0]; + auto s2 = scale[1]; + auto s3 = -scale[2]; // flip Z to convert from GLTF to Vulkan + + modelMatrix[0] = (1 - s * (q2 * q2 + q3 * q3)) * s1; + modelMatrix[1] = ( s * (q1 * q2 - q3 * a)) * s2; + modelMatrix[2] = ( s * (q1 * q3 + q2 * a)) * s3; + + modelMatrix[4] = ( s * (q1 * q2 + q3 * a)) * s1; + modelMatrix[5] = (1 - s * (q1 * q1 + q3 * q3)) * s2; + modelMatrix[6] = ( s * (q2 * q3 - q1 * a)) * s3; + + modelMatrix[8] = ( s * (q1 * q3 - q2 * a)) * s1; + modelMatrix[9] = ( s * (q2 * q3 + q1 * a)) * s2; + modelMatrix[10] = (1 - s * (q1 * q1 + q2 * q2)) * s3; return modelMatrix; } } + + static std::array<float, 16> multiplyMatrix(const std::array<float, 16>& matrix, + const std::array<float, 16>& other) { + std::array<float, 16> result; + size_t i, j, k; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 4; j++) { + float sum = 0.0f; + + for (k = 0; k < 4; k++) { + sum += matrix[i * 4 + k] * other[k * 4 + j]; + } + + result[i * 4 + j] = sum; + } + } + + return result; + } bool Material::hasTexture(const PBRTextureTarget target) const { return textureMask & bitflag(target); @@ -496,9 +519,23 @@ namespace vkcv::asset { try { if (path.extension() == ".glb") { - sceneObjects = fx::gltf::LoadFromBinary(path.string()); + sceneObjects = fx::gltf::LoadFromBinary( + path.string(), + { + fx::gltf::detail::DefaultMaxBufferCount, + fx::gltf::detail::DefaultMaxMemoryAllocation * 16, + fx::gltf::detail::DefaultMaxMemoryAllocation * 8 + } + ); } else { - sceneObjects = fx::gltf::LoadFromText(path.string()); + sceneObjects = fx::gltf::LoadFromText( + path.string(), + { + fx::gltf::detail::DefaultMaxBufferCount, + fx::gltf::detail::DefaultMaxMemoryAllocation, + fx::gltf::detail::DefaultMaxMemoryAllocation * 8 + } + ); } } catch (const std::system_error& err) { recurseExceptionPrint(err, path.string()); @@ -536,15 +573,54 @@ namespace vkcv::asset { scene.meshes.push_back(mesh); } - // This only works if the node has a mesh and it only loads the meshes and ignores cameras and lights - for (const auto& node : sceneObjects.nodes) { + std::vector< std::array<float, 16> > matrices; + std::vector< int32_t > parents; + + matrices.reserve(sceneObjects.nodes.size()); + parents.resize(sceneObjects.nodes.size(), -1); + + for (size_t i = 0; i < sceneObjects.nodes.size(); i++) { + const auto &node = sceneObjects.nodes[i]; + + matrices.push_back(calculateModelMatrix( + node.translation, + node.scale, + node.rotation, + node.matrix + )); + + for (int32_t child : node.children) + if ((child >= 0) && (child < parents.size())) + parents[child] = static_cast<int32_t>(i); + } + + std::vector< std::array<float, 16> > final_matrices; + final_matrices.reserve(matrices.size()); + + for (size_t i = 0; i < matrices.size(); i++) { + std::vector<int> order; + order.push_back(static_cast<int32_t>(i)); + + while (parents[ order[order.size() - 1] ] >= 0) + order.push_back(parents[ order[order.size() - 1] ]); + + std::array<float, 16> matrix = matrices[ order[order.size() - 1] ]; + + for (size_t j = order.size() - 1; j > 0; j--) { + const auto id = order[j - 1]; + const std::array<float, 16> matrix_other = matrices[ id ]; + + matrix = multiplyMatrix(matrix, matrix_other); + } + + final_matrices.push_back(matrix); + } + + for (size_t i = 0; i < sceneObjects.nodes.size(); i++) { + const auto &node = sceneObjects.nodes[i]; + if ((node.mesh >= 0) && (node.mesh < scene.meshes.size())) { - scene.meshes[node.mesh].modelMatrix = calculateModelMatrix( - node.translation, - node.scale, - node.rotation, - node.matrix - ); + scene.meshes[node.mesh].modelMatrix = final_matrices[i]; } } } diff --git a/modules/scene/src/vkcv/scene/MeshPart.cpp b/modules/scene/src/vkcv/scene/MeshPart.cpp index f9c87f0a0587bd8a897e42d5b8536fe07c61c749..50d14ed49d43496ada3853034be1455b044bd902 100644 --- a/modules/scene/src/vkcv/scene/MeshPart.cpp +++ b/modules/scene/src/vkcv/scene/MeshPart.cpp @@ -71,8 +71,23 @@ namespace vkcv::scene { if (*this) { const auto& material = getMaterial(); + IndexBitCount indexBitCount; + + switch (vertexGroup.indexBuffer.type) { + case asset::IndexType::UINT16: + indexBitCount = IndexBitCount::Bit16; + break; + case asset::IndexType::UINT32: + indexBitCount = IndexBitCount::Bit32; + break; + default: + indexBitCount = IndexBitCount::Bit16; + vkcv_log(LogLevel::WARNING, "Unsupported index type!"); + break; + } + drawcalls.push_back(DrawcallInfo( - vkcv::Mesh(m_vertexBindings, indexBuffer.getVulkanHandle(), m_indexCount), + vkcv::Mesh(m_vertexBindings, indexBuffer.getVulkanHandle(), m_indexCount, indexBitCount), { DescriptorSetUsage(0, material.getDescriptorSet()) } )); } diff --git a/projects/CMakeLists.txt b/projects/CMakeLists.txt index ffe8546c961697869354993539697b118fa8d6be..997c907fb26db2344f028ff5eaec8de3f69038b7 100644 --- a/projects/CMakeLists.txt +++ b/projects/CMakeLists.txt @@ -5,6 +5,7 @@ include(${vkcv_config_ext}/ProjectFix.cmake) add_subdirectory(first_triangle) add_subdirectory(first_mesh) add_subdirectory(first_scene) +add_subdirectory(head_demo) add_subdirectory(particle_simulation) add_subdirectory(rtx_ambient_occlusion) add_subdirectory(sph) diff --git a/projects/head_demo/.gitignore b/projects/head_demo/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..151f56c5bb7098a3beb7b8e049c0ade02914cd91 --- /dev/null +++ b/projects/head_demo/.gitignore @@ -0,0 +1 @@ +head_demo \ No newline at end of file diff --git a/projects/head_demo/CMakeLists.txt b/projects/head_demo/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..09e5f693d6c6ddc243d884a74981bdb980fb9065 --- /dev/null +++ b/projects/head_demo/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.16) +project(head_demo) + +# setting c++ standard for the project +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# this should fix the execution path to load local files from the project +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + +# adding source files to the project +add_executable(head_demo src/main.cpp) +fix_project(head_demo) + +# including headers of dependencies and the VkCV framework +target_include_directories(head_demo SYSTEM BEFORE PRIVATE ${vkcv_include} ${vkcv_includes} ${vkcv_asset_loader_include} ${vkcv_camera_include} ${vkcv_scene_include} ${vkcv_shader_compiler_include} ${vkcv_gui_include}) + +# linking with libraries from all dependencies and the VkCV framework +target_link_libraries(head_demo vkcv ${vkcv_libraries} vkcv_asset_loader ${vkcv_asset_loader_libraries} vkcv_camera vkcv_scene vkcv_shader_compiler vkcv_gui) diff --git a/projects/head_demo/assets/shaders/clip.inc b/projects/head_demo/assets/shaders/clip.inc new file mode 100644 index 0000000000000000000000000000000000000000..edb5ac3ccfe5d7f6ad1e59dd88bee4446b85118f --- /dev/null +++ b/projects/head_demo/assets/shaders/clip.inc @@ -0,0 +1,19 @@ + +#define CLIP_SCALE 10000.0f + +vec4 clipPosition(vec4 pos) { + return vec4( + max(clipX, pos.x), + max(clipY, pos.y), + max(clipZ, pos.z), + 1.0f / CLIP_SCALE + ); +} + +vec4 clipByLimit(vec4 pos) { + if (pos.x / pos.w < clipLimit) { + return vec4(pos.xyz / pos.w, 1.0f); + } else { + return vec4(clipLimit, pos.y / pos.w, pos.z / pos.w, 1.0f); + } +} diff --git a/projects/head_demo/assets/shaders/red.frag b/projects/head_demo/assets/shaders/red.frag new file mode 100644 index 0000000000000000000000000000000000000000..3991f9396323bb25c57f03e5ba7b5f9a280ed556 --- /dev/null +++ b/projects/head_demo/assets/shaders/red.frag @@ -0,0 +1,10 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 passNormal; + +layout(location = 0) out vec3 outColor; + +void main() { + outColor = (vec3(0.3f, 0, 0) + max(dot(passNormal, vec3(1.0f, -1.0f, 0.5f)), 0.0f) * vec3(0.7f, 0, 0)); +} \ No newline at end of file diff --git a/projects/head_demo/assets/shaders/shader.frag b/projects/head_demo/assets/shaders/shader.frag new file mode 100644 index 0000000000000000000000000000000000000000..b8756a6b84af4e93f9ac932ec01d28e4f2e9638b --- /dev/null +++ b/projects/head_demo/assets/shaders/shader.frag @@ -0,0 +1,10 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 passNormal; + +layout(location = 0) out vec3 outColor; + +void main() { + outColor = (vec3(0.3f) + max(dot(passNormal, vec3(1.0f, -1.0f, 0.5f)), 0.0f) * vec3(0.7f)); +} \ No newline at end of file diff --git a/projects/head_demo/assets/shaders/shader.geom b/projects/head_demo/assets/shaders/shader.geom new file mode 100644 index 0000000000000000000000000000000000000000..275b300ee3466e117876aa46a6ea1cde11f6f17d --- /dev/null +++ b/projects/head_demo/assets/shaders/shader.geom @@ -0,0 +1,53 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +layout(triangles) in; +layout(triangle_strip, max_vertices = 3) out; + +layout(location = 0) in vec3 geomNormal[]; + +layout(location = 0) out vec3 passNormal; + +layout(set=1, binding=0) uniform clipBuffer { + float clipLimit; + float clipX; + float clipY; + float clipZ; +}; + +layout( push_constant ) uniform constants{ + mat4 mvp; +}; + +#include "clip.inc" + +void main() { + vec4 v0 = gl_in[0].gl_Position; + vec4 v1 = gl_in[1].gl_Position; + vec4 v2 = gl_in[2].gl_Position; + + v0 = clipPosition(v0 / CLIP_SCALE); + v1 = clipPosition(v1 / CLIP_SCALE); + v2 = clipPosition(v2 / CLIP_SCALE); + + float dx = abs(v0.x - clipX) + abs(v1.x - clipX) + abs(v2.x - clipX); + float dy = abs(v0.y - clipY) + abs(v1.y - clipY) + abs(v2.y - clipY); + float dz = abs(v0.z - clipZ) + abs(v1.z - clipZ) + abs(v2.z - clipZ); + + if (dx * dy * dz > 0.0f) { + gl_Position = mvp * (v0 * CLIP_SCALE); + passNormal = geomNormal[0]; + EmitVertex(); + + gl_Position = mvp * (v1 * CLIP_SCALE); + passNormal = geomNormal[1]; + EmitVertex(); + + gl_Position = mvp * (v2 * CLIP_SCALE); + passNormal = geomNormal[2]; + EmitVertex(); + + EndPrimitive(); + } +} diff --git a/projects/head_demo/assets/shaders/shader.vert b/projects/head_demo/assets/shaders/shader.vert new file mode 100644 index 0000000000000000000000000000000000000000..26e43e9c89dc2ffb2355d60be8288fa9832f8baa --- /dev/null +++ b/projects/head_demo/assets/shaders/shader.vert @@ -0,0 +1,12 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable + +layout(location = 0) in vec3 inPosition; +layout(location = 1) in vec3 inNormal; + +layout(location = 0) out vec3 geomNormal; + +void main() { + gl_Position = vec4(inPosition, 1.0); + geomNormal = inNormal; +} \ No newline at end of file diff --git a/projects/head_demo/assets/shaders/wired.geom b/projects/head_demo/assets/shaders/wired.geom new file mode 100644 index 0000000000000000000000000000000000000000..0063360547b859fc7a305b5786532654b5b35f34 --- /dev/null +++ b/projects/head_demo/assets/shaders/wired.geom @@ -0,0 +1,51 @@ +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_GOOGLE_include_directive : enable + +layout(triangles) in; +layout(points, max_vertices = 1) out; + +layout(location = 0) in vec3 geomNormal[]; + +layout(location = 0) out vec3 passNormal; + +layout(set=1, binding=0) uniform clipBuffer { + float clipLimit; + float clipX; + float clipY; + float clipZ; +}; + +layout( push_constant ) uniform constants{ + mat4 mvp; +}; + +#include "clip.inc" + +void main() { + vec4 v0 = gl_in[0].gl_Position; + vec4 v1 = gl_in[1].gl_Position; + vec4 v2 = gl_in[2].gl_Position; + + v0 = clipPosition(v0 / CLIP_SCALE); + v1 = clipPosition(v1 / CLIP_SCALE); + v2 = clipPosition(v2 / CLIP_SCALE); + + float dx = abs(v0.x - clipX) + abs(v1.x - clipX) + abs(v2.x - clipX); + float dy = abs(v0.y - clipY) + abs(v1.y - clipY) + abs(v2.y - clipY); + float dz = abs(v0.z - clipZ) + abs(v1.z - clipZ) + abs(v2.z - clipZ); + + if (dx * dy * dz <= 0.0f) { + v0 = clipByLimit(mvp * gl_in[0].gl_Position); + v1 = clipByLimit(mvp * gl_in[1].gl_Position); + v2 = clipByLimit(mvp * gl_in[2].gl_Position); + + if ((v0.x < clipLimit) || (v1.x < clipLimit) || (v2.x < clipLimit)) { + gl_Position = (v0 + v1 + v2) / 3; + passNormal = (geomNormal[0] + geomNormal[1] + geomNormal[2]) / 3; + EmitVertex(); + + EndPrimitive(); + } + } +} diff --git a/projects/head_demo/assets/skull/license.txt b/projects/head_demo/assets/skull/license.txt new file mode 100644 index 0000000000000000000000000000000000000000..6816d6d659087b54dfc6b8e0c2c0e158daa001f0 --- /dev/null +++ b/projects/head_demo/assets/skull/license.txt @@ -0,0 +1,11 @@ +Model Information: +* title: The Anatomy of the Human Skull +* source: https://sketchfab.com/3d-models/the-anatomy-of-the-human-skull-baf6ac7b781a46218dca2b59dee58817 +* author: HannahNewey (https://sketchfab.com/HannahNewey) + +Model License: +* license type: CC-BY-NC-SA-4.0 (http://creativecommons.org/licenses/by-nc-sa/4.0/) +* requirements: Author must be credited. No commercial use. Modified versions must have the same license. + +If you use this 3D model in your project be sure to copy paste this credit wherever you share it: +This work is based on "The Anatomy of the Human Skull" (https://sketchfab.com/3d-models/the-anatomy-of-the-human-skull-baf6ac7b781a46218dca2b59dee58817) by HannahNewey (https://sketchfab.com/HannahNewey) licensed under CC-BY-NC-SA-4.0 (http://creativecommons.org/licenses/by-nc-sa/4.0/) \ No newline at end of file diff --git a/projects/head_demo/assets/skull/scene.bin b/projects/head_demo/assets/skull/scene.bin new file mode 100644 index 0000000000000000000000000000000000000000..e995091c9d2f10b15959a65d3b0e0de3c9edb0e4 --- /dev/null +++ b/projects/head_demo/assets/skull/scene.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:df3cb5e715426a8e7a3c4883eb7c53022e09011ded9ae385cd6bc59824129ed8 +size 78176672 diff --git a/projects/head_demo/assets/skull/scene.gltf b/projects/head_demo/assets/skull/scene.gltf new file mode 100644 index 0000000000000000000000000000000000000000..6a2b75fa5af1e826bf3851db576dd3051e7b77c3 --- /dev/null +++ b/projects/head_demo/assets/skull/scene.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8cd4f673e0a555dc138b96e07be60546a799f9ef11837870eae27b16ffd5c1c7 +size 36442 diff --git a/projects/head_demo/assets/skull_scaled/scene.bin b/projects/head_demo/assets/skull_scaled/scene.bin new file mode 100644 index 0000000000000000000000000000000000000000..3edc8865ed5465c33cb8c9d2f2b0eb83b1a5b599 --- /dev/null +++ b/projects/head_demo/assets/skull_scaled/scene.bin @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:685e971ce4e99be286464c56a373e528dc507ce18b5bfdff45f90db27e49176b +size 56596296 diff --git a/projects/head_demo/assets/skull_scaled/scene.gltf b/projects/head_demo/assets/skull_scaled/scene.gltf new file mode 100644 index 0000000000000000000000000000000000000000..72087f182e4cd1ce1a73f7af9db1d36608df2029 --- /dev/null +++ b/projects/head_demo/assets/skull_scaled/scene.gltf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f05a4c8f979dab2793540bafe2b392133d64af028a0ff97f0159dbc52fc20230 +size 4843 diff --git a/projects/head_demo/src/main.cpp b/projects/head_demo/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c25ed49f989f47b63e4e7f828550016d6a2fbaeb --- /dev/null +++ b/projects/head_demo/src/main.cpp @@ -0,0 +1,260 @@ +#include <iostream> +#include <vkcv/Core.hpp> +#include <GLFW/glfw3.h> +#include <vkcv/camera/CameraManager.hpp> +#include <vkcv/gui/GUI.hpp> +#include <chrono> +#include <vkcv/asset/asset_loader.hpp> +#include <vkcv/shader/GLSLCompiler.hpp> +#include <vkcv/scene/Scene.hpp> + +int main(int argc, const char** argv) { + const char* applicationName = "First Scene"; + + uint32_t windowWidth = 800; + uint32_t windowHeight = 600; + + vkcv::Core core = vkcv::Core::create( + applicationName, + VK_MAKE_VERSION(0, 0, 1), + {vk::QueueFlagBits::eTransfer, vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute}, + { VK_KHR_SWAPCHAIN_EXTENSION_NAME } + ); + vkcv::WindowHandle windowHandle = core.createWindow(applicationName, windowWidth, windowHeight, false); + vkcv::Window& window = core.getWindow(windowHandle); + vkcv::camera::CameraManager cameraManager(window); + + vkcv::gui::GUI gui (core, windowHandle); + + uint32_t camIndex0 = cameraManager.addCamera(vkcv::camera::ControllerType::PILOT); + uint32_t camIndex1 = cameraManager.addCamera(vkcv::camera::ControllerType::TRACKBALL); + + cameraManager.getCamera(camIndex0).setPosition(glm::vec3(15.5f, 0, 0)); + cameraManager.getCamera(camIndex0).setNearFar(0.1f, 30.0f); + + cameraManager.getCamera(camIndex1).setNearFar(0.1f, 30.0f); + + vkcv::scene::Scene scene = vkcv::scene::Scene::load(core, std::filesystem::path( + argc > 1 ? argv[1] : "assets/skull_scaled/scene.gltf" + )); + + const vkcv::AttachmentDescription present_color_attachment0( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + core.getSwapchain(windowHandle).getFormat() + ); + + const vkcv::AttachmentDescription depth_attachment0( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + vk::Format::eD32Sfloat + ); + + vkcv::PassConfig scenePassDefinition({ present_color_attachment0, depth_attachment0 }); + vkcv::PassHandle scenePass = core.createPass(scenePassDefinition); + + const vkcv::AttachmentDescription present_color_attachment1( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::LOAD, + core.getSwapchain(windowHandle).getFormat() + ); + + const vkcv::AttachmentDescription depth_attachment1( + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::LOAD, + vk::Format::eD32Sfloat + ); + + vkcv::PassConfig linePassDefinition({ present_color_attachment1, depth_attachment1 }); + vkcv::PassHandle linePass = core.createPass(linePassDefinition); + + if ((!scenePass) || (!linePass)) { + std::cout << "Error. Could not create renderpass. Exiting." << std::endl; + return EXIT_FAILURE; + } + + vkcv::ShaderProgram sceneShaderProgram; + vkcv::ShaderProgram lineShaderProgram; + vkcv::shader::GLSLCompiler compiler; + + compiler.compileProgram(sceneShaderProgram, { + { vkcv::ShaderStage::VERTEX, "assets/shaders/shader.vert" }, + { vkcv::ShaderStage::GEOMETRY, "assets/shaders/shader.geom" }, + { vkcv::ShaderStage::FRAGMENT, "assets/shaders/shader.frag" } + }, nullptr); + + compiler.compileProgram(lineShaderProgram, { + { vkcv::ShaderStage::VERTEX, "assets/shaders/shader.vert" }, + { vkcv::ShaderStage::GEOMETRY, "assets/shaders/wired.geom" }, + { vkcv::ShaderStage::FRAGMENT, "assets/shaders/red.frag" } + }, nullptr); + + const std::vector<vkcv::VertexAttachment> vertexAttachments = sceneShaderProgram.getVertexAttachments(); + std::vector<vkcv::VertexBinding> bindings; + for (size_t i = 0; i < vertexAttachments.size(); i++) { + bindings.push_back(vkcv::VertexBinding(i, { vertexAttachments[i] })); + } + + const auto& clipBindings = sceneShaderProgram.getReflectedDescriptors().at(1); + + auto clipDescriptorSetLayout = core.createDescriptorSetLayout(clipBindings); + auto clipDescriptorSet = core.createDescriptorSet(clipDescriptorSetLayout); + + float clipLimit = 1.0f; + float clipX = 0.0f; + float clipY = 0.0f; + float clipZ = 0.0f; + + auto clipBuffer = core.createBuffer<float>(vkcv::BufferType::UNIFORM, 4); + clipBuffer.fill({ clipLimit, -clipX, -clipY, -clipZ }); + + vkcv::DescriptorWrites clipWrites; + clipWrites.uniformBufferWrites = { + vkcv::BufferDescriptorWrite(0, clipBuffer.getHandle()) + }; + + core.writeDescriptorSet(clipDescriptorSet, clipWrites); + + float mouseX = -0.0f; + bool dragLimit = false; + + window.e_mouseMove.add([&](double x, double y) { + double cx = (x - window.getWidth() * 0.5); + double dx = cx / window.getWidth(); + + mouseX = 2.0f * static_cast<float>(dx); + + if (dragLimit) { + clipLimit = mouseX; + } + }); + + window.e_mouseButton.add([&](int button, int action, int mods) { + if ((std::abs(mouseX - clipLimit) < 0.1f) && (action == GLFW_PRESS)) { + dragLimit = true; + } else { + dragLimit = false; + } + }); + + const vkcv::VertexLayout sceneLayout(bindings); + + const auto& material0 = scene.getMaterial(0); + + const vkcv::GraphicsPipelineConfig scenePipelineDefinition{ + sceneShaderProgram, + UINT32_MAX, + UINT32_MAX, + scenePass, + {sceneLayout}, + { material0.getDescriptorSetLayout(), clipDescriptorSetLayout }, + true + }; + + const vkcv::GraphicsPipelineConfig linePipelineDefinition{ + lineShaderProgram, + UINT32_MAX, + UINT32_MAX, + linePass, + {sceneLayout}, + { material0.getDescriptorSetLayout(), clipDescriptorSetLayout }, + true + }; + + vkcv::GraphicsPipelineHandle scenePipeline = core.createGraphicsPipeline(scenePipelineDefinition); + vkcv::GraphicsPipelineHandle linePipeline = core.createGraphicsPipeline(linePipelineDefinition); + + if ((!scenePipeline) || (!linePipeline)) { + std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; + return EXIT_FAILURE; + } + + auto swapchainExtent = core.getSwapchain(windowHandle).getExtent(); + + vkcv::ImageHandle depthBuffer = core.createImage( + vk::Format::eD32Sfloat, + swapchainExtent.width, + swapchainExtent.height + ).getHandle(); + + const vkcv::ImageHandle swapchainInput = vkcv::ImageHandle::createSwapchainImageHandle(); + + auto start = std::chrono::system_clock::now(); + while (vkcv::Window::hasOpenWindow()) { + vkcv::Window::pollEvents(); + + if(window.getHeight() == 0 || window.getWidth() == 0) + continue; + + uint32_t swapchainWidth, swapchainHeight; + if (!core.beginFrame(swapchainWidth, swapchainHeight,windowHandle)) { + continue; + } + + if ((swapchainWidth != swapchainExtent.width) || ((swapchainHeight != swapchainExtent.height))) { + depthBuffer = core.createImage(vk::Format::eD32Sfloat, swapchainWidth, swapchainHeight).getHandle(); + + swapchainExtent.width = swapchainWidth; + swapchainExtent.height = swapchainHeight; + } + + auto end = std::chrono::system_clock::now(); + auto deltatime = std::chrono::duration_cast<std::chrono::microseconds>(end - start); + + start = end; + cameraManager.update(0.000001 * static_cast<double>(deltatime.count())); + + clipBuffer.fill({ clipLimit, -clipX, -clipY, -clipZ }); + + const std::vector<vkcv::ImageHandle> renderTargets = { swapchainInput, depthBuffer }; + auto cmdStream = core.createCommandStream(vkcv::QueueType::Graphics); + + auto recordMesh = [&](const glm::mat4& MVP, const glm::mat4& M, + vkcv::PushConstants &pushConstants, + vkcv::DrawcallInfo& drawcallInfo) { + pushConstants.appendDrawcall(MVP); + drawcallInfo.descriptorSets.push_back( + vkcv::DescriptorSetUsage(1, clipDescriptorSet) + ); + }; + + scene.recordDrawcalls(cmdStream, + cameraManager.getActiveCamera(), + scenePass, + scenePipeline, + sizeof(glm::mat4), + recordMesh, + renderTargets, + windowHandle); + + scene.recordDrawcalls(cmdStream, + cameraManager.getActiveCamera(), + linePass, + linePipeline, + sizeof(glm::mat4), + recordMesh, + renderTargets, + windowHandle); + + core.prepareSwapchainImageForPresent(cmdStream); + core.submitCommandStream(cmdStream); + + auto stop = std::chrono::system_clock::now(); + auto kektime = std::chrono::duration_cast<std::chrono::microseconds>(stop - start); + + gui.beginGUI(); + + ImGui::Begin("Settings"); + ImGui::SliderFloat("Clip X", &clipX, -1.0f, 1.0f); + ImGui::SliderFloat("Clip Y", &clipY, -1.0f, 1.0f); + ImGui::SliderFloat("Clip Z", &clipZ, -1.0f, 1.0f); + ImGui::Text("Mesh by HannahNewey (https://sketchfab.com/HannahNewey)"); + ImGui::End(); + + gui.endGUI(); + + core.endFrame(windowHandle); + } + + return 0; +} diff --git a/src/vkcv/Context.cpp b/src/vkcv/Context.cpp index f7cd67eb756f353d9eb98c4768e2b0d74bbc1ab6..8988e479f0f57693c49ab3dbfc40f056a4cc4d8c 100644 --- a/src/vkcv/Context.cpp +++ b/src/vkcv/Context.cpp @@ -341,25 +341,16 @@ namespace vkcv vma::AllocatorCreateFlags vmaFlags; const vma::AllocatorCreateInfo allocatorCreateInfo ( - vma::AllocatorCreateFlags(), + vmaFlags, physicalDevice, device, 0, nullptr, nullptr, - 0, - nullptr, nullptr, nullptr, instance, - - /* Uses default version when set to 0 (currently VK_VERSION_1_0): - * - * The reason for this is that the allocator restricts the allowed version - * to be at maximum VK_VERSION_1_1 which is already less than - * VK_HEADER_VERSION_COMPLETE at most platforms. - * */ - 0 + VK_HEADER_VERSION_COMPLETE ); vma::Allocator allocator = vma::createAllocator(allocatorCreateInfo);