diff --git a/CMake/External/CMakeLists.txt b/CMake/External/CMakeLists.txt index 86c2dfee0e38a9350c8fbf593257328ce48af780..a5f1537100f340172c81fa71ea488fcfb89e6f87 100644 --- a/CMake/External/CMakeLists.txt +++ b/CMake/External/CMakeLists.txt @@ -121,5 +121,6 @@ ExternalProject_Add( ${PROJECT_NAME} -D${PROJECT_NAME}_USE_OMNI:BOOL=${${PROJECT_NAME}_USE_OMNI} -D${PROJECT_NAME}_USE_ODE:BOOL=${${PROJECT_NAME}_USE_ODE} -DODE_ROOT_DIR:PATH=${ODE_ROOT_DIR} + -D${PROJECT_NAME}_USE_Vulkan:BOOL=${${PROJECT_NAME}_USE_Vulkan} DEPENDS ${${PROJECT_NAME}_DEPENDENCIES} ) diff --git a/CMake/External/External_glfw.cmake b/CMake/External/External_glfw.cmake new file mode 100644 index 0000000000000000000000000000000000000000..25b847293047ac67fa752e106342e4b6bf329dee --- /dev/null +++ b/CMake/External/External_glfw.cmake @@ -0,0 +1,12 @@ +#----------------------------------------------------------------------------- +# Add External Project +#----------------------------------------------------------------------------- +include(imstkAddExternalProject) +imstk_add_external_project( glfw + GIT_REPOSITORY https://github.com/glfw/glfw.git + GIT_TAG 3.2.1 + INSTALL_COMMAND ${SKIP_STEP_COMMAND} + RELATIVE_INCLUDE_PATH "" + DEPENDENCIES "" + #VERBOSE + ) diff --git a/CMake/External/External_gli.cmake b/CMake/External/External_gli.cmake new file mode 100644 index 0000000000000000000000000000000000000000..90a5faa0865b92a12514cee1b8eb842abe4a302a --- /dev/null +++ b/CMake/External/External_gli.cmake @@ -0,0 +1,12 @@ +#----------------------------------------------------------------------------- +# Add External Project +#----------------------------------------------------------------------------- +include(imstkAddExternalProject) +imstk_add_external_project( gli + GIT_REPOSITORY https://github.com/g-truc/gli.git + GIT_TAG 0.8.2 + INSTALL_COMMAND ${SKIP_STEP_COMMAND} + RELATIVE_INCLUDE_PATH "" + DEPENDENCIES "" + #VERBOSE + ) diff --git a/CMake/External/External_glm.cmake b/CMake/External/External_glm.cmake new file mode 100644 index 0000000000000000000000000000000000000000..0ab26775feb06587cc1c173d42704d1675a00396 --- /dev/null +++ b/CMake/External/External_glm.cmake @@ -0,0 +1,12 @@ +#----------------------------------------------------------------------------- +# Add External Project +#----------------------------------------------------------------------------- +include(imstkAddExternalProject) +imstk_add_external_project( glm + GIT_REPOSITORY https://github.com/g-truc/glm.git + GIT_TAG 0.9.8.3 + INSTALL_COMMAND ${SKIP_STEP_COMMAND} + RELATIVE_INCLUDE_PATH "" + DEPENDENCIES "" + #VERBOSE + ) diff --git a/CMake/FindVulkanSDK.cmake b/CMake/FindVulkanSDK.cmake new file mode 100644 index 0000000000000000000000000000000000000000..f217fb135b4b36675e2595945479538fa429dc64 --- /dev/null +++ b/CMake/FindVulkanSDK.cmake @@ -0,0 +1,32 @@ +#----------------------------------------------------------------------------- +# Vulkan renderer +#----------------------------------------------------------------------------- +message(STATUS "Superbuild - Vulkan SDK => ENABLING Vulkan renderer") +if(NOT DEFINED VulkanSDK_ROOT_DIR) + set(VulkanSDK_ROOT_DIR "$ENV{VULKAN_SDK}" CACHE PATH "Path to Vulkan SDK install directory." FORCE) +endif() +if(NOT EXISTS ${VulkanSDK_ROOT_DIR}) + message(FATAL_ERROR "\nCan not support Vulkan renderer without Vulkan SDK.\nSet VulkanSDK_ROOT_DIR to Vulkan SDK installation directory.\n\n") +endif() + +#----------------------------------------------------------------------------- +# Find path +#----------------------------------------------------------------------------- +find_path(VulkanSDK_INCLUDE_DIR + NAMES + vulkan/vulkan.h + PATHS + ${VulkanSDK_ROOT_DIR}/Include + ) +mark_as_advanced(VulkanSDK_INCLUDE_DIR) + +#----------------------------------------------------------------------------- +# Find library +#----------------------------------------------------------------------------- +find_library(VulkanSDK_LIBRARY + NAMES + vulkan-1 + ) +mark_as_advanced(VulkanSDK_LIBRARY) + +set(VulkanSDK_LIBRARIES ${VulkanSDK_LIBRARY}) \ No newline at end of file diff --git a/CMake/Findglfw.cmake b/CMake/Findglfw.cmake new file mode 100644 index 0000000000000000000000000000000000000000..50a654b62261548f52b867ff1294bb8ee87ba0bb --- /dev/null +++ b/CMake/Findglfw.cmake @@ -0,0 +1,43 @@ +#----------------------------------------------------------------------------- +# Find path +#----------------------------------------------------------------------------- +find_path(glfw_INCLUDE_DIR + NAMES + GLFW/glfw3.h + PATH_SUFFIXES + include + ) +mark_as_advanced(glfw_INCLUDE_DIR) +message(STATUS "glfw_INCLUDE_DIR : ${glfw_INCLUDE_DIR}") + +#----------------------------------------------------------------------------- +# Find library +#----------------------------------------------------------------------------- +find_library(glfw_LIBRARY + NAMES + glfw3 + ) +mark_as_advanced(glfw_LIBRARY) +#message(STATUS "glfw_LIBRARY : ${glfw_LIBRARY}") + +set(glfw_LIBRARIES ${glfw_LIBRARY}) + +#----------------------------------------------------------------------------- +# Find package +#----------------------------------------------------------------------------- +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(glfw + REQUIRED_VARS + glfw_INCLUDE_DIR + glfw_LIBRARIES) + +#----------------------------------------------------------------------------- +# If missing target, create it +#----------------------------------------------------------------------------- +if(GLFW_FOUND AND NOT TARGET glfw) + add_library(glfw INTERFACE IMPORTED) + set_target_properties(glfw PROPERTIES + INTERFACE_LINK_LIBRARIES "${glfw_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${glfw_INCLUDE_DIR}" + ) +endif() diff --git a/CMake/Findgli.cmake b/CMake/Findgli.cmake new file mode 100644 index 0000000000000000000000000000000000000000..7391ccbb12347a57cfd42fcad76092211fc18dee --- /dev/null +++ b/CMake/Findgli.cmake @@ -0,0 +1,28 @@ +#----------------------------------------------------------------------------- +# Find path +#----------------------------------------------------------------------------- +find_path(gli_INCLUDE_DIR + NAMES + gli/gli.hpp + ) +mark_as_advanced(gli_INCLUDE_DIR) +message(STATUS "gli_INCLUDE_DIR : ${gli_INCLUDE_DIR}") + +#----------------------------------------------------------------------------- +# Find package +#----------------------------------------------------------------------------- +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(gli + REQUIRED_VARS + gli_INCLUDE_DIR) + +#----------------------------------------------------------------------------- +# If missing target, create it +#----------------------------------------------------------------------------- +if(GLM_FOUND AND NOT TARGET gli) + add_library(gli INTERFACE IMPORTED) + set_target_properties(gli PROPERTIES + INTERFACE_LINK_LIBRARIES "${gli_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${gli_INCLUDE_DIR}" + ) +endif() diff --git a/CMake/Findglm.cmake b/CMake/Findglm.cmake new file mode 100644 index 0000000000000000000000000000000000000000..82c4d05a662c5ca0642fa3d8560f209ad068d95d --- /dev/null +++ b/CMake/Findglm.cmake @@ -0,0 +1,28 @@ +#----------------------------------------------------------------------------- +# Find path +#----------------------------------------------------------------------------- +find_path(glm_INCLUDE_DIR + NAMES + glm/glm.hpp + ) +mark_as_advanced(glm_INCLUDE_DIR) +message(STATUS "glm_INCLUDE_DIR : ${glm_INCLUDE_DIR}") + +#----------------------------------------------------------------------------- +# Find package +#----------------------------------------------------------------------------- +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(glm + REQUIRED_VARS + glm_INCLUDE_DIR) + +#----------------------------------------------------------------------------- +# If missing target, create it +#----------------------------------------------------------------------------- +if(GLM_FOUND AND NOT TARGET glm) + add_library(glm INTERFACE IMPORTED) + set_target_properties(glm PROPERTIES + INTERFACE_LINK_LIBRARIES "${glm_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${glm_INCLUDE_DIR}" + ) +endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b4b63dfdf59d3ba29369430bb1fd9069f5dce26..a17c8a969c9f0e394ad80e9947f3ad44e0641f09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,14 @@ if(${PROJECT_NAME}_SUPERBUILD) imstk_define_dependency(Uncrustify) endif() + option(${PROJECT_NAME}_USE_Vulkan "Use the custom Vulkan renderer." OFF) + + if(${PROJECT_NAME}_USE_Vulkan) + imstk_define_dependency(glfw) + imstk_define_dependency(glm) + imstk_define_dependency(gli) + endif() + if(WIN32) imstk_define_dependency(PThreads) imstk_define_dependency(Libusb) #for VRPN @@ -196,6 +204,20 @@ endif(Uncrustify_EXECUTABLE) find_package( Assimp REQUIRED ) include_directories( ${Assimp_INCLUDE_DIRS} ) +if( ${PROJECT_NAME}_USE_Vulkan ) + # glfw + find_package(glfw) + include_directories( ${glfw_INCLUDE_DIR} ) + + # glm + find_package(glm) + include_directories( ${glm_INCLUDE_DIR} ) + + # gli + find_package(gli) + include_directories( ${gli_INCLUDE_DIR} ) +endif() + # g3log find_package( g3log REQUIRED ) include_directories( ${g3log_INCLUDE_DIR} ) @@ -238,6 +260,15 @@ else() remove_definitions( -DiMSTK_USE_ODE ) endif() +# Vulkan +if(${PROJECT_NAME}_USE_Vulkan) + find_package( VulkanSDK ) + include_directories( ${VulkanSDK_INCLUDE_DIR} ) + add_definitions( -DiMSTK_USE_Vulkan ) +else() + remove_definitions( -DiMSTK_USE_Vulkan ) +endif() + # Google Test if(BUILD_TESTING) find_package( GoogleTest REQUIRED ) diff --git a/Examples/Sandbox/CMakeLists.txt b/Examples/Sandbox/CMakeLists.txt index 2b6073a245c6ab7fc4873710a872b6c521c18fc7..716ed702d1003c15285f67a02cf38f3dd67b010c 100644 --- a/Examples/Sandbox/CMakeLists.txt +++ b/Examples/Sandbox/CMakeLists.txt @@ -58,7 +58,38 @@ imstk_add_data(${PROJECT_NAME} ${FILE_LIST}) #----------------------------------------------------------------------------- # Shaders #----------------------------------------------------------------------------- -file(COPY ${CMAKE_SOURCE_DIR}/Source/Rendering/VTKShaders - DESTINATION ${PROJECT_BINARY_DIR}/Shaders) -file(COPY ${CMAKE_SOURCE_DIR}/Source/Rendering/VTKShaders - DESTINATION ${CMAKE_PROGRAM_PATH}/Shaders) \ No newline at end of file +function(compileShaders sourceShader binaryShader) + add_custom_command( + TARGET Sandbox + COMMAND glslangvalidator -V ${PROJECT_BINARY_DIR}/Shaders/VulkanShaders/${sourceShader} -o ${PROJECT_BINARY_DIR}/Shaders/VulkanShaders/${binaryShader}) +endfunction() + +if( iMSTK_USE_Vulkan ) + file(COPY ${CMAKE_SOURCE_DIR}/Source/Rendering/VulkanRenderer/VulkanShaders + DESTINATION ${PROJECT_BINARY_DIR}/Shaders) + + # Mesh shaders + compileShaders(Mesh/mesh_vert.vert Mesh/mesh_vert.spv) + compileShaders(Mesh/mesh_tesc.tesc Mesh/mesh_tesc.spv) + compileShaders(Mesh/mesh_tese.tese Mesh/mesh_tese.spv) + compileShaders(Mesh/mesh_frag.frag Mesh/mesh_frag.spv) + + # Post processing shaders + compileShaders(PostProcessing/HDR_tonemap_frag.frag PostProcessing/HDR_tonemap_frag.spv) + compileShaders(PostProcessing/postprocess_vert.vert PostProcessing/postprocess_vert.spv) + compileShaders(PostProcessing/postprocess_frag.frag PostProcessing/postprocess_frag.spv) + compileShaders(PostProcessing/sss_frag.frag PostProcessing/sss_frag.spv) + compileShaders(PostProcessing/composite_frag.frag PostProcessing/composite_frag.spv) + compileShaders(PostProcessing/bloom_threshold_frag.frag PostProcessing/bloom_threshold_frag.spv) + compileShaders(PostProcessing/blur_horizontal_frag.frag PostProcessing/blur_horizontal_frag.spv) + compileShaders(PostProcessing/blur_vertical_frag.frag PostProcessing/blur_vertical_frag.spv) + compileShaders(PostProcessing/bloom_threshold_frag.frag PostProcessing/bloom_threshold_frag.spv) + + file(COPY ${PROJECT_BINARY_DIR}/Shaders/VulkanShaders + DESTINATION ${CMAKE_PROGRAM_PATH}/Shaders) +else( iMSTK_USE_Vulkan ) + file(COPY ${CMAKE_SOURCE_DIR}/Source/Rendering/VTKRenderer/VTKShaders + DESTINATION ${PROJECT_BINARY_DIR}/Shaders) + file(COPY ${CMAKE_SOURCE_DIR}/Source/Rendering/VTKRenderer/VTKShaders + DESTINATION ${CMAKE_PROGRAM_PATH}/Shaders) +endif() diff --git a/Examples/Sandbox/main.cpp b/Examples/Sandbox/main.cpp index 330dfb392fda4484399f330405e576866aba17c1..62f9a554a4fcf573c060ea3293e8a95e1b2bde44 100644 --- a/Examples/Sandbox/main.cpp +++ b/Examples/Sandbox/main.cpp @@ -218,6 +218,79 @@ void testMshAndVegaIO() sdk->startSimulation(true); } +void testVTKTexture() +{ + // Parse command line arguments + + std::string inputFilename = iMSTK_DATA_ROOT "/ETI/resources/OperatingRoom/cloth.obj"; + std::string texturename = iMSTK_DATA_ROOT "/ETI/resources/TextureOR/cloth.jpg"; + + std::string inputFilename1 = iMSTK_DATA_ROOT "/ETI/resources/OperatingRoom/bed1.obj"; + std::string texturename1 = iMSTK_DATA_ROOT "/ETI/resources/TextureOR/bed-1.jpg"; + + vtkSmartPointer<vtkOBJReader> reader = + vtkSmartPointer<vtkOBJReader>::New(); + reader->SetFileName(inputFilename.c_str()); + reader->Update(); + + + vtkSmartPointer<vtkOBJReader> reader1 = + vtkSmartPointer<vtkOBJReader>::New(); + reader1->SetFileName(inputFilename1.c_str()); + reader1->Update(); + + // Visualize + vtkSmartPointer<vtkPolyDataMapper> mapper = + vtkSmartPointer<vtkPolyDataMapper>::New(); + mapper->SetInputConnection(reader->GetOutputPort()); + + vtkSmartPointer<vtkPolyDataMapper> mapper1 = + vtkSmartPointer<vtkPolyDataMapper>::New(); + mapper1->SetInputConnection(reader1->GetOutputPort()); + + vtkSmartPointer<vtkActor> actor = + vtkSmartPointer<vtkActor>::New(); + actor->SetMapper(mapper); + + vtkSmartPointer<vtkActor> actor1 = + vtkSmartPointer<vtkActor>::New(); + actor1->SetMapper(mapper1); + + vtkSmartPointer<vtkJPEGReader> jpgReader = + vtkSmartPointer<vtkJPEGReader>::New(); + jpgReader->SetFileName(texturename.c_str()); + jpgReader->Update(); + vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New(); + texture->SetInputConnection(jpgReader->GetOutputPort()); + texture->InterpolateOn(); + actor->SetTexture(texture); + + vtkSmartPointer<vtkJPEGReader> jpgReader1 = + vtkSmartPointer<vtkJPEGReader>::New(); + jpgReader1->SetFileName(texturename1.c_str()); + jpgReader1->Update(); + vtkSmartPointer<vtkTexture> texture1 = vtkSmartPointer<vtkTexture>::New(); + texture1->SetInputConnection(jpgReader1->GetOutputPort()); + texture1->InterpolateOn(); + actor1->SetTexture(texture1); + + vtkSmartPointer<vtkRenderer> renderer = + vtkSmartPointer<vtkRenderer>::New(); + renderer->AddActor(actor); + renderer->AddActor(actor1); + renderer->SetBackground(.3, .6, .3); // Background color green + + vtkSmartPointer<vtkRenderWindow> renderWindow = + vtkSmartPointer<vtkRenderWindow>::New(); + renderWindow->AddRenderer(renderer); + + vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = + vtkSmartPointer<vtkRenderWindowInteractor>::New(); + renderWindowInteractor->SetRenderWindow(renderWindow); + + renderWindowInteractor->Start(); +} + void testMultiObjectWithTextures() { // SDK and Scene @@ -930,7 +1003,7 @@ void testIsometricMap() // Start simulation sdk->setActiveScene(geometryMapTest); - sdk->startSimulation(VTKRenderer::Mode::DEBUG); + sdk->startSimulation(imstk::Renderer::Mode::DEBUG); } void testTetraTriangleMap() @@ -2499,14 +2572,19 @@ void testScreenShotUtility() cam1->setPosition(Vec3d(-5.5, 2.5, 32)); cam1->setFocalPoint(Vec3d(1, 1, 0)); +#ifndef iMSTK_USE_Vulkan + auto viewer = std::dynamic_pointer_cast<VTKViewer>(sdk->getViewer()); + auto screenShotUtility + = std::dynamic_pointer_cast<VTKScreenCaptureUtility>(viewer->getScreenCaptureUtility()); // Set up for screen shot sdk->getViewer()->getScreenCaptureUtility()->setScreenShotPrefix("screenShot_"); // Create a call back on key press of 'b' to take the screen shot - sdk->getViewer()->setOnCharFunction('b', [&](VTKInteractorStyle* c) -> bool + viewer->setOnCharFunction('b', [&](VTKInteractorStyle* c) -> bool { - sdk->getViewer()->getScreenCaptureUtility()->saveScreenShot(); + screenShotUtility->saveScreenShot(); return false; }); +#endif // Run sdk->setActiveScene(sceneTest); @@ -3293,11 +3371,11 @@ int main() /*------------------ Test physics ------------------*/ - testPbdVolume(); + //testPbdVolume(); testPbdCloth(); //testPbdCollision(); - testPbdFluidBenchmarking(); - testPbdFluid(); + //testPbdFluidBenchmarking(); + //testPbdFluid(); //testDeformableBody(); //testDeformableBodyCollision(); //liverToolInteraction(); diff --git a/Source/Geometry/Reader/imstkAssimpMeshIO.cpp b/Source/Geometry/Reader/imstkAssimpMeshIO.cpp index 72919ef5fd6852765847eb5b8b484c30adafa1e3..b3cfca9479f2ab8e0fc3f71d15615195a47b8a6a 100644 --- a/Source/Geometry/Reader/imstkAssimpMeshIO.cpp +++ b/Source/Geometry/Reader/imstkAssimpMeshIO.cpp @@ -80,6 +80,7 @@ AssimpMeshIO::readMeshData(const std::string& filePath) // Vertex positions StdVectorOfVec3d positions(numVertices); + for (unsigned int i = 0; i < numVertices; i++) { auto positionX = importedMesh->mVertices[i].x; @@ -90,6 +91,7 @@ AssimpMeshIO::readMeshData(const std::string& filePath) // Triangles std::vector<SurfaceMesh::TriangleArray> triangles(numTriangles); + for (unsigned int i = 0; i < numTriangles; i++) { auto triangle = importedMesh->mFaces[i]; @@ -152,7 +154,6 @@ AssimpMeshIO::readMeshData(const std::string& filePath) mesh->setDefaultTCoords("tCoords"); mesh->setPointDataArray("tCoords",UVs); } - return mesh; } } diff --git a/Source/Materials/imstkRenderMaterial.cpp b/Source/Materials/imstkRenderMaterial.cpp index 672246021924614bc9856269a6cc3415770cfddf..0117bc21fa71f6d766f80442d9174e6f39bb1e6a 100644 --- a/Source/Materials/imstkRenderMaterial.cpp +++ b/Source/Materials/imstkRenderMaterial.cpp @@ -50,6 +50,24 @@ RenderMaterial::setDisplayMode(const DisplayMode displayMode) m_modified = true; } +bool +RenderMaterial::getTessellated() const +{ + return m_tessellated; +} + +void +RenderMaterial::setTessellated(const bool tessellated) +{ + if (tessellated == m_tessellated) + { + return; + } + m_tessellated = tessellated; + m_stateModified = true; + m_modified = true; +} + float RenderMaterial::getLineWidth() const { diff --git a/Source/Materials/imstkRenderMaterial.h b/Source/Materials/imstkRenderMaterial.h index ed8d22154f4f3dee7d1f4f05ae076d7e87b3ef67..68bfd4dfebf0e09a2c089d336ecd6fec26bc5bba 100644 --- a/Source/Materials/imstkRenderMaterial.h +++ b/Source/Materials/imstkRenderMaterial.h @@ -55,6 +55,12 @@ public: DisplayMode getDisplayMode() const; void setDisplayMode(const DisplayMode displayMode); + /// + /// \brief Get/Set tessellated + /// + bool getTessellated() const; + void setTessellated(const bool tessellated); + /// /// \brief Get/Set line width or the wireframe /// @@ -129,6 +135,7 @@ protected: // State DisplayMode m_displayMode = DisplayMode::SURFACE; + bool m_tessellated = false; float m_lineWidth = 1.0; float m_pointSize = 1.0; bool m_backfaceCulling = true; ///< For performance, uncommon for this to be false diff --git a/Source/Materials/imstkTexture.cpp b/Source/Materials/imstkTexture.cpp index 4e8a4dd46a8d576f16ee23a36353e77dc8530b0a..2065bb49a313b8651ee17ad86b891daccf8de89d 100644 --- a/Source/Materials/imstkTexture.cpp +++ b/Source/Materials/imstkTexture.cpp @@ -40,4 +40,10 @@ Texture::getPath() const { return m_path; } + +bool +Texture::getMipmapsEnabled() +{ + return m_mipmapsEnabled; +} } \ No newline at end of file diff --git a/Source/Materials/imstkTexture.h b/Source/Materials/imstkTexture.h index 9484e8224273a73b50f538b1a4f5e55c51aa60ac..16b60bc0131b95e46c9c38b60d0f50538e807e45 100644 --- a/Source/Materials/imstkTexture.h +++ b/Source/Materials/imstkTexture.h @@ -30,9 +30,6 @@ namespace imstk /// /// \class Texture /// -/// \brief iMSTK texture class. There are a few texture types that -/// dictate how texture are to be treated. -/// class Texture { public: @@ -46,9 +43,12 @@ public: SPECULAR, ROUGHNESS, METALNESS, + SUBSURFACE_SCATTERING, AMBIENT_OCCLUSION, CAVITY, CUBEMAP, + IRRADIANCE_CUBEMAP, + RADIANCE_CUBEMAP, NONE }; @@ -74,10 +74,17 @@ public: /// const std::string getPath() const; -protected: + /// + /// \brief Get type + /// + bool getMipmapsEnabled(); +protected: Type m_type; ///< Texture type std::string m_path; ///< Texture file path + + // Helps with texture aliasing (and a little with performance) + bool m_mipmapsEnabled = true; }; } diff --git a/Source/Rendering/CMakeLists.txt b/Source/Rendering/CMakeLists.txt index b7f79ac025cc5fd0940a476f55aad641aa0db995..548319723db63a1fea32a47d669e3eafb8679397 100644 --- a/Source/Rendering/CMakeLists.txt +++ b/Source/Rendering/CMakeLists.txt @@ -1,46 +1,111 @@ #----------------------------------------------------------------------------- # Create target #----------------------------------------------------------------------------- + +set(VTK_H_FILES + VTKRenderer/imstkVTKRenderer.h + VTKRenderer/imstkVTKTextureDelegate.h + VTKRenderer/imstkVTKCustomPolyDataMapper.h + VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h + VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h + VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h + VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h + VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h + VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h + VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h + VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h + VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h + VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h + VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h) + +set(VTK_CPP_FILES + VTKRenderer/imstkVTKRenderer.cpp + VTKRenderer/imstkVTKTextureDelegate.cpp + VTKRenderer/imstkVTKCustomPolyDataMapper.cpp + VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp + VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp + VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp + VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp + VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp + VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp + VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp + VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp + VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp + VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp + VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp) + +set(VULKAN_H_FILES + VulkanRenderer/imstkVulkanRenderer.h + VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.h + VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.h + VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.h + VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.h + VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.h + VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.h + VulkanRenderer/imstkVulkanMaterialDelegate.h + VulkanRenderer/imstkVulkanTextureDelegate.h + VulkanRenderer/imstkVulkanMemoryManager.h + VulkanRenderer/imstkVulkanValidation.h + VulkanRenderer/imstkVulkanBuffer.h + VulkanRenderer/imstkVulkanUniformBuffer.h + VulkanRenderer/imstkVulkanVertexBuffer.h + VulkanRenderer/imstkVulkanFramebuffer.h + VulkanRenderer/PostProcessing/imstkVulkanPostProcess.h + VulkanRenderer/PostProcessing/imstkVulkanPostProcessingChain.h) + +set(VULKAN_CPP_FILES + VulkanRenderer/imstkVulkanRenderer.cpp + VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.cpp + VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.cpp + VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.cpp + VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp + VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.cpp + VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.cpp + VulkanRenderer/imstkVulkanMaterialDelegate.cpp + VulkanRenderer/imstkVulkanTextureDelegate.cpp + VulkanRenderer/imstkVulkanMemoryManager.cpp + VulkanRenderer/imstkVulkanUniformBuffer.cpp + VulkanRenderer/imstkVulkanVertexBuffer.cpp + VulkanRenderer/imstkVulkanFramebuffer.cpp + VulkanRenderer/PostProcessing/imstkVulkanPostProcess.cpp + VulkanRenderer/PostProcessing/imstkVulkanPostProcessingChain.cpp) + +if( NOT iMSTK_USE_Vulkan ) + set(RENDERING_H_FILES ${VTK_H_FILES}) + set(RENDERING_CPP_FILES ${VTK_CPP_FILES}) + set(RENDERING_SUBDIR + VTKRenderer + VTKRenderer/RenderDelegate) + set(RENDERING_DEPENDENCIES) +else() + set(RENDERING_H_FILES ${VULKAN_H_FILES}) + set(RENDERING_CPP_FILES ${VULKAN_CPP_FILES}) + set(RENDERING_SUBDIR + VulkanRenderer + VulkanRenderer/RenderDelegate + VulkanRenderer/PostProcessing) + set(RENDERING_DEPENDENCIES + ${VulkanSDK_LIBRARIES} + glfw + glm + gli) +endif() + include(imstkAddLibrary) imstk_add_library( Rendering H_FILES - imstkVTKRenderer.h - imstkVTKTextureDelegate.h - imstkVTKCustomPolyDataMapper.h - RenderDelegate/imstkVTKCubeRenderDelegate.h - RenderDelegate/imstkVTKLineMeshRenderDelegate.h - RenderDelegate/imstkVTKPlaneRenderDelegate.h - RenderDelegate/imstkVTKCylinderRenderDelegate.h - RenderDelegate/imstkVTKCapsuleRenderDelegate.h - RenderDelegate/imstkVTKRenderDelegate.h - RenderDelegate/imstkVTKSphereRenderDelegate.h - RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h - RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h - RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h - RenderDelegate/imstkVTKPointSetRenderDelegate.h - RenderDelegate/vtkCapsuleSource.h - + imstkRenderer.h + ${RENDERING_H_FILES} + vtkCapsuleSource.h CPP_FILES - imstkVTKRenderer.cpp - imstkVTKTextureDelegate.cpp - imstkVTKCustomPolyDataMapper.cpp - RenderDelegate/imstkVTKCubeRenderDelegate.cpp - RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp - RenderDelegate/imstkVTKPlaneRenderDelegate.cpp - RenderDelegate/imstkVTKCylinderRenderDelegate.cpp - RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp - RenderDelegate/imstkVTKRenderDelegate.cpp - RenderDelegate/imstkVTKSphereRenderDelegate.cpp - RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp - RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp - RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp - RenderDelegate/imstkVTKPointSetRenderDelegate.cpp - RenderDelegate/vtkCapsuleSource.cpp - + imstkRenderer.cpp + ${RENDERING_CPP_FILES} + vtkCapsuleSource.cpp SUBDIR_LIST - RenderDelegate + ${RENDERING_SUBDIR} DEPENDS ${VTK_LIBRARIES} + ${RENDERING_DEPENDENCIES} Scene #VERBOSE ) diff --git a/Source/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.cpp diff --git a/Source/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKCapsuleRenderDelegate.h rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCapsuleRenderDelegate.h diff --git a/Source/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.cpp rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.cpp diff --git a/Source/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKCubeRenderDelegate.h rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCubeRenderDelegate.h diff --git a/Source/Rendering/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.cpp diff --git a/Source/Rendering/RenderDelegate/imstkVTKCylinderRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKCylinderRenderDelegate.h rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKCylinderRenderDelegate.h diff --git a/Source/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.cpp diff --git a/Source/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKHexahedralMeshRenderDelegate.h diff --git a/Source/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.cpp diff --git a/Source/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKLineMeshRenderDelegate.h rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKLineMeshRenderDelegate.h diff --git a/Source/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.cpp diff --git a/Source/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKPlaneRenderDelegate.h rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPlaneRenderDelegate.h diff --git a/Source/Rendering/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.cpp diff --git a/Source/Rendering/RenderDelegate/imstkVTKPointSetRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKPointSetRenderDelegate.h rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKPointSetRenderDelegate.h diff --git a/Source/Rendering/RenderDelegate/imstkVTKRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKRenderDelegate.cpp rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.cpp diff --git a/Source/Rendering/RenderDelegate/imstkVTKRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKRenderDelegate.h rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKRenderDelegate.h diff --git a/Source/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.cpp rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.cpp diff --git a/Source/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKSphereRenderDelegate.h rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSphereRenderDelegate.h diff --git a/Source/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.cpp diff --git a/Source/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKSurfaceMeshRenderDelegate.h diff --git a/Source/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.cpp diff --git a/Source/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h b/Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h similarity index 100% rename from Source/Rendering/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h rename to Source/Rendering/VTKRenderer/RenderDelegate/imstkVTKTetrahedralMeshRenderDelegate.h diff --git a/Source/Rendering/VTKShaders/mesh.frag b/Source/Rendering/VTKRenderer/VTKShaders/mesh.frag similarity index 100% rename from Source/Rendering/VTKShaders/mesh.frag rename to Source/Rendering/VTKRenderer/VTKShaders/mesh.frag diff --git a/Source/Rendering/VTKShaders/mesh.vert b/Source/Rendering/VTKRenderer/VTKShaders/mesh.vert similarity index 100% rename from Source/Rendering/VTKShaders/mesh.vert rename to Source/Rendering/VTKRenderer/VTKShaders/mesh.vert diff --git a/Source/Rendering/imstkVTKCustomPolyDataMapper.cpp b/Source/Rendering/VTKRenderer/imstkVTKCustomPolyDataMapper.cpp similarity index 100% rename from Source/Rendering/imstkVTKCustomPolyDataMapper.cpp rename to Source/Rendering/VTKRenderer/imstkVTKCustomPolyDataMapper.cpp diff --git a/Source/Rendering/imstkVTKCustomPolyDataMapper.h b/Source/Rendering/VTKRenderer/imstkVTKCustomPolyDataMapper.h similarity index 100% rename from Source/Rendering/imstkVTKCustomPolyDataMapper.h rename to Source/Rendering/VTKRenderer/imstkVTKCustomPolyDataMapper.h diff --git a/Source/Rendering/imstkVTKRenderer.cpp b/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp similarity index 98% rename from Source/Rendering/imstkVTKRenderer.cpp rename to Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp index 9be6bbe06ad6138fd96d2dc3fa2f821abdfdeac5..93908e2dc61fc8dd36f36c6ee09c5cf4d217deab 100644 --- a/Source/Rendering/imstkVTKRenderer.cpp +++ b/Source/Rendering/VTKRenderer/imstkVTKRenderer.cpp @@ -122,7 +122,7 @@ VTKRenderer::getVtkRenderer() const } void -VTKRenderer::setMode(Mode mode) +VTKRenderer::setMode(Renderer::Mode mode) { if( mode == Mode::EMPTY && m_currentMode != Mode::EMPTY ) { @@ -174,12 +174,6 @@ VTKRenderer::setMode(Mode mode) m_currentMode = mode; } -const VTKRenderer::Mode& -VTKRenderer::getMode() -{ - return m_currentMode; -} - void VTKRenderer::updateSceneCamera(std::shared_ptr<Camera> imstkCam) { diff --git a/Source/Rendering/imstkVTKRenderer.h b/Source/Rendering/VTKRenderer/imstkVTKRenderer.h similarity index 87% rename from Source/Rendering/imstkVTKRenderer.h rename to Source/Rendering/VTKRenderer/imstkVTKRenderer.h index b134f53589403bfa248a2b0d2c6fa84889513794..29d4424ff5c969f73e5b2bfff1577af972d10f55 100644 --- a/Source/Rendering/imstkVTKRenderer.h +++ b/Source/Rendering/VTKRenderer/imstkVTKRenderer.h @@ -28,6 +28,7 @@ #include "imstkMath.h" #include "imstkTextureManager.h" #include "imstkVTKTextureDelegate.h" +#include "imstkRenderer.h" #include "vtkSmartPointer.h" #include "vtkRenderer.h" @@ -46,19 +47,9 @@ class VTKRenderDelegate; /// /// \brief /// -class VTKRenderer +class VTKRenderer : public Renderer { public: - /// - /// \brief Enumerations for the render mode - /// - enum Mode - { - EMPTY, - DEBUG, - SIMULATION - }; - /// /// \brief Constructor /// @@ -73,8 +64,7 @@ public: /// \brief Set/Get the rendering mode which defined the /// visibility of the renderer actors and the default camera /// - void setMode(Mode mode); - const Mode& getMode(); + virtual void setMode(Mode mode); /// /// \brief @@ -94,7 +84,7 @@ public: /// /// \brief Update background colors /// - void updateBackground(const Vec3d color1, const Vec3d color2 = Vec3d::Zero(), const bool gradientBackground = false); + virtual void updateBackground(const Vec3d color1, const Vec3d color2 = Vec3d::Zero(), const bool gradientBackground = false); protected: /// @@ -116,8 +106,6 @@ protected: std::vector<std::shared_ptr<VTKRenderDelegate>> m_renderDelegates; - Mode m_currentMode = Mode::EMPTY; - TextureManager<VTKTextureDelegate> m_textureManager; }; } diff --git a/Source/Rendering/imstkVTKTextureDelegate.cpp b/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp similarity index 100% rename from Source/Rendering/imstkVTKTextureDelegate.cpp rename to Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.cpp diff --git a/Source/Rendering/imstkVTKTextureDelegate.h b/Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.h similarity index 100% rename from Source/Rendering/imstkVTKTextureDelegate.h rename to Source/Rendering/VTKRenderer/imstkVTKTextureDelegate.h diff --git a/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcess.cpp b/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcess.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a7c1dc4a60e3d7afa730155e2f144f1ef8bd4b04 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcess.cpp @@ -0,0 +1,571 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanPostProcess.h" + +#include "imstkVulkanRenderer.h" + +namespace imstk +{ +VulkanPostProcess::VulkanPostProcess(VulkanRenderer * renderer, unsigned int level, bool lastPass) +{ + m_lastPass = lastPass; + m_downsampleLevels = level; + this->createFramebuffer(renderer, level, lastPass); +} + +void +VulkanPostProcess::initialize(VulkanRenderer * renderer, std::string fragmentShaderPath) +{ + this->initializeFramebuffer(renderer); + this->createDescriptorSetLayouts(renderer); + this->createFullscreenQuad(renderer); + this->createPipeline(renderer, fragmentShaderPath); + this->createDescriptors(renderer); +} + +void +VulkanPostProcess::createPipeline(VulkanRenderer * renderer, std::string fragmentSource) +{ + // The vertex shader should be the same for every postprocess + std::string vertexShaderPath = "./Shaders/VulkanShaders/PostProcessing/postprocess_vert.spv"; + std::ifstream vertexShaderDataStream(vertexShaderPath, std::ios_base::binary); + char vertexShaderData[16000]; + vertexShaderDataStream.read(vertexShaderData, 15999); + vertexShaderData[(int)vertexShaderDataStream.gcount()] = '\0'; + + VkShaderModuleCreateInfo vertexShaderInfo; + vertexShaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + vertexShaderInfo.pNext = nullptr; + vertexShaderInfo.flags = 0; + vertexShaderInfo.codeSize = vertexShaderDataStream.gcount(); + vertexShaderInfo.pCode = (uint32_t *)vertexShaderData; + if (vkCreateShaderModule(renderer->m_renderDevice, &vertexShaderInfo, nullptr, &m_pipelineComponents.vertexShader) != VK_SUCCESS) + { + LOG(FATAL) << "Unable to build vertex shader : " << vertexShaderPath; + } + + std::string fragmentShaderPath = fragmentSource; + std::ifstream fragmentShaderDataStream(fragmentShaderPath, std::ios_base::binary); + char fragmentShaderData[16000]; + fragmentShaderDataStream.read(fragmentShaderData, 15999); + fragmentShaderData[(int)fragmentShaderDataStream.gcount()] = '\0'; + + VkShaderModuleCreateInfo fragmentShaderInfo; + fragmentShaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + fragmentShaderInfo.pNext = nullptr; + fragmentShaderInfo.flags = 0; + fragmentShaderInfo.codeSize = fragmentShaderDataStream.gcount(); + fragmentShaderInfo.pCode = (uint32_t *)fragmentShaderData; + if (vkCreateShaderModule(renderer->m_renderDevice, &fragmentShaderInfo, nullptr, &m_pipelineComponents.fragmentShader) != VK_SUCCESS) + { + LOG(FATAL) << "Unable to build fragment shader: " << fragmentShaderPath; + } + + m_pipelineComponents.shaderInfo.resize(2); + + m_pipelineComponents.fragmentSpecializationInfo.mapEntryCount = 0; + m_pipelineComponents.fragmentSpecializationInfo.pMapEntries = nullptr; + m_pipelineComponents.fragmentSpecializationInfo.dataSize = 0; + m_pipelineComponents.fragmentSpecializationInfo.pData = nullptr; + + // Vertex Shader + m_pipelineComponents.shaderInfo[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + m_pipelineComponents.shaderInfo[0].pNext = nullptr; + m_pipelineComponents.shaderInfo[0].flags = 0; + m_pipelineComponents.shaderInfo[0].stage = VK_SHADER_STAGE_VERTEX_BIT; + m_pipelineComponents.shaderInfo[0].module = m_pipelineComponents.vertexShader; + m_pipelineComponents.shaderInfo[0].pName = "main"; + m_pipelineComponents.shaderInfo[0].pSpecializationInfo = &m_pipelineComponents.fragmentSpecializationInfo; + + // Fragment Shader + m_pipelineComponents.shaderInfo[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + m_pipelineComponents.shaderInfo[1].pNext = nullptr; + m_pipelineComponents.shaderInfo[1].flags = 0; + m_pipelineComponents.shaderInfo[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT; + m_pipelineComponents.shaderInfo[1].module = m_pipelineComponents.fragmentShader; + m_pipelineComponents.shaderInfo[1].pName = "main"; + m_pipelineComponents.shaderInfo[1].pSpecializationInfo = &m_pipelineComponents.fragmentSpecializationInfo; + + // Vertex Attributes + m_pipelineComponents.vertexBindingDescription.resize(1); + + m_pipelineComponents.vertexBindingDescription[0].binding = 0; + m_pipelineComponents.vertexBindingDescription[0].stride = 4 * 5; + m_pipelineComponents.vertexBindingDescription[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + // Vertex Attributes + m_pipelineComponents.vertexAttributeDescription.resize(2); + + m_pipelineComponents.vertexAttributeDescription[0].location = 0; + m_pipelineComponents.vertexAttributeDescription[0].binding = 0; + m_pipelineComponents.vertexAttributeDescription[0].format = VK_FORMAT_R32G32B32_SFLOAT; + m_pipelineComponents.vertexAttributeDescription[0].offset = 0; + + m_pipelineComponents.vertexAttributeDescription[1].location = 1; + m_pipelineComponents.vertexAttributeDescription[1].binding = 0; + m_pipelineComponents.vertexAttributeDescription[1].format = VK_FORMAT_R32G32_SFLOAT; + m_pipelineComponents.vertexAttributeDescription[1].offset = 4 * 3; + + // Pipeline stages + m_pipelineComponents.vertexInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + m_pipelineComponents.vertexInfo.pNext = nullptr; + m_pipelineComponents.vertexInfo.flags = 0; + m_pipelineComponents.vertexInfo.vertexBindingDescriptionCount = (uint32_t)m_pipelineComponents.vertexBindingDescription.size(); + m_pipelineComponents.vertexInfo.pVertexBindingDescriptions = &m_pipelineComponents.vertexBindingDescription[0]; + m_pipelineComponents.vertexInfo.vertexAttributeDescriptionCount = (uint32_t)m_pipelineComponents.vertexAttributeDescription.size(); + m_pipelineComponents.vertexInfo.pVertexAttributeDescriptions = &m_pipelineComponents.vertexAttributeDescription[0]; + + m_pipelineComponents.inputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + m_pipelineComponents.inputAssemblyInfo.pNext = nullptr; + m_pipelineComponents.inputAssemblyInfo.flags = 0; + m_pipelineComponents.inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + m_pipelineComponents.inputAssemblyInfo.primitiveRestartEnable = VK_FALSE; + + m_pipelineComponents.tessellationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + m_pipelineComponents.tessellationInfo.pNext = nullptr; + m_pipelineComponents.tessellationInfo.flags = 0; + m_pipelineComponents.tessellationInfo.patchControlPoints = 1; // For now, this should be changed in the future + + m_pipelineComponents.viewports.resize(1); + + m_pipelineComponents.viewports[0].x = 0; + m_pipelineComponents.viewports[0].y = 0; + m_pipelineComponents.viewports[0].height = m_framebuffer->m_height; + m_pipelineComponents.viewports[0].width = m_framebuffer->m_width; + m_pipelineComponents.viewports[0].minDepth = 0.0; + m_pipelineComponents.viewports[0].maxDepth = 1.0; + + m_pipelineComponents.scissors.resize(1); + + m_pipelineComponents.scissors[0].offset = { 0, 0 }; + m_pipelineComponents.scissors[0].extent = { m_framebuffer->m_width, m_framebuffer->m_height }; + + m_pipelineComponents.viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + m_pipelineComponents.viewportInfo.pNext = nullptr; + m_pipelineComponents.viewportInfo.flags = 0; + m_pipelineComponents.viewportInfo.viewportCount = (uint32_t)m_pipelineComponents.viewports.size(); + m_pipelineComponents.viewportInfo.pViewports = &m_pipelineComponents.viewports[0]; + m_pipelineComponents.viewportInfo.scissorCount = (uint32_t)m_pipelineComponents.scissors.size(); + m_pipelineComponents.viewportInfo.pScissors = &m_pipelineComponents.scissors[0]; + + m_pipelineComponents.rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + m_pipelineComponents.rasterizationInfo.pNext = nullptr; + m_pipelineComponents.rasterizationInfo.flags = 0; + m_pipelineComponents.rasterizationInfo.depthClampEnable = VK_FALSE; + m_pipelineComponents.rasterizationInfo.rasterizerDiscardEnable = VK_FALSE; + m_pipelineComponents.rasterizationInfo.polygonMode = VK_POLYGON_MODE_FILL; + m_pipelineComponents.rasterizationInfo.cullMode = VK_CULL_MODE_NONE; + m_pipelineComponents.rasterizationInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + m_pipelineComponents.rasterizationInfo.depthBiasEnable = VK_FALSE; + m_pipelineComponents.rasterizationInfo.depthBiasConstantFactor = 0.0; + m_pipelineComponents.rasterizationInfo.depthBiasClamp = VK_FALSE; + m_pipelineComponents.rasterizationInfo.depthBiasSlopeFactor = 0.0; + m_pipelineComponents.rasterizationInfo.lineWidth = 1.0; + + m_pipelineComponents.multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + m_pipelineComponents.multisampleInfo.pNext = nullptr; + m_pipelineComponents.multisampleInfo.flags = 0; + m_pipelineComponents.multisampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; // TODO: Enable multisampling + m_pipelineComponents.multisampleInfo.sampleShadingEnable = VK_FALSE; + m_pipelineComponents.multisampleInfo.minSampleShading = 0; + m_pipelineComponents.multisampleInfo.pSampleMask = nullptr; + m_pipelineComponents.multisampleInfo.alphaToCoverageEnable = VK_FALSE; + m_pipelineComponents.multisampleInfo.alphaToOneEnable = VK_FALSE; + + VkStencilOpState states[2]; + states[0].failOp = VK_STENCIL_OP_ZERO; + states[0].passOp = VK_STENCIL_OP_KEEP; + states[0].depthFailOp = VK_STENCIL_OP_ZERO; + states[0].compareOp = VK_COMPARE_OP_LESS; + states[0].compareMask = 0; + states[0].writeMask = 0; + states[0].reference = 0; + + states[1].failOp = VK_STENCIL_OP_ZERO; + states[1].passOp = VK_STENCIL_OP_KEEP; + states[1].depthFailOp = VK_STENCIL_OP_ZERO; + states[1].compareOp = VK_COMPARE_OP_LESS; + states[1].compareMask = 0; + states[1].writeMask = 0; + states[1].reference = 0; + + m_pipelineComponents.depthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + m_pipelineComponents.depthStencilInfo.pNext = nullptr; + m_pipelineComponents.depthStencilInfo.flags = 0; + m_pipelineComponents.depthStencilInfo.depthTestEnable = VK_FALSE; + m_pipelineComponents.depthStencilInfo.depthWriteEnable = VK_FALSE; + m_pipelineComponents.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS; + m_pipelineComponents.depthStencilInfo.depthBoundsTestEnable = VK_FALSE; + m_pipelineComponents.depthStencilInfo.stencilTestEnable = VK_FALSE; + m_pipelineComponents.depthStencilInfo.front = states[0]; + m_pipelineComponents.depthStencilInfo.back = states[1]; + m_pipelineComponents.depthStencilInfo.minDepthBounds = VK_FALSE; + m_pipelineComponents.depthStencilInfo.maxDepthBounds = VK_FALSE; + + m_pipelineComponents.colorBlendAttachments.resize(m_colorAttachments.size()); + for (int i = 0; i < m_pipelineComponents.colorBlendAttachments.size(); i++) + { + m_pipelineComponents.colorBlendAttachments[i].blendEnable = VK_TRUE; + m_pipelineComponents.colorBlendAttachments[i].srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + m_pipelineComponents.colorBlendAttachments[i].dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + m_pipelineComponents.colorBlendAttachments[i].colorBlendOp = VK_BLEND_OP_ADD; + m_pipelineComponents.colorBlendAttachments[i].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + m_pipelineComponents.colorBlendAttachments[i].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + m_pipelineComponents.colorBlendAttachments[i].alphaBlendOp = VK_BLEND_OP_ADD; + m_pipelineComponents.colorBlendAttachments[i].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT; + } + + m_pipelineComponents.colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + m_pipelineComponents.colorBlendInfo.pNext = nullptr; + m_pipelineComponents.colorBlendInfo.flags = 0; + m_pipelineComponents.colorBlendInfo.logicOpEnable = VK_FALSE; + m_pipelineComponents.colorBlendInfo.logicOp = VK_LOGIC_OP_SET; + m_pipelineComponents.colorBlendInfo.attachmentCount = (uint32_t)m_pipelineComponents.colorBlendAttachments.size(); + m_pipelineComponents.colorBlendInfo.pAttachments = &m_pipelineComponents.colorBlendAttachments[0]; + m_pipelineComponents.colorBlendInfo.blendConstants[0] = 1.0; + m_pipelineComponents.colorBlendInfo.blendConstants[1] = 1.0; + m_pipelineComponents.colorBlendInfo.blendConstants[2] = 1.0; + m_pipelineComponents.colorBlendInfo.blendConstants[3] = 1.0; + + VkPushConstantRange pushConstants; + pushConstants.offset = 0; + pushConstants.size = 128; // Minimum on all devices + pushConstants.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + + VkPipelineLayoutCreateInfo layoutInfo; + layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + layoutInfo.pNext = nullptr; + layoutInfo.flags = 0; + layoutInfo.setLayoutCount = (uint32_t)m_descriptorSetLayouts.size(); + layoutInfo.pSetLayouts = &m_descriptorSetLayouts[0]; + layoutInfo.pushConstantRangeCount = 1; + layoutInfo.pPushConstantRanges = &pushConstants; + + vkCreatePipelineLayout(renderer->m_renderDevice, &layoutInfo, nullptr, &m_pipelineLayout); + + m_graphicsPipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + m_graphicsPipelineInfo.pNext = nullptr; + m_graphicsPipelineInfo.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; + m_graphicsPipelineInfo.stageCount = (uint32_t)m_pipelineComponents.shaderInfo.size(); + m_graphicsPipelineInfo.pStages = &m_pipelineComponents.shaderInfo[0]; + m_graphicsPipelineInfo.pVertexInputState = &m_pipelineComponents.vertexInfo; + m_graphicsPipelineInfo.pInputAssemblyState = &m_pipelineComponents.inputAssemblyInfo; + m_graphicsPipelineInfo.pTessellationState = &m_pipelineComponents.tessellationInfo; + m_graphicsPipelineInfo.pViewportState = &m_pipelineComponents.viewportInfo; + m_graphicsPipelineInfo.pRasterizationState = &m_pipelineComponents.rasterizationInfo; + m_graphicsPipelineInfo.pMultisampleState = &m_pipelineComponents.multisampleInfo; + m_graphicsPipelineInfo.pDepthStencilState = &m_pipelineComponents.depthStencilInfo; + m_graphicsPipelineInfo.pColorBlendState = &m_pipelineComponents.colorBlendInfo; + m_graphicsPipelineInfo.pDynamicState = nullptr; + m_graphicsPipelineInfo.layout = m_pipelineLayout; + m_graphicsPipelineInfo.renderPass = m_renderPass; + m_graphicsPipelineInfo.subpass = 0; + m_graphicsPipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + m_graphicsPipelineInfo.basePipelineIndex = 0; +} + +void +VulkanPostProcess::createFullscreenQuad(VulkanRenderer * renderer) +{ + m_vertexBuffer = std::make_shared<VulkanVertexBuffer>(renderer->m_memoryManager, 4, 4 * 5, 2); + + { + auto data = (float*)m_vertexBuffer->mapVertices(); + data[0] = -1; + data[1] = -1; + data[2] = 0; + data[3] = 0; + data[4] = 0; + + data[5] = -1; + data[6] = 1; + data[7] = 0; + data[8] = 0; + data[9] = 1; + + data[10] = 1; + data[11] = -1; + data[12] = 0; + data[13] = 1; + data[14] = 0; + + data[15] = 1; + data[16] = 1; + data[17] = 0; + data[18] = 1; + data[19] = 1; + + m_vertexBuffer->unmapVertices(); + } + + { + auto data = (uint32_t*)m_vertexBuffer->mapTriangles(); + data[0] = 0; + data[1] = 1; + data[2] = 2; + data[3] = 1; + data[4] = 2; + data[5] = 3; + m_vertexBuffer->unmapTriangles(); + } + + m_vertexBuffer->initializeBuffers(renderer->m_memoryManager); +} + + +void +VulkanPostProcess::createDescriptors(VulkanRenderer * renderer) +{ + this->createDescriptorPool(renderer); + this->createDescriptorSets(renderer); +} + +void +VulkanPostProcess::createDescriptorSetLayouts(VulkanRenderer * renderer) +{ + m_descriptorSets.resize(1); + m_descriptorSetLayouts.resize(1); + + std::vector<VkDescriptorSetLayoutBinding> fragmentDescriptorSetLayoutBindings; + + // Diffuse texture + for (int i = 0; i < m_samplers.size(); i++) + { + VkDescriptorSetLayoutBinding fragmentLayoutBinding; + fragmentLayoutBinding.binding = i; + fragmentLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + fragmentLayoutBinding.descriptorCount = 1; + fragmentLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + fragmentLayoutBinding.pImmutableSamplers = nullptr; + fragmentDescriptorSetLayoutBindings.push_back(fragmentLayoutBinding); + } + + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo[1]; + descriptorSetLayoutInfo[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutInfo[0].pNext = nullptr; + descriptorSetLayoutInfo[0].flags = 0; + descriptorSetLayoutInfo[0].bindingCount = (uint32_t)fragmentDescriptorSetLayoutBindings.size(); + descriptorSetLayoutInfo[0].pBindings = &fragmentDescriptorSetLayoutBindings[0]; + + for (int i = 0; i < m_descriptorSetLayouts.size(); i++) + { + vkCreateDescriptorSetLayout(renderer->m_renderDevice, &descriptorSetLayoutInfo[i], nullptr, &m_descriptorSetLayouts[i]); + } +} + +void +VulkanPostProcess::createDescriptorPool(VulkanRenderer * renderer) +{ + std::vector<VkDescriptorPoolSize> descriptorPoolSizes; + + // Fragment shader textures + VkDescriptorPoolSize poolSize; + poolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSize.descriptorCount = (uint32_t)m_samplers.size(); + descriptorPoolSizes.push_back(poolSize); + + VkDescriptorPoolCreateInfo descriptorPoolInfo; + descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptorPoolInfo.pNext = nullptr; + descriptorPoolInfo.flags = 0; + descriptorPoolInfo.maxSets = (uint32_t)m_descriptorSets.size(); + descriptorPoolInfo.poolSizeCount = (uint32_t)descriptorPoolSizes.size(); + descriptorPoolInfo.pPoolSizes = &descriptorPoolSizes[0]; + + vkCreateDescriptorPool(renderer->m_renderDevice, &descriptorPoolInfo, nullptr, &m_descriptorPool); +} + +void +VulkanPostProcess::createDescriptorSets(VulkanRenderer * renderer) +{ + VkDescriptorSetAllocateInfo descriptorSetAllocationInfo[1]; + descriptorSetAllocationInfo[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocationInfo[0].pNext = nullptr; + descriptorSetAllocationInfo[0].descriptorPool = m_descriptorPool; + descriptorSetAllocationInfo[0].descriptorSetCount = (uint32_t)m_descriptorSetLayouts.size(); + descriptorSetAllocationInfo[0].pSetLayouts = &m_descriptorSetLayouts[0]; + + VkDeviceSize size = { VK_WHOLE_SIZE }; + + std::vector<VkDescriptorImageInfo> fragmentTextureInfo; + + // Textures + for (int i = 0; i < m_samplers.size(); i++) + { + VkDescriptorImageInfo textureInfo; + textureInfo.sampler = *m_samplers[i]; + textureInfo.imageView = *m_imageViews[i]; + textureInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + fragmentTextureInfo.push_back(textureInfo); + } + + vkAllocateDescriptorSets(renderer->m_renderDevice, descriptorSetAllocationInfo, &m_descriptorSets[0]); + + m_writeDescriptorSets.resize(1); + + m_writeDescriptorSets[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + m_writeDescriptorSets[0].pNext = nullptr; + m_writeDescriptorSets[0].dstBinding = 0; + m_writeDescriptorSets[0].dstArrayElement = 0; + m_writeDescriptorSets[0].dstSet = m_descriptorSets[0]; + m_writeDescriptorSets[0].descriptorCount = (uint32_t)fragmentTextureInfo.size(); + m_writeDescriptorSets[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + m_writeDescriptorSets[0].pBufferInfo = nullptr; + m_writeDescriptorSets[0].pImageInfo = &fragmentTextureInfo[0]; + m_writeDescriptorSets[0].pTexelBufferView = nullptr; + + vkUpdateDescriptorSets(renderer->m_renderDevice, (uint32_t)m_writeDescriptorSets.size(), &m_writeDescriptorSets[0], 0, nullptr); +} + +void +VulkanPostProcess::createRenderPass(VulkanRenderer * renderer) +{ + std::vector<VkAttachmentDescription> attachments; + bool depth = false; + + // Color attachment + { + VkAttachmentDescription attachment; + attachment.flags = 0; + attachment.format = m_framebuffer->m_colorFormat; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.finalLayout = + m_lastPass ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + attachments.push_back(attachment); + } + + if (m_framebuffer->m_depthFormat != VK_FORMAT_UNDEFINED) + { + depth = true; + + // Depth attachment + VkAttachmentDescription attachment; + attachment.flags = 0; + attachment.format = m_framebuffer->m_depthFormat; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + attachments.push_back(attachment); + } + + // Color attachment + VkAttachmentReference colorReference; + colorReference.attachment = 0; + colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + // Depth attachment + VkAttachmentReference depthReference; + depthReference.attachment = 1; + depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + // Normal attachment + VkAttachmentReference normalReference; + normalReference.attachment = 2; + normalReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + // First pass: geometry + m_colorAttachments.push_back(colorReference); + + // Render subpasses + VkSubpassDescription subpassInfo[1]; + subpassInfo[0].flags = 0; + subpassInfo[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassInfo[0].inputAttachmentCount = 0; + subpassInfo[0].pInputAttachments = nullptr; + subpassInfo[0].colorAttachmentCount = (uint32_t)m_colorAttachments.size(); + subpassInfo[0].pColorAttachments = &m_colorAttachments[0]; + subpassInfo[0].pResolveAttachments = nullptr; + subpassInfo[0].pDepthStencilAttachment = depth ? &depthReference : nullptr; + subpassInfo[0].preserveAttachmentCount = 0; + subpassInfo[0].pPreserveAttachments = nullptr; + + VkSubpassDependency dependencies[2]; + dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; + dependencies[0].dstSubpass = 0; + dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[0].srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + dependencies[1].srcSubpass = 0; + dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; + dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + dependencies[1].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + VkRenderPassCreateInfo renderPassInfo; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.pNext = nullptr; + renderPassInfo.flags = 0; + renderPassInfo.attachmentCount = (uint32_t)attachments.size(); + renderPassInfo.pAttachments = &attachments[0]; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = subpassInfo; + renderPassInfo.dependencyCount = 2; + renderPassInfo.pDependencies = dependencies; + + vkCreateRenderPass(renderer->m_renderDevice, &renderPassInfo, nullptr, &m_renderPass); +} + +void +VulkanPostProcess::initializeFramebuffer(VulkanRenderer * renderer) +{ + this->createRenderPass(renderer); + m_framebuffer->initializeFramebuffer(&m_renderPass); +} + +void +VulkanPostProcess::createFramebuffer(VulkanRenderer * renderer, + unsigned int level, + bool lastPass) +{ + m_framebuffer = std::make_shared<VulkanFramebuffer>( + renderer->m_memoryManager, + renderer->m_width >> level, + renderer->m_height >> level, + lastPass); +} + +void +VulkanPostProcess::addInputImage( + VkSampler * sampler, + VkImageView * imageView) +{ + m_samplers.push_back(sampler); + m_imageViews.push_back(imageView); +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcess.h b/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcess.h new file mode 100644 index 0000000000000000000000000000000000000000..c1ebfe333c9573412a2beb53077fbc68d4ed133d --- /dev/null +++ b/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcess.h @@ -0,0 +1,108 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanPostProcess_h +#define imstkVulkanPostProcess_h + +#include "vulkan/vulkan.h" +#include "glm/glm.hpp" + +#include "imstkVulkanMaterialDelegate.h" +#include "imstkVulkanVertexBuffer.h" +#include "imstkVulkanFramebuffer.h" +#include "imstkVulkanTextureDelegate.h" + +#include <memory> +#include <vector> + +namespace imstk +{ +class VulkanRenderer; + +class VulkanPostProcess +{ +public: + /// + /// \brief Constructor + /// + VulkanPostProcess(VulkanRenderer * renderer, unsigned int level = 0, bool lastPass = false); + + void addInputImage( + VkSampler * sampler, + VkImageView * imageView); + + void generateMipmaps(VkCommandBuffer& commandBuffer, + unsigned int levels, + VkImage& image); + +protected: + friend class VulkanRenderer; + friend class VulkanPostProcessingChain; + + /// + /// \brief Creates a parent pipeline object that gets inherited by other materials + /// + void createPipeline(VulkanRenderer * renderer, std::string fragmentSource); + void createRenderPass(VulkanRenderer * renderer); + void createFramebuffer(VulkanRenderer * renderer, + unsigned int level = 0, + bool lastPass = false); + + void createFullscreenQuad(VulkanRenderer * renderer); + + virtual void initialize(VulkanRenderer * renderer, + std::string = "./Shaders/VulkanShaders/PostProcessing/postprocess_frag.spv"); + void initializeFramebuffer(VulkanRenderer * renderer); + + + void createDescriptors(VulkanRenderer * renderer); + void createDescriptorSetLayouts(VulkanRenderer * renderer); + void createDescriptorPool(VulkanRenderer * renderer); + void createDescriptorSets(VulkanRenderer * renderer); + + VkPipeline m_pipeline; + VkGraphicsPipelineCreateInfo m_graphicsPipelineInfo; + VkPipelineLayout m_pipelineLayout; + VulkanMaterialPipelineComponents m_pipelineComponents; + + VkDescriptorPool m_descriptorPool; + std::vector<VkDescriptorSet> m_descriptorSets; + std::vector<VkDescriptorSetLayout> m_descriptorSetLayouts; + std::vector<VkWriteDescriptorSet> m_writeDescriptorSets; + + std::shared_ptr<VulkanVertexBuffer> m_vertexBuffer; + + std::shared_ptr<VulkanFramebuffer> m_framebuffer; + + // Resources + std::vector<VkSampler *> m_samplers; + std::vector<VkImageView *> m_imageViews; + unsigned int m_downsampleLevels = 0; + unsigned int m_outputIndex = 0; + bool m_lastPass = false; + + std::vector<VkAttachmentReference> m_colorAttachments; + VkRenderPass m_renderPass; + float m_pushConstantData[32]; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcessingChain.cpp b/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcessingChain.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8621042f5402e329b4b70e2a551c095c68cabe03 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcessingChain.cpp @@ -0,0 +1,207 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanPostProcessingChain.h" + +#include "imstkVulkanRenderer.h" + +namespace imstk +{ +VulkanPostProcessingChain::VulkanPostProcessingChain(VulkanRenderer * renderer) +{ + bool bloom = false; + bool sss = true; + + // Subsurface scattering pass + // The buffer indices are hardcoded because it's before the accumulation composition pass + if (sss) + { + int sssSamples = 5; + + auto sssHorizontalBlurPass = std::make_shared<VulkanPostProcess>(renderer, 0); + sssHorizontalBlurPass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_HDRImageView[0][0]); + sssHorizontalBlurPass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_depthImageView[0]); + sssHorizontalBlurPass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_normalImageView); + sssHorizontalBlurPass->m_framebuffer->setColor(&renderer->m_HDRImageView[2][0], VK_FORMAT_R16G16B16A16_SFLOAT); + sssHorizontalBlurPass->initialize(renderer, "./Shaders/VulkanShaders/PostProcessing/sss_frag.spv"); + sssHorizontalBlurPass->m_pushConstantData[0] = 1.0; + sssHorizontalBlurPass->m_pushConstantData[1] = 0.0; + sssHorizontalBlurPass->m_pushConstantData[2] = renderer->m_fov; + sssHorizontalBlurPass->m_pushConstantData[3] = 3.0; + sssHorizontalBlurPass->m_pushConstantData[4] = renderer->m_nearPlane; + sssHorizontalBlurPass->m_pushConstantData[5] = renderer->m_farPlane; + sssHorizontalBlurPass->m_pushConstantData[6] = sssSamples; + this->calculateBlurValues(sssSamples, + &sssHorizontalBlurPass->m_pushConstantData[7], + renderer->m_nearPlane); + this->calculateBlurValues(sssSamples, + &sssHorizontalBlurPass->m_pushConstantData[17], + renderer->m_farPlane); + m_postProcesses.push_back(sssHorizontalBlurPass); + + auto sssVerticalBlurPass = std::make_shared<VulkanPostProcess>(renderer, 0); + sssVerticalBlurPass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_HDRImageView[2][0]); + sssVerticalBlurPass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_depthImageView[0]); + sssVerticalBlurPass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_normalImageView); + sssVerticalBlurPass->m_framebuffer->setColor(&renderer->m_HDRImageView[0][0], VK_FORMAT_R16G16B16A16_SFLOAT); + sssVerticalBlurPass->initialize(renderer, "./Shaders/VulkanShaders/PostProcessing/sss_frag.spv"); + sssVerticalBlurPass->m_pushConstantData[0] = 0.0; + sssVerticalBlurPass->m_pushConstantData[1] = 1.0; + sssVerticalBlurPass->m_pushConstantData[2] = renderer->m_fov; + sssVerticalBlurPass->m_pushConstantData[3] = 3.0; + sssVerticalBlurPass->m_pushConstantData[4] = renderer->m_nearPlane; + sssVerticalBlurPass->m_pushConstantData[5] = renderer->m_farPlane; + sssVerticalBlurPass->m_pushConstantData[6] = sssSamples; + this->calculateBlurValues(sssSamples, + &sssVerticalBlurPass->m_pushConstantData[7], + renderer->m_nearPlane); + this->calculateBlurValues(sssSamples, + &sssVerticalBlurPass->m_pushConstantData[17], + renderer->m_farPlane); + m_postProcesses.push_back(sssVerticalBlurPass); + } + + // Accumulation composition pass + auto accumulationCompositePass = std::make_shared<VulkanPostProcess>(renderer); + accumulationCompositePass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_HDRImageView[0][0]); + accumulationCompositePass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_HDRImageView[1][0]); + accumulationCompositePass->m_framebuffer->setColor(&renderer->m_HDRImageView[2][0], VK_FORMAT_R16G16B16A16_SFLOAT); + accumulationCompositePass->initialize(renderer, "./Shaders/VulkanShaders/PostProcessing/composite_frag.spv"); + m_postProcesses.push_back(accumulationCompositePass); + + // Bloom pass + if (bloom) + { + int level = 1; + int bloomSamples = 5; + + auto bloomThresholdPass = std::make_shared<VulkanPostProcess>(renderer, level); + bloomThresholdPass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_HDRImageView[m_lastOutput][0]); + bloomThresholdPass->m_framebuffer->setColor(&renderer->m_HDRImageView[m_lastInput][level], VK_FORMAT_R16G16B16A16_SFLOAT); + bloomThresholdPass->initialize(renderer, "./Shaders/VulkanShaders/PostProcessing/bloom_threshold_frag.spv"); + m_postProcesses.push_back(bloomThresholdPass); + + auto bloomHorizontalBlurPass = std::make_shared<VulkanPostProcess>(renderer, level); + bloomHorizontalBlurPass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_HDRImageView[m_lastInput][level]); + bloomHorizontalBlurPass->m_framebuffer->setColor(&renderer->m_HDRImageView[m_lastOutput][level], VK_FORMAT_R16G16B16A16_SFLOAT); + bloomHorizontalBlurPass->initialize(renderer, "./Shaders/VulkanShaders/PostProcessing/blur_horizontal_frag.spv"); + bloomHorizontalBlurPass->m_pushConstantData[0] = std::max(renderer->m_width >> level, 1u); + bloomHorizontalBlurPass->m_pushConstantData[1] = std::max(renderer->m_height >> level, 1u); + bloomHorizontalBlurPass->m_pushConstantData[2] = bloomSamples; + this->calculateBlurValuesLinear(bloomSamples, + &bloomHorizontalBlurPass->m_pushConstantData[3], + &bloomHorizontalBlurPass->m_pushConstantData[13]); + m_postProcesses.push_back(bloomHorizontalBlurPass); + + auto bloomVerticalBlurPass = std::make_shared<VulkanPostProcess>(renderer, level); + bloomVerticalBlurPass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_HDRImageView[m_lastOutput][level]); + bloomVerticalBlurPass->m_framebuffer->setColor(&renderer->m_HDRImageView[m_lastInput][level], VK_FORMAT_R16G16B16A16_SFLOAT); + bloomVerticalBlurPass->initialize(renderer, "./Shaders/Vulkan/PostProcessing/blur_vertical_frag.spv"); + bloomVerticalBlurPass->m_pushConstantData[0] = std::max(renderer->m_width >> level, 1u); + bloomVerticalBlurPass->m_pushConstantData[1] = std::max(renderer->m_height >> level, 1u); + bloomVerticalBlurPass->m_pushConstantData[2] = bloomSamples; + this->calculateBlurValuesLinear(bloomSamples, + &bloomVerticalBlurPass->m_pushConstantData[3], + &bloomVerticalBlurPass->m_pushConstantData[13]); + m_postProcesses.push_back(bloomVerticalBlurPass); + + auto bloomCompositePass = std::make_shared<VulkanPostProcess>(renderer); + bloomCompositePass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_HDRImageView[m_lastOutput][0]); + bloomCompositePass->addInputImage(&renderer->m_HDRImageSampler, &renderer->m_HDRImageView[m_lastInput][level]); + bloomCompositePass->m_framebuffer->setColor(&renderer->m_HDRImageView[m_lastInput][0], VK_FORMAT_R16G16B16A16_SFLOAT); + bloomCompositePass->initialize(renderer, "./Shaders/VulkanShaders/PostProcessing/composite_frag.spv"); + m_postProcesses.push_back(bloomCompositePass); + this->incrementBufferNumbers(); + } +} + +std::vector<std::shared_ptr<VulkanPostProcess>>& +VulkanPostProcessingChain::getPostProcesses() +{ + return m_postProcesses; +} + +void +VulkanPostProcessingChain::incrementBufferNumbers() +{ + m_lastInput = (m_lastInput + 1) % 3; + m_lastOutput = (m_lastOutput + 1) % 3; +} + +void +VulkanPostProcessingChain::calculateBlurValuesLinear(int samples, float * values, float * offsets) +{ + std::vector<float> intermediateValues(samples * 2 - 1); + float total = 0; + + // Calculate normal distribution + for (int i = 0; i < intermediateValues.size(); i++) + { + float x = (i / (float)intermediateValues.size()) * 3; + intermediateValues[i] = 1.0 / std::sqrt(2 * PI) * std::pow(NLOG_E, -(x * x) / 2); + total += intermediateValues[i] * 2; + } + + // Normalize + for (int i = 0; i < intermediateValues.size(); i++) + { + intermediateValues[i] /= total; + } + + values[0] = intermediateValues[0]; + offsets[0] = 0.0; + + // Linear sampling optimization + for (int i = 1; i < samples; i++) + { + values[i] = intermediateValues[2 * i - 1] + intermediateValues[2 * i]; + offsets[i] = (((2 * i - 1) * intermediateValues[2 * i - 1]) + + ((2 * i) * intermediateValues[2 * i])) / values[i]; + } +} + +void +VulkanPostProcessingChain::calculateBlurValues(int samples, float * values, float stdDev) +{ + float total = 0; + + // Calculate normal distribution + for (int i = 0; i < samples; i++) + { + values[i] = 1.0 / std::sqrt(2 * PI * stdDev * stdDev) * std::pow(NLOG_E, -(i * i) / (2 * stdDev * stdDev)); + + if (i == 0) + { + total += values[i]; + } + else + { + total += values[i] * 2; + } + } + + // Normalize + for (int i = 0; i < samples; i++) + { + values[i] /= total; + } +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcessingChain.h b/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcessingChain.h new file mode 100644 index 0000000000000000000000000000000000000000..afd0c8eb9eb16c92998efa5130ead3542d4cd0c0 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/PostProcessing/imstkVulkanPostProcessingChain.h @@ -0,0 +1,60 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanPostProcessingChain_h +#define imstkVulkanPostProcessingChain_h + +#include "vulkan/vulkan.h" +#include "glm/glm.hpp" + +#include "imstkVulkanPostProcess.h" + +#include <memory> +#include <vector> + +namespace imstk +{ +class VulkanRenderer; + +class VulkanPostProcessingChain +{ +public: + /// + /// \brief Constructor + /// + VulkanPostProcessingChain(VulkanRenderer * renderer); + + std::vector<std::shared_ptr<VulkanPostProcess>>& getPostProcesses(); + +protected: + friend class VulkanRenderer; + + std::vector<std::shared_ptr<VulkanPostProcess>> m_postProcesses; + void incrementBufferNumbers(); + void calculateBlurValuesLinear(int samples, float * values, float * offsets); + void calculateBlurValues(int samples, float * values, float stdDev = 0.0); + + unsigned int m_lastOutput = 2; ///< 2 by default because of accumulation composition + unsigned int m_lastInput = 0; ///< 0 by default because of accumulation composition +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05be1fa866e0f5bfdbd77b02fd8fe1226a8c7fb5 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.cpp @@ -0,0 +1,107 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanCapsuleRenderDelegate.h" + +namespace imstk +{ +VulkanCapsuleRenderDelegate::VulkanCapsuleRenderDelegate(std::shared_ptr<Capsule> capsule, VulkanMemoryManager& memoryManager) + : m_geometry(capsule) +{ + auto source = vtkSmartPointer<vtkCapsuleSource>::New(); + source->SetCenter(WORLD_ORIGIN[0], WORLD_ORIGIN[1], WORLD_ORIGIN[2]); + source->SetRadius(m_geometry->getRadius()); + source->SetCylinderLength(m_geometry->getLength()); + source->SetLatLongTessellation(20); + source->SetPhiResolution(20); + source->SetThetaResolution(20); + source->Update(); + + auto triangulate = vtkSmartPointer<vtkTriangleFilter>::New(); + triangulate->SetInputConnection(source->GetOutputPort()); + + triangulate->Update(); + + auto sourceData = triangulate->GetOutput(); + + auto positions = sourceData->GetPoints(); + auto normals = sourceData->GetPointData()->GetNormals(); + auto triangles = sourceData->GetPolys(); + + for (int i = 0; i < sourceData->GetNumberOfPoints(); i++) + { + auto position = positions->GetPoint(i); + auto normal = normals->GetTuple(i); + + VulkanBasicVertex capsuleVertex; + + capsuleVertex.position[0] = position[0]; + capsuleVertex.position[1] = position[1]; + capsuleVertex.position[2] = position[2]; + + capsuleVertex.normal[0] = normal[0]; + capsuleVertex.normal[1] = normal[1]; + capsuleVertex.normal[2] = normal[2]; + + m_capsuleVertices.push_back(capsuleVertex); + } + + triangles->InitTraversal(); + + for (int i = 0; i < triangles->GetNumberOfCells(); i++) + { + auto points = vtkSmartPointer<vtkIdList>::New(); + auto triangle = triangles->GetNextCell(points); + + std::array<uint32_t, 3> trianglePoints = { + (uint32_t)points->GetId(0), + (uint32_t)points->GetId(1), + (uint32_t)points->GetId(2) + }; + + m_capsuleTriangles.push_back(trianglePoints); + } + + m_numVertices = (uint32_t)m_capsuleVertices.size(); + m_numTriangles = (uint32_t)m_capsuleTriangles.size(); + m_vertexSize = sizeof(VulkanBasicVertex); + + this->initializeData(memoryManager); + + m_vertexBuffer->updateVertexBuffer(&m_capsuleVertices, &m_capsuleTriangles); + + this->update(); +} + +void +VulkanCapsuleRenderDelegate::update() +{ + this->updateTransform(m_geometry); + m_vertexUniformBuffer->updateUniforms(sizeof(VulkanLocalVertexUniforms), + (void *)&m_localVertexUniforms); +} + +std::shared_ptr<Geometry> +VulkanCapsuleRenderDelegate::getGeometry() const +{ + return m_geometry; +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..e548bbf562ca8f7d63536917eda7f90a271ce2ab --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCapsuleRenderDelegate.h @@ -0,0 +1,67 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanCapsuleRenderDelegate_h +#define imstkVulkanCapsuleRenderDelegate_h + +#include "imstkCapsule.h" + +#include "imstkVulkanRenderDelegate.h" + +#include "vtkCapsuleSource.h" +#include "vtkPointData.h" +#include "vtkTriangleFilter.h" + +namespace imstk +{ +class VulkanCapsuleRenderDelegate : public VulkanRenderDelegate +{ +public: + + /// + /// \brief Default destructor + /// + ~VulkanCapsuleRenderDelegate() = default; + + /// + /// \brief Default constructor + /// + VulkanCapsuleRenderDelegate(std::shared_ptr<Capsule> capsule, VulkanMemoryManager& memoryManager); + + /// + /// \brief Update render geometry + /// + void update() override; + + /// + /// \brief Get source geometry + /// + std::shared_ptr<Geometry> getGeometry() const override; + +protected: + std::shared_ptr<Capsule> m_geometry; + + std::vector<std::array<uint32_t, 3>> m_capsuleTriangles; + std::vector<VulkanBasicVertex> m_capsuleVertices; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..79f5145139aa8d0e0c42ca0ed48ac9ae0004a812 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.cpp @@ -0,0 +1,107 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanCubeRenderDelegate.h" + +namespace imstk +{ +VulkanCubeRenderDelegate::VulkanCubeRenderDelegate(std::shared_ptr<Cube> cube, VulkanMemoryManager& memoryManager) + : m_geometry(cube) +{ + auto width = m_geometry->getWidth(); + + auto source = vtkSmartPointer<vtkCubeSource>::New(); + source->SetCenter(WORLD_ORIGIN[0], WORLD_ORIGIN[1], WORLD_ORIGIN[2]); + source->SetXLength(width); + source->SetYLength(width); + source->SetZLength(width); + source->Update(); + + auto triangulate = vtkSmartPointer<vtkTriangleFilter>::New(); + triangulate->SetInputConnection(source->GetOutputPort()); + + triangulate->Update(); + + auto sourceData = triangulate->GetOutput(); + + auto positions = sourceData->GetPoints(); + auto normals = sourceData->GetPointData()->GetNormals(); + auto triangles = sourceData->GetPolys(); + + for (int i = 0; i < sourceData->GetNumberOfPoints(); i++) + { + auto position = positions->GetPoint(i); + auto normal = normals->GetTuple(i); + + VulkanBasicVertex cubeVertex; + + cubeVertex.position[0] = position[0]; + cubeVertex.position[1] = position[1]; + cubeVertex.position[2] = position[2]; + + cubeVertex.normal[0] = normal[0]; + cubeVertex.normal[1] = normal[1]; + cubeVertex.normal[2] = normal[2]; + + m_cubeVertices.push_back(cubeVertex); + } + + triangles->InitTraversal(); + + for (int i = 0; i < triangles->GetNumberOfCells(); i++) + { + auto points = vtkSmartPointer<vtkIdList>::New(); + auto triangle = triangles->GetNextCell(points); + + std::array<uint32_t, 3> trianglePoints = { + (uint32_t)points->GetId(0), + (uint32_t)points->GetId(1), + (uint32_t)points->GetId(2) + }; + + m_cubeTriangles.push_back(trianglePoints); + } + + m_numVertices = (uint32_t)m_cubeVertices.size(); + m_numTriangles = (uint32_t)m_cubeTriangles.size(); + m_vertexSize = sizeof(VulkanBasicVertex); + + this->initializeData(memoryManager); + + m_vertexBuffer->updateVertexBuffer(&m_cubeVertices, &m_cubeTriangles); + + this->update(); +} + +void +VulkanCubeRenderDelegate::update() +{ + this->updateTransform(m_geometry); + m_vertexUniformBuffer->updateUniforms(sizeof(VulkanLocalVertexUniforms), + (void *)&m_localVertexUniforms); +} + +std::shared_ptr<Geometry> +VulkanCubeRenderDelegate::getGeometry() const +{ + return m_geometry; +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..cd551f584e0b7c8bbd5adaa09acc9cb8072f86a3 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanCubeRenderDelegate.h @@ -0,0 +1,67 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanCubeRenderDelegate_h +#define imstkVulkanCubeRenderDelegate_h + +#include "imstkCube.h" + +#include "imstkVulkanRenderDelegate.h" + +#include "vtkCubeSource.h" +#include "vtkPointData.h" +#include "vtkTriangleFilter.h" + +namespace imstk +{ +class VulkanCubeRenderDelegate : public VulkanRenderDelegate +{ +public: + + /// + /// \brief Default destructor + /// + ~VulkanCubeRenderDelegate() = default; + + /// + /// \brief Default constructor + /// + VulkanCubeRenderDelegate(std::shared_ptr<Cube> cube, VulkanMemoryManager& memoryManager); + + /// + /// \brief Update render geometry + /// + void update() override; + + /// + /// \brief Get source geometry + /// + std::shared_ptr<Geometry> getGeometry() const override; + +protected: + std::shared_ptr<Cube> m_geometry; + + std::vector<std::array<uint32_t, 3>> m_cubeTriangles; + std::vector<VulkanBasicVertex> m_cubeVertices; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b5dfcb2ea5cef5423bd9ab1a54cde2eee85f41af --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.cpp @@ -0,0 +1,105 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanPlaneRenderDelegate.h" + +namespace imstk +{ +VulkanPlaneRenderDelegate::VulkanPlaneRenderDelegate(std::shared_ptr<Plane> plane, VulkanMemoryManager& memoryManager) + : m_geometry(plane) +{ + auto width = m_geometry->getWidth(); + + auto source = vtkSmartPointer<vtkPlaneSource>::New(); + source->SetCenter(WORLD_ORIGIN[0], WORLD_ORIGIN[1], WORLD_ORIGIN[2]); + source->SetNormal(UP_VECTOR[0], UP_VECTOR[1], UP_VECTOR[2]); + source->Update(); + + auto triangulate = vtkSmartPointer<vtkTriangleFilter>::New(); + triangulate->SetInputConnection(source->GetOutputPort()); + + triangulate->Update(); + + auto sourceData = triangulate->GetOutput(); + + auto positions = sourceData->GetPoints(); + auto normals = sourceData->GetPointData()->GetNormals(); + auto triangles = sourceData->GetPolys(); + + for (int i = 0; i < sourceData->GetNumberOfPoints(); i++) + { + auto position = positions->GetPoint(i); + auto normal = normals->GetTuple(i); + + VulkanBasicVertex planeVertex; + + planeVertex.position[0] = position[0] * width; + planeVertex.position[1] = position[1] * width; + planeVertex.position[2] = position[2] * width; + + planeVertex.normal[0] = normal[0]; + planeVertex.normal[1] = normal[1]; + planeVertex.normal[2] = normal[2]; + + m_planeVertices.push_back(planeVertex); + } + + triangles->InitTraversal(); + + for (int i = 0; i < triangles->GetNumberOfCells(); i++) + { + auto points = vtkSmartPointer<vtkIdList>::New(); + auto triangle = triangles->GetNextCell(points); + + std::array<uint32_t, 3> trianglePoints = { + (uint32_t)points->GetId(0), + (uint32_t)points->GetId(1), + (uint32_t)points->GetId(2) + }; + + m_planeTriangles.push_back(trianglePoints); + } + + m_numVertices = (uint32_t)m_planeVertices.size(); + m_numTriangles = (uint32_t)m_planeTriangles.size(); + m_vertexSize = sizeof(VulkanBasicVertex); + + this->initializeData(memoryManager); + + m_vertexBuffer->updateVertexBuffer(&m_planeVertices, &m_planeTriangles); + + this->update(); +} + +void +VulkanPlaneRenderDelegate::update() +{ + this->updateTransform(m_geometry); + m_vertexUniformBuffer->updateUniforms(sizeof(VulkanLocalVertexUniforms), + (void *)&m_localVertexUniforms); +} + +std::shared_ptr<Geometry> +VulkanPlaneRenderDelegate::getGeometry() const +{ + return m_geometry; +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..d8593dcf6c7dc209da48602c8a982685bea38d3f --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanPlaneRenderDelegate.h @@ -0,0 +1,68 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanPlaneRenderDelegate_h +#define imstkVulkanPlaneRenderDelegate_h + +#include "imstkPlane.h" + +#include "imstkVulkanRenderDelegate.h" +#include "vtkSphereSource.h" + +#include "vtkPlaneSource.h" +#include "vtkPointData.h" +#include "vtkTriangleFilter.h" + +namespace imstk +{ +class VulkanPlaneRenderDelegate : public VulkanRenderDelegate +{ +public: + + /// + /// \brief Default destructor + /// + ~VulkanPlaneRenderDelegate() = default; + + /// + /// \brief Default constructor + /// + VulkanPlaneRenderDelegate(std::shared_ptr<Plane> plane, VulkanMemoryManager& memoryManager); + + /// + /// \brief Update render geometry + /// + void update() override; + + /// + /// \brief Get source geometry + /// + std::shared_ptr<Geometry> getGeometry() const override; + +protected: + std::shared_ptr<Plane> m_geometry; + + std::vector<std::array<uint32_t, 3>> m_planeTriangles; + std::vector<VulkanBasicVertex> m_planeVertices; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dfb8560d9c37f0643fc4d41e88f2b95f2f4587df --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.cpp @@ -0,0 +1,144 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanRenderDelegate.h" + +#include "g3log/g3log.hpp" + +#include "imstkPlane.h" +#include "imstkSphere.h" +#include "imstkCube.h" +#include "imstkCapsule.h" +#include "imstkSurfaceMesh.h" +#include "imstkTetrahedralMesh.h" + +#include "imstkVulkanPlaneRenderDelegate.h" +#include "imstkVulkanSphereRenderDelegate.h" +#include "imstkVulkanCubeRenderDelegate.h" +#include "imstkVulkanCapsuleRenderDelegate.h" +#include "imstkVulkanSurfaceMeshRenderDelegate.h" + +namespace imstk +{ +std::shared_ptr<VulkanRenderDelegate> +VulkanRenderDelegate::make_delegate(std::shared_ptr<Geometry> geom, VulkanMemoryManager& memoryManager) +{ + switch (geom->getType()) + { + case Geometry::Type::Plane: + { + auto plane = std::dynamic_pointer_cast<Plane>(geom); + return std::make_shared<VulkanPlaneRenderDelegate>(plane, memoryManager); + } + case Geometry::Type::Sphere: + { + auto sphere = std::dynamic_pointer_cast<Sphere>(geom); + return std::make_shared<VulkanSphereRenderDelegate>(sphere, memoryManager); + } + case Geometry::Type::Cube: + { + auto cube = std::dynamic_pointer_cast<Cube>(geom); + return std::make_shared<VulkanCubeRenderDelegate>(cube, memoryManager); + } + case Geometry::Type::Capsule: + { + auto capsule = std::dynamic_pointer_cast<Capsule>(geom); + return std::make_shared<VulkanCapsuleRenderDelegate>(capsule, memoryManager); + } + case Geometry::Type::SurfaceMesh: + { + auto surfaceMesh = std::dynamic_pointer_cast<SurfaceMesh>(geom); + return std::make_shared<VulkanSurfaceMeshRenderDelegate>(surfaceMesh, memoryManager); + } + /*case Geometry::Type::TetrahedralMesh: + { + auto tetrahedralMesh = std::dynamic_pointer_cast<TetrahedralMesh>(geom); + return std::make_shared<VulkanTetrahedralMeshRenderDelegate>(tetrahedralMesh); + } + case Geometry::Type::LineMesh: + { + LOG(WARNING) << "RenderDelegate::make_delegate error: LineMeshRenderDelegate not yet implemented"; + return nullptr; + } + case Geometry::Type::HexahedralMesh: + { + LOG(WARNING) << "RenderDelegate::make_delegate error: HexahedralMeshRenderDelegate not yet implemented"; + return nullptr; + }*/ + default: + { + LOG(WARNING) << "RenderDelegate::make_delegate error: Geometry type incorrect."; + return nullptr; + } + } +} + +vtkSmartPointer<vtkPolyDataMapper> +VulkanRenderDelegate::setUpMapper(vtkAlgorithmOutput * source) +{ + vtkSmartPointer<vtkPolyDataMapper> mapper; + mapper->SetInputConnection(source); + mapper->Update(); + return mapper; +} + +std::shared_ptr<VulkanVertexBuffer> +VulkanRenderDelegate::getBuffer() +{ + return m_vertexBuffer; +} + +void +VulkanRenderDelegate::initializeData(VulkanMemoryManager& memoryManager, std::shared_ptr<RenderMaterial> material) +{ + m_vertexUniformBuffer = std::make_shared<VulkanUniformBuffer>(memoryManager, (uint32_t)sizeof(VulkanLocalVertexUniforms)); + m_fragmentUniformBuffer = std::make_shared<VulkanUniformBuffer>(memoryManager, (uint32_t)sizeof(VulkanLocalFragmentUniforms)); + + m_material = std::make_shared<VulkanMaterialDelegate>(m_vertexUniformBuffer, + m_fragmentUniformBuffer, + material, + memoryManager); + + m_vertexBuffer = std::make_shared<VulkanVertexBuffer>(memoryManager, m_numVertices, m_vertexSize, m_numTriangles); +} + +void +VulkanRenderDelegate::updateTransform(std::shared_ptr<Geometry> geometry) +{ + glm::mat4 transform; + + glm::vec3 scale(geometry->getScaling()); + transform = glm::scale(transform, scale); + + auto rotation = geometry->getRotation(); + glm::mat3 rotationMatrix(rotation(0, 0), rotation(0, 1), rotation(0, 2), + rotation(1, 0), rotation(1, 1), rotation(1, 2), + rotation(2, 0), rotation(2, 1), rotation(2, 2)); + + transform = glm::mat4(rotationMatrix) * transform; + + transform[3][0] = geometry->getTranslation().x(); + transform[3][1] = geometry->getTranslation().y(); + transform[3][2] = geometry->getTranslation().z(); + + m_localVertexUniforms.transform = transform; +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..2ba54e6ecb53f47c59d9054d2f76c7edcb444abe --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanRenderDelegate.h @@ -0,0 +1,120 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanRenderDelegate_h +#define imstkVulkanRenderDelegate_h + +#include "glm/glm.hpp" +#include "glm/gtc/matrix_transform.hpp" +#include "glm/gtc/quaternion.hpp" + +#include <array> + +#include "imstkGeometry.h" +#include "imstkVulkanVertexBuffer.h" +#include "imstkVulkanUniformBuffer.h" +#include "imstkVulkanMaterialDelegate.h" + +#include "vtkPolyDataMapper.h" + +namespace imstk +{ +class VulkanRenderDelegate +{ +public: + + /// + /// \brief Default destructor + /// + ~VulkanRenderDelegate() = default; + + /// + /// \brief Creates a render delegate from geometry + /// + static std::shared_ptr<VulkanRenderDelegate> make_delegate( + std::shared_ptr<Geometry> geom, + VulkanMemoryManager& details); + + /// + /// \brief Get source geometry + /// + virtual std::shared_ptr<Geometry> getGeometry() const = 0; + + /// + /// \brief Update render geometry. This is implemented a little differently + /// in that memory is directly mapped from the Geometry to the + /// RenderDelegate. + /// + virtual void update(){}; + + /// + /// \brief Initialize memory backing + /// + void initialize(VkDevice &device, uint32_t memoryIndex, std::shared_ptr<Geometry> geometry); + + /// + /// \brief Get vertex buffer + /// + std::shared_ptr<VulkanVertexBuffer> getBuffer(); + + /// + /// \brief Get vertex buffer + /// + vtkSmartPointer<vtkPolyDataMapper> setUpMapper(vtkAlgorithmOutput * source); + + /// + /// \brief Initialize data + /// + void initializeData(VulkanMemoryManager& memoryManager, + std::shared_ptr<RenderMaterial> material = nullptr); + + /// + /// \brief Initialize data + /// + void updateTransform(std::shared_ptr<Geometry> geometry); + +protected: + friend class VulkanVertexBuffer; + friend class VulkanRenderer; + friend class VulkanUniformBuffer; + + unsigned int m_numTriangles; + unsigned int m_numVertices; + unsigned int m_vertexSize; + + /// + /// \brief Default constructor (protected) + /// + VulkanRenderDelegate(){}; + + std::shared_ptr<VulkanVertexBuffer> m_vertexBuffer; + + std::shared_ptr<VulkanUniformBuffer> m_vertexUniformBuffer; + std::shared_ptr<VulkanUniformBuffer> m_fragmentUniformBuffer; + + std::shared_ptr<VulkanMaterialDelegate> m_material; + + VulkanLocalVertexUniforms m_localVertexUniforms; + VulkanLocalFragmentUniforms m_localFragmentUniforms; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..41efdd7f3511cda6e5954ecd2710babf52b47b5b --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.cpp @@ -0,0 +1,107 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanSphereRenderDelegate.h" + +namespace imstk +{ +VulkanSphereRenderDelegate::VulkanSphereRenderDelegate(std::shared_ptr<Sphere> sphere, VulkanMemoryManager& memoryManager) + : m_geometry(sphere) +{ + auto radius = m_geometry->getRadius(); + + auto source = vtkSmartPointer<vtkSphereSource>::New(); + source->SetCenter(WORLD_ORIGIN[0], WORLD_ORIGIN[1], WORLD_ORIGIN[2]); + source->SetPhiResolution(20); + source->SetThetaResolution(20); + source->SetRadius(radius); + source->Update(); + + auto triangulate = vtkSmartPointer<vtkTriangleFilter>::New(); + triangulate->SetInputConnection(source->GetOutputPort()); + + triangulate->Update(); + + auto sourceData = triangulate->GetOutput(); + + auto positions = sourceData->GetPoints(); + auto normals = sourceData->GetPointData()->GetNormals(); + auto triangles = sourceData->GetPolys(); + + for (int i = 0; i < sourceData->GetNumberOfPoints(); i++) + { + auto position = positions->GetPoint(i); + auto normal = normals->GetTuple(i); + + VulkanBasicVertex sphereVertex; + + sphereVertex.position[0] = position[0]; + sphereVertex.position[1] = position[1]; + sphereVertex.position[2] = position[2]; + + sphereVertex.normal[0] = normal[0]; + sphereVertex.normal[1] = normal[1]; + sphereVertex.normal[2] = normal[2]; + + m_sphereVertices.push_back(sphereVertex); + } + + triangles->InitTraversal(); + + for (int i = 0; i < triangles->GetNumberOfCells(); i++) + { + auto points = vtkSmartPointer<vtkIdList>::New(); + auto triangle = triangles->GetNextCell(points); + + std::array<uint32_t, 3> trianglePoints = { + (uint32_t)points->GetId(0), + (uint32_t)points->GetId(1), + (uint32_t)points->GetId(2) + }; + + m_sphereTriangles.push_back(trianglePoints); + } + + m_numVertices = (uint32_t)m_sphereVertices.size(); + m_numTriangles = (uint32_t)m_sphereTriangles.size(); + m_vertexSize = sizeof(VulkanBasicVertex); + + this->initializeData(memoryManager); + + m_vertexBuffer->updateVertexBuffer(&m_sphereVertices, &m_sphereTriangles); + + this->update(); +} + +void +VulkanSphereRenderDelegate::update() +{ + this->updateTransform(m_geometry); + m_vertexUniformBuffer->updateUniforms(sizeof(VulkanLocalVertexUniforms), + (void *)&m_localVertexUniforms); +} + +std::shared_ptr<Geometry> +VulkanSphereRenderDelegate::getGeometry() const +{ + return m_geometry; +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..2f42035c20f52ff1b933085957c9c54c1bef481e --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSphereRenderDelegate.h @@ -0,0 +1,67 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanSphereRenderDelegate_h +#define imstkVulkanSphereRenderDelegate_h + +#include "imstkSphere.h" + +#include "imstkVulkanRenderDelegate.h" + +#include "vtkSphereSource.h" +#include "vtkPointData.h" +#include "vtkTriangleFilter.h" + +namespace imstk +{ +class VulkanSphereRenderDelegate : public VulkanRenderDelegate +{ +public: + + /// + /// \brief Default destructor + /// + ~VulkanSphereRenderDelegate() = default; + + /// + /// \brief Default constructor + /// + VulkanSphereRenderDelegate(std::shared_ptr<Sphere> sphere, VulkanMemoryManager& memoryManager); + + /// + /// \brief Update render geometry + /// + void update() override; + + /// + /// \brief Get source geometry + /// + std::shared_ptr<Geometry> getGeometry() const override; + +protected: + std::shared_ptr<Sphere> m_geometry; + + std::vector<std::array<uint32_t, 3>> m_sphereTriangles; + std::vector<VulkanBasicVertex> m_sphereVertices; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.cpp b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c8bf4986e31573440adab37bdcb35783fbd01b6 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.cpp @@ -0,0 +1,125 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanSurfaceMeshRenderDelegate.h" + +namespace imstk +{ +VulkanSurfaceMeshRenderDelegate::VulkanSurfaceMeshRenderDelegate(std::shared_ptr<SurfaceMesh> surfaceMesh, VulkanMemoryManager& memoryManager) + : m_geometry(surfaceMesh) +{ + m_numVertices = (uint32_t)m_geometry->getNumVertices(); + m_numTriangles = (uint32_t)m_geometry->getNumTriangles(); + m_vertexSize = sizeof(VulkanBasicVertex); + + this->initializeData(memoryManager, m_geometry->getRenderMaterial()); + + this->updateVertexBuffer(); + + this->update(); +} + +void +VulkanSurfaceMeshRenderDelegate::updateVertexBuffer() +{ + auto vertices = (VulkanBasicVertex *)m_vertexBuffer->mapVertices(); + + auto normals = m_geometry->getVertexNormals(); + auto tangents = m_geometry->getVertexTangents(); + auto bitangents = m_geometry->getVertexBitangents(); + const StdVectorOfVectorf* UVs; + + if (m_geometry->getDefaultTCoords() != "") + { + UVs = m_geometry->getPointDataArray(m_geometry->getDefaultTCoords()); + } + else + { + UVs = nullptr; + } + + for (unsigned i = 0; i < m_geometry->getNumVertices(); i++) + { + vertices[i].position = glm::vec3( + m_geometry->getVertexPosition(i)[0], + m_geometry->getVertexPosition(i)[1], + m_geometry->getVertexPosition(i)[2]); + + if (normals.size() == m_geometry->getNumVertices()) + { + vertices[i].normal = glm::vec3( + normals[i][0], + normals[i][1], + normals[i][2]); + } + + if (tangents.size() == m_geometry->getNumVertices()) + { + vertices[i].tangent = glm::vec3( + tangents[i][0], + tangents[i][1], + tangents[i][2]); + + vertices[i].bitangent = glm::vec3( + bitangents[i][0], + bitangents[i][1], + bitangents[i][2]); + } + + if (UVs && UVs->size() == m_geometry->getNumVertices()) + { + vertices[i].uv = glm::vec2( + (*UVs)[i][0], + (*UVs)[i][1]); + } + } + + m_vertexBuffer->unmapVertices(); + + auto triangles = (std::array<uint32_t, 3> *)m_vertexBuffer->mapTriangles(); + + for (unsigned i = 0; i < m_geometry->getNumTriangles(); i++) + { + triangles[i][0] = (uint32_t)m_geometry->getTrianglesVertices()[i][0]; + triangles[i][1] = (uint32_t)m_geometry->getTrianglesVertices()[i][1]; + triangles[i][2] = (uint32_t)m_geometry->getTrianglesVertices()[i][2]; + } + m_vertexBuffer->unmapTriangles(); +} + +void +VulkanSurfaceMeshRenderDelegate::update() +{ + this->updateTransform(m_geometry); + m_vertexUniformBuffer->updateUniforms(sizeof(VulkanLocalVertexUniforms), + (void *)&m_localVertexUniforms); + + m_geometry->computeVertexNormals(); // This method needs to be rewritten + // TODO: only update if deformable + this->updateVertexBuffer(); +} + +std::shared_ptr<Geometry> +VulkanSurfaceMeshRenderDelegate::getGeometry() const +{ + return m_geometry; +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.h b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..fe8e44a9646386c9eeac6034f77e755338a3cc98 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/RenderDelegate/imstkVulkanSurfaceMeshRenderDelegate.h @@ -0,0 +1,65 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanSurfaceMeshRenderDelegate_h +#define imstkVulkanSurfaceMeshRenderDelegate_h + +#include "imstkSurfaceMesh.h" + +#include "imstkVulkanRenderDelegate.h" + +namespace imstk +{ +class VulkanSurfaceMeshRenderDelegate : public VulkanRenderDelegate { +public: + + /// + /// \brief Default destructor + /// + ~VulkanSurfaceMeshRenderDelegate() = default; + + /// + /// \brief Default constructor + /// + VulkanSurfaceMeshRenderDelegate(std::shared_ptr<SurfaceMesh> surfaceMesh, VulkanMemoryManager& memoryManager); + + /// + /// \brief Update render geometry + /// + void update() override; + + /// + /// \brief Get source geometry + /// + std::shared_ptr<Geometry> getGeometry() const override; + + + /// + /// \brief Fill vertex buffer + /// + void updateVertexBuffer(); + +protected: + std::shared_ptr<SurfaceMesh> m_geometry; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/HDR_tonemap_frag.frag b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/HDR_tonemap_frag.frag new file mode 100644 index 0000000000000000000000000000000000000000..4452b3bab53a4c6066f208c6e09c81169ad03654 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/HDR_tonemap_frag.frag @@ -0,0 +1,48 @@ +#version 450 + +layout (set = 0, binding = 0) uniform sampler2D colorTexture; + +layout (location = 0) out vec4 finalColor; + +layout (location = 3) in vertexData{ + vec2 uv; +}vertex; + +// Reinhard tonemapping +vec3 tonemap(vec3 color) +{ + vec3 tempColor = (color / (color + 1)); + return tempColor; +} + +// John Hable's filmic tonemapping +vec3 tonemapTwoHelper(vec3 color) +{ + float shoulderValue = 0.22; + float linearValue = 0.3; + float linearDir = 0.1; + float toeValue = 0.2; + float toeUpper = 0.001; + float toeLower = 0.3; + + vec3 x = color * (color * shoulderValue + linearValue * linearDir) + toeValue * toeUpper; + vec3 y = color * (color * shoulderValue + linearValue) + toeValue * toeLower; + float z = toeUpper/toeLower; + + return (x / y) - z; +} + +vec3 tonemapTwo(vec3 color) +{ + vec3 whiteColor = vec3(1.0); + vec3 tempColor = tonemapTwoHelper(color); + vec3 normalizedColor = tonemapTwoHelper(whiteColor); + + return tempColor / whiteColor; +} + +void main(void) +{ + vec4 inputColor = texture(colorTexture, vertex.uv); + finalColor = vec4(tonemapTwo(inputColor.rgb), inputColor.a); +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/bloom_threshold_frag.frag b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/bloom_threshold_frag.frag new file mode 100644 index 0000000000000000000000000000000000000000..2b45532cb30bc5cf11d76f94f228c0fb890bda43 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/bloom_threshold_frag.frag @@ -0,0 +1,15 @@ +#version 450 + +layout (set = 0, binding = 0) uniform sampler2D colorTexture; + +layout (location = 0) out vec4 finalColor; + +layout (location = 3) in vertexData{ + vec2 uv; +}vertex; + +void main(void) +{ + vec3 inputColor = texture(colorTexture, vertex.uv).rgb; + finalColor = vec4(inputColor.rgb * vec3(0.1), 1); +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/blur_horizontal_frag.frag b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/blur_horizontal_frag.frag new file mode 100644 index 0000000000000000000000000000000000000000..648286ed042d8e8049aa5b17f75399407b61c612 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/blur_horizontal_frag.frag @@ -0,0 +1,34 @@ +#version 450 + +layout (set = 0, binding = 0) uniform sampler2D colorTexture; + +layout (location = 0) out vec4 finalColor; + +layout (location = 3) in vertexData{ + vec2 uv; +}vertex; + +layout (push_constant) uniform pushConstants +{ + float width; + float height; + float numSamples; + float values[10]; + float offsets[10]; +}constants; + +void main(void) +{ + vec3 inputColor = vec3(0); + inputColor += texture(colorTexture, vertex.uv).rgb * constants.values[0]; + + for (int i = 1; i < constants.numSamples; i++) + { + vec3 color = texture(colorTexture, vertex.uv + vec2(constants.offsets[i] / constants.width, 0) ).rgb; + inputColor += color * constants.values[i]; + color = texture(colorTexture, vertex.uv - vec2(constants.offsets[i] / constants.width, 0) ).rgb; + inputColor += color * constants.values[i]; + } + + finalColor = vec4(inputColor, 1); +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/blur_vertical_frag.frag b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/blur_vertical_frag.frag new file mode 100644 index 0000000000000000000000000000000000000000..5a9c1f8b01cf6e2c922fea2d47b11de9c414b7ce --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/blur_vertical_frag.frag @@ -0,0 +1,34 @@ +#version 450 + +layout (set = 0, binding = 0) uniform sampler2D colorTexture; + +layout (location = 0) out vec4 finalColor; + +layout (location = 3) in vertexData{ + vec2 uv; +}vertex; + +layout (push_constant) uniform pushConstants +{ + float width; + float height; + float numSamples; + float values[10]; + float offsets[10]; +}constants; + +void main(void) +{ + vec3 inputColor = vec3(0); + inputColor += texture(colorTexture, vertex.uv).rgb * constants.values[0]; + + for (int i = 1; i < constants.numSamples; i++) + { + vec3 color = texture(colorTexture, vertex.uv + vec2(0, constants.offsets[i] / constants.height) ).rgb; + inputColor += color * constants.values[i]; + color = texture(colorTexture, vertex.uv - vec2(0, constants.offsets[i] / constants.height) ).rgb; + inputColor += color * constants.values[i]; + } + + finalColor = vec4(inputColor, 1); +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/composite_frag.frag b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/composite_frag.frag new file mode 100644 index 0000000000000000000000000000000000000000..3b9bda38788fffb6125a9ea8d7119589a969570f --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/composite_frag.frag @@ -0,0 +1,17 @@ +#version 450 + +layout (set = 0, binding = 0) uniform sampler2D colorTexture1; +layout (set = 0, binding = 1) uniform sampler2D colorTexture2; + +layout (location = 0) out vec4 finalColor; + +layout (location = 3) in vertexData{ + vec2 uv; +}vertex; + +void main(void) +{ + vec4 color1 = texture(colorTexture1, vertex.uv); + vec4 color2 = texture(colorTexture2, vertex.uv); + finalColor = vec4(color1.rgb + color2.rgb, color1.a); +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/postprocess_frag.frag b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/postprocess_frag.frag new file mode 100644 index 0000000000000000000000000000000000000000..4b55c9ba9a3e662c9e48cfae272b60870482a92c --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/postprocess_frag.frag @@ -0,0 +1,15 @@ +#version 450 + +layout (set = 0, binding = 0) uniform sampler2D colorTexture; + +layout (location = 0) out vec4 finalColor; + +layout (location = 3) in vertexData{ + vec2 uv; +}vertex; + +void main(void) +{ + vec4 inputColor = texture(colorTexture, vertex.uv); + finalColor = inputColor * vec4(1,0,0,1); +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/postprocess_vert.vert b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/postprocess_vert.vert new file mode 100644 index 0000000000000000000000000000000000000000..90996d0141e9e814756bd67aebccc86a93974b22 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/postprocess_vert.vert @@ -0,0 +1,14 @@ +#version 450 + +layout (location = 0) in vec3 vertexPosition; +layout (location = 1) in vec2 vertexUV; + +layout (location = 3) out vertexData{ + vec2 uv; +}vertex; + +void main(void) +{ + vertex.uv = vertexUV; + gl_Position = vec4(vertexPosition, 1.0); +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/sss_frag.frag b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/sss_frag.frag new file mode 100644 index 0000000000000000000000000000000000000000..eb06949aedf0b977d786317db952c0beb121084a --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/PostProcessing/sss_frag.frag @@ -0,0 +1,109 @@ +#version 450 + +layout (set = 0, binding = 0) uniform sampler2D colorTexture; +layout (set = 0, binding = 1) uniform sampler2D depthTexture; +layout (set = 0, binding = 2) uniform sampler2D normalTexture; + +layout (location = 0) out vec4 finalColor; + +layout (location = 3) in vertexData{ + vec2 uv; +}vertex; + +layout (push_constant) uniform pushConstants +{ + vec2 direction; + float fov; + float kernelWidth; + float nearPlane; + float farPlane; + float numSamples; + float nearValues[10]; + float farValues[10]; +}constants; + +const float e = 2.7183; +const float pi = 3.1415; + +const vec3 near = vec3(0.25, 0.08, 0.02); +const vec3 far = vec3(1.0, 0.3, 0.05); +const float w = 0.6; + +vec3 maxValue = vec3(0.0); + +float getLinearDepth(float depth); +vec3 separableKernel(float x, float w, vec3 near, vec3 far, float depth); +vec3 calculateGaussian(float x, vec3 stdDev); + +void main(void) +{ + vec3 inputColor = vec3(0); + + vec4 normal = texture(normalTexture, vertex.uv); + float sss = normal.a; + + + if (sss >= 0.001) + { + float depth = getLinearDepth(texture(depthTexture, vertex.uv).r); + float dx = 0.001 / (tan(constants.fov / 2.0) * depth); + dx = dx * normal.a / (constants.kernelWidth); + + maxValue = separableKernel(0, w, near, far, depth) * sss; + + for (int i = 1; i < constants.numSamples; i++) + { + vec2 offset = vec2(i * dx) * constants.direction; + float partOfMeshPos = texture(normalTexture, vertex.uv + offset).a; + float partOfMeshNeg = texture(normalTexture, vertex.uv - offset).a; + + depth = getLinearDepth(texture(depthTexture, vertex.uv + offset).r); + maxValue += separableKernel(i/(constants.numSamples), w, near, far, depth) * partOfMeshPos; + + depth = getLinearDepth(texture(depthTexture, vertex.uv - offset).r); + maxValue += separableKernel(-i/(constants.numSamples), w, near, far, depth) * partOfMeshNeg; + } + + inputColor += texture(colorTexture, vertex.uv).rgb * separableKernel(0, w, near, far, depth) * sss; + + for (int i = 1; i < constants.numSamples; i++) + { + vec2 offset = vec2(i * dx) * constants.direction; + float partOfMeshPos = texture(normalTexture, vertex.uv + offset).a; + float partOfMeshNeg = texture(normalTexture, vertex.uv - offset).a; + + vec3 color = texture(colorTexture, vertex.uv + offset).rgb; + depth = getLinearDepth(texture(depthTexture, vertex.uv + offset).r); + inputColor += color * separableKernel(i/(constants.numSamples), w, near, far, depth) * partOfMeshPos; + + color = texture(colorTexture, vertex.uv - offset).rgb; + depth = getLinearDepth(texture(depthTexture, vertex.uv - offset).r); + inputColor += color * separableKernel(-i/(constants.numSamples), w, near, far, depth) * partOfMeshNeg; + } + inputColor = inputColor / maxValue; + } + else + { + inputColor = texture(colorTexture, vertex.uv).rgb; + } + + finalColor = vec4(inputColor, 1); +} + +float getLinearDepth(float depth) +{ + return (2 * constants.nearPlane * constants.farPlane) / + (constants.nearPlane + constants.farPlane - (depth * (constants.farPlane - constants.nearPlane))); +} + +vec3 separableKernel(float x, float w, vec3 near, vec3 far, float depth) +{ + vec3 depthCompensation = vec3(1.0);//pow(vec3(e), (- depth * depth) / (2 * max(near, far))); + vec3 separableKernelValue = w * calculateGaussian(x, near) + (1 - w) * calculateGaussian(x, far); + return depthCompensation * separableKernelValue; +} + +vec3 calculateGaussian(float x, vec3 stdDev) +{ + return (1 / sqrt(2 * pi * stdDev * stdDev)) * pow(vec3(e), -(x * x) / (2 * stdDev * stdDev)); +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_frag.frag b/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_frag.frag new file mode 100644 index 0000000000000000000000000000000000000000..0bcc11b6196ddf0355ea5de94908bbe64013736d --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_frag.frag @@ -0,0 +1,196 @@ +#version 450 + +layout (location = 0) out vec4 outputColor; +layout (location = 1) out vec4 outputNormal; +layout (location = 2) out vec4 outputSpecular; + +layout (constant_id = 0) const uint numLights = 0; +layout (constant_id = 1) const bool tessellation = false; +layout (constant_id = 2) const bool hasDiffuseTexture = false; +layout (constant_id = 3) const bool hasNormalTexture = false; +layout (constant_id = 4) const bool hasSpecularTexture = false; +layout (constant_id = 5) const bool hasRoughnessTexture = false; +layout (constant_id = 6) const bool hasMetalnessTexture = false; +layout (constant_id = 7) const bool hasSubsurfaceScatteringTexture = false; + +struct light +{ + vec3 lightVector; + float lightAngle; + vec3 lightColor; + float lightIntensity; +}; + +layout (set = 1, binding = 0) uniform globalUniforms +{ + light lights[16]; +} globals; + +layout (location = 0) in vertexData{ + vec3 position; + vec3 normal; + vec2 uv; + mat3 TBN; + vec3 cameraPosition; +}vertex; + +layout (set = 1, binding = 2) uniform sampler2D diffuseTexture; +layout (set = 1, binding = 3) uniform sampler2D normalTexture; +layout (set = 1, binding = 4) uniform sampler2D roughnessTexture; +layout (set = 1, binding = 5) uniform sampler2D metalnessTexture; +layout (set = 1, binding = 6) uniform sampler2D subsurfaceScatteringTexture; +//layout (set = 1, binding = 6) uniform samplerCube irradianceCubemapTexture; + +// Constants +const float PI = 3.1415; + +// Global variables +vec3 finalDiffuse = vec3(0); +vec3 finalSpecular = vec3(0); +vec3 diffuseColor = vec3(1, 1, 1); +vec3 normal = vec3(0, 0, 1); +float specularValue = 20; +vec3 cameraDirection = vec3(0, 0, 1); +float specularPow = 0; +vec3 specularColor = vec3(1, 1, 1); +float roughness = 1.0; +float metalness = 0.0; +float subsurfaceScattering = 0.0; +vec3 diffuseIndirect = vec3(0, 0, 0); + +// Functions +void readTextures(); +void calculateIndirectLighting(); +void calculateClassicalLighting(vec3 lightDirection, vec3 lightColor); +void calculatePBRLighting(vec3 lightDirection, vec3 lightColor); +float geometryTerm(vec3 vector); +float squared(float x); + +void main(void) +{ + readTextures(); + + // If it's 0, then there's a divide by zero error + roughness = max(roughness * roughness, 0.0001); + + cameraDirection = normalize(vertex.cameraPosition - vertex.position); + + //calculateIndirectLighting(); + + for (int i = 0; i < numLights; i++) + { + calculatePBRLighting(normalize(globals.lights[i].lightVector), globals.lights[i].lightColor * 5); + } + + finalDiffuse *= diffuseColor; + outputColor = vec4(finalDiffuse, 1); + outputSpecular = vec4(finalSpecular, 1); + + outputNormal = vec4(normal, subsurfaceScattering); +} + +void readTextures() +{ + float mipLevel = textureQueryLod(diffuseTexture, vertex.uv).x; + + if (hasDiffuseTexture) + { + diffuseColor = texture(diffuseTexture, vertex.uv, mipLevel).rgb; + } + + if (hasNormalTexture) + { + normal = vertex.TBN * normalize((2.0 * texture(normalTexture, vertex.uv, mipLevel).rgb) - 1.0); + } + else + { + normal = vertex.TBN * normal; + } + + if (hasRoughnessTexture) + { + roughness = texture(roughnessTexture, vertex.uv, mipLevel).r; + } + + if (hasMetalnessTexture) + { + metalness = texture(metalnessTexture, vertex.uv, mipLevel).r; + } + + if (hasSubsurfaceScatteringTexture) + { + subsurfaceScattering = texture(subsurfaceScatteringTexture, vertex.uv, mipLevel).r; + } +} + +void calculateIndirectLighting() +{ + // Fresnel term: Schlick's approximation + vec3 F_0 = mix(vec3(0.04), diffuseColor, metalness); + vec3 F = (F_0) + (1.0 - F_0) * pow(1.0 - max(dot(cameraDirection, normal), 0), 5); + + // Energy conservation + vec3 k_s = F; + vec3 k_d = (1 - k_s) * (1.0 - metalness); + + finalDiffuse += diffuseIndirect * k_d; +} + +void calculateClassicalLighting(vec3 lightDirection, vec3 lightColor) +{ + // Lambert BRDF + float l_dot_n = max(dot(normal, lightDirection), 0); + + vec3 halfway = normalize(lightDirection + cameraDirection); + + // Blinn-Phong BRDF + float specularity = max(dot(normal, halfway), 0); + specularPow = pow(specularity, specularValue); + + finalDiffuse += lightColor * l_dot_n; + finalSpecular += specularPow * specularColor * l_dot_n; +} + +void calculatePBRLighting(vec3 lightDirection, vec3 lightColor) +{ + // Lambert BRDF + float diffusePow = 1.0 / PI; + float l_dot_n = max(dot(normal, lightDirection), 0); + + vec3 halfway = normalize(normalize(lightDirection) + cameraDirection); + + // Cook-Torrance BRDF + + // Distribution term: Trowbridge-Reitz + float roughness_squared = roughness * roughness; + float D = roughness_squared / (PI * squared(squared(max(dot(halfway, normal), 0)) * (roughness_squared - 1) + 1)); + + // Fresnel term: Schlick's approximation + vec3 F_0 = mix(vec3(0.04), diffuseColor, metalness); + vec3 F = (F_0) + (1.0 - F_0) * pow(1.0 - max(dot(cameraDirection, halfway), 0), 5); + + // Geometry term: Schlick's GGX + float G = geometryTerm(cameraDirection) * geometryTerm(lightDirection); + + vec3 specularPow = (D * F * G) / + (4 * max(dot(normal, cameraDirection), 0.01) * max(dot(normal, lightDirection), 0.01)); + + // Energy conservation + vec3 k_s = F; + vec3 k_d = (1 - k_s) * (1.0 - metalness); + + finalDiffuse += k_d * diffusePow * lightColor * l_dot_n; + finalSpecular += specularPow * specularColor * lightColor * l_dot_n; +} + +float geometryTerm(vec3 vector) +{ + float k = roughness / 2; + float vector_dot_n = max(dot(vector, normal), 0); + return vector_dot_n / (vector_dot_n * (1 - k) + k); +} + +float squared(float x) +{ + return x * x; +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_tesc.tesc b/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_tesc.tesc new file mode 100644 index 0000000000000000000000000000000000000000..c88f1747864447812cc57bf49be15465d054b1fe --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_tesc.tesc @@ -0,0 +1,138 @@ +#version 450 + +// PN triangles implementation + +layout (constant_id = 0) const uint numLights = 0; +layout (constant_id = 3) const bool hasNormalTexture = false; + +layout (vertices = 3) out; + +struct light +{ + vec3 lightVector; + float lightAngle; + vec3 lightColor; + float lightIntensity; +}; + +layout (set = 0, binding = 0) uniform globalUniforms +{ + mat4 projectionMatrix; + mat4 viewMatrix; + vec4 cameraPosition; + light lights[16]; +} globals; + +layout (set = 0, binding = 1) uniform localUniforms +{ + mat4 transform; +} locals; + +layout(location = 0) in vertexData{ + vec3 position; + vec3 normal; + vec2 uv; + mat3 TBN; + vec3 cameraPosition; +}vertex[]; + +layout (location = 0) out vertexDataTessellation{ + vec3 position; + vec3 normal; + vec2 uv; + mat3 TBN; + vec3 cameraPosition; +}vertexTessellation[]; + +patch out TrianglePatch +{ + vec3 b300; + vec3 b030; + vec3 b003; + vec3 b012; + vec3 b021; + vec3 b102; + vec3 b120; + vec3 b201; + vec3 b210; + vec3 b111; + vec3 n200; + vec3 n020; + vec3 n002; + vec3 n110; + vec3 n011; + vec3 n101; +} trianglePatch; + +float projectPosition(vec3 point, vec3 planePoint, vec3 planeNormal) +{ + return dot(point - planePoint, planeNormal); +} + +float projectNormal(vec3 point1, vec3 point2, vec3 normal1, vec3 normal2) +{ + vec3 difference = point2 - point1; + return dot(difference, normal1 + normal2) / dot(difference, difference); +} + +vec3 computeEdgeControlPosition(int index1, int index2) +{ + vec3 point1 = vertex[index1].position; + vec3 point2 = vertex[index2].position; + vec3 normal1 = vertex[index1].normal; + return (2 * point1 + point2 - projectPosition(point2, point1, normal1) * normal1) / 3; +} + +vec3 computeEdgeControlNormal(int index1, int index2) +{ + vec3 point1 = vertex[index1].position; + vec3 point2 = vertex[index2].position; + vec3 normal1 = vertex[index1].normal; + vec3 normal2 = vertex[index2].normal; + return normalize(normal1 + normal2 - projectNormal(point1, point2, normal1, normal2) * (point2 - point1)); +} + +void main(void) +{ + // Pass through vertex values + vertexTessellation[gl_InvocationID].position = vertex[gl_InvocationID].position; + vertexTessellation[gl_InvocationID].normal = vertex[gl_InvocationID].normal; + vertexTessellation[gl_InvocationID].uv = vertex[gl_InvocationID].uv; + vertexTessellation[gl_InvocationID].TBN = vertex[gl_InvocationID].TBN; + vertexTessellation[gl_InvocationID].cameraPosition = vertex[gl_InvocationID].cameraPosition; + + // Calculate patch control point positions + trianglePatch.b300 = vertex[0].position; + trianglePatch.b030 = vertex[1].position; + trianglePatch.b003 = vertex[2].position; + trianglePatch.b012 = computeEdgeControlPosition(2, 1); + trianglePatch.b021 = computeEdgeControlPosition(1, 2); + trianglePatch.b102 = computeEdgeControlPosition(2, 0); + trianglePatch.b120 = computeEdgeControlPosition(1, 0); + trianglePatch.b201 = computeEdgeControlPosition(0, 2); + trianglePatch.b210 = computeEdgeControlPosition(0, 1); + vec3 averageEdge = (trianglePatch.b012 + trianglePatch.b021 + + trianglePatch.b102 + trianglePatch.b120 + + trianglePatch.b201 + trianglePatch.b210) / 6; + vec3 averageVertex = (trianglePatch.b300 + trianglePatch.b030 + trianglePatch.b003) / 3; + trianglePatch.b111 = averageEdge + (averageEdge - averageVertex) / 2; + + // Calculate patch control point normals + trianglePatch.n200 = vertex[0].normal; + trianglePatch.n020 = vertex[1].normal; + trianglePatch.n002 = vertex[2].normal; + trianglePatch.n110 = computeEdgeControlNormal(0, 1); + trianglePatch.n011 = computeEdgeControlNormal(1, 2); + trianglePatch.n101 = computeEdgeControlNormal(2, 1); + + // Determines how much to tessellate + if (gl_InvocationID == 0) + { + gl_TessLevelOuter[0] = 3; + gl_TessLevelOuter[1] = 3; + gl_TessLevelOuter[2] = 3; + gl_TessLevelInner[0] = 3; + } + + //vertexTessellation[0] = vertex[0]; +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_tese.tese b/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_tese.tese new file mode 100644 index 0000000000000000000000000000000000000000..6d6e1091670441a437576fac6acbe17d6b4b0b88 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_tese.tese @@ -0,0 +1,111 @@ +#version 450 + +// PN triangles implementation + +layout (constant_id = 0) const uint numLights = 0; +layout (constant_id = 3) const bool hasNormalTexture = false; + +layout (triangles, equal_spacing, cw) in; + +struct light +{ + vec3 lightVector; + float lightAngle; + vec3 lightColor; + float lightIntensity; +}; + +layout (set = 0, binding = 0) uniform globalUniforms +{ + mat4 projectionMatrix; + mat4 viewMatrix; + vec4 cameraPosition; + light lights[16]; +} globals; + +layout (set = 0, binding = 1) uniform localUniforms +{ + mat4 transform; +} locals; + +layout (location = 0) out vertexData{ + vec3 position; + vec3 normal; + vec2 uv; + mat3 TBN; + vec3 cameraPosition; +}vertex; + +layout (location = 0) in vertexDataTessellation{ + vec3 position; + vec3 normal; + vec2 uv; + mat3 TBN; + vec3 cameraPosition; +}vertexTessellation[]; + +patch in TrianglePatch +{ + vec3 b300; + vec3 b030; + vec3 b003; + vec3 b012; + vec3 b021; + vec3 b102; + vec3 b120; + vec3 b201; + vec3 b210; + vec3 b111; + vec3 n200; + vec3 n020; + vec3 n002; + vec3 n110; + vec3 n011; + vec3 n101; +} trianglePatch; + +void main(void) +{ + // Calculate normal + vec3 normal = vec3(1); + normal.xyz = trianglePatch.n200 * pow(gl_TessCoord.z, 2) + + trianglePatch.n020 * pow(gl_TessCoord.x, 2) + + trianglePatch.n002 * pow(gl_TessCoord.y, 2) + + trianglePatch.n011 * gl_TessCoord.x * gl_TessCoord.y + + trianglePatch.n101 * gl_TessCoord.z * gl_TessCoord.y + + trianglePatch.n110 * gl_TessCoord.z * gl_TessCoord.x; + + // Calculate position + vec4 position = vec4(1); + position.xyz = trianglePatch.b300 * pow(gl_TessCoord.z, 3) + + trianglePatch.b030 * pow(gl_TessCoord.x, 3) + + trianglePatch.b003 * pow(gl_TessCoord.y, 3) + + 3 * trianglePatch.b012 * pow(gl_TessCoord.y, 2) * gl_TessCoord.x + + 3 * trianglePatch.b021 * pow(gl_TessCoord.x, 2) * gl_TessCoord.y + + 3 * trianglePatch.b102 * pow(gl_TessCoord.y, 2) * gl_TessCoord.z + + 3 * trianglePatch.b120 * pow(gl_TessCoord.x, 2) * gl_TessCoord.z + + 3 * trianglePatch.b201 * pow(gl_TessCoord.z, 2) * gl_TessCoord.y + + 3 * trianglePatch.b210 * pow(gl_TessCoord.z, 2) * gl_TessCoord.x + + 6 * trianglePatch.b111 * gl_TessCoord.x * gl_TessCoord.y * gl_TessCoord.z; + + // Interpolate vertex + vertex.normal = normalize(normal); + vertex.uv = vertexTessellation[0].uv * gl_TessCoord.z + + vertexTessellation[1].uv * gl_TessCoord.x + + vertexTessellation[2].uv * gl_TessCoord.y; + vertex.TBN[0] = normalize(vertexTessellation[0].TBN[0] * gl_TessCoord.z + + vertexTessellation[1].TBN[0] * gl_TessCoord.x + + vertexTessellation[2].TBN[0] * gl_TessCoord.y); + vertex.TBN[1] = normalize(vertexTessellation[0].TBN[1] * gl_TessCoord.z + + vertexTessellation[1].TBN[1] * gl_TessCoord.x + + vertexTessellation[2].TBN[1] * gl_TessCoord.y); + //vertex.TBN[1] = normalize(cross(vertex.normal, vertex.TBN[0])); + //vertex.TBN[0] = normalize(cross(vertex.TBN[1], vertex.normal)); + vertex.TBN[2] = vertex.normal; + vertex.cameraPosition = vertexTessellation[0].cameraPosition * gl_TessCoord.z + + vertexTessellation[1].cameraPosition * gl_TessCoord.x + + vertexTessellation[2].cameraPosition * gl_TessCoord.y; + vertex.position = position.xyz; + + gl_Position = globals.projectionMatrix * globals.viewMatrix * position; +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_vert.vert b/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_vert.vert new file mode 100644 index 0000000000000000000000000000000000000000..c88f4c781d6998667b3916978c66f42cad58099b --- /dev/null +++ b/Source/Rendering/VulkanRenderer/VulkanShaders/mesh/mesh_vert.vert @@ -0,0 +1,59 @@ +#version 450 + +layout (constant_id = 0) const uint numLights = 0; +layout (constant_id = 1) const bool tessellation = false; +layout (constant_id = 3) const bool hasNormalTexture = false; + +layout (location = 0) in vec3 vertexPosition; +layout (location = 1) in vec3 vertexNormal; +layout (location = 2) in vec3 vertexTangent; +layout (location = 3) in vec3 vertexBitangent; +layout (location = 4) in vec2 vertexUV; + +struct light +{ + vec3 lightVector; + float lightAngle; + vec3 lightColor; + float lightIntensity; +}; + +layout (set = 0, binding = 0) uniform globalUniforms +{ + mat4 projectionMatrix; + mat4 viewMatrix; + vec4 cameraPosition; + light lights[16]; +} globals; + +layout (set = 0, binding = 1) uniform localUniforms +{ + mat4 transform; +} locals; + +layout (location = 0) out vertexData{ + vec3 position; + vec3 normal; + vec2 uv; + mat3 TBN; + vec3 cameraPosition; +}vertex; + +void main(void) +{ + vec4 position = locals.transform * vec4(vertexPosition, 1.0); + vec4 normal = normalize(locals.transform * vec4(normalize(vertexNormal), 0.0)); + vec4 tangent = normalize(locals.transform * vec4(normalize(vertexTangent), 0.0)); + vec4 bitangent = normalize(locals.transform * vec4(normalize(vertexBitangent), 0.0)); + + bitangent = vec4(cross(normal.xyz, tangent.xyz), 0.0); + + vertex.TBN = mat3(tangent.xyz, bitangent.xyz, normal.xyz); + + vertex.cameraPosition = globals.cameraPosition.xyz; + vertex.position = position.xyz; + vertex.normal = normalize(normal.xyz); + vertex.uv = vertexUV; + + gl_Position = globals.projectionMatrix * globals.viewMatrix * position; +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanBuffer.h b/Source/Rendering/VulkanRenderer/imstkVulkanBuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..9b0dd783dde274fd8e47ef120754cde8140747c4 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanBuffer.h @@ -0,0 +1,48 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanBuffer_h +#define imstkVulkanBuffer_h + +#include "vulkan/vulkan.h" + +#include "glm/glm.hpp" + +#include <vector> + +namespace imstk +{ +/// +/// \class VulkanBuffer +/// +/// \brief Abstract class for buffers +/// +class VulkanBuffer +{ +public: + /// + /// \brief Binds the buffer to memory + /// + virtual void bind(){}; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanFramebuffer.cpp b/Source/Rendering/VulkanRenderer/imstkVulkanFramebuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e0ea0be738182002660e44cee22353363b22918 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanFramebuffer.cpp @@ -0,0 +1,156 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanFramebuffer.h" + +namespace imstk +{ +VulkanFramebuffer::VulkanFramebuffer( + VulkanMemoryManager& memoryManager, + uint32_t width, + uint32_t height, + bool lastPass, + VkSampleCountFlagBits samples) +{ + m_renderDevice = memoryManager.m_device; + m_width = width; + m_height = height; + m_lastPass = lastPass; + m_samples = samples; +} + +void +VulkanFramebuffer::initializeFramebuffer(VkRenderPass * renderPass) +{ + m_renderPass = renderPass; + std::vector<VkImageView> framebufferAttachments; + + // Color attachment + if (m_colorFormat != VK_FORMAT_UNDEFINED) + { + VkAttachmentDescription attachment; + attachment.flags = 0; + attachment.format = m_colorFormat; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.finalLayout = + m_lastPass ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + m_attachments.push_back(attachment); + framebufferAttachments.push_back(*m_colorImageView); + } + + // Depth attachment + if (m_depthFormat != VK_FORMAT_UNDEFINED) + { + VkAttachmentDescription attachment; + attachment.flags = 0; + attachment.format = m_depthFormat; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + m_attachments.push_back(attachment); + framebufferAttachments.push_back(*m_depthImageView); + } + + // Normal attachment + if (m_normalFormat != VK_FORMAT_UNDEFINED) + { + VkAttachmentDescription attachment; + attachment.flags = 0; + attachment.format = m_normalFormat; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + m_attachments.push_back(attachment); + framebufferAttachments.push_back(*m_normalImageView); + } + + // Normal attachment + if (m_specularFormat != VK_FORMAT_UNDEFINED) + { + VkAttachmentDescription attachment; + attachment.flags = 0; + attachment.format = m_specularFormat; + attachment.samples = VK_SAMPLE_COUNT_1_BIT; + attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachment.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + m_attachments.push_back(attachment); + framebufferAttachments.push_back(*m_specularImageView); + } + + VkFramebufferCreateInfo framebufferInfo; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.pNext = nullptr; + framebufferInfo.flags = 0; + framebufferInfo.renderPass = *m_renderPass; + framebufferInfo.attachmentCount = (uint32_t)framebufferAttachments.size(); + framebufferInfo.pAttachments = &framebufferAttachments[0]; + framebufferInfo.height = m_height; + framebufferInfo.width = m_width; + framebufferInfo.layers = 1; + + vkCreateFramebuffer(m_renderDevice, &framebufferInfo, nullptr, &m_framebuffer); +} + +void +VulkanFramebuffer::setColor(VkImageView * color, VkFormat format) +{ + m_colorImageView = color; + m_colorFormat = format; +} + +void +VulkanFramebuffer::setDepth(VkImageView * depth, VkFormat format) +{ + m_depthImageView = depth; + m_depthFormat = format; +} + +void +VulkanFramebuffer::setNormal(VkImageView * normal, VkFormat format) +{ + m_normalImageView = normal; + m_normalFormat = format; +} + +void +VulkanFramebuffer::setSpecular(VkImageView * specular, VkFormat format) +{ + m_specularImageView = specular; + m_specularFormat = format; +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanFramebuffer.h b/Source/Rendering/VulkanRenderer/imstkVulkanFramebuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..43ebff2a88c0547c8fc6659d4397d669078a9aab --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanFramebuffer.h @@ -0,0 +1,101 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanFramebuffer_h +#define imstkVulkanFramebuffer_h + +#include "vulkan/vulkan.h" + +#include "imstkVulkanMemoryManager.h" + +#include <array> +#include <vector> + +namespace imstk +{ +class VulkanFramebuffer +{ +public: + VulkanFramebuffer( + VulkanMemoryManager& memoryManager, + unsigned int width, + unsigned int height, + bool lastPass = false, + VkSampleCountFlagBits samples = VK_SAMPLE_COUNT_1_BIT); + + void setColor(VkImageView * imageView, VkFormat format); + + void setSpecular(VkImageView * imageView, VkFormat format); + + void setDepth(VkImageView * depthImage, VkFormat format); + + void setNormal(VkImageView * normalImage, VkFormat format); + + void initializeFramebuffer(VkRenderPass * renderPass); + + ~VulkanFramebuffer(){}; + + void changeImageLayout(VkCommandBuffer& commandBuffer, + VkImage& image, + VkImageLayout layout1, + VkImageLayout layout2, + VkAccessFlags sourceFlags, + VkAccessFlags destinationFlags, + VkImageSubresourceRange range); + +private: + friend class VulkanRenderer; + friend class VulkanPostProcess; + friend class VulkanPostProcessingChain; + + uint32_t m_width; + uint32_t m_height; + bool m_lastPass = false; + VkSampleCountFlagBits m_samples; + VkDevice m_renderDevice; + + // Depth buffer + VkImageView * m_depthImageView; + VkFormat m_depthFormat = VK_FORMAT_UNDEFINED; + + // Normal buffer + VkImageView * m_normalImageView; + VkFormat m_normalFormat = VK_FORMAT_UNDEFINED; + + // Color accumulation buffer + VkImageView * m_colorImageView; + VkFormat m_colorFormat = VK_FORMAT_UNDEFINED; + + // Specular accumulation buffer + VkImageView * m_specularImageView; + VkFormat m_specularFormat = VK_FORMAT_UNDEFINED; + + // Attachments + std::vector<VkAttachmentDescription> m_attachments; + + VkFramebuffer m_framebuffer; + + // Renderpass + VkRenderPass * m_renderPass; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanMaterialDelegate.cpp b/Source/Rendering/VulkanRenderer/imstkVulkanMaterialDelegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf87985118032ae4cd31d725a4d271ff86e362db --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanMaterialDelegate.cpp @@ -0,0 +1,801 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanMaterialDelegate.h" + +#include "imstkVulkanRenderer.h" + +namespace imstk +{ +VulkanMaterialDelegate::VulkanMaterialDelegate( + std::shared_ptr<VulkanUniformBuffer> vertexUniformBuffer, + std::shared_ptr<VulkanUniformBuffer> fragmentUniformBuffer, + std::shared_ptr<RenderMaterial> material, + VulkanMemoryManager& memoryManager) +{ + m_vertexUniformBuffer = vertexUniformBuffer; + m_fragmentUniformBuffer = fragmentUniformBuffer; + + m_memoryManager = &memoryManager; + + if (material) + { + m_material = material; + } + else + { + m_material = std::make_shared<RenderMaterial>(); + } +} + +void +VulkanMaterialDelegate::initialize(VulkanRenderer * renderer) +{ + this->createDescriptorSetLayouts(renderer); + this->createPipeline(renderer); + this->initializeTextures(renderer); + this->createDescriptors(renderer); +} + +void +VulkanMaterialDelegate::createPipeline(VulkanRenderer * renderer) +{ + m_memoryManager->m_device = renderer->m_renderDevice; + m_memoryManager->m_queueFamilyIndex = renderer->m_renderQueueFamily; + + std::string vertexShaderPath = "./Shaders/VulkanShaders/Mesh/mesh_vert.spv"; + std::ifstream vertexShaderDataStream(vertexShaderPath, std::ios_base::binary); + char vertexShaderData[16000]; + vertexShaderDataStream.read(vertexShaderData, 15999); + vertexShaderData[(int)vertexShaderDataStream.gcount()] = '\0'; + + VkShaderModuleCreateInfo vertexShaderInfo; + vertexShaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + vertexShaderInfo.pNext = nullptr; + vertexShaderInfo.flags = 0; + vertexShaderInfo.codeSize = vertexShaderDataStream.gcount(); + vertexShaderInfo.pCode = (uint32_t *)vertexShaderData; + if (vkCreateShaderModule(renderer->m_renderDevice, &vertexShaderInfo, nullptr, &m_pipelineComponents.vertexShader) != VK_SUCCESS) + { + LOG(FATAL) << "Unable to build vertex shader : " << vertexShaderPath; + } + + if (m_material->getTessellated()) + { + std::string tessellationControlShaderPath = "./Shaders/VulkanShaders/Mesh/mesh_tesc.spv"; + std::ifstream tessellationControlShaderDataStream(tessellationControlShaderPath, std::ios_base::binary); + char tessellationControlShaderData[16000]; + tessellationControlShaderDataStream.read(tessellationControlShaderData, 15999); + tessellationControlShaderData[(int)tessellationControlShaderDataStream.gcount()] = '\0'; + + VkShaderModuleCreateInfo tessellationControlShaderInfo; + tessellationControlShaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + tessellationControlShaderInfo.pNext = nullptr; + tessellationControlShaderInfo.flags = 0; + tessellationControlShaderInfo.codeSize = tessellationControlShaderDataStream.gcount(); + tessellationControlShaderInfo.pCode = (uint32_t *)tessellationControlShaderData; + if (vkCreateShaderModule(renderer->m_renderDevice, &tessellationControlShaderInfo, nullptr, &m_pipelineComponents.tessellationControlShader) != VK_SUCCESS) + { + LOG(FATAL) << "Unable to build fragment shader: " << tessellationControlShaderPath; + } + + std::string tessellatedEvaluationShaderPath = "./Shaders/VulkanShaders/Mesh/mesh_tese.spv"; + std::ifstream tessellationEvaluationShaderDataStream(tessellatedEvaluationShaderPath, std::ios_base::binary); + char tessellationEvaluationShaderData[16000]; + tessellationEvaluationShaderDataStream.read(tessellationEvaluationShaderData, 15999); + tessellationEvaluationShaderData[(int)tessellationEvaluationShaderDataStream.gcount()] = '\0'; + + VkShaderModuleCreateInfo tessellationEvaluationShaderInfo; + tessellationEvaluationShaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + tessellationEvaluationShaderInfo.pNext = nullptr; + tessellationEvaluationShaderInfo.flags = 0; + tessellationEvaluationShaderInfo.codeSize = tessellationEvaluationShaderDataStream.gcount(); + tessellationEvaluationShaderInfo.pCode = (uint32_t *)tessellationEvaluationShaderData; + if (vkCreateShaderModule(renderer->m_renderDevice, &tessellationEvaluationShaderInfo, nullptr, &m_pipelineComponents.tessellationEvaluationShader) != VK_SUCCESS) + { + LOG(FATAL) << "Unable to build fragment shader: " << tessellatedEvaluationShaderPath; + } + } + + std::string fragmentShaderPath = "./Shaders/VulkanShaders/Mesh/mesh_frag.spv"; + std::ifstream fragmentShaderDataStream(fragmentShaderPath, std::ios_base::binary); + char fragmentShaderData[16000]; + fragmentShaderDataStream.read(fragmentShaderData, 15999); + fragmentShaderData[(int)fragmentShaderDataStream.gcount()] = '\0'; + + VkShaderModuleCreateInfo fragmentShaderInfo; + fragmentShaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + fragmentShaderInfo.pNext = nullptr; + fragmentShaderInfo.flags = 0; + fragmentShaderInfo.codeSize = fragmentShaderDataStream.gcount(); + fragmentShaderInfo.pCode = (uint32_t *)fragmentShaderData; + if (vkCreateShaderModule(renderer->m_renderDevice, &fragmentShaderInfo, nullptr, &m_pipelineComponents.fragmentShader) != VK_SUCCESS) + { + LOG(FATAL) << "Unable to build fragment shader: " << fragmentShaderPath; + } + + // Copy renderer constants to material constants + renderer->m_constants.numLights = (uint32_t)renderer->m_scene->getLights().size(); + + m_constants.numLights = renderer->m_constants.numLights; + m_constants.tessellation = m_material->getTessellated(); + m_constants.diffuseTexture = (m_material->getTexture(Texture::Type::DIFFUSE)->getPath() != ""); + m_constants.normalTexture = (m_material->getTexture(Texture::Type::NORMAL)->getPath() != ""); + m_constants.specularTexture = (m_material->getTexture(Texture::Type::SPECULAR)->getPath() != ""); + m_constants.roughnessTexture = (m_material->getTexture(Texture::Type::ROUGHNESS)->getPath() != ""); + m_constants.metalnessTexture = (m_material->getTexture(Texture::Type::METALNESS)->getPath() != ""); + m_constants.subsurfaceScatteringTexture = (m_material->getTexture(Texture::Type::SUBSURFACE_SCATTERING)->getPath() != ""); + m_constants.irradianceCubemapTexture = (m_material->getTexture(Texture::Type::IRRADIANCE_CUBEMAP)->getPath() != ""); + + this->addSpecializationConstant(sizeof(m_constants.numLights), + offsetof(VulkanMaterialConstants, numLights)); + this->addSpecializationConstant(sizeof(m_constants.tessellation), + offsetof(VulkanMaterialConstants, tessellation)); + this->addSpecializationConstant(sizeof(m_constants.diffuseTexture), + offsetof(VulkanMaterialConstants, diffuseTexture)); + this->addSpecializationConstant(sizeof(m_constants.normalTexture), + offsetof(VulkanMaterialConstants, normalTexture)); + this->addSpecializationConstant(sizeof(m_constants.specularTexture), + offsetof(VulkanMaterialConstants, specularTexture)); + this->addSpecializationConstant(sizeof(m_constants.roughnessTexture), + offsetof(VulkanMaterialConstants, roughnessTexture)); + this->addSpecializationConstant(sizeof(m_constants.metalnessTexture), + offsetof(VulkanMaterialConstants, metalnessTexture)); + this->addSpecializationConstant(sizeof(m_constants.subsurfaceScatteringTexture), + offsetof(VulkanMaterialConstants, subsurfaceScatteringTexture)); + this->addSpecializationConstant(sizeof(m_constants.irradianceCubemapTexture), + offsetof(VulkanMaterialConstants, irradianceCubemapTexture)); + + m_pipelineComponents.fragmentSpecializationInfo.mapEntryCount = m_numConstants; + m_pipelineComponents.fragmentSpecializationInfo.pMapEntries = &m_pipelineComponents.fragmentMapEntries[0]; + m_pipelineComponents.fragmentSpecializationInfo.dataSize = sizeof(m_constants); + m_pipelineComponents.fragmentSpecializationInfo.pData = (void *)(&m_constants); + + m_pipelineComponents.shaderInfo.clear(); + + // Vertex Shader + { + VkPipelineShaderStageCreateInfo shaderInfo; + shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderInfo.pNext = nullptr; + shaderInfo.flags = 0; + shaderInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + shaderInfo.module = m_pipelineComponents.vertexShader; + shaderInfo.pName = "main"; + shaderInfo.pSpecializationInfo = &m_pipelineComponents.fragmentSpecializationInfo; + m_pipelineComponents.shaderInfo.push_back(shaderInfo); + } + + // Tessellation Shaders + if (m_material->getTessellated()) + { + { + VkPipelineShaderStageCreateInfo shaderInfo; + shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderInfo.pNext = nullptr; + shaderInfo.flags = 0; + shaderInfo.stage = VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT; + shaderInfo.module = m_pipelineComponents.tessellationControlShader; + shaderInfo.pName = "main"; + shaderInfo.pSpecializationInfo = &m_pipelineComponents.fragmentSpecializationInfo; + m_pipelineComponents.shaderInfo.push_back(shaderInfo); + } + + { + VkPipelineShaderStageCreateInfo shaderInfo; + shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderInfo.pNext = nullptr; + shaderInfo.flags = 0; + shaderInfo.stage = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + shaderInfo.module = m_pipelineComponents.tessellationEvaluationShader; + shaderInfo.pName = "main"; + shaderInfo.pSpecializationInfo = &m_pipelineComponents.fragmentSpecializationInfo; + m_pipelineComponents.shaderInfo.push_back(shaderInfo); + } + } + + // Fragment Shader + { + VkPipelineShaderStageCreateInfo shaderInfo; + shaderInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderInfo.pNext = nullptr; + shaderInfo.flags = 0; + shaderInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + shaderInfo.module = m_pipelineComponents.fragmentShader; + shaderInfo.pName = "main"; + shaderInfo.pSpecializationInfo = &m_pipelineComponents.fragmentSpecializationInfo; + m_pipelineComponents.shaderInfo.push_back(shaderInfo); + } + + // Vertex Attributes + m_pipelineComponents.vertexBindingDescription.resize(1); + + m_pipelineComponents.vertexBindingDescription[0].binding = 0; + m_pipelineComponents.vertexBindingDescription[0].stride = sizeof(VulkanBasicVertex); + m_pipelineComponents.vertexBindingDescription[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + // Vertex Attributes + m_pipelineComponents.vertexAttributeDescription.resize(5); + + m_pipelineComponents.vertexAttributeDescription[0].location = 0; + m_pipelineComponents.vertexAttributeDescription[0].binding = 0; + m_pipelineComponents.vertexAttributeDescription[0].format = VK_FORMAT_R32G32B32_SFLOAT; + m_pipelineComponents.vertexAttributeDescription[0].offset = offsetof(VulkanBasicVertex, position); + + m_pipelineComponents.vertexAttributeDescription[1].location = 1; + m_pipelineComponents.vertexAttributeDescription[1].binding = 0; + m_pipelineComponents.vertexAttributeDescription[1].format = VK_FORMAT_R32G32B32_SFLOAT; + m_pipelineComponents.vertexAttributeDescription[1].offset = offsetof(VulkanBasicVertex, normal); + + m_pipelineComponents.vertexAttributeDescription[2].location = 2; + m_pipelineComponents.vertexAttributeDescription[2].binding = 0; + m_pipelineComponents.vertexAttributeDescription[2].format = VK_FORMAT_R32G32B32_SFLOAT; + m_pipelineComponents.vertexAttributeDescription[2].offset = offsetof(VulkanBasicVertex, tangent); + + m_pipelineComponents.vertexAttributeDescription[3].location = 3; + m_pipelineComponents.vertexAttributeDescription[3].binding = 0; + m_pipelineComponents.vertexAttributeDescription[3].format = VK_FORMAT_R32G32B32_SFLOAT; + m_pipelineComponents.vertexAttributeDescription[3].offset = offsetof(VulkanBasicVertex, bitangent); + + m_pipelineComponents.vertexAttributeDescription[4].location = 4; + m_pipelineComponents.vertexAttributeDescription[4].binding = 0; + m_pipelineComponents.vertexAttributeDescription[4].format = VK_FORMAT_R32G32_SFLOAT; + m_pipelineComponents.vertexAttributeDescription[4].offset = offsetof(VulkanBasicVertex, uv); + + // Pipeline stages + m_pipelineComponents.vertexInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + m_pipelineComponents.vertexInfo.pNext = nullptr; + m_pipelineComponents.vertexInfo.flags = 0; + m_pipelineComponents.vertexInfo.vertexBindingDescriptionCount = (uint32_t)m_pipelineComponents.vertexBindingDescription.size(); + m_pipelineComponents.vertexInfo.pVertexBindingDescriptions = &m_pipelineComponents.vertexBindingDescription[0]; + m_pipelineComponents.vertexInfo.vertexAttributeDescriptionCount = (uint32_t)m_pipelineComponents.vertexAttributeDescription.size(); + m_pipelineComponents.vertexInfo.pVertexAttributeDescriptions = &m_pipelineComponents.vertexAttributeDescription[0]; + + m_pipelineComponents.inputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + m_pipelineComponents.inputAssemblyInfo.pNext = nullptr; + m_pipelineComponents.inputAssemblyInfo.flags = 0; + + if (m_material->getTessellated()) + { + m_pipelineComponents.inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; + } + else + { + m_pipelineComponents.inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + } + + m_pipelineComponents.inputAssemblyInfo.primitiveRestartEnable = VK_FALSE; + + m_pipelineComponents.tessellationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; + m_pipelineComponents.tessellationInfo.pNext = nullptr; + m_pipelineComponents.tessellationInfo.flags = 0; + if (m_material->getTessellated()) + { + m_pipelineComponents.tessellationInfo.patchControlPoints = + 3;//renderer->m_deviceLimits.maxTessellationPatchSize; + } + else + { + m_pipelineComponents.tessellationInfo.patchControlPoints = 1; + } + + m_pipelineComponents.viewports.resize(1); + + m_pipelineComponents.viewports[0].x = 0; + m_pipelineComponents.viewports[0].y = 0; + m_pipelineComponents.viewports[0].height = renderer->m_height; + m_pipelineComponents.viewports[0].width = renderer->m_width; + m_pipelineComponents.viewports[0].minDepth = 0.0; + m_pipelineComponents.viewports[0].maxDepth = 1.0; + + m_pipelineComponents.scissors.resize(1); + + m_pipelineComponents.scissors[0].offset = { 0, 0 }; + m_pipelineComponents.scissors[0].extent = { renderer->m_width, renderer->m_height }; + + m_pipelineComponents.viewportInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + m_pipelineComponents.viewportInfo.pNext = nullptr; + m_pipelineComponents.viewportInfo.flags = 0; + m_pipelineComponents.viewportInfo.viewportCount = (uint32_t)m_pipelineComponents.viewports.size(); + m_pipelineComponents.viewportInfo.pViewports = &m_pipelineComponents.viewports[0]; + m_pipelineComponents.viewportInfo.scissorCount = (uint32_t)m_pipelineComponents.scissors.size(); + m_pipelineComponents.viewportInfo.pScissors = &m_pipelineComponents.scissors[0]; + + m_pipelineComponents.rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + m_pipelineComponents.rasterizationInfo.pNext = nullptr; + m_pipelineComponents.rasterizationInfo.flags = 0; + m_pipelineComponents.rasterizationInfo.depthClampEnable = VK_FALSE; + m_pipelineComponents.rasterizationInfo.rasterizerDiscardEnable = VK_FALSE; // Might be enabled later + + if (m_material->getDisplayMode() == RenderMaterial::DisplayMode::WIREFRAME) + { + m_pipelineComponents.rasterizationInfo.polygonMode = VK_POLYGON_MODE_LINE; + } + else + { + m_pipelineComponents.rasterizationInfo.polygonMode = VK_POLYGON_MODE_FILL; + } + + m_pipelineComponents.rasterizationInfo.cullMode = VK_CULL_MODE_NONE; // TODO: Allow backface culling + m_pipelineComponents.rasterizationInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + m_pipelineComponents.rasterizationInfo.depthBiasEnable = VK_FALSE; + m_pipelineComponents.rasterizationInfo.depthBiasConstantFactor = 0.0; + m_pipelineComponents.rasterizationInfo.depthBiasClamp = VK_FALSE; + m_pipelineComponents.rasterizationInfo.depthBiasSlopeFactor = 0.0; + m_pipelineComponents.rasterizationInfo.lineWidth = 1.0; + + m_pipelineComponents.multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + m_pipelineComponents.multisampleInfo.pNext = nullptr; + m_pipelineComponents.multisampleInfo.flags = 0; + m_pipelineComponents.multisampleInfo.rasterizationSamples = renderer->m_samples; // TODO: Enable multisampling + m_pipelineComponents.multisampleInfo.sampleShadingEnable = VK_FALSE; + m_pipelineComponents.multisampleInfo.minSampleShading = 0; + m_pipelineComponents.multisampleInfo.pSampleMask = nullptr; + m_pipelineComponents.multisampleInfo.alphaToCoverageEnable = VK_FALSE; + m_pipelineComponents.multisampleInfo.alphaToOneEnable = VK_FALSE; + + VkStencilOpState states[2]; + states[0].failOp = VK_STENCIL_OP_ZERO; + states[0].passOp = VK_STENCIL_OP_KEEP; + states[0].depthFailOp = VK_STENCIL_OP_ZERO; + states[0].compareOp = VK_COMPARE_OP_LESS; + states[0].compareMask = 0; + states[0].writeMask = 0; + states[0].reference = 0; + + states[1].failOp = VK_STENCIL_OP_ZERO; + states[1].passOp = VK_STENCIL_OP_KEEP; + states[1].depthFailOp = VK_STENCIL_OP_ZERO; + states[1].compareOp = VK_COMPARE_OP_LESS; + states[1].compareMask = 0; + states[1].writeMask = 0; + states[1].reference = 0; + + m_pipelineComponents.depthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + m_pipelineComponents.depthStencilInfo.pNext = nullptr; + m_pipelineComponents.depthStencilInfo.flags = 0; + m_pipelineComponents.depthStencilInfo.depthTestEnable = VK_TRUE; + m_pipelineComponents.depthStencilInfo.depthWriteEnable = VK_TRUE; + m_pipelineComponents.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS; + m_pipelineComponents.depthStencilInfo.depthBoundsTestEnable = VK_FALSE; + m_pipelineComponents.depthStencilInfo.stencilTestEnable = VK_FALSE; + m_pipelineComponents.depthStencilInfo.front = states[0]; + m_pipelineComponents.depthStencilInfo.back = states[1]; + m_pipelineComponents.depthStencilInfo.minDepthBounds = VK_FALSE; + m_pipelineComponents.depthStencilInfo.maxDepthBounds = VK_FALSE; + + m_pipelineComponents.colorBlendAttachments.resize(3); + for (int i = 0; i < m_pipelineComponents.colorBlendAttachments.size(); i++) + { + m_pipelineComponents.colorBlendAttachments[i].blendEnable = VK_FALSE; + m_pipelineComponents.colorBlendAttachments[i].srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + m_pipelineComponents.colorBlendAttachments[i].dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + m_pipelineComponents.colorBlendAttachments[i].colorBlendOp = VK_BLEND_OP_ADD; + m_pipelineComponents.colorBlendAttachments[i].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + m_pipelineComponents.colorBlendAttachments[i].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + m_pipelineComponents.colorBlendAttachments[i].alphaBlendOp = VK_BLEND_OP_ADD; + m_pipelineComponents.colorBlendAttachments[i].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | + VK_COLOR_COMPONENT_G_BIT | + VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT; + } + + m_pipelineComponents.colorBlendInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + m_pipelineComponents.colorBlendInfo.pNext = nullptr; + m_pipelineComponents.colorBlendInfo.flags = 0; + m_pipelineComponents.colorBlendInfo.logicOpEnable = VK_FALSE; + m_pipelineComponents.colorBlendInfo.logicOp = VK_LOGIC_OP_SET; + m_pipelineComponents.colorBlendInfo.attachmentCount = (uint32_t)m_pipelineComponents.colorBlendAttachments.size(); + m_pipelineComponents.colorBlendInfo.pAttachments = &m_pipelineComponents.colorBlendAttachments[0]; + m_pipelineComponents.colorBlendInfo.blendConstants[0] = 1.0; + m_pipelineComponents.colorBlendInfo.blendConstants[1] = 1.0; + m_pipelineComponents.colorBlendInfo.blendConstants[2] = 1.0; + m_pipelineComponents.colorBlendInfo.blendConstants[3] = 1.0; + + VkPipelineLayoutCreateInfo layoutInfo; + layoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + layoutInfo.pNext = nullptr; + layoutInfo.flags = 0; + layoutInfo.setLayoutCount = (uint32_t)m_descriptorSetLayouts.size(); + layoutInfo.pSetLayouts = &m_descriptorSetLayouts[0]; + layoutInfo.pushConstantRangeCount = 0; + layoutInfo.pPushConstantRanges = nullptr; + + vkCreatePipelineLayout(renderer->m_renderDevice, &layoutInfo, nullptr, &m_pipelineLayout); + + m_graphicsPipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + m_graphicsPipelineInfo.pNext = nullptr; + m_graphicsPipelineInfo.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; + m_graphicsPipelineInfo.stageCount = (uint32_t)m_pipelineComponents.shaderInfo.size(); + m_graphicsPipelineInfo.pStages = &m_pipelineComponents.shaderInfo[0]; + m_graphicsPipelineInfo.pVertexInputState = &m_pipelineComponents.vertexInfo; + m_graphicsPipelineInfo.pInputAssemblyState = &m_pipelineComponents.inputAssemblyInfo; + m_graphicsPipelineInfo.pTessellationState = &m_pipelineComponents.tessellationInfo; + m_graphicsPipelineInfo.pViewportState = &m_pipelineComponents.viewportInfo; + m_graphicsPipelineInfo.pRasterizationState = &m_pipelineComponents.rasterizationInfo; + m_graphicsPipelineInfo.pMultisampleState = &m_pipelineComponents.multisampleInfo; + m_graphicsPipelineInfo.pDepthStencilState = &m_pipelineComponents.depthStencilInfo; + m_graphicsPipelineInfo.pColorBlendState = &m_pipelineComponents.colorBlendInfo; + m_graphicsPipelineInfo.pDynamicState = nullptr; + m_graphicsPipelineInfo.layout = m_pipelineLayout; + m_graphicsPipelineInfo.renderPass = renderer->m_renderPasses[0]; + m_graphicsPipelineInfo.subpass = 0; + m_graphicsPipelineInfo.basePipelineHandle = VK_NULL_HANDLE; + m_graphicsPipelineInfo.basePipelineIndex = 0; +} + +void +VulkanMaterialDelegate::initializeTextures(VulkanRenderer * renderer) +{ + auto defaultTexture = std::make_shared<Texture>(""); + auto defaultCubemap = std::make_shared<Texture>("", Texture::Type::IRRADIANCE_CUBEMAP); + + if (m_material->getTexture(Texture::Type::DIFFUSE)) + { + m_diffuseTexture = + std::make_shared<VulkanTextureDelegate>(*m_memoryManager, m_material->getTexture(Texture::Type::DIFFUSE)); + } + else + { + m_diffuseTexture = + std::make_shared<VulkanTextureDelegate>(*m_memoryManager, defaultTexture); + } + + if (m_material->getTexture(Texture::Type::NORMAL)) + { + m_normalTexture = + std::make_shared<VulkanTextureDelegate>(*m_memoryManager, m_material->getTexture(Texture::Type::NORMAL)); + } + else + { + m_normalTexture = + std::make_shared<VulkanTextureDelegate>(*m_memoryManager, defaultTexture); + } + + if (m_material->getTexture(Texture::Type::ROUGHNESS)) + { + m_roughnessTexture = + std::make_shared<VulkanTextureDelegate>(*m_memoryManager, m_material->getTexture(Texture::Type::ROUGHNESS)); + } + else + { + m_roughnessTexture = + std::make_shared<VulkanTextureDelegate>(*m_memoryManager, defaultTexture); + } + + if (m_material->getTexture(Texture::Type::METALNESS)) + { + m_metalnessTexture = + std::make_shared<VulkanTextureDelegate>(*m_memoryManager, m_material->getTexture(Texture::Type::METALNESS)); + } + else + { + m_metalnessTexture = + std::make_shared<VulkanTextureDelegate>(*m_memoryManager, defaultTexture); + } + + if (m_material->getTexture(Texture::Type::SUBSURFACE_SCATTERING)) + { + m_subsurfaceScatteringTexture = + std::make_shared<VulkanTextureDelegate>(*m_memoryManager, m_material->getTexture(Texture::Type::SUBSURFACE_SCATTERING)); + } + else + { + m_subsurfaceScatteringTexture = + std::make_shared<VulkanTextureDelegate>(*m_memoryManager, defaultCubemap); + } +} + +void +VulkanMaterialDelegate::addSpecializationConstant(uint32_t size, uint32_t offset) +{ + m_pipelineComponents.fragmentMapEntries.push_back(VkSpecializationMapEntry()); + + m_pipelineComponents.fragmentMapEntries[m_numConstants].constantID = m_numConstants; + m_pipelineComponents.fragmentMapEntries[m_numConstants].offset = offset; + m_pipelineComponents.fragmentMapEntries[m_numConstants].size = size; + + m_numConstants++; +} + +void +VulkanMaterialDelegate::createDescriptors(VulkanRenderer * renderer) +{ + this->createDescriptorPool(renderer); + this->createDescriptorSets(renderer); +} + +void +VulkanMaterialDelegate::createDescriptorSetLayouts(VulkanRenderer * renderer) +{ + m_descriptorSets.resize(2); + m_descriptorSetLayouts.resize(2); + + // Descriptor Sets + VkDescriptorSetLayoutBinding vertexDescriptorSetLayoutBindings[2]; + vertexDescriptorSetLayoutBindings[0].binding = 0; + vertexDescriptorSetLayoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + vertexDescriptorSetLayoutBindings[0].descriptorCount = 1; + vertexDescriptorSetLayoutBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT + | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT + | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + vertexDescriptorSetLayoutBindings[0].pImmutableSamplers = nullptr; + + vertexDescriptorSetLayoutBindings[1].binding = 1; + vertexDescriptorSetLayoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + vertexDescriptorSetLayoutBindings[1].descriptorCount = 1; + vertexDescriptorSetLayoutBindings[1].stageFlags = VK_SHADER_STAGE_VERTEX_BIT + | VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT + | VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT; + vertexDescriptorSetLayoutBindings[1].pImmutableSamplers = nullptr; + + std::vector<VkDescriptorSetLayoutBinding> fragmentDescriptorSetLayoutBindings; + + // Global uniform buffer + { + VkDescriptorSetLayoutBinding fragmentLayoutBinding; + fragmentLayoutBinding.binding = 0; + fragmentLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + fragmentLayoutBinding.descriptorCount = 1; + fragmentLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + fragmentLayoutBinding.pImmutableSamplers = nullptr; + fragmentDescriptorSetLayoutBindings.push_back(fragmentLayoutBinding); + } + + // Local uniform buffer + { + VkDescriptorSetLayoutBinding fragmentLayoutBinding; + fragmentLayoutBinding.binding = 1; + fragmentLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + fragmentLayoutBinding.descriptorCount = 1; + fragmentLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + fragmentLayoutBinding.pImmutableSamplers = nullptr; + fragmentDescriptorSetLayoutBindings.push_back(fragmentLayoutBinding); + } + + // Diffuse texture + { + VkDescriptorSetLayoutBinding fragmentLayoutBinding; + fragmentLayoutBinding.binding = 2; + fragmentLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + fragmentLayoutBinding.descriptorCount = 1; + fragmentLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + fragmentLayoutBinding.pImmutableSamplers = nullptr; + fragmentDescriptorSetLayoutBindings.push_back(fragmentLayoutBinding); + } + + // Normal texture + { + VkDescriptorSetLayoutBinding fragmentLayoutBinding; + fragmentLayoutBinding.binding = 3; + fragmentLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + fragmentLayoutBinding.descriptorCount = 1; + fragmentLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + fragmentLayoutBinding.pImmutableSamplers = nullptr; + fragmentDescriptorSetLayoutBindings.push_back(fragmentLayoutBinding); + } + + // Roughness texture + { + VkDescriptorSetLayoutBinding fragmentLayoutBinding; + fragmentLayoutBinding.binding = 4; + fragmentLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + fragmentLayoutBinding.descriptorCount = 1; + fragmentLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + fragmentLayoutBinding.pImmutableSamplers = nullptr; + fragmentDescriptorSetLayoutBindings.push_back(fragmentLayoutBinding); + } + + // Metalness texture + { + VkDescriptorSetLayoutBinding fragmentLayoutBinding; + fragmentLayoutBinding.binding = 5; + fragmentLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + fragmentLayoutBinding.descriptorCount = 1; + fragmentLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + fragmentLayoutBinding.pImmutableSamplers = nullptr; + fragmentDescriptorSetLayoutBindings.push_back(fragmentLayoutBinding); + } + + // Subsurface scattering texture + { + VkDescriptorSetLayoutBinding fragmentLayoutBinding; + fragmentLayoutBinding.binding = 6; + fragmentLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + fragmentLayoutBinding.descriptorCount = 1; + fragmentLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + fragmentLayoutBinding.pImmutableSamplers = nullptr; + fragmentDescriptorSetLayoutBindings.push_back(fragmentLayoutBinding); + } + + VkDescriptorSetLayoutCreateInfo descriptorSetLayoutInfo[2]; + descriptorSetLayoutInfo[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutInfo[0].pNext = nullptr; + descriptorSetLayoutInfo[0].flags = 0; + descriptorSetLayoutInfo[0].bindingCount = 2; + descriptorSetLayoutInfo[0].pBindings = vertexDescriptorSetLayoutBindings; + + descriptorSetLayoutInfo[1].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + descriptorSetLayoutInfo[1].pNext = nullptr; + descriptorSetLayoutInfo[1].flags = 0; + descriptorSetLayoutInfo[1].bindingCount = (uint32_t)fragmentDescriptorSetLayoutBindings.size(); + descriptorSetLayoutInfo[1].pBindings = &fragmentDescriptorSetLayoutBindings[0]; + + for (int i = 0; i < m_descriptorSetLayouts.size(); i++) + { + vkCreateDescriptorSetLayout(renderer->m_renderDevice, &descriptorSetLayoutInfo[i], nullptr, &m_descriptorSetLayouts[i]); + } +} + +void +VulkanMaterialDelegate::createDescriptorPool(VulkanRenderer * renderer) +{ + std::vector<VkDescriptorPoolSize> descriptorPoolSizes; + + // Vertex shader uniform buffers + { + VkDescriptorPoolSize poolSize; + poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSize.descriptorCount = 2; + descriptorPoolSizes.push_back(poolSize); + } + + // Fragment shader uniform buffers + { + VkDescriptorPoolSize poolSize; + poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSize.descriptorCount = 2; + descriptorPoolSizes.push_back(poolSize); + } + + // Fragment shader textures + { + VkDescriptorPoolSize poolSize; + poolSize.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSize.descriptorCount = 5; // Number of textures + descriptorPoolSizes.push_back(poolSize); + } + + VkDescriptorPoolCreateInfo descriptorPoolInfo; + descriptorPoolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + descriptorPoolInfo.pNext = nullptr; + descriptorPoolInfo.flags = 0; + descriptorPoolInfo.maxSets = (uint32_t)m_descriptorSets.size(); + descriptorPoolInfo.poolSizeCount = (uint32_t)descriptorPoolSizes.size(); + descriptorPoolInfo.pPoolSizes = &descriptorPoolSizes[0]; + + vkCreateDescriptorPool(renderer->m_renderDevice, &descriptorPoolInfo, nullptr, &m_descriptorPool); +} + +void +VulkanMaterialDelegate::createDescriptorSets(VulkanRenderer * renderer) +{ + VkDescriptorSetAllocateInfo descriptorSetAllocationInfo[1]; + descriptorSetAllocationInfo[0].sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + descriptorSetAllocationInfo[0].pNext = nullptr; + descriptorSetAllocationInfo[0].descriptorPool = m_descriptorPool; + descriptorSetAllocationInfo[0].descriptorSetCount = (uint32_t)m_descriptorSetLayouts.size(); + descriptorSetAllocationInfo[0].pSetLayouts = &m_descriptorSetLayouts[0]; + + VkDeviceSize size = { VK_WHOLE_SIZE }; + + // Global Buffers + std::vector<VkDescriptorBufferInfo> vertexBufferInfo(2); + vertexBufferInfo[0].offset = 0; + vertexBufferInfo[0].range = size; + vertexBufferInfo[0].buffer = *(renderer->m_globalVertexUniformBuffer->getUniformBuffer()); + + vertexBufferInfo[1].offset = 0; + vertexBufferInfo[1].range = size; + vertexBufferInfo[1].buffer = *(m_vertexUniformBuffer->getUniformBuffer()); + + // Global buffers + std::vector<VkDescriptorBufferInfo> fragmentBufferInfo(2); + fragmentBufferInfo[0].offset = 0; + fragmentBufferInfo[0].range = size; + fragmentBufferInfo[0].buffer = *(renderer->m_globalFragmentUniformBuffer->getUniformBuffer()); + + fragmentBufferInfo[1].offset = 0; + fragmentBufferInfo[1].range = size; + fragmentBufferInfo[1].buffer = *(m_fragmentUniformBuffer->getUniformBuffer()); + + std::vector<VkDescriptorImageInfo> fragmentTextureInfo; + + // Textures + { + VkDescriptorImageInfo textureInfo; + textureInfo.sampler = m_diffuseTexture->m_sampler; + textureInfo.imageView = m_diffuseTexture->m_imageView; + textureInfo.imageLayout = m_diffuseTexture->m_layout; + fragmentTextureInfo.push_back(textureInfo); + } + + { + VkDescriptorImageInfo textureInfo; + textureInfo.sampler = m_normalTexture->m_sampler; + textureInfo.imageView = m_normalTexture->m_imageView; + textureInfo.imageLayout = m_normalTexture->m_layout; + fragmentTextureInfo.push_back(textureInfo); + } + + { + VkDescriptorImageInfo textureInfo; + textureInfo.sampler = m_roughnessTexture->m_sampler; + textureInfo.imageView = m_roughnessTexture->m_imageView; + textureInfo.imageLayout = m_roughnessTexture->m_layout; + fragmentTextureInfo.push_back(textureInfo); + } + + { + VkDescriptorImageInfo textureInfo; + textureInfo.sampler = m_metalnessTexture->m_sampler; + textureInfo.imageView = m_metalnessTexture->m_imageView; + textureInfo.imageLayout = m_metalnessTexture->m_layout; + fragmentTextureInfo.push_back(textureInfo); + } + + { + VkDescriptorImageInfo textureInfo; + textureInfo.sampler = m_subsurfaceScatteringTexture->m_sampler; + textureInfo.imageView = m_subsurfaceScatteringTexture->m_imageView; + textureInfo.imageLayout = m_subsurfaceScatteringTexture->m_layout; + fragmentTextureInfo.push_back(textureInfo); + } + + vkAllocateDescriptorSets(renderer->m_renderDevice, descriptorSetAllocationInfo, &m_descriptorSets[0]); + + m_writeDescriptorSets.resize(2); + VkWriteDescriptorSet set; + m_writeDescriptorSets.push_back(set); + + for (int i = 0; i < m_writeDescriptorSets.size(); i++) + { + m_writeDescriptorSets[i].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + m_writeDescriptorSets[i].pNext = nullptr; + m_writeDescriptorSets[i].dstBinding = 0; + m_writeDescriptorSets[i].dstArrayElement = 0; + m_writeDescriptorSets[i].descriptorCount = 0; + m_writeDescriptorSets[i].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + m_writeDescriptorSets[i].pBufferInfo = &vertexBufferInfo[0]; + m_writeDescriptorSets[i].pImageInfo = nullptr; + m_writeDescriptorSets[i].pTexelBufferView = nullptr; + } + + // Vertex descriptor set + m_writeDescriptorSets[0].descriptorCount = 2; + m_writeDescriptorSets[0].dstSet = m_descriptorSets[0]; + m_writeDescriptorSets[0].pBufferInfo = &vertexBufferInfo[0]; + + // Fragment descriptor set + m_writeDescriptorSets[1].descriptorCount = 2; + m_writeDescriptorSets[1].dstSet = m_descriptorSets[1]; + m_writeDescriptorSets[1].pBufferInfo = &fragmentBufferInfo[0]; + + // Fragment texture descriptor set + m_writeDescriptorSets[2].descriptorCount = (uint32_t)fragmentTextureInfo.size(); + m_writeDescriptorSets[2].dstBinding = 2; + m_writeDescriptorSets[2].dstSet = m_descriptorSets[1]; + m_writeDescriptorSets[2].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + m_writeDescriptorSets[2].pImageInfo = &fragmentTextureInfo[0]; + + vkUpdateDescriptorSets(renderer->m_renderDevice, (uint32_t)m_writeDescriptorSets.size(), &m_writeDescriptorSets[0], 0, nullptr); +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanMaterialDelegate.h b/Source/Rendering/VulkanRenderer/imstkVulkanMaterialDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..65b80110fb74625e4edc527be92b52419f20a4f5 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanMaterialDelegate.h @@ -0,0 +1,139 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanMaterial_h +#define imstkVulkanMaterial_h + +#include "vulkan/vulkan.h" +#include "glm/glm.hpp" + +#include "imstkRenderMaterial.h" +#include "imstkVulkanUniformBuffer.h" +#include "imstkVulkanTextureDelegate.h" + +#include <memory> +#include <vector> + +namespace imstk +{ +class VulkanRenderer; + +// Large struct to contain pipeline components for later pipeline creation +struct VulkanMaterialPipelineComponents +{ + VkShaderModule fragmentShader; + VkShaderModule tessellationControlShader; + VkShaderModule tessellationEvaluationShader; + VkShaderModule vertexShader; + std::vector<VkPipelineShaderStageCreateInfo> shaderInfo; + std::vector<VkSpecializationMapEntry> fragmentMapEntries; + VkSpecializationInfo fragmentSpecializationInfo; + std::vector<VkVertexInputBindingDescription> vertexBindingDescription; + std::vector<VkVertexInputAttributeDescription> vertexAttributeDescription; + VkPipelineVertexInputStateCreateInfo vertexInfo; + VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo; + VkPipelineTessellationStateCreateInfo tessellationInfo; + std::vector<VkViewport> viewports; + std::vector<VkRect2D> scissors; + VkPipelineViewportStateCreateInfo viewportInfo; + VkPipelineRasterizationStateCreateInfo rasterizationInfo; + VkPipelineMultisampleStateCreateInfo multisampleInfo; + VkPipelineDepthStencilStateCreateInfo depthStencilInfo; + std::vector<VkPipelineColorBlendAttachmentState> colorBlendAttachments; + VkPipelineColorBlendStateCreateInfo colorBlendInfo; +}; + +struct VulkanMaterialConstants +{ + unsigned int numLights; + bool tessellation; + bool diffuseTexture; + bool normalTexture; + bool specularTexture; + bool roughnessTexture; + bool metalnessTexture; + bool subsurfaceScatteringTexture; + bool irradianceCubemapTexture; +}; + +class VulkanMaterialDelegate +{ +public: + /// + /// \brief Constructor + /// + VulkanMaterialDelegate( + std::shared_ptr<VulkanUniformBuffer> vertexUniformBuffer, + std::shared_ptr<VulkanUniformBuffer> fragmentUniformBuffer, + std::shared_ptr<RenderMaterial> material, + VulkanMemoryManager& memoryManager); + +protected: + friend class VulkanRenderer; + + /// + /// \brief Creates a parent pipeline object that gets inherited by other materials + /// + void createPipeline(VulkanRenderer * renderer); + + void initializeTextures(VulkanRenderer * renderer); + + void initialize(VulkanRenderer * renderer); + + void addSpecializationConstant(uint32_t size, uint32_t offset); + uint32_t m_numConstants = 0; + VulkanMaterialConstants m_constants; + + uint32_t m_numTextures = 0; + + void createDescriptors(VulkanRenderer * renderer); + void createDescriptorSetLayouts(VulkanRenderer * renderer); + void createDescriptorPool(VulkanRenderer * renderer); + void createDescriptorSets(VulkanRenderer * renderer); + + std::shared_ptr<RenderMaterial> m_material; + + VkPipeline m_pipeline; + VkGraphicsPipelineCreateInfo m_graphicsPipelineInfo; + VkPipelineLayout m_pipelineLayout; + VulkanMaterialPipelineComponents m_pipelineComponents; + + VkDescriptorPool m_descriptorPool; + std::vector<VkDescriptorSet> m_descriptorSets; + std::vector<VkDescriptorSetLayout> m_descriptorSetLayouts; + std::vector<VkWriteDescriptorSet> m_writeDescriptorSets; + + std::shared_ptr<VulkanUniformBuffer> m_vertexUniformBuffer; + std::shared_ptr<VulkanUniformBuffer> m_fragmentUniformBuffer; + + std::shared_ptr<VulkanTextureDelegate> m_diffuseTexture; + std::shared_ptr<VulkanTextureDelegate> m_normalTexture; + std::shared_ptr<VulkanTextureDelegate> m_roughnessTexture; + std::shared_ptr<VulkanTextureDelegate> m_metalnessTexture; + std::shared_ptr<VulkanTextureDelegate> m_subsurfaceScatteringTexture; + std::shared_ptr<VulkanTextureDelegate> m_irradianceCubemapTexture; + std::shared_ptr<VulkanTextureDelegate> m_radianceCubemapTexture; + + VulkanMemoryManager * m_memoryManager; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanMemoryManager.cpp b/Source/Rendering/VulkanRenderer/imstkVulkanMemoryManager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..606c1367d31ad88ed1135dc52d89505eb2092652 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanMemoryManager.cpp @@ -0,0 +1,85 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanMemoryManager.h" + +namespace imstk +{ +VulkanMemoryManager::VulkanMemoryManager() +{ +} + +VkDeviceMemory * +VulkanMemoryManager::allocateMemory( + const VkMemoryRequirements& memoryRequirements, + uint32_t location) +{ + auto memory = new VkDeviceMemory(); + + // Get device memory types + VkPhysicalDeviceMemoryProperties deviceMemoryProperties; + vkGetPhysicalDeviceMemoryProperties(m_physicalDevice, &deviceMemoryProperties); + + uint32_t memoryIndex = 0; + bool foundIndex = false; + + for (uint32_t i = 0; i < deviceMemoryProperties.memoryTypeCount; i++) + { + // Determine if the memory type is valid for this resource + if ((1 << i) & memoryRequirements.memoryTypeBits) + { + // Determine if the memory type has the correct properties + if (deviceMemoryProperties.memoryTypes[i].propertyFlags & location) + { + memoryIndex = i; + foundIndex = true; + break; + } + } + } + + if (!foundIndex) + { + LOG(FATAL) << "Couldn't find correct memory object"; + } + + VkMemoryAllocateInfo memoryInfo; + memoryInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memoryInfo.pNext = nullptr; + memoryInfo.allocationSize = memoryRequirements.size; + memoryInfo.memoryTypeIndex = memoryIndex; + + vkAllocateMemory(m_device, &memoryInfo, nullptr, memory); + + m_memoryAllocations.push_back(memory); + + return memory; +} + +void +VulkanMemoryManager::clear() +{ + for (unsigned int i = 0; i < m_memoryAllocations.size(); i++) + { + vkFreeMemory(m_device, *m_memoryAllocations[i], nullptr); + } +} +}; \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanMemoryManager.h b/Source/Rendering/VulkanRenderer/imstkVulkanMemoryManager.h new file mode 100644 index 0000000000000000000000000000000000000000..a11cc9408e4a544a30cfed662ca04c6306488a54 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanMemoryManager.h @@ -0,0 +1,54 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanMemoryManager_h +#define imstkVulkanMemoryManager_h + +#include "vulkan/vulkan.h" + +#include <vector> + +#include "g3log/g3log.hpp" + +namespace imstk +{ +class VulkanMemoryManager +{ +public: + VulkanMemoryManager(); + void clear(); + + VkDeviceMemory * allocateMemory( + const VkMemoryRequirements& memoryRequirements, + uint32_t location); + + VkPhysicalDevice m_physicalDevice; + VkDevice m_device; + uint32_t m_queueFamilyIndex; + VkCommandBuffer * m_transferCommandBuffer; + VkQueue * m_transferQueue; + +protected: + std::vector<VkDeviceMemory*> m_memoryAllocations; +}; +}; + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.cpp b/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5377667f5c4ecf936422eed4a5ae5df9358f60c5 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.cpp @@ -0,0 +1,1099 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanRenderer.h" + +namespace imstk { +VulkanRenderer::VulkanRenderer(std::shared_ptr<Scene> scene) +{ + m_scene = scene; +} + +void +VulkanRenderer::initialize() +{ + // If debug mode, enable validation layer (slower performance) +#ifndef NDEBUG + m_layers.push_back(VulkanValidation::getValidationLayer()); + m_extensions.push_back(VulkanValidation::getValidationExtension()); +#endif + + // Instance of a Vulkan application + VkInstanceCreateInfo m_creationInfo; + m_creationInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + m_creationInfo.pNext = nullptr; + m_creationInfo.flags = 0; + m_creationInfo.pApplicationInfo = nullptr; + m_creationInfo.enabledLayerCount = (uint32_t)m_layers.size(); + m_creationInfo.ppEnabledLayerNames = &m_layers[0]; + m_creationInfo.enabledExtensionCount = (uint32_t)m_extensions.size(); + m_creationInfo.ppEnabledExtensionNames = &m_extensions[0]; + + for (int i = 0; i < m_extensions.size(); i++) + { + std::cout << "Enabled extension: " << m_creationInfo.ppEnabledExtensionNames[i] << std::endl; + } + + m_instance = new VkInstance(); + + vkCreateInstance(&m_creationInfo, nullptr, m_instance); + +#ifndef NDEBUG + VkDebugReportCallbackCreateInfoEXT debugReportInfo; + debugReportInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; + debugReportInfo.pNext = nullptr; + debugReportInfo.flags = + VK_DEBUG_REPORT_WARNING_BIT_EXT | + VK_DEBUG_REPORT_ERROR_BIT_EXT; + debugReportInfo.pfnCallback = &(VulkanValidation::debugReportCallback); + debugReportInfo.pUserData = nullptr; + + VkDebugReportCallbackEXT debugReportCallback; + PFN_vkCreateDebugReportCallbackEXT createCallback = + (PFN_vkCreateDebugReportCallbackEXT)vkGetInstanceProcAddr(*m_instance, "vkCreateDebugReportCallbackEXT"); + createCallback(*m_instance, &debugReportInfo, nullptr, &debugReportCallback); +#endif + + auto camera = m_scene->getCamera(); + m_fov = (float)glm::radians(camera->getViewAngle()); + + // Setup logical devices + this->setupGPUs(); + this->printGPUs(); + + // Setup command pool(s) - right now we just have one + this->setupCommandPools(); + this->buildCommandBuffer(); + this->setupRenderPasses(); + this->setupSynchronization(); + this->setupMemoryManager(); + this->createGlobalUniformBuffers(); + + std::vector<VkPipeline> graphicsPipelines; + std::vector<VkGraphicsPipelineCreateInfo> graphicsPipelinesInfo; + + VkPhysicalDeviceProperties deviceProperties; + vkGetPhysicalDeviceProperties(m_renderPhysicalDevice, &deviceProperties); + m_deviceLimits = deviceProperties.limits; + + VkPipelineCacheCreateInfo pipelineCacheCreateInfo; + pipelineCacheCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO; + pipelineCacheCreateInfo.pNext = nullptr; + pipelineCacheCreateInfo.flags = 0; + pipelineCacheCreateInfo.initialDataSize = 0; + pipelineCacheCreateInfo.pInitialData = nullptr; + + vkCreatePipelineCache(m_renderDevice, &pipelineCacheCreateInfo, nullptr, &m_pipelineCache); + + // Geometry pipeline creation + for (int i = 0; i < m_scene->getSceneObjects().size(); i++) + { + std::shared_ptr<Geometry> geometry = m_scene->getSceneObjects()[i]->getVisualGeometry(); + auto renderDelegate = loadGeometry(geometry); + + if (renderDelegate) + { + auto material = renderDelegate->m_material; + material->initialize(this); + + graphicsPipelines.push_back(material->m_pipeline); + graphicsPipelinesInfo.push_back(material->m_graphicsPipelineInfo); + } + } + + if (graphicsPipelines.size() > 0) + { + vkCreateGraphicsPipelines(m_renderDevice, + m_pipelineCache, + (uint32_t)graphicsPipelines.size(), + &graphicsPipelinesInfo[0], + nullptr, + &graphicsPipelines[0]); + } + + for (int i = 0; i < m_renderDelegates.size(); i++) + { + m_renderDelegates[i]->m_material->m_pipeline = graphicsPipelines[i]; + } +} + +void +VulkanRenderer::setupGPUs() +{ + // Prevent devices from being set up multiple times + if (m_physicalDeviceCount != 0) + { + return; + } + + // Setup physical devices + vkEnumeratePhysicalDevices(*m_instance, &m_physicalDeviceCount, nullptr); + m_physicalDevices = new VkPhysicalDevice[(int)m_physicalDeviceCount](); + vkEnumeratePhysicalDevices(*m_instance, &m_physicalDeviceCount, m_physicalDevices); + m_renderPhysicalDevice = m_physicalDevices[0]; + + // Get render queue family + vkGetPhysicalDeviceQueueFamilyProperties(m_renderPhysicalDevice, &m_queueFamilyPropertiesCount, nullptr); + m_queueFamilyProperties = new VkQueueFamilyProperties[(int)m_queueFamilyPropertiesCount](); + vkGetPhysicalDeviceQueueFamilyProperties(m_renderPhysicalDevice, &m_queueFamilyPropertiesCount, m_queueFamilyProperties); + + m_renderQueueFamily = 0; + + for (int i = 0; i < (int)(m_queueFamilyPropertiesCount); i++) + { + if (m_queueFamilyProperties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + { + m_renderQueueFamily = i; + break; + } + } + + std::vector<float> priorities(m_queueFamilyProperties[m_renderQueueFamily].queueCount); + std::fill(priorities.begin(), priorities.end(), 0.0f); + priorities[m_renderQueueFamily] = 1.0; + + //Setup logical devices + m_deviceCount = m_physicalDeviceCount; + m_devices = new VkDevice[(int)(m_deviceCount)](); + + VkDeviceQueueCreateInfo queueInfo; + queueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueInfo.pNext = nullptr; + queueInfo.flags = 0; + queueInfo.queueFamilyIndex = m_renderQueueFamily; + queueInfo.queueCount = m_queueFamilyProperties[m_renderQueueFamily].queueCount; + queueInfo.pQueuePriorities = &priorities[0]; + + // The display system isn't part of the Vulkan core + char * deviceExtensions[1]; + deviceExtensions[0] = "VK_KHR_swapchain"; + + // Enabling optional Vulkan features + VkPhysicalDeviceFeatures features = {VK_FALSE}; + features.fillModeNonSolid = VK_TRUE; + features.tessellationShader = VK_TRUE; + + VkDeviceCreateInfo deviceInfo; + deviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceInfo.pNext = nullptr; + deviceInfo.flags = 0; + deviceInfo.queueCreateInfoCount = 1; + deviceInfo.pQueueCreateInfos = &queueInfo; +#ifndef NDEBUG + deviceInfo.enabledLayerCount = (uint32_t)m_layers.size(); + deviceInfo.ppEnabledLayerNames = &m_layers[0]; +#else + deviceInfo.enabledLayerCount = 0; + deviceInfo.ppEnabledLayerNames = nullptr; +#endif + deviceInfo.enabledExtensionCount = 1; + deviceInfo.ppEnabledExtensionNames = deviceExtensions; + deviceInfo.pEnabledFeatures = &features; + + for (int i = 0; i < (int)(m_physicalDeviceCount); i++) + { + vkCreateDevice(m_physicalDevices[i], &deviceInfo, nullptr, &m_devices[i]); + } + + // This decision needs some work, may pick weaker device + m_renderDevice = m_devices[0]; + + // Get the first render-capable queue + vkGetDeviceQueue(m_renderDevice, m_renderQueueFamily, 0, &m_renderQueue); +} + +void +VulkanRenderer::printGPUs() +{ + this->setupGPUs(); + + VkPhysicalDeviceProperties properties; + + std::cout << "Devices:" << std::endl; + + for (int i = 0; i < (int)(m_physicalDeviceCount); i++) + { + vkGetPhysicalDeviceProperties(m_physicalDevices[i], &properties); + properties.limits.maxMemoryAllocationCount; + std::cout << (i + 1) << ". " << properties.deviceName << std::endl; + } +} + +void +VulkanRenderer::setupCommandPools() +{ + // Create command pools (only one for now) + VkCommandPoolCreateInfo commandPoolInfo; + commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + commandPoolInfo.pNext = nullptr; + commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + commandPoolInfo.queueFamilyIndex = 0; + + vkCreateCommandPool(m_renderDevice, &commandPoolInfo, nullptr, &m_renderCommandPool); +} + +void +VulkanRenderer::buildCommandBuffer() +{ + // Build command buffer + VkCommandBufferAllocateInfo commandBufferInfo; + commandBufferInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + commandBufferInfo.pNext = nullptr; + commandBufferInfo.commandPool = m_renderCommandPool; + commandBufferInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + commandBufferInfo.commandBufferCount = 1; // TODO: increase this for double/triple buffering + + vkAllocateCommandBuffers(m_renderDevice, &commandBufferInfo, &m_renderCommandBuffer); + + vkAllocateCommandBuffers(m_renderDevice, &commandBufferInfo, &m_postProcessingCommandBuffer); +} + +void +VulkanRenderer::setupRenderPasses() +{ + // Number of geometry passes + m_renderPasses.resize(1); + + VkAttachmentDescription attachments[4]; + + // Color attachment + attachments[0].flags = 0; + attachments[0].format = VK_FORMAT_R16G16B16A16_SFLOAT; + attachments[0].samples = m_samples; + attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachments[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + // Depth attachment + attachments[1].flags = 0; + attachments[1].format = VK_FORMAT_D32_SFLOAT; + attachments[1].samples = m_samples; + attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + + // Normal attachment + attachments[2].flags = 0; + attachments[2].format = VK_FORMAT_R8G8B8A8_SNORM; + attachments[2].samples = m_samples; + attachments[2].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments[2].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[2].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[2].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[2].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachments[2].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + // Specular attachment + attachments[3].flags = 0; + attachments[3].format = VK_FORMAT_R16G16B16A16_SFLOAT; + attachments[3].samples = m_samples; + attachments[3].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachments[3].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachments[3].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + attachments[3].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachments[3].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachments[3].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + // Color attachment + VkAttachmentReference colorReference; + colorReference.attachment = 0; + colorReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + // Depth attachment + VkAttachmentReference depthReference; + depthReference.attachment = 1; + depthReference.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + // Normal attachment + VkAttachmentReference normalReference; + normalReference.attachment = 2; + normalReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + // Specular attachment + VkAttachmentReference specularReference; + specularReference.attachment = 3; + specularReference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + // Render subpasses + VkSubpassDescription subpassInfo[1]; + + // First pass: geometry + VkAttachmentReference colorAttachments[] = { colorReference, normalReference, specularReference }; + subpassInfo[0].flags = 0; + subpassInfo[0].pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpassInfo[0].inputAttachmentCount = 0; + subpassInfo[0].pInputAttachments = nullptr; + subpassInfo[0].colorAttachmentCount = 3; + subpassInfo[0].pColorAttachments = colorAttachments; + subpassInfo[0].pResolveAttachments = nullptr; + subpassInfo[0].pDepthStencilAttachment = &depthReference; + subpassInfo[0].preserveAttachmentCount = 0; + subpassInfo[0].pPreserveAttachments = nullptr; + + VkSubpassDependency dependencies[2]; + dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL; + dependencies[0].dstSubpass = 0; + dependencies[0].srcStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + dependencies[1].srcSubpass = 0; + dependencies[1].dstSubpass = VK_SUBPASS_EXTERNAL; + dependencies[1].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + dependencies[1].dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + dependencies[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + dependencies[1].dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; + dependencies[1].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT; + + VkRenderPassCreateInfo renderPassInfo; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.pNext = nullptr; + renderPassInfo.flags = 0; + renderPassInfo.attachmentCount = 4; + renderPassInfo.pAttachments = attachments; + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = subpassInfo; + renderPassInfo.dependencyCount = 2; + renderPassInfo.pDependencies = dependencies; + + vkCreateRenderPass(m_renderDevice, &renderPassInfo, nullptr, &m_renderPasses[0]); +} + +void +VulkanRenderer::resizeFramebuffers(VkSwapchainKHR * swapchain, int width, int height) +{ + m_width = width; + m_height = height; + + std::vector<VkPipeline> pipelines; + std::vector<VkGraphicsPipelineCreateInfo> pipelineInfos; + + for (int i = 0; i < m_renderDelegates.size(); i++) + { + auto material = m_renderDelegates[i]->m_material; + vkDestroyPipeline(m_renderDevice, material->m_pipeline, nullptr); + material->createPipeline(this); + pipelines.push_back(material->m_pipeline); + pipelineInfos.push_back(material->m_graphicsPipelineInfo); + } + if (pipelines.size() > 0) + { + vkCreateGraphicsPipelines(m_renderDevice, + m_pipelineCache, + (uint32_t)m_renderDelegates.size(), + &pipelineInfos[0], + nullptr, + &pipelines[0]); + } + + for (int i = 0; i < m_renderDelegates.size(); i++) + { + m_renderDelegates[i]->m_material->m_pipeline = pipelines[i]; + } + + this->deleteFramebuffers(); + + this->initializeFramebuffers(swapchain); +} + +void +VulkanRenderer::initializeFramebuffers(VkSwapchainKHR * swapchain) +{ + m_mipLevels = std::log2(std::max(m_width, m_height)) + 1; + + // Get images from surface (color images) + m_swapchain = swapchain; + vkGetSwapchainImagesKHR(m_renderDevice, *m_swapchain, &m_swapchainImageCount, nullptr); + m_swapchainImages.resize(m_swapchainImageCount); + vkGetSwapchainImagesKHR(m_renderDevice, *m_swapchain, &m_swapchainImageCount, &m_swapchainImages[0]); + + // Depth image + VkImageCreateInfo depthImageInfo; + depthImageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + depthImageInfo.pNext = nullptr; + depthImageInfo.flags = 0; + depthImageInfo.imageType = VK_IMAGE_TYPE_2D; + depthImageInfo.format = VK_FORMAT_D32_SFLOAT; + depthImageInfo.extent = { m_width, m_height, 1 }; + depthImageInfo.mipLevels = 1; + depthImageInfo.arrayLayers = 1; + depthImageInfo.samples = m_samples; + depthImageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + depthImageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT; + depthImageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + depthImageInfo.queueFamilyIndexCount = 0; + depthImageInfo.pQueueFamilyIndices = nullptr; + depthImageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + m_depthImage.resize(m_mipLevels); + for (uint32_t i = 0; i < m_mipLevels; i++) + { + depthImageInfo.extent = { std::max(m_width >> i, 1u), std::max(m_height >> i, 1u), 1 }; + vkCreateImage(m_renderDevice, &depthImageInfo, nullptr, &m_depthImage[i]); + } + + // Normal image + auto normalImageInfo = depthImageInfo; + normalImageInfo.extent = { m_width, m_height, 1 }; + normalImageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT; + normalImageInfo.format = VK_FORMAT_R8G8B8A8_SNORM; + + vkCreateImage(m_renderDevice, &normalImageInfo, nullptr, &m_normalImage); + + // HDR image + auto HDRImageInfo = depthImageInfo; + HDRImageInfo.format = VK_FORMAT_R16G16B16A16_SFLOAT; + HDRImageInfo.mipLevels = 1; + HDRImageInfo.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT + | VK_IMAGE_USAGE_SAMPLED_BIT; + + m_HDRImage[0].resize(m_mipLevels); + m_HDRImage[1].resize(m_mipLevels); + m_HDRImage[2].resize(m_mipLevels); + for (uint32_t i = 0; i < m_mipLevels; i++) + { + HDRImageInfo.extent = { std::max(m_width >> i, 1u), std::max(m_height >> i, 1u), 1 }; + vkCreateImage(m_renderDevice, &HDRImageInfo, nullptr, &m_HDRImage[0][i]); + vkCreateImage(m_renderDevice, &HDRImageInfo, nullptr, &m_HDRImage[1][i]); + vkCreateImage(m_renderDevice, &HDRImageInfo, nullptr, &m_HDRImage[2][i]); + } + + for (uint32_t i = 0; i < m_swapchainImageCount; i++) + { + m_HDRTonemaps.resize(m_swapchainImageCount); + } + + // Create image views + m_swapchainImageViews.resize(m_swapchainImageCount); + m_depthImageView.resize(m_mipLevels); + m_depthImageMemory.resize(m_mipLevels); + + for (uint32_t i = 0; i < m_mipLevels; i++) + { + VkMemoryRequirements memReqs; + vkGetImageMemoryRequirements(m_renderDevice, m_depthImage[i], &memReqs); + + m_depthImageMemory[i] = m_memoryManager.allocateMemory(memReqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkBindImageMemory(m_renderDevice, m_depthImage[i], *m_depthImageMemory[i], 0); + + VkComponentMapping componentMap; + componentMap.r = VK_COMPONENT_SWIZZLE_R; + componentMap.g = VK_COMPONENT_SWIZZLE_G; + componentMap.b = VK_COMPONENT_SWIZZLE_B; + componentMap.a = VK_COMPONENT_SWIZZLE_A; + + VkImageSubresourceRange subresourceRange; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = 1; + subresourceRange.baseArrayLayer = 0; + subresourceRange.layerCount = 1; + + VkImageViewCreateInfo imageViewInfo; + imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewInfo.pNext = nullptr; + imageViewInfo.flags = 0; + imageViewInfo.image = m_depthImage[i]; + imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageViewInfo.format = VK_FORMAT_D32_SFLOAT; + imageViewInfo.components = componentMap; + imageViewInfo.subresourceRange = subresourceRange; + + vkCreateImageView(m_renderDevice, &imageViewInfo, nullptr, &m_depthImageView[i]); + } + + { + VkMemoryRequirements memReqs; + vkGetImageMemoryRequirements(m_renderDevice, m_normalImage, &memReqs); + + m_normalImageMemory = m_memoryManager.allocateMemory(memReqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkBindImageMemory(m_renderDevice, m_normalImage, *m_normalImageMemory, 0); + + VkComponentMapping componentMap; + componentMap.r = VK_COMPONENT_SWIZZLE_R; + componentMap.g = VK_COMPONENT_SWIZZLE_G; + componentMap.b = VK_COMPONENT_SWIZZLE_B; + componentMap.a = VK_COMPONENT_SWIZZLE_A; + + VkImageSubresourceRange subresourceRange; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = 1; + subresourceRange.baseArrayLayer = 0; + subresourceRange.layerCount = 1; + + VkImageViewCreateInfo imageViewInfo; + imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewInfo.pNext = nullptr; + imageViewInfo.flags = 0; + imageViewInfo.image = m_normalImage; + imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageViewInfo.format = VK_FORMAT_R8G8B8A8_SNORM; + imageViewInfo.components = componentMap; + imageViewInfo.subresourceRange = subresourceRange; + + vkCreateImageView(m_renderDevice, &imageViewInfo, nullptr, &m_normalImageView); + } + + for (int i = 0; i < 3; i++) + { + m_HDRImageView[i].resize(m_mipLevels); + m_HDRImageMemory[i].resize(m_mipLevels); + + VkSamplerCreateInfo samplerInfo; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.pNext = nullptr; + samplerInfo.flags = 0; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; // Trilinear interpolation + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.mipLodBias = 0.0; + samplerInfo.anisotropyEnable = VK_FALSE; // TODO:: add option to enable + samplerInfo.maxAnisotropy = 1.0; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.minLod = 0; + samplerInfo.maxLod = 0; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + + vkCreateSampler(m_renderDevice, &samplerInfo, nullptr, &m_HDRImageSampler); + + for (uint32_t j = 0; j < m_mipLevels; j++) + { + VkMemoryRequirements memReqs; + vkGetImageMemoryRequirements(m_renderDevice, m_HDRImage[i][j], &memReqs); + + m_HDRImageMemory[i][j] = m_memoryManager.allocateMemory(memReqs, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + vkBindImageMemory(m_renderDevice, m_HDRImage[i][j], *m_HDRImageMemory[i][j], 0); + + VkComponentMapping componentMap; + componentMap.r = VK_COMPONENT_SWIZZLE_R; + componentMap.g = VK_COMPONENT_SWIZZLE_G; + componentMap.b = VK_COMPONENT_SWIZZLE_B; + componentMap.a = VK_COMPONENT_SWIZZLE_A; + + VkImageSubresourceRange subresourceRange; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = 1; + subresourceRange.baseArrayLayer = 0; + subresourceRange.layerCount = 1; + + VkImageViewCreateInfo imageViewInfo; + imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewInfo.pNext = nullptr; + imageViewInfo.flags = 0; + imageViewInfo.image = m_HDRImage[i][j]; + imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageViewInfo.format = VK_FORMAT_R16G16B16A16_SFLOAT; + imageViewInfo.components = componentMap; + imageViewInfo.subresourceRange = subresourceRange; + + vkCreateImageView(m_renderDevice, &imageViewInfo, nullptr, &m_HDRImageView[i][j]); + } + } + + m_swapchainImageSamplers.resize(m_swapchainImageCount); + for (uint32_t i = 0; i < m_swapchainImageCount; i++) + { + VkComponentMapping componentMap; + componentMap.r = VK_COMPONENT_SWIZZLE_R; + componentMap.g = VK_COMPONENT_SWIZZLE_G; + componentMap.b = VK_COMPONENT_SWIZZLE_B; + componentMap.a = VK_COMPONENT_SWIZZLE_A; + + VkImageSubresourceRange subresourceRange; + subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + subresourceRange.baseMipLevel = 0; + subresourceRange.levelCount = 1; + subresourceRange.baseArrayLayer = 0; + subresourceRange.layerCount = 1; + + VkImageViewCreateInfo imageViewInfo; + imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewInfo.pNext = nullptr; + imageViewInfo.flags = 0; + imageViewInfo.image = m_swapchainImages[i]; + imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageViewInfo.format = VK_FORMAT_B8G8R8A8_SRGB; + imageViewInfo.components = componentMap; + imageViewInfo.subresourceRange = subresourceRange; + + vkCreateImageView(m_renderDevice, &imageViewInfo, nullptr, &m_swapchainImageViews[i]); + + VkSamplerCreateInfo samplerInfo; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.pNext = nullptr; + samplerInfo.flags = 0; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; // Trilinear interpolation + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.mipLodBias = 0.0; + samplerInfo.anisotropyEnable = VK_FALSE; // TODO:: add option to enable + samplerInfo.maxAnisotropy = 1.0; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.minLod = 0; + samplerInfo.maxLod = 0; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + + vkCreateSampler(m_renderDevice, &samplerInfo, nullptr, &m_swapchainImageSamplers[i]); + } + + this->initializePostProcesses(); + + m_drawingFramebuffers.clear(); + m_drawingFramebuffers.push_back( + std::make_shared<VulkanFramebuffer>(m_memoryManager, m_width, m_height, false, m_samples)); + m_drawingFramebuffers[0]->setColor(&m_HDRImageView[0][0], VK_FORMAT_R16G16B16A16_SFLOAT); + m_drawingFramebuffers[0]->setSpecular(&m_HDRImageView[1][0], VK_FORMAT_R16G16B16A16_SFLOAT); + m_drawingFramebuffers[0]->setDepth(&m_depthImageView[0], VK_FORMAT_D32_SFLOAT); + m_drawingFramebuffers[0]->setNormal(&m_normalImageView, VK_FORMAT_R8G8B8A8_SNORM); + m_drawingFramebuffers[0]->initializeFramebuffer(&m_renderPasses[0]); +} + +void +VulkanRenderer::deleteFramebuffers() +{ + // The framebuffers/command buffers may still be in use + vkDeviceWaitIdle(m_renderDevice); + + // Depth buffer + for (uint32_t i = 0; i < m_mipLevels; i++) + { + vkDestroyImage(m_renderDevice, m_depthImage[i], nullptr); + vkDestroyImageView(m_renderDevice, m_depthImageView[i], nullptr); + } + + + // HDR buffers + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < m_HDRImageView[i].size(); j++) + { + vkDestroyImage(m_renderDevice, m_HDRImage[i][j], nullptr); + vkDestroyImageView(m_renderDevice, m_HDRImageView[i][j], nullptr); + } + } + + // Normal buffer + vkDestroyImage(m_renderDevice, m_normalImage, nullptr); + vkDestroyImageView(m_renderDevice, m_normalImageView, nullptr); + + for (uint32_t i = 0; i < m_swapchainImageCount; i++) + { + vkDestroyImageView(m_renderDevice, m_swapchainImageViews[i], nullptr); + } + + // Delete all post processing resources + for (int i = 0; i < m_postProcessingChain->m_postProcesses.size(); i++) + { + vkDestroyFramebuffer(m_renderDevice, m_postProcessingChain->m_postProcesses[i]->m_framebuffer->m_framebuffer, nullptr); + } + + // Delete all HDR resources + for (int i = 0; i < m_HDRTonemaps.size(); i++) + { + vkDestroyFramebuffer(m_renderDevice, m_HDRTonemaps[i]->m_framebuffer->m_framebuffer, nullptr); + } + + // Delete all drawing resources + for (int i = 0; i < m_drawingFramebuffers.size() - 1; i++) + { + vkDestroyFramebuffer(m_renderDevice, m_drawingFramebuffers[i]->m_framebuffer, nullptr); + } +} + +void +VulkanRenderer::renderFrame() +{ + m_frameNumber++; + + // Update global uniforms + this->updateGlobalUniforms(); + + // Update local uniforms + for (unsigned int renderDelegateIndex = 0; renderDelegateIndex < m_renderDelegates.size(); renderDelegateIndex++) + { + m_renderDelegates[renderDelegateIndex]->update(); + } + + // The swapchain contains multiple buffers, so get one that is available (i.e., not currently being written to) + uint32_t nextImageIndex; + vkAcquireNextImageKHR(m_renderDevice, *m_swapchain, UINT64_MAX, m_readyToRender, VK_NULL_HANDLE, &nextImageIndex); + + VkCommandBufferBeginInfo commandBufferBeginInfo; + commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + commandBufferBeginInfo.pNext = nullptr; + commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + commandBufferBeginInfo.pInheritanceInfo = nullptr; + + vkBeginCommandBuffer(m_renderCommandBuffer, &commandBufferBeginInfo); + + VkRect2D renderArea; + renderArea.offset = { 0, 0 }; + renderArea.extent = { m_width, m_height }; + + std::array<VkClearValue, 4> clearValues; + clearValues[0].color = { { 0.5, 0.5, 0.5, 1 } }; // Color + clearValues[1].depthStencil = { { 1.0 }, { 0 } }; // Depth + clearValues[2].color = { { 0, 0, 0, 0 } }; // Normal + clearValues[3].color = { { 0, 0, 0, 0 } }; // Specular + + VkRenderPassBeginInfo renderPassBeginInfo; + renderPassBeginInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassBeginInfo.pNext = nullptr; + renderPassBeginInfo.renderPass = m_renderPasses[0]; + renderPassBeginInfo.framebuffer = m_drawingFramebuffers[0]->m_framebuffer; + renderPassBeginInfo.renderArea = renderArea; + renderPassBeginInfo.clearValueCount = (uint32_t)clearValues.size(); + renderPassBeginInfo.pClearValues = &clearValues[0]; + + // Do buffer transfers + for (unsigned int renderDelegateIndex = 0; renderDelegateIndex < m_renderDelegates.size(); renderDelegateIndex++) + { + auto buffers = m_renderDelegates[renderDelegateIndex]->getBuffer().get(); + buffers->uploadBuffers(m_renderCommandBuffer); + } + + vkCmdBeginRenderPass(m_renderCommandBuffer, &renderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + VkDeviceSize deviceSize = { 0 }; + + // Pass 1: Render all geometry + for (unsigned int renderDelegateIndex = 0; renderDelegateIndex < m_renderDelegates.size(); renderDelegateIndex++) + { + auto material = m_renderDelegates[renderDelegateIndex]->m_material; + vkCmdBindPipeline(m_renderCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, material->m_pipeline); + + vkCmdBindDescriptorSets(m_renderCommandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + material->m_pipelineLayout, 0, (uint32_t)material->m_descriptorSets.size(), + &material->m_descriptorSets[0], 0, &m_dynamicOffsets); + + auto buffers = m_renderDelegates[renderDelegateIndex]->getBuffer().get(); + + vkCmdBindVertexBuffers(m_renderCommandBuffer, 0, 1, &buffers->m_vertexBuffer, &deviceSize); + vkCmdBindIndexBuffer(m_renderCommandBuffer, buffers->m_indexBuffer, deviceSize, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(m_renderCommandBuffer, buffers->m_numIndices, 1, 0, 0, 0); + } + + vkCmdEndRenderPass(m_renderCommandBuffer); + vkEndCommandBuffer(m_renderCommandBuffer); + + vkBeginCommandBuffer(m_postProcessingCommandBuffer, &commandBufferBeginInfo); + + // Pass 2 to N - 1: Post processing + for (unsigned int postProcessIndex = 0; postProcessIndex < m_postProcessingChain->m_postProcesses.size(); postProcessIndex++) + { + clearValues[0].color = { { 1.0, 0.0, 0.0, 1 } }; // Color + + auto postProcess = m_postProcessingChain->m_postProcesses[postProcessIndex]; + + auto postProcessRenderPassBeginInfo = renderPassBeginInfo; + auto framebuffer = postProcess->m_framebuffer; + postProcessRenderPassBeginInfo.renderPass = + postProcess->m_renderPass; + postProcessRenderPassBeginInfo.framebuffer = framebuffer->m_framebuffer; + postProcessRenderPassBeginInfo.clearValueCount = (uint32_t)framebuffer->m_attachments.size(); + postProcessRenderPassBeginInfo.renderArea.extent = { framebuffer->m_width, framebuffer->m_height }; + + vkCmdBeginRenderPass(m_postProcessingCommandBuffer, &postProcessRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdPushConstants(m_postProcessingCommandBuffer, postProcess->m_pipelineLayout, + VK_SHADER_STAGE_FRAGMENT_BIT, 0, 128, (void*)postProcess->m_pushConstantData); + + vkCmdBindPipeline(m_postProcessingCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, + postProcess->m_pipeline); + + vkCmdBindDescriptorSets(m_postProcessingCommandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + postProcess->m_pipelineLayout, 0, + (uint32_t)postProcess->m_descriptorSets.size(), + &postProcess->m_descriptorSets[0], 0, &m_dynamicOffsets); + + auto buffers = postProcess->m_vertexBuffer; + vkCmdBindVertexBuffers(m_postProcessingCommandBuffer, 0, 1, &buffers->m_vertexBuffer, &deviceSize); + vkCmdBindIndexBuffer(m_postProcessingCommandBuffer, buffers->m_indexBuffer, deviceSize, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(m_postProcessingCommandBuffer, buffers->m_numIndices, 1, 0, 0, 0); + + vkCmdEndRenderPass(m_postProcessingCommandBuffer); + } + + // Pass N: HDR tonemap (this is special because of the swapchain) + { + auto postProcessRenderPassBeginInfo = renderPassBeginInfo; + postProcessRenderPassBeginInfo.renderPass = m_HDRTonemaps[nextImageIndex]->m_renderPass; + postProcessRenderPassBeginInfo.framebuffer = m_HDRTonemaps[nextImageIndex]->m_framebuffer->m_framebuffer; + postProcessRenderPassBeginInfo.clearValueCount = (uint32_t)m_HDRTonemaps[nextImageIndex]->m_framebuffer->m_attachments.size(); + + vkCmdBeginRenderPass(m_postProcessingCommandBuffer, &postProcessRenderPassBeginInfo, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(m_postProcessingCommandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_HDRTonemaps[nextImageIndex]->m_pipeline); + + vkCmdBindDescriptorSets(m_postProcessingCommandBuffer, + VK_PIPELINE_BIND_POINT_GRAPHICS, + m_HDRTonemaps[nextImageIndex]->m_pipelineLayout, 0, (uint32_t)m_HDRTonemaps[nextImageIndex]->m_descriptorSets.size(), + &m_HDRTonemaps[nextImageIndex]->m_descriptorSets[0], 0, &m_dynamicOffsets); + + auto buffers = m_HDRTonemaps[nextImageIndex]->m_vertexBuffer; + vkCmdBindVertexBuffers(m_postProcessingCommandBuffer, 0, 1, &buffers->m_vertexBuffer, &deviceSize); + vkCmdBindIndexBuffer(m_postProcessingCommandBuffer, buffers->m_indexBuffer, deviceSize, VK_INDEX_TYPE_UINT32); + vkCmdDrawIndexed(m_postProcessingCommandBuffer, buffers->m_numIndices, 1, 0, 0, 0); + + vkCmdEndRenderPass(m_postProcessingCommandBuffer); + } + + vkEndCommandBuffer(m_postProcessingCommandBuffer); + + VkCommandBuffer commandBuffers[2]; + commandBuffers[0] = m_renderCommandBuffer; + commandBuffers[1] = m_postProcessingCommandBuffer; + + VkPipelineStageFlags stageWaitFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + VkSubmitInfo submitInfo[2]; + submitInfo[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo[0].pNext = nullptr; + submitInfo[0].waitSemaphoreCount = 1; + submitInfo[0].pWaitSemaphores = &m_readyToRender; + submitInfo[0].pWaitDstStageMask = &stageWaitFlags; + submitInfo[0].commandBufferCount = 1; + submitInfo[0].pCommandBuffers = &commandBuffers[0]; + submitInfo[0].signalSemaphoreCount = 1; + submitInfo[0].pSignalSemaphores = &m_drawingComplete; + + submitInfo[1] = submitInfo[0]; + submitInfo[1].pWaitSemaphores = &m_drawingComplete; + submitInfo[1].pWaitDstStageMask = &stageWaitFlags; + submitInfo[1].pCommandBuffers = &commandBuffers[1]; + submitInfo[1].pSignalSemaphores = &m_presentImages; + + // Submit command buffers + vkQueueSubmit(m_renderQueue, 2, submitInfo, m_commandBufferSubmit); + + VkSwapchainKHR swapchains[] = {*m_swapchain}; + + VkPresentInfoKHR presentInfo; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.pNext = nullptr; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = &m_presentImages; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = swapchains; + presentInfo.pImageIndices = &nextImageIndex; // change this in the future for multi-screen rendering + presentInfo.pResults = nullptr; + + // Display backbuffer + vkQueuePresentKHR(m_renderQueue, &presentInfo); + + // Wait until command buffer is done so that we can write to it again + vkWaitForFences(m_renderDevice, 1, &m_commandBufferSubmit, VK_TRUE, UINT64_MAX); + vkResetFences(m_renderDevice, 1, &m_commandBufferSubmit); +} + +void +VulkanRenderer::setupSynchronization() +{ + VkSemaphoreCreateInfo semaphoreInfo; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + semaphoreInfo.pNext = nullptr; + semaphoreInfo.flags = 0; + + vkCreateSemaphore(m_renderDevice, &semaphoreInfo, nullptr, &m_readyToRender); + + vkCreateSemaphore(m_renderDevice, &semaphoreInfo, nullptr, &m_presentImages); + + vkCreateSemaphore(m_renderDevice, &semaphoreInfo, nullptr, &m_drawingComplete); + + VkFenceCreateInfo fenceInfo; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.pNext = nullptr; + fenceInfo.flags = 0; + + vkCreateFence(m_renderDevice, &fenceInfo, nullptr, &m_commandBufferSubmit); +} + +std::shared_ptr<VulkanRenderDelegate> +VulkanRenderer::loadGeometry(std::shared_ptr<Geometry> geometry) +{ + auto renderDelegate = VulkanRenderDelegate::make_delegate(geometry, m_memoryManager); + if (renderDelegate != nullptr) + { + m_renderDelegates.push_back(renderDelegate); + renderDelegate->getBuffer()->initializeBuffers(m_memoryManager); + } + return renderDelegate; +} + +void +VulkanRenderer::setupMemoryManager() +{ + m_memoryManager.m_device = m_renderDevice; + m_memoryManager.m_physicalDevice = m_renderPhysicalDevice; + m_memoryManager.m_queueFamilyIndex = m_renderQueueFamily; + m_memoryManager.m_transferCommandBuffer = &m_renderCommandBuffer; + m_memoryManager.m_transferQueue = &m_renderQueue; +} + +void +VulkanRenderer::createGlobalUniformBuffers() +{ + m_globalVertexUniformBuffer = std::make_shared<VulkanUniformBuffer>(m_memoryManager, (uint32_t)sizeof(VulkanGlobalVertexUniforms)); + m_globalFragmentUniformBuffer = std::make_shared<VulkanUniformBuffer>(m_memoryManager, (uint32_t)sizeof(VulkanGlobalFragmentUniforms)); +} + +void +VulkanRenderer::initializePostProcesses() +{ + std::vector<VkPipeline> graphicsPipelines; + std::vector<VkGraphicsPipelineCreateInfo> graphicsPipelinesInfo; + m_postProcessingChain = std::make_shared<VulkanPostProcessingChain>(this); + + // HDR pipeline creation + for (uint32_t i = 0; i < m_swapchainImageCount; i++) + { + m_HDRTonemaps[i] = std::make_shared<VulkanPostProcess>(this, 0, true); + m_HDRTonemaps[i]->addInputImage(&m_swapchainImageSamplers[i], &m_HDRImageView[m_postProcessingChain->m_lastOutput][0]); + m_HDRTonemaps[i]->m_framebuffer->setColor(&m_swapchainImageViews[i], VK_FORMAT_B8G8R8A8_SRGB); + m_HDRTonemaps[i]->initialize(this, "./Shaders/VulkanShaders/PostProcessing/HDR_tonemap_frag.spv"); + + graphicsPipelines.push_back(m_HDRTonemaps[i]->m_pipeline); + graphicsPipelinesInfo.push_back(m_HDRTonemaps[i]->m_graphicsPipelineInfo); + } + + // Post processing pipeline creation + for (int i = 0; i < m_postProcessingChain->m_postProcesses.size(); i++) + { + graphicsPipelines.push_back(m_postProcessingChain->m_postProcesses[i]->m_pipeline); + graphicsPipelinesInfo.push_back(m_postProcessingChain->m_postProcesses[i]->m_graphicsPipelineInfo); + } + + vkCreateGraphicsPipelines(m_renderDevice, + m_pipelineCache, + (uint32_t)graphicsPipelines.size(), + &graphicsPipelinesInfo[0], + nullptr, + &graphicsPipelines[0]); + + for (uint32_t i = 0; i < m_swapchainImageCount; i++) + { + m_HDRTonemaps[i]->m_pipeline = graphicsPipelines[i]; + } + + for (int i = m_swapchainImageCount; i < m_postProcessingChain->m_postProcesses.size() + m_swapchainImageCount; i++) + { + m_postProcessingChain->m_postProcesses[i - m_swapchainImageCount]->m_pipeline = graphicsPipelines[i]; + } +} + +void +VulkanRenderer::updateGlobalUniforms() +{ + // Vertex uniforms + { + // Projection matrix + auto camera = m_scene->getCamera(); + m_fov = (float)glm::radians(camera->getViewAngle()); + m_globalVertexUniforms.projectionMatrix = glm::perspective(m_fov, (float)(m_width) / (float)(m_height), m_nearPlane, m_farPlane); + m_globalVertexUniforms.projectionMatrix[1][1] *= -1; // Must do this for Vulkan + + // View matrix + + auto eye = glm::tvec3<float>(camera->getPosition().x(), camera->getPosition().y(), camera->getPosition().z()); + auto center = glm::tvec3<float>(camera->getFocalPoint().x(), camera->getFocalPoint().y(), camera->getFocalPoint().z()); + auto up = glm::tvec3<float>(camera->getViewUp().x(), camera->getViewUp().y(), camera->getViewUp().z()); + m_globalVertexUniforms.cameraPosition = glm::vec4(camera->getPosition().x(), camera->getPosition().y(), camera->getPosition().z(), 0.0); + + m_globalVertexUniforms.viewMatrix = glm::lookAt(eye, center, up); + } + + // Lights uniforms + { + // Update lights - need to optimize + auto lights = m_scene->getLights(); + for (int i = 0; i < lights.size(); i++) + { + // Only supports directional lights right now + auto focalPoint = lights[i]->getFocalPoint(); + auto position = Vec3d(0,0,0); + + m_globalFragmentUniforms.lights[i].lightVector.x = position.x() - focalPoint.x(); + m_globalFragmentUniforms.lights[i].lightVector.y = position.y() - focalPoint.y(); + m_globalFragmentUniforms.lights[i].lightVector.z = position.z() - focalPoint.z(); + + m_globalFragmentUniforms.lights[i].lightVector = glm::normalize(m_globalFragmentUniforms.lights[i].lightVector); + + Color lightColor = lights[i]->getColor(); + m_globalFragmentUniforms.lights[i].lightColor.r = lightColor.r; + m_globalFragmentUniforms.lights[i].lightColor.g = lightColor.g; + m_globalFragmentUniforms.lights[i].lightColor.b = lightColor.b; + + memcpy(&m_globalVertexUniforms.lights, &m_globalFragmentUniforms.lights, sizeof(m_globalFragmentUniforms.lights)); + } + } + + m_globalVertexUniformBuffer->updateUniforms(sizeof(VulkanGlobalVertexUniforms), &m_globalVertexUniforms); + m_globalFragmentUniformBuffer->updateUniforms(sizeof(VulkanGlobalFragmentUniforms), &m_globalFragmentUniforms); +} + +VulkanRenderer::~VulkanRenderer() +{ + // Delete devices + for (int i = 0; i < (int)(m_deviceCount); i++) + { + // Important: must wait for device to be finished + vkDeviceWaitIdle(m_devices[i]); + vkDestroySemaphore(m_renderDevice, m_readyToRender, nullptr); + vkDestroySemaphore(m_renderDevice, m_drawingComplete, nullptr); + + // Clear all memory + m_memoryManager.clear(); + + for (int x = 0; x < m_renderDelegates.size(); x++) + { + // TODO: Clear all render delegates + } + + vkDestroyDevice(m_devices[i], nullptr); + } + + vkDestroyInstance(*m_instance, nullptr); +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.h b/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.h new file mode 100644 index 0000000000000000000000000000000000000000..772cd3ff89f8166e2d1b1d66444a804f5408a6f5 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanRenderer.h @@ -0,0 +1,244 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanRenderer_h +#define imstkVulkanRenderer_h + +#include <iostream> +#include <memory> +#include <vector> +#include <fstream> + +#include "vulkan/vulkan.h" + +#include "glm/glm.hpp" +#include "glm/gtc/matrix_transform.hpp" + +#include "imstkScene.h" +#include "imstkRenderer.h" + +#include "imstkVulkanValidation.h" +#include "imstkVulkanVertexBuffer.h" +#include "imstkVulkanUniformBuffer.h" +#include "imstkVulkanRenderDelegate.h" +#include "imstkVulkanMaterialDelegate.h" + +#include "imstkVulkanPostProcess.h" +#include "imstkVulkanPostProcessingChain.h" + +#include "imstkVulkanMemoryManager.h" + +#include "imstkVulkanFramebuffer.h" + +namespace imstk +{ +struct VulkanRendererConstants +{ + unsigned int numLights; +}; + +class VulkanRenderer : public Renderer { +public: + VulkanRenderer(std::shared_ptr<Scene> scene); + ~VulkanRenderer(); + + /// + /// \brief Populates the device fields for the rendering class (both physical and logical devices) + /// + void setupGPUs(); + + /// + /// \brief Prints the physical device name + /// + void printGPUs(); + + /// + /// \brief Sets up command pools + /// + void setupCommandPools(); + + /// + /// \brief Sets up command pools + /// + void buildCommandBuffer(); + + /// + /// \brief Sets up render pass + /// + void setupRenderPasses(); + + /// + /// \brief Sets up swapchain + /// + void setupSwapchain(); + + /// + /// \brief Initializes the framebuffer + /// + void initializeFramebuffers(VkSwapchainKHR * swapchain); + + /// + /// \brief Deletes the framebuffer + /// + void deleteFramebuffers(); + + /// + /// \brief Initializes the framebuffer + /// + void resizeFramebuffers(VkSwapchainKHR * swapchain, int width, int height); + + /// + /// \brief Renders the frame + /// + void renderFrame(); + + /// + /// \brief Setups semaphores/fences + /// + void setupSynchronization(); + + /// + /// \brief Get device memory properties + /// + void setupMemoryManager(); + + /// + /// \brief Create global uniforms + /// + void createGlobalUniformBuffers(); + + /// + /// \brief Initialize the post processing effects + /// + void initializePostProcesses(); + + /// + /// \brief Update global uniforms + /// + void updateGlobalUniforms(); + +protected: + friend class VulkanViewer; + friend class VulkanMaterialDelegate; + friend class VulkanPostProcess; + friend class VulkanPostProcessingChain; + + void initialize(); + std::shared_ptr<VulkanRenderDelegate> loadGeometry(std::shared_ptr<Geometry> geometry); + + unsigned int m_width = 1000; + unsigned int m_height = 800; + float m_fov = PI; + float m_nearPlane = 0.01; + float m_farPlane = 1000; + + VulkanRendererConstants m_constants; + + std::vector<char *> m_extensions; + std::vector<char *> m_layers; + + std::shared_ptr<Scene> m_scene = nullptr; + + VkInstance * m_instance = nullptr; + + uint32_t m_physicalDeviceCount = 0; + VkPhysicalDevice * m_physicalDevices = nullptr; + VkPhysicalDevice m_renderPhysicalDevice; + + uint32_t m_deviceCount = 0; + VkDevice * m_devices = nullptr; + VkPhysicalDeviceLimits m_deviceLimits; + VkDevice m_renderDevice; + + VkPipelineCache m_pipelineCache; + + uint32_t m_queueFamilyPropertiesCount = 0; + VkQueueFamilyProperties * m_queueFamilyProperties = nullptr; + VkQueue m_renderQueue; + + VkCommandPool m_renderCommandPool; + VkCommandBuffer m_renderCommandBuffer; + VkCommandBuffer m_postProcessingCommandBuffer; + + uint32_t m_dynamicOffsets = {0}; + + VulkanMemoryManager m_memoryManager; + + std::shared_ptr<VulkanUniformBuffer> m_globalVertexUniformBuffer; + std::shared_ptr<VulkanUniformBuffer> m_globalFragmentUniformBuffer; + VulkanGlobalVertexUniforms m_globalVertexUniforms; + VulkanGlobalFragmentUniforms m_globalFragmentUniforms; + + VkDescriptorPool m_globalDescriptorPool; + std::vector<VkDescriptorSet> m_globalDescriptorSets; + std::vector<VkDescriptorSetLayout> m_globalDescriptorSetLayouts; + std::vector<VkWriteDescriptorSet> m_globalWriteDescriptorSets; + + std::vector<VkRenderPass> m_renderPasses; + + // Framebuffers + VkSwapchainKHR * m_swapchain = nullptr; + uint32_t m_swapchainImageCount = 0; + std::vector<VkImage> m_swapchainImages; + std::vector<VkImageView> m_swapchainImageViews; + std::vector<VkSampler> m_swapchainImageSamplers; + + // Depth buffer + std::vector<VkImage> m_depthImage; + std::vector<VkImageView> m_depthImageView; + std::vector<VkDeviceMemory*> m_depthImageMemory; + + // Normal buffer + VkImage m_normalImage; + VkImageView m_normalImageView; + VkDeviceMemory * m_normalImageMemory; + + // Color buffers + std::vector<VkImage> m_HDRImage[3]; + VkSampler m_HDRImageSampler; + std::vector<VkImageView> m_HDRImageView[3]; + std::vector<VkDeviceMemory*> m_HDRImageMemory[3]; + uint32_t m_mipLevels = 1; + + std::vector<std::shared_ptr<VulkanFramebuffer>> m_drawingFramebuffers; + std::vector<std::shared_ptr<VulkanPostProcess>> m_HDRTonemaps; + std::shared_ptr<VulkanPostProcessingChain> m_postProcessingChain; + + VkSemaphore m_readyToRender; + VkSemaphore m_drawingComplete; + VkSemaphore m_presentImages; + + unsigned int m_buffering = 3; + + int m_frameNumber = 0; + VkSampleCountFlagBits m_samples = VK_SAMPLE_COUNT_1_BIT; + + VkFence m_commandBufferSubmit; + + glm::mat4 m_projectionMatrix; + + std::vector<std::shared_ptr<VulkanRenderDelegate>> m_renderDelegates; + + uint32_t m_renderQueueFamily = 0; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanTextureDelegate.cpp b/Source/Rendering/VulkanRenderer/imstkVulkanTextureDelegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad41d71fd985cc6178e7649ce6cddc262ba0a4ba --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanTextureDelegate.cpp @@ -0,0 +1,531 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanTextureDelegate.h" + +namespace imstk +{ +VulkanTextureDelegate::VulkanTextureDelegate( + VulkanMemoryManager& memoryManager, + std::shared_ptr<Texture> texture) +{ + m_path = texture->getPath(); + m_type = texture->getType(); + + // Load textures and get texture information + if ((texture->getType() != Texture::Type::IRRADIANCE_CUBEMAP) + && (texture->getType() != Texture::Type::RADIANCE_CUBEMAP)) + { + m_arrayLayers = 1; + this->loadTexture(memoryManager); + m_imageInfo.flags = 0; + } + else + { + m_arrayLayers = 6; + this->loadCubemapTexture(memoryManager); + m_imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + m_isCubemap = true; + } + + // Determine number of mipmaps + if (m_mipLevels < 1) + { + if (!texture->getMipmapsEnabled()) + { + m_mipLevels = 1; + } + else + { + m_mipLevels = std::log2(std::max(m_width, m_height)) + 1; + } + } + + m_layout = VK_IMAGE_LAYOUT_GENERAL; + + m_imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + m_imageInfo.pNext = nullptr; + + if (m_type == Texture::Type::DIFFUSE) + { + m_imageInfo.format = VK_FORMAT_B8G8R8A8_SRGB; + } + else + { + m_imageInfo.format = VK_FORMAT_B8G8R8A8_UNORM; + } + + m_imageInfo.imageType = VK_IMAGE_TYPE_2D; + m_imageInfo.extent = { m_width, m_height, 1 }; + m_imageInfo.mipLevels = m_mipLevels; + m_imageInfo.arrayLayers = m_arrayLayers; + m_imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + m_imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + m_imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + m_imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + m_imageInfo.queueFamilyIndexCount = 1; + m_imageInfo.pQueueFamilyIndices = &memoryManager.m_queueFamilyIndex; + m_imageInfo.initialLayout = VK_IMAGE_LAYOUT_PREINITIALIZED; + + vkCreateImage(memoryManager.m_device, &m_imageInfo, nullptr, &m_image); + + m_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + m_range.baseMipLevel = 0; + m_range.levelCount = m_mipLevels; + m_range.baseArrayLayer = 0; + m_range.layerCount = m_arrayLayers; + + if (m_isCubemap) + { + this->uploadCubemapTexture(memoryManager); + } + else + { + this->uploadTexture(memoryManager); + } + + VkComponentMapping mapping; + mapping.r = VK_COMPONENT_SWIZZLE_R; + mapping.g = VK_COMPONENT_SWIZZLE_G; + mapping.b = VK_COMPONENT_SWIZZLE_B; + mapping.a = VK_COMPONENT_SWIZZLE_A; + + VkImageViewCreateInfo imageViewInfo; + imageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewInfo.pNext = nullptr; + imageViewInfo.flags = 0; + imageViewInfo.image = m_image; + + if (!m_isCubemap) + { + imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + } + else + { + imageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; + } + + imageViewInfo.format = m_imageInfo.format; + imageViewInfo.components = mapping; + imageViewInfo.subresourceRange = m_range; + + vkCreateImageView(memoryManager.m_device, &imageViewInfo, nullptr, &m_imageView); + + VkSamplerCreateInfo samplerInfo; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.pNext = nullptr; + samplerInfo.flags = 0; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; // Trilinear interpolation + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.mipLodBias = 0.0; + samplerInfo.anisotropyEnable = VK_FALSE; // TODO:: add option to enable + samplerInfo.maxAnisotropy = 1.0; + samplerInfo.compareEnable = VK_FALSE; + samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerInfo.minLod = 0; + samplerInfo.maxLod = 0; + samplerInfo.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + samplerInfo.unnormalizedCoordinates = VK_FALSE; + + vkCreateSampler(memoryManager.m_device, &samplerInfo, nullptr, &m_sampler); +} + +void +VulkanTextureDelegate::loadTexture(VulkanMemoryManager& memoryManager) +{ + if (m_path != "") + { + auto readerGenerator = vtkSmartPointer<vtkImageReader2Factory>::New(); + auto reader = readerGenerator->CreateImageReader2(m_path.c_str()); + + reader->SetFileName(m_path.c_str()); + reader->Update(); + + auto data = reader->GetOutput(); + m_width = data->GetDimensions()[0]; + m_height = data->GetDimensions()[1]; + m_channels = reader->GetNumberOfScalarComponents(); + m_data = (unsigned char *)data->GetScalarPointer(); + } + else + { + std::vector<unsigned char> data(4); + data[0] = '\255'; + data[1] = '\255'; + data[2] = '\255'; + data[3] = '\255'; + m_width = 1; + m_height = 1; + m_data = &data[0]; + } +} + +void +VulkanTextureDelegate::loadCubemapTexture(VulkanMemoryManager& memoryManager) +{ + if (m_path != "") + { + m_cubemap = gli::texture_cube(gli::load(m_path)); + + m_width = m_cubemap.extent().x; + m_height = m_cubemap.extent().y; + m_mipLevels = (uint32_t)m_cubemap.levels(); + } + else + { + m_cubemap = gli::texture_cube(gli::format::FORMAT_BGRA8_UNORM_PACK8, gli::extent2d(1,1), 1); + m_width = 1; + m_height = 1; + m_mipLevels = 1; + } +} + +void +VulkanTextureDelegate::uploadTexture(VulkanMemoryManager& memoryManager) +{ + uint32_t imageSize = m_width * m_height * 4; + + // Staging image + VkBufferCreateInfo stagingBufferInfo; + stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + stagingBufferInfo.pNext = nullptr; + stagingBufferInfo.flags = 0; + stagingBufferInfo.size = imageSize; + stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + stagingBufferInfo.queueFamilyIndexCount = 0; + stagingBufferInfo.pQueueFamilyIndices = nullptr; + + vkCreateBuffer(memoryManager.m_device, &stagingBufferInfo, nullptr, &m_stagingBuffer); + + VkMemoryRequirements memoryRequirementsStagingBuffer; + vkGetBufferMemoryRequirements(memoryManager.m_device, m_stagingBuffer, &memoryRequirementsStagingBuffer); + m_stagingBufferMemory = *memoryManager.allocateMemory(memoryRequirementsStagingBuffer, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + VkMemoryRequirements memoryRequirementsImage; + vkGetImageMemoryRequirements(memoryManager.m_device, m_image, &memoryRequirementsImage); + m_imageMemory = *memoryManager.allocateMemory(memoryRequirementsImage, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + void * imageData; + vkMapMemory(memoryManager.m_device, m_stagingBufferMemory, 0, imageSize, 0, &imageData); + + auto imageEditData = (unsigned char*)imageData; + + unsigned int y_offset = 0; + unsigned int colorChannels = std::min(m_channels, 3u); + + for (unsigned int y = 0; y < m_height; y++) + { + y_offset = y * m_width; + for (unsigned int x = 0; x < m_width; x++) + { + // Fill in image data + for (unsigned int z = 0; z < colorChannels; z++) + { + imageEditData[4 * (y_offset + x) + z] = + m_data[m_channels * (y_offset + x) + (colorChannels - z - 1)]; + } + + // Fill in the rest of the memory + memset(&imageEditData[4 * (y_offset + x) + colorChannels], + (unsigned char)255, + (4 - colorChannels) * sizeof(unsigned char)); + } + } + + vkUnmapMemory(memoryManager.m_device, m_stagingBufferMemory); + + // Start transfer commands + VkCommandBufferBeginInfo commandBufferBeginInfo; + commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + commandBufferBeginInfo.pNext = nullptr; + commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + commandBufferBeginInfo.pInheritanceInfo = nullptr; + + vkBeginCommandBuffer(*memoryManager.m_transferCommandBuffer, &commandBufferBeginInfo); + vkBindBufferMemory(memoryManager.m_device, m_stagingBuffer, m_stagingBufferMemory, 0); + vkBindImageMemory(memoryManager.m_device, m_image, m_imageMemory, 0); + + VkImageSubresourceLayers layersDestination; + layersDestination.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + layersDestination.mipLevel = 0; + layersDestination.baseArrayLayer = 0; + layersDestination.layerCount = 1; + + VkBufferImageCopy copyInfo; + copyInfo.bufferOffset = 0; + copyInfo.bufferRowLength = m_width; + copyInfo.bufferImageHeight = m_height; + copyInfo.imageSubresource = layersDestination; + copyInfo.imageOffset = { 0, 0, 0 }; + copyInfo.imageExtent = { m_width, m_height, 1 }; + + VkImageSubresourceRange baseRange = m_range; + baseRange.levelCount = 1; + + this->changeImageLayout(*memoryManager.m_transferCommandBuffer, m_image, + VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, m_range); + vkCmdCopyBufferToImage(*memoryManager.m_transferCommandBuffer, m_stagingBuffer, + m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Info); + + if (m_mipLevels != 1) + { + this->generateMipmaps(*memoryManager.m_transferCommandBuffer); + } + + this->changeImageLayout(*memoryManager.m_transferCommandBuffer, m_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, m_range); + + vkEndCommandBuffer(*memoryManager.m_transferCommandBuffer); + + VkCommandBuffer commandBuffers[] = { *memoryManager.m_transferCommandBuffer }; + + VkPipelineStageFlags stageWaitFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + VkSubmitInfo submitInfo[1]; + submitInfo[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo[0].pNext = nullptr; + submitInfo[0].waitSemaphoreCount = 0; + submitInfo[0].pWaitSemaphores = nullptr; + submitInfo[0].pWaitDstStageMask = &stageWaitFlags; + submitInfo[0].commandBufferCount = 1; + submitInfo[0].pCommandBuffers = commandBuffers; + submitInfo[0].signalSemaphoreCount = 0; + submitInfo[0].pSignalSemaphores = nullptr; + + vkQueueSubmit(*memoryManager.m_transferQueue, 1, submitInfo, nullptr); + vkDeviceWaitIdle(memoryManager.m_device); +} + +void +VulkanTextureDelegate::uploadCubemapTexture(VulkanMemoryManager& memoryManager) +{ + uint32_t imageSize = (uint32_t)m_cubemap.size(); + + // Staging image + VkBufferCreateInfo stagingBufferInfo; + stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + stagingBufferInfo.pNext = nullptr; + stagingBufferInfo.flags = 0; + stagingBufferInfo.size = imageSize; + stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + stagingBufferInfo.queueFamilyIndexCount = 0; + stagingBufferInfo.pQueueFamilyIndices = nullptr; + + vkCreateBuffer(memoryManager.m_device, &stagingBufferInfo, nullptr, &m_stagingBuffer); + + VkMemoryRequirements memoryRequirementsStagingBuffer; + vkGetBufferMemoryRequirements(memoryManager.m_device, m_stagingBuffer, &memoryRequirementsStagingBuffer); + m_stagingBufferMemory = *memoryManager.allocateMemory(memoryRequirementsStagingBuffer, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + VkMemoryRequirements memoryRequirementsImage; + vkGetImageMemoryRequirements(memoryManager.m_device, m_image, &memoryRequirementsImage); + m_imageMemory = *memoryManager.allocateMemory(memoryRequirementsImage, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + void * imageData; + vkMapMemory(memoryManager.m_device, m_stagingBufferMemory, 0, imageSize, 0, &imageData); + + memcpy(imageData, m_cubemap.data(), m_cubemap.size()); + + vkUnmapMemory(memoryManager.m_device, m_stagingBufferMemory); + + // Start transfer commands + VkCommandBufferBeginInfo commandBufferBeginInfo; + commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + commandBufferBeginInfo.pNext = nullptr; + commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + commandBufferBeginInfo.pInheritanceInfo = nullptr; + + vkBeginCommandBuffer(*memoryManager.m_transferCommandBuffer, &commandBufferBeginInfo); + vkBindBufferMemory(memoryManager.m_device, m_stagingBuffer, m_stagingBufferMemory, 0); + vkBindImageMemory(memoryManager.m_device, m_image, m_imageMemory, 0); + + std::vector<VkBufferImageCopy> copyInfos(m_mipLevels * m_arrayLayers); + + unsigned int currentOffset = 0; + for (unsigned int layer = 0; layer < m_arrayLayers; layer++) + { + for (unsigned int level = 0; level < m_mipLevels; level++) + { + VkImageSubresourceLayers layersDestination; + layersDestination.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + layersDestination.mipLevel = level; + layersDestination.baseArrayLayer = layer; + layersDestination.layerCount = 1; + + unsigned int currentRegion = layer * m_mipLevels + level; + + copyInfos[currentRegion].bufferOffset = currentOffset; + copyInfos[currentRegion].bufferRowLength = m_cubemap[layer][level].extent().x; + copyInfos[currentRegion].bufferImageHeight = m_cubemap[layer][level].extent().y; + copyInfos[currentRegion].imageSubresource = layersDestination; + copyInfos[currentRegion].imageOffset = { 0, 0, 0 }; + copyInfos[currentRegion].imageExtent = { + m_cubemap[layer][level].extent().x, + m_cubemap[layer][level].extent().y, + 1 + }; + currentOffset += (unsigned int)m_cubemap[layer][level].size(); + } + } + + this->changeImageLayout(*memoryManager.m_transferCommandBuffer, m_image, + VK_IMAGE_LAYOUT_PREINITIALIZED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_ACCESS_HOST_WRITE_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, m_range); + + vkCmdCopyBufferToImage(*memoryManager.m_transferCommandBuffer, m_stagingBuffer, + m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, (uint32_t)copyInfos.size(), ©Infos[0]); + + this->changeImageLayout(*memoryManager.m_transferCommandBuffer, m_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT, m_range); + + vkEndCommandBuffer(*memoryManager.m_transferCommandBuffer); + + VkCommandBuffer commandBuffers[] = { *memoryManager.m_transferCommandBuffer }; + + VkPipelineStageFlags stageWaitFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + VkSubmitInfo submitInfo[1]; + submitInfo[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo[0].pNext = nullptr; + submitInfo[0].waitSemaphoreCount = 0; + submitInfo[0].pWaitSemaphores = nullptr; + submitInfo[0].pWaitDstStageMask = &stageWaitFlags; + submitInfo[0].commandBufferCount = 1; + submitInfo[0].pCommandBuffers = commandBuffers; + submitInfo[0].signalSemaphoreCount = 0; + submitInfo[0].pSignalSemaphores = nullptr; + + vkQueueSubmit(*memoryManager.m_transferQueue, 1, submitInfo, nullptr); + vkDeviceWaitIdle(memoryManager.m_device); +} + +void +VulkanTextureDelegate::changeImageLayout(VkCommandBuffer& commandBuffer, + VkImage& image, + VkImageLayout layout1, + VkImageLayout layout2, + VkAccessFlags sourceFlags, + VkAccessFlags destinationFlags, + VkImageSubresourceRange range) +{ + VkImageMemoryBarrier layoutChange; + layoutChange.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + layoutChange.pNext = nullptr; + layoutChange.srcAccessMask = sourceFlags; + layoutChange.dstAccessMask = destinationFlags; + layoutChange.oldLayout = layout1; + layoutChange.newLayout = layout2; + layoutChange.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + layoutChange.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + layoutChange.image = image; + layoutChange.subresourceRange = range; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, + 0, + 0, + nullptr, + 0, + nullptr, + 1, + &layoutChange); +} + +void +VulkanTextureDelegate::generateMipmaps(VkCommandBuffer& commandBuffer) +{ + for (uint32_t i = 0; i < m_mipLevels - 1; i++) + { + VkImageSubresourceLayers sourceLayers; + sourceLayers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + sourceLayers.mipLevel = i; + sourceLayers.baseArrayLayer = 0; + sourceLayers.layerCount = 1; + + VkImageSubresourceLayers destinationLayers; + destinationLayers.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + destinationLayers.mipLevel = i + 1; + destinationLayers.baseArrayLayer = 0; + destinationLayers.layerCount = 1; + + VkOffset3D sourceOffsets[2]; + sourceOffsets[0].x = 0; + sourceOffsets[0].y = 0; + sourceOffsets[0].z = 0; + + sourceOffsets[1].x = m_width / (1 << i); + sourceOffsets[1].y = m_height / (1 << i); + sourceOffsets[1].z = 1; + + VkOffset3D destinationOffsets[2]; + destinationOffsets[0].x = 0; + destinationOffsets[0].y = 0; + destinationOffsets[0].z = 0; + + destinationOffsets[1].x = m_width / (1 << (i + 1)); + destinationOffsets[1].y = m_height / (1 << (i + 1)); + destinationOffsets[1].z = 1; + + VkImageBlit mipFormat; + mipFormat.srcSubresource = sourceLayers; + mipFormat.srcOffsets[0] = sourceOffsets[0]; + mipFormat.srcOffsets[1] = sourceOffsets[1]; + mipFormat.dstSubresource = destinationLayers; + mipFormat.dstOffsets[0] = destinationOffsets[0]; + mipFormat.dstOffsets[1] = destinationOffsets[1]; + + VkImageSubresourceRange mipHighRange = m_range; + mipHighRange.baseMipLevel = i; + mipHighRange.levelCount = 1; + + VkImageSubresourceRange mipLowRange = m_range; + mipLowRange.baseMipLevel = i + 1; + mipLowRange.levelCount = 1; + + this->changeImageLayout(commandBuffer, m_image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT, m_range); + + vkCmdBlitImage(commandBuffer, + m_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + m_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &mipFormat, VK_FILTER_LINEAR); + + this->changeImageLayout(commandBuffer, m_image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_ACCESS_TRANSFER_READ_BIT, VK_ACCESS_TRANSFER_WRITE_BIT, m_range); + } +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanTextureDelegate.h b/Source/Rendering/VulkanRenderer/imstkVulkanTextureDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..b6f4dc2399fc084c0b217bd80e4ead8948972bfa --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanTextureDelegate.h @@ -0,0 +1,105 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanTexture_h +#define imstkVulkanTexture_h + +#include "imstkTexture.h" +#include "imstkVulkanMemoryManager.h" + +#include "vulkan/vulkan.h" + +#include "gli/gli.hpp" + +#include <vtkImageReader2.h> +#include <vtkSmartPointer.h> +#include <vtkImageData.h> +#include <vtkImageReader2Factory.h> + +#include <string> +#include <memory> +#include <vector> + +namespace imstk +{ +/// +/// \class VulkanTexture +/// +/// \brief Vulkan texture implementation. +/// +class VulkanTextureDelegate +{ +public: + /// + /// \brief Constructor + /// \param path Path to the texture source file + /// \param type Type of texture + /// + VulkanTextureDelegate(VulkanMemoryManager& memoryManager, + std::shared_ptr<Texture> texture); + + void loadTexture(VulkanMemoryManager& memoryManager); + void loadCubemapTexture(VulkanMemoryManager& memoryManager); + void uploadTexture(VulkanMemoryManager& memoryManager); + void uploadCubemapTexture(VulkanMemoryManager& memoryManager); + static void changeImageLayout(VkCommandBuffer& commandBuffer, + VkImage& image, + VkImageLayout layout1, + VkImageLayout layout2, + VkAccessFlags sourceFlags, + VkAccessFlags destinationFlags, + VkImageSubresourceRange range); + + void generateMipmaps(VkCommandBuffer& commandBuffer); +protected: + friend class VulkanMaterialDelegate; + + VkImage m_image; + + VkImageView m_imageView; + VkSampler m_sampler; + VkImageLayout m_layout; + VkImageCreateInfo m_imageInfo; + VkDeviceMemory m_imageMemory; + + VkImageSubresourceRange m_range; + + VkBuffer m_stagingBuffer; + VkDeviceMemory m_stagingBufferMemory; + + std::string m_path; + Texture::Type m_type; + unsigned int m_mipLevels = 0; + unsigned int m_arrayLayers = 1; + + unsigned int m_width = 0; + unsigned int m_height = 0; + unsigned int m_channels = 0; + + unsigned char * m_data; + gli::texture_cube m_cubemap; ///> Only used for cubemaps + bool m_isCubemap = false; + + VulkanMemoryManager * m_memoryManager; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanUniformBuffer.cpp b/Source/Rendering/VulkanRenderer/imstkVulkanUniformBuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9ae19902979e27acdcf24faf19a05ffda64af7e1 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanUniformBuffer.cpp @@ -0,0 +1,90 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanUniformBuffer.h" + +namespace imstk +{ +VulkanUniformBuffer::VulkanUniformBuffer(VulkanMemoryManager& memoryManager, uint32_t uniformSize) +{ + m_renderDevice = memoryManager.m_device; + + // Uniform buffer + VkBufferCreateInfo uniformBufferInfo; + uniformBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + uniformBufferInfo.pNext = nullptr; + uniformBufferInfo.flags = 0; + uniformBufferInfo.size = uniformSize; + uniformBufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + uniformBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + uniformBufferInfo.queueFamilyIndexCount = 0; + uniformBufferInfo.pQueueFamilyIndices = nullptr; + + vkCreateBuffer(m_renderDevice, &uniformBufferInfo, nullptr, &m_uniformBuffer); + + VkMemoryRequirements memoryRequirements; + vkGetBufferMemoryRequirements(m_renderDevice, m_uniformBuffer, &memoryRequirements); + + // Allocate vertex memory + m_uniformBufferSize = uniformSize; + + m_uniformMemory = *memoryManager.allocateMemory(memoryRequirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + + this->Bind(); +} + +void +VulkanUniformBuffer::updateUniforms(uint32_t uniformSize, void * uniformData) +{ + auto uniformMemory = this->mapUniforms(); + + memcpy(uniformMemory, uniformData, uniformSize); + + this->unmapUniforms(); +} + +VkBuffer * +VulkanUniformBuffer::getUniformBuffer() +{ + return &m_uniformBuffer; +} + +void * +VulkanUniformBuffer::mapUniforms() +{ + void * uniformData; + vkMapMemory(m_renderDevice, m_uniformMemory, 0, m_uniformBufferSize, 0, &uniformData); + + return uniformData; +} + +void +VulkanUniformBuffer::unmapUniforms() +{ + vkUnmapMemory(m_renderDevice, m_uniformMemory); +} + +void +VulkanUniformBuffer::Bind() +{ + vkBindBufferMemory(m_renderDevice, m_uniformBuffer, m_uniformMemory, 0); +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanUniformBuffer.h b/Source/Rendering/VulkanRenderer/imstkVulkanUniformBuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..f4d7da4fce428a67571f763e0e47487525c430c1 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanUniformBuffer.h @@ -0,0 +1,106 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanUniformBuffer_h +#define imstkVulkanUniformBuffer_h + +#include "imstkVulkanBuffer.h" +#include "imstkVulkanMemoryManager.h" + +#include "vulkan/vulkan.h" + +#include "glm/glm.hpp" + +#include <vector> + +namespace imstk +{ +struct VulkanLocalVertexUniforms +{ + glm::mat4 transform; +}; + +struct VulkanLocalFragmentUniforms +{ + glm::mat4 transform; +}; + +struct VulkanLight +{ + glm::vec3 lightVector; + float lightAngle; + glm::vec3 lightColor; + float lightIntensity; +}; + +struct VulkanGlobalVertexUniforms +{ + glm::mat4 projectionMatrix; + glm::mat4 viewMatrix; + glm::vec4 cameraPosition; + VulkanLight lights[16]; +}; + +struct VulkanGlobalFragmentUniforms +{ + VulkanLight lights[16]; +}; + + +class VulkanUniformBuffer : public VulkanBuffer +{ +public: + VulkanUniformBuffer(VulkanMemoryManager& memoryManager, uint32_t uniformSize); + + void updateUniforms(uint32_t uniformSize, void * uniformData); + + ~VulkanUniformBuffer() = default; + + /// + /// \brief Binds the vertex buffer to memory + /// + void Bind(); + +protected: + friend class VulkanRenderer; + friend class VulkanMaterialDelegate; + + VkBuffer * getUniformBuffer(); + + void * mapUniforms(); + void unmapUniforms(); + + VkBuffer m_uniformBuffer; + VkDeviceMemory m_uniformMemory; + + VkDevice m_renderDevice; + uint32_t m_bufferMemoryIndex; + + VkDeviceSize m_uniformBufferSize; + + static const uint32_t maxBufferSize = 1024 * 1024; + +private: + VulkanUniformBuffer() = delete; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanValidation.h b/Source/Rendering/VulkanRenderer/imstkVulkanValidation.h new file mode 100644 index 0000000000000000000000000000000000000000..41a581fb67acda6e38a6a8b3f746194f83abc425 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanValidation.h @@ -0,0 +1,57 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanValidation_h +#define imstkVulkanValidation_h + +#include "g3log/g3log.hpp" + +namespace imstk +{ +class VulkanValidation +{ +public: + static char * getValidationLayer() + { + return "VK_LAYER_LUNARG_standard_validation"; + }; + + static char * getValidationExtension() + { + return "VK_EXT_debug_report"; + }; + + static VKAPI_ATTR VkBool32 VKAPI_CALL debugReportCallback(VkDebugReportFlagsEXT debugReportFlags, + VkDebugReportObjectTypeEXT debugReportObjectType, + uint64_t callbackObject, + size_t level, + int32_t code, + const char * prefix, + const char * message, + void * data) + { + LOG(WARNING) << prefix << ": " << message; + return VK_FALSE; + }; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanVertexBuffer.cpp b/Source/Rendering/VulkanRenderer/imstkVulkanVertexBuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e12e527fe5e08caca5220349a45b5235e0dfeef2 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanVertexBuffer.cpp @@ -0,0 +1,230 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanVertexBuffer.h" + +namespace imstk +{ +VulkanVertexBuffer::VulkanVertexBuffer(VulkanMemoryManager& memoryManager, + unsigned int numVertices, + unsigned int vertexSize, + unsigned int numTriangles, + VulkanVertexBufferMode mode) +{ + m_mode = mode; + m_renderDevice = memoryManager.m_device; + m_vertexBufferSize = numVertices * vertexSize; + m_numIndices = numTriangles; + m_indexBufferSize = m_numIndices * 3 * sizeof(uint32_t); + + // Vertex buffer + { + VkBufferCreateInfo vertexBufferInfo; + vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + vertexBufferInfo.pNext = nullptr; + vertexBufferInfo.flags = 0; + vertexBufferInfo.size = m_vertexBufferSize; + vertexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + vertexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + vertexBufferInfo.queueFamilyIndexCount = 0; + vertexBufferInfo.pQueueFamilyIndices = nullptr; + + auto vertexStagingBufferInfo = vertexBufferInfo; + vertexStagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + + vkCreateBuffer(m_renderDevice, &vertexBufferInfo, nullptr, &m_vertexBuffer); + vkCreateBuffer(m_renderDevice, &vertexStagingBufferInfo, nullptr, &m_vertexStagingBuffer); + } + + // Index buffer + { + VkBufferCreateInfo indexBufferInfo; + indexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + indexBufferInfo.pNext = nullptr; + indexBufferInfo.flags = 0; + indexBufferInfo.size = m_indexBufferSize; + indexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + indexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + indexBufferInfo.queueFamilyIndexCount = 0; + indexBufferInfo.pQueueFamilyIndices = nullptr; + + auto indexStagingBufferInfo = indexBufferInfo; + indexStagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + + vkCreateBuffer(m_renderDevice, &indexBufferInfo, nullptr, &m_indexBuffer); + vkCreateBuffer(m_renderDevice, &indexStagingBufferInfo, nullptr, &m_indexStagingBuffer); + } + + // Allocate vertex memory + { + VkMemoryRequirements memoryRequirements; + vkGetBufferMemoryRequirements(m_renderDevice, m_vertexStagingBuffer, &memoryRequirements); + m_vertexStagingMemory = *memoryManager.allocateMemory(memoryRequirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + + vkGetBufferMemoryRequirements(m_renderDevice, m_vertexBuffer, &memoryRequirements); + m_vertexMemory = *memoryManager.allocateMemory(memoryRequirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + } + + // Allocate index memory + { + VkMemoryRequirements memoryRequirements; + m_numIndices = numTriangles * 3; + vkGetBufferMemoryRequirements(m_renderDevice, m_indexStagingBuffer, &memoryRequirements); + m_indexStagingMemory = *memoryManager.allocateMemory(memoryRequirements, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT); + + vkGetBufferMemoryRequirements(m_renderDevice, m_indexBuffer, &memoryRequirements); + m_indexMemory = *memoryManager.allocateMemory(memoryRequirements, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + } +} + +void * +VulkanVertexBuffer::mapVertices() +{ + void * vertexData; + vkMapMemory(m_renderDevice, m_vertexStagingMemory, 0, m_vertexBufferSize, 0, &vertexData); + + return vertexData; +} + +void +VulkanVertexBuffer::unmapVertices() +{ + m_vertexBufferModified = true; + vkUnmapMemory(m_renderDevice, m_vertexStagingMemory); +} + +void * +VulkanVertexBuffer::mapTriangles() +{ + void * indexData; + vkMapMemory(m_renderDevice, m_indexStagingMemory, 0, m_indexBufferSize, 0, &indexData); + return indexData; +} + +void +VulkanVertexBuffer::unmapTriangles() +{ + m_indexBufferModified = true; + vkUnmapMemory(m_renderDevice, m_indexStagingMemory); +} + +void +VulkanVertexBuffer::bind() +{ + // Testing +} + +void +VulkanVertexBuffer::updateVertexBuffer(std::vector<VulkanBasicVertex> * vertices, + std::vector<std::array<uint32_t, 3>> * triangles) +{ + auto local_vertices = (VulkanBasicVertex *)this->mapVertices(); + + for (unsigned i = 0; i < vertices->size(); i++) + { + local_vertices[i].position = glm::vec3( + (*vertices)[i].position.x, + (*vertices)[i].position.y, + (*vertices)[i].position.z); + + local_vertices[i].normal = glm::vec3( + (*vertices)[i].normal.x, + (*vertices)[i].normal.y, + (*vertices)[i].normal.z); + } + + this->unmapVertices(); + + if (triangles != nullptr) + { + auto local_triangles = (std::array<uint32_t, 3> *) this->mapTriangles(); + + for (unsigned i = 0; i < triangles->size(); i++) + { + local_triangles[i][0] = (*triangles)[i][0]; + local_triangles[i][1] = (*triangles)[i][1]; + local_triangles[i][2] = (*triangles)[i][2]; + } + + this->unmapTriangles(); + } +} + +void +VulkanVertexBuffer::uploadBuffers(VkCommandBuffer& commandBuffer) +{ + if (m_vertexBufferModified) + { + VkBufferCopy copyInfo; + copyInfo.size = m_vertexBufferSize; + copyInfo.srcOffset = 0; + copyInfo.dstOffset = 0; + + vkCmdCopyBuffer(commandBuffer, m_vertexStagingBuffer, m_vertexBuffer, 1, ©Info); + } + if (m_indexBufferModified) + { + VkBufferCopy copyInfo; + copyInfo.size = m_indexBufferSize; + copyInfo.srcOffset = 0; + copyInfo.dstOffset = 0; + + vkCmdCopyBuffer(commandBuffer, m_indexStagingBuffer, m_indexBuffer, 1, ©Info); + } +} + +void +VulkanVertexBuffer::initializeBuffers(VulkanMemoryManager& memoryManager) +{ + vkBindBufferMemory(m_renderDevice, m_vertexBuffer, m_vertexMemory, 0); + vkBindBufferMemory(m_renderDevice, m_indexBuffer, m_indexMemory, 0); + vkBindBufferMemory(m_renderDevice, m_vertexStagingBuffer, m_vertexStagingMemory, 0); + vkBindBufferMemory(m_renderDevice, m_indexStagingBuffer, m_indexStagingMemory, 0); + + // Start transfer commands + VkCommandBufferBeginInfo commandBufferBeginInfo; + commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + commandBufferBeginInfo.pNext = nullptr; + commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + commandBufferBeginInfo.pInheritanceInfo = nullptr; + + vkBeginCommandBuffer(*memoryManager.m_transferCommandBuffer, &commandBufferBeginInfo); + this->uploadBuffers(*memoryManager.m_transferCommandBuffer); + vkEndCommandBuffer(*memoryManager.m_transferCommandBuffer); + + VkCommandBuffer commandBuffers[] = { *memoryManager.m_transferCommandBuffer }; + + VkPipelineStageFlags stageWaitFlags = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + VkSubmitInfo submitInfo[1]; + submitInfo[0].sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo[0].pNext = nullptr; + submitInfo[0].waitSemaphoreCount = 0; + submitInfo[0].pWaitSemaphores = nullptr; + submitInfo[0].pWaitDstStageMask = &stageWaitFlags; + submitInfo[0].commandBufferCount = 1; + submitInfo[0].pCommandBuffers = commandBuffers; + submitInfo[0].signalSemaphoreCount = 0; + submitInfo[0].pSignalSemaphores = nullptr; + + vkQueueSubmit(*memoryManager.m_transferQueue, 1, submitInfo, nullptr); + vkDeviceWaitIdle(memoryManager.m_device); +} +} \ No newline at end of file diff --git a/Source/Rendering/VulkanRenderer/imstkVulkanVertexBuffer.h b/Source/Rendering/VulkanRenderer/imstkVulkanVertexBuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..0647d91c9ecafadac0897f395ddb2711a0535e41 --- /dev/null +++ b/Source/Rendering/VulkanRenderer/imstkVulkanVertexBuffer.h @@ -0,0 +1,112 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanVertexBuffer_h +#define imstkVulkanVertexBuffer_h + +#include "vulkan/vulkan.h" + +#include "imstkVulkanBuffer.h" +#include "imstkVulkanMemoryManager.h" + +#include <array> +#include <vector> + +namespace imstk +{ +enum VulkanVertexBufferMode +{ + VERTEX_BUFFER_STATIC = 0, + VERTEX_BUFFER_DYNAMIC, + VERTEX_BUFFER_DYNAMIC_RESIZEABLE +}; + +struct VulkanBasicVertex +{ + glm::vec3 position; + glm::vec3 normal; + glm::vec3 tangent; + glm::vec3 bitangent; + glm::vec2 uv; +}; + +class VulkanVertexBuffer : public VulkanBuffer +{ +public: + VulkanVertexBuffer(VulkanMemoryManager& memoryManager, + unsigned int numVertices, + unsigned int vertexSize, + unsigned int numTriangles, + VulkanVertexBufferMode mode = VERTEX_BUFFER_STATIC); + + void * mapVertices(); + void unmapVertices(); + + void * mapTriangles(); + void unmapTriangles(); + + ~VulkanVertexBuffer() = default; + + /// + /// \brief Utility function to update buffers + /// + void updateVertexBuffer(std::vector<VulkanBasicVertex> * vertices, + std::vector<std::array<uint32_t, 3>> * triangles); + + /// + /// \brief Binds the vertex buffer to memory + /// + void bind(); + + void uploadBuffers(VkCommandBuffer& commandBuffer); + + void initializeBuffers(VulkanMemoryManager& memoryManager); + +private: + friend class VulkanRenderer; + + VkBuffer m_vertexBuffer; + VkBuffer m_vertexStagingBuffer; + VkDeviceMemory m_vertexMemory; + VkDeviceMemory m_vertexStagingMemory; + + uint32_t m_numIndices; + + VkBuffer m_indexBuffer; + VkBuffer m_indexStagingBuffer; + VkDeviceMemory m_indexMemory; + VkDeviceMemory m_indexStagingMemory; + + VkDevice m_renderDevice; + uint32_t m_bufferMemoryIndex; + + VulkanVertexBufferMode m_mode; + + uint32_t m_vertexBufferSize = 0; + uint32_t m_indexBufferSize = 0; + bool m_vertexBufferModified = true; + bool m_indexBufferModified = true; + + static const uint32_t maxBufferSize = 1024 * 1024; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/imstkRenderer.cpp b/Source/Rendering/imstkRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..93a5ae1d7abf16ff9b3a8e1c09349a017812f051 --- /dev/null +++ b/Source/Rendering/imstkRenderer.cpp @@ -0,0 +1,43 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkRenderer.h" + +namespace imstk +{ +std::shared_ptr<Renderer> +Renderer::getRenderer() +{ + return nullptr; +} + +void +Renderer::setMode(Renderer::Mode mode) +{ + m_currentMode = mode; +} + +const Renderer::Mode& +Renderer::getMode() +{ + return m_currentMode; +} +} \ No newline at end of file diff --git a/Source/Rendering/imstkRenderer.h b/Source/Rendering/imstkRenderer.h new file mode 100644 index 0000000000000000000000000000000000000000..f0fec4d2f5205b6d45eb849e21bca7af81b60ed0 --- /dev/null +++ b/Source/Rendering/imstkRenderer.h @@ -0,0 +1,70 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkRenderer_h +#define imstkRenderer_h + +#include "imstkTextureManager.h" +#include "imstkMath.h" + +#include <memory> + +namespace imstk +{ +class Renderer +{ +public: + /// + /// \brief Enumerations for the render mode + /// + enum Mode + { + EMPTY, + DEBUG, + SIMULATION + }; + + /// + /// \brief Get renderer + /// + virtual std::shared_ptr<Renderer> getRenderer(); + + /// + /// \brief Set rendering mode + /// + virtual void setMode(Renderer::Mode mode); + + /// + /// \brief Get rendering mode + /// + virtual const Renderer::Mode& getMode(); + + /// + /// \brief Update background colors + /// + virtual void updateBackground(const Vec3d color1, const Vec3d color2 = Vec3d::Zero(), const bool gradientBackground = false){}; + +protected: + Renderer::Mode m_currentMode = Renderer::Mode::EMPTY; +}; +} + +#endif \ No newline at end of file diff --git a/Source/Rendering/RenderDelegate/vtkCapsuleSource.cpp b/Source/Rendering/vtkCapsuleSource.cpp similarity index 100% rename from Source/Rendering/RenderDelegate/vtkCapsuleSource.cpp rename to Source/Rendering/vtkCapsuleSource.cpp diff --git a/Source/Rendering/RenderDelegate/vtkCapsuleSource.h b/Source/Rendering/vtkCapsuleSource.h similarity index 100% rename from Source/Rendering/RenderDelegate/vtkCapsuleSource.h rename to Source/Rendering/vtkCapsuleSource.h diff --git a/Source/SimulationManager/CMakeLists.txt b/Source/SimulationManager/CMakeLists.txt index 12a1943c05a5444a7500c1dc9b467ba05dddeefb..9ed3ab9850fdb61705512fa3ab789c359663e200 100644 --- a/Source/SimulationManager/CMakeLists.txt +++ b/Source/SimulationManager/CMakeLists.txt @@ -1,8 +1,57 @@ #----------------------------------------------------------------------------- # Create target #----------------------------------------------------------------------------- + +set(VTK_H_FILES + VTKRenderer/imstkVTKInteractorStyle.h + VTKRenderer/imstkVTKScreenCaptureUtility.h + VTKRenderer/imstkVTKViewer.h) + +set(VTK_CPP_FILES + VTKRenderer/imstkVTKInteractorStyle.cpp + VTKRenderer/imstkVTKScreenCaptureUtility.cpp + VTKRenderer/imstkVTKViewer.cpp) + +set(VULKAN_H_FILES + VulkanRenderer/imstkVulkanInteractorStyle.h + VulkanRenderer/imstkVulkanInteractorStyleTrackballCamera.h + VulkanRenderer/imstkVulkanScreenCaptureUtility.h + VulkanRenderer/imstkVulkanViewer.h) + +set(VULKAN_CPP_FILES + VulkanRenderer/imstkVulkanInteractorStyle.cpp + VulkanRenderer/imstkVulkanInteractorStyleTrackballCamera.cpp + VulkanRenderer/imstkVulkanScreenCaptureUtility.cpp + VulkanRenderer/imstkVulkanViewer.cpp) + +if( NOT iMSTK_USE_Vulkan ) + set(SIMULATIONMANAGER_H_FILES ${VTK_H_FILES}) + set(SIMULATIONMANAGER_CPP_FILES ${VTK_CPP_FILES}) + set(SIMULATIONMANAGER_SUBDIR + VTKRenderer) +else() + set(SIMULATIONMANAGER_H_FILES ${VULKAN_H_FILES}) + set(SIMULATIONMANAGER_CPP_FILES ${VULKAN_CPP_FILES}) + set(SIMULATIONMANAGER_SUBDIR + VulkanRenderer) +endif() + include(imstkAddLibrary) imstk_add_library( SimulationManager + H_FILES + imstkSceneManager.h + imstkSimulationManager.h + imstkViewer.h + imstkScreenCaptureUtility.h + ${SIMULATIONMANAGER_H_FILES} + CPP_FILES + imstkSceneManager.cpp + imstkSimulationManager.cpp + imstkViewer.cpp + imstkScreenCaptureUtility.cpp + ${SIMULATIONMANAGER_CPP_FILES} + SUBDIR_LIST + ${SIMULATIONMANAGER_SUBDIR} DEPENDS Rendering Devices diff --git a/Source/SimulationManager/imstkVTKInteractorStyle.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.cpp similarity index 87% rename from Source/SimulationManager/imstkVTKInteractorStyle.cpp rename to Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.cpp index 80b055beef41edc393d426ada28145e199fef472..4d66696f1fb88061579af89b42167b856ea59527 100644 --- a/Source/SimulationManager/imstkVTKInteractorStyle.cpp +++ b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.cpp @@ -71,11 +71,13 @@ VTKInteractorStyle::SetCurrentRenderer(vtkRenderer* ren) void VTKInteractorStyle::OnTimer() { + auto renderer = std::static_pointer_cast<VTKRenderer>(m_simManager->getViewer()->getActiveRenderer()); + // Update Camera - m_simManager->getViewer()->getActiveRenderer()->updateSceneCamera(m_simManager->getActiveScene()->getCamera()); + renderer->updateSceneCamera(m_simManager->getActiveScene()->getCamera()); // Update render delegates - m_simManager->getViewer()->getActiveRenderer()->updateRenderDelegates(); + renderer->updateRenderDelegates(); // Reset camera clipping range this->CurrentRenderer->ResetCameraClippingRange(); @@ -160,13 +162,13 @@ VTKInteractorStyle::OnChar() } else if (key == 'd' || key == 'D') // switch rendering mode { - if (m_simManager->getViewer()->getRenderingMode() != VTKRenderer::Mode::SIMULATION) + if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::SIMULATION) { - m_simManager->getViewer()->setRenderingMode(VTKRenderer::Mode::SIMULATION); + m_simManager->getViewer()->setRenderingMode(Renderer::Mode::SIMULATION); } else { - m_simManager->getViewer()->setRenderingMode(VTKRenderer::Mode::DEBUG); + m_simManager->getViewer()->setRenderingMode(Renderer::Mode::DEBUG); } } else if (key == '\u001B') // quit viewer @@ -197,7 +199,7 @@ VTKInteractorStyle::OnMouseMove() } // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != VTKRenderer::Mode::DEBUG) + if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG) { return; } @@ -218,7 +220,7 @@ VTKInteractorStyle::OnLeftButtonDown() } // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != VTKRenderer::Mode::DEBUG) + if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG) { return; } @@ -239,7 +241,7 @@ VTKInteractorStyle::OnLeftButtonUp() } // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != VTKRenderer::Mode::DEBUG) + if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG) { return; } @@ -260,7 +262,7 @@ VTKInteractorStyle::OnMiddleButtonDown() } // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != VTKRenderer::Mode::DEBUG) + if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG) { return; } @@ -281,7 +283,7 @@ VTKInteractorStyle::OnMiddleButtonUp() } // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != VTKRenderer::Mode::DEBUG) + if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG) { return; } @@ -302,7 +304,7 @@ VTKInteractorStyle::OnRightButtonDown() } // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != VTKRenderer::Mode::DEBUG) + if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG) { return; } @@ -323,7 +325,7 @@ VTKInteractorStyle::OnRightButtonUp() } // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != VTKRenderer::Mode::DEBUG) + if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG) { return; } @@ -344,7 +346,7 @@ VTKInteractorStyle::OnMouseWheelForward() } // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != VTKRenderer::Mode::DEBUG) + if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG) { return; } @@ -365,7 +367,7 @@ VTKInteractorStyle::OnMouseWheelBackward() } // Default behavior : ignore mouse if simulation active - if (m_simManager->getViewer()->getRenderingMode() != VTKRenderer::Mode::DEBUG) + if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::DEBUG) { return; } diff --git a/Source/SimulationManager/imstkVTKInteractorStyle.h b/Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.h similarity index 100% rename from Source/SimulationManager/imstkVTKInteractorStyle.h rename to Source/SimulationManager/VTKRenderer/imstkVTKInteractorStyle.h diff --git a/Source/SimulationManager/imstkVTKScreenCaptureUtility.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.cpp similarity index 98% rename from Source/SimulationManager/imstkVTKScreenCaptureUtility.cpp rename to Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.cpp index 278980732ce1031652223690d15d6ae6965198f0..b0658e016793a199ffe9f97edbf6924cae114282 100644 --- a/Source/SimulationManager/imstkVTKScreenCaptureUtility.cpp +++ b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.cpp @@ -26,8 +26,8 @@ namespace imstk { VTKScreenCaptureUtility::VTKScreenCaptureUtility(vtkRenderWindow* const rw, const std::string prefix /*= "Screenshot-"*/) - : m_screenShotNumber(0) { + m_screenShotNumber = 0; m_screenShotPrefix = prefix; if (rw != nullptr) { @@ -35,7 +35,6 @@ VTKScreenCaptureUtility::VTKScreenCaptureUtility(vtkRenderWindow* const rw, cons } } - void VTKScreenCaptureUtility::saveScreenShot() { @@ -70,7 +69,6 @@ VTKScreenCaptureUtility::saveScreenShot() m_screenShotNumber++; } - unsigned int VTKScreenCaptureUtility::getScreenShotNumber() const { diff --git a/Source/SimulationManager/imstkVTKScreenCaptureUtility.h b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.h similarity index 74% rename from Source/SimulationManager/imstkVTKScreenCaptureUtility.h rename to Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.h index 189d412397b265b5e7561b94c9f9e051b96301d1..f2e797bb2f48de6101952c80cc4f855f4391b650 100644 --- a/Source/SimulationManager/imstkVTKScreenCaptureUtility.h +++ b/Source/SimulationManager/VTKRenderer/imstkVTKScreenCaptureUtility.h @@ -17,10 +17,12 @@ See the License for the specific language governing permissions and limitations under the License. -=========================================================================*/ + =========================================================================*/ -#ifndef imstkScreenCaptureUtility_h -#define imstkScreenCaptureUtility_h +#ifndef imstkVTKScreenCaptureUtility_h +#define imstkVTKScreenCaptureUtility_h + +#include "imstkScreenCaptureUtility.h" #include "vtkNew.h" #include "vtkRenderWindow.h" @@ -36,7 +38,7 @@ namespace imstk /// /// \brief Utility class to manage screen capture through VTK /// -class VTKScreenCaptureUtility +class VTKScreenCaptureUtility : public ScreenCaptureUtility { public: /// @@ -52,27 +54,18 @@ public: /// /// \brief Saves the screenshot as a png file /// - void saveScreenShot(); + virtual void saveScreenShot(); - /// - /// \brief Returns the number of the screenshot - /// unsigned int getScreenShotNumber() const; - /// - /// \brief set/reset the prefix amd the count numbers void setScreenShotPrefix(const std::string newPrefix); - /// - /// \brief reset the screenshot number indicator void resetScreenShotNumber(); protected: vtkNew<vtkWindowToImageFilter> m_windowToImageFilter; vtkNew<vtkPNGWriter> m_pngWriter; //> using vtk's png writer to save the screenshots vtkRenderWindow* m_renderWindow; //> render window whose screen shot will be taken - unsigned int m_screenShotNumber; //> screen shot number is added to the file prefix, and incremented everytime a screen shot is taken - std::string m_screenShotPrefix; //> the prefix for the screenshots to be saved }; } // imstk diff --git a/Source/SimulationManager/imstkVTKViewer.cpp b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp similarity index 82% rename from Source/SimulationManager/imstkVTKViewer.cpp rename to Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp index 281fe38c85288d5a4f56826d58f0e421c8eb6e5d..58ac64f9d42684a2afc33ac734a004d1b5990ca9 100644 --- a/Source/SimulationManager/imstkVTKViewer.cpp +++ b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.cpp @@ -21,33 +21,25 @@ #include "imstkVTKViewer.h" -#include "g3log/g3log.hpp" - #include "imstkVTKRenderDelegate.h" namespace imstk { -std::shared_ptr<Scene> -VTKViewer::getActiveScene() const -{ - return m_activeScene; -} - void -VTKViewer::setActiveScene(std::shared_ptr<Scene> scene) +VTKViewer::setActiveScene(std::shared_ptr<Scene>scene) { // If already current scene - if( scene == m_activeScene ) + if (scene == m_activeScene) { LOG(WARNING) << scene->getName() << " already is the viewer current scene."; return; } // If the current scene has a renderer, remove it - if( m_activeScene ) + if (m_activeScene) { - auto vtkRenderer = this->getActiveRenderer()->getVtkRenderer(); - if(m_vtkRenderWindow->HasRenderer(vtkRenderer)) + auto vtkRenderer = std::dynamic_pointer_cast<VTKRenderer>(this->getActiveRenderer())->getVtkRenderer(); + if (m_vtkRenderWindow->HasRenderer(vtkRenderer)) { m_vtkRenderWindow->RemoveRenderer(vtkRenderer); } @@ -62,26 +54,23 @@ VTKViewer::setActiveScene(std::shared_ptr<Scene> scene) m_rendererMap[m_activeScene] = std::make_shared<VTKRenderer>(m_activeScene); } + // Cast to VTK renderer + auto vtkRenderer = std::dynamic_pointer_cast<VTKRenderer>(this->getActiveRenderer())->getVtkRenderer(); + // Set renderer to renderWindow - m_vtkRenderWindow->AddRenderer(this->getActiveRenderer()->getVtkRenderer()); + m_vtkRenderWindow->AddRenderer(vtkRenderer); // Set renderer to interactorStyle - m_interactorStyle->SetCurrentRenderer(this->getActiveRenderer()->getVtkRenderer()); + m_interactorStyle->SetCurrentRenderer(vtkRenderer); // Set name to renderWindow m_vtkRenderWindow->SetWindowName(m_activeScene->getName().data()); } -std::shared_ptr<VTKRenderer> -VTKViewer::getActiveRenderer() const -{ - return m_rendererMap.at(m_activeScene); -} - void -VTKViewer::setRenderingMode(const VTKRenderer::Mode mode) +VTKViewer::setRenderingMode(Renderer::Mode mode) { - if( !m_activeScene ) + if (!m_activeScene) { LOG(WARNING) << "Missing scene, can not set rendering mode.\n" << "Use Viewer::setCurrentScene to setup scene."; @@ -90,7 +79,7 @@ VTKViewer::setRenderingMode(const VTKRenderer::Mode mode) // Setup renderer this->getActiveRenderer()->setMode(mode); - if( !m_running ) + if (!m_running) { return; } @@ -99,8 +88,9 @@ VTKViewer::setRenderingMode(const VTKRenderer::Mode mode) m_vtkRenderWindow->Render(); // Setup render window - if (mode == VTKRenderer::Mode::SIMULATION) + if (mode == Renderer::Mode::SIMULATION) { + m_interactorStyle->HighlightProp(nullptr); m_vtkRenderWindow->HideCursor(); //m_vtkRenderWindow->BordersOff(); //m_vtkRenderWindow->FullScreenOn(1); @@ -113,7 +103,7 @@ VTKViewer::setRenderingMode(const VTKRenderer::Mode mode) } } -const VTKRenderer::Mode& +const Renderer::Mode VTKViewer::getRenderingMode() { return this->getActiveRenderer()->getMode(); @@ -123,11 +113,10 @@ void VTKViewer::startRenderingLoop() { m_running = true; - auto interactor = m_vtkRenderWindow->GetInteractor(); - interactor->Initialize(); - interactor->CreateOneShotTimer(0); - interactor->Start(); - interactor->DestroyTimer(); + m_vtkRenderWindow->GetInteractor()->Initialize(); + m_vtkRenderWindow->GetInteractor()->CreateOneShotTimer(0); + m_vtkRenderWindow->GetInteractor()->Start(); + m_vtkRenderWindow->GetInteractor()->DestroyTimer(); m_running = false; } @@ -147,12 +136,6 @@ VTKViewer::getVtkRenderWindow() const return m_vtkRenderWindow; } -bool -VTKViewer::isRendering() const -{ - return m_running; -} - double VTKViewer::getTargetFrameRate() const { @@ -166,7 +149,7 @@ VTKViewer::getTargetFrameRate() const } void -VTKViewer::setTargetFrameRate(const double fps) +VTKViewer::setTargetFrameRate(const double& fps) { if(fps < 0) { @@ -252,7 +235,7 @@ VTKViewer::setOnTimerFunction(VTKEventHandlerFunction func) std::shared_ptr<VTKScreenCaptureUtility> VTKViewer::getScreenCaptureUtility() const { - return m_screenCapturer; + return std::static_pointer_cast<VTKScreenCaptureUtility>(m_screenCapturer); } void diff --git a/Source/SimulationManager/imstkVTKViewer.h b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h similarity index 73% rename from Source/SimulationManager/imstkVTKViewer.h rename to Source/SimulationManager/VTKRenderer/imstkVTKViewer.h index 76dbd4fb7f571b354862ccd3186ea6594fd8e2b8..79f5958a0671ad0d93483e82d754c9bb76afb0be 100644 --- a/Source/SimulationManager/imstkVTKViewer.h +++ b/Source/SimulationManager/VTKRenderer/imstkVTKViewer.h @@ -25,16 +25,19 @@ #include <memory> #include <unordered_map> +#include "g3log/g3log.hpp" + #include "imstkScene.h" #include "imstkVTKRenderer.h" #include "imstkVTKInteractorStyle.h" #include "imstkVTKScreenCaptureUtility.h" - +#include "imstkViewer.h" +#include "imstkVTKRenderDelegate.h" #include "vtkSmartPointer.h" #include "vtkRenderWindow.h" #include "vtkRenderWindowInteractor.h" -// Screenshot utility +//Screenshot utility #include "imstkVTKScreenCaptureUtility.h" namespace imstk @@ -46,7 +49,7 @@ class SimulationManager; /// /// \brief Viewer /// -class VTKViewer +class VTKViewer : public Viewer { public: /// @@ -56,61 +59,45 @@ public: { m_interactorStyle->m_simManager = manager; m_vtkRenderWindow->SetInteractor(m_vtkRenderWindow->MakeRenderWindowInteractor()); - m_vtkRenderWindow->GetInteractor()->SetInteractorStyle(m_interactorStyle); - m_vtkRenderWindow->SetSize(1000, 800); + m_vtkRenderWindow->GetInteractor()->SetInteractorStyle( m_interactorStyle ); + m_vtkRenderWindow->SetSize(1000,800); m_screenCapturer = std::make_shared<VTKScreenCaptureUtility>(m_vtkRenderWindow); } /// /// \brief Destructor /// - ~VTKViewer() = default; + virtual void setRenderingMode(Renderer::Mode mode); /// - /// \brief Get scene currently being rendered + /// \brief Destructor /// - std::shared_ptr<Scene> getActiveScene() const; + ~VTKViewer() = default; /// /// \brief Set scene to be rendered /// - void setActiveScene(std::shared_ptr<Scene> scene); - - /// - /// \brief Retrieve the renderer associated with the current scene - /// - std::shared_ptr<VTKRenderer> getActiveRenderer() const; - - /// - /// \brief Setup the current renderer to render what's needed - /// based on the mode chosen - /// - void setRenderingMode(const VTKRenderer::Mode mode); + virtual void setActiveScene(std::shared_ptr<Scene>scene); /// /// \brief Get the current renderer mode /// - const VTKRenderer::Mode& getRenderingMode(); + virtual const Renderer::Mode getRenderingMode(); /// /// \brief Start rendering /// - void startRenderingLoop(); + virtual void startRenderingLoop(); /// /// \brief Terminate rendering /// - void endRenderingLoop(); + virtual void endRenderingLoop(); /// /// \brief Get pointer to the vtkRenderWindow rendering /// - vtkSmartPointer<vtkRenderWindow> getVtkRenderWindow() const; - - /// - /// \brief Returns true if the Viewer is rendering - /// - bool isRendering() const; + vtkSmartPointer<vtkRenderWindow>getVtkRenderWindow() const; /// /// \brief Get the target FPS for rendering @@ -120,7 +107,7 @@ public: /// /// \brief Set the target FPS for rendering /// - void setTargetFrameRate(const double fps); + void setTargetFrameRate(const double& fps); /// /// \brief Set custom event handlers on interactor style @@ -151,16 +138,12 @@ public: /// \brief Set the coloring of the screen background /// If 'gradientBackground' is false or not supplied color1 will fill the entire background /// - void setBackgroundColors(const Vec3d color1, const Vec3d color2 = Vec3d::Zero(), const bool gradientBackground = false); + virtual void setBackgroundColors(const Vec3d color1, const Vec3d color2 = Vec3d::Zero(), const bool gradientBackground = false); protected: vtkSmartPointer<vtkRenderWindow> m_vtkRenderWindow = vtkSmartPointer<vtkRenderWindow>::New(); vtkSmartPointer<VTKInteractorStyle> m_interactorStyle = vtkSmartPointer<VTKInteractorStyle>::New(); - std::shared_ptr<Scene> m_activeScene; - std::unordered_map<std::shared_ptr<Scene>, std::shared_ptr<VTKRenderer>> m_rendererMap; - std::shared_ptr<VTKScreenCaptureUtility> m_screenCapturer; ///> Screen shot utility - bool m_running = false; }; } // imstk diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyle.cpp b/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cd499e53033afee2a48b248b3841d58c1d7f95b6 --- /dev/null +++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyle.cpp @@ -0,0 +1,248 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanInteractorStyle.h" + +#include "imstkVulkanViewer.h" +#include "imstkSimulationManager.h" + +namespace imstk +{ +VulkanInteractorStyle::VulkanInteractorStyle() +{ +} + +void +VulkanInteractorStyle::OnTimer() +{ +} + +void +VulkanInteractorStyle::OnChar(int keyID, int type) +{ + char key = (char)keyID; + + if (type != GLFW_PRESS) + { + return; + } + + // Call custom function if exists, and return + // if it returned `override=true` + if(m_onCharFunctionMap.count(key) && + m_onCharFunctionMap.at(key) && + m_onCharFunctionMap.at(key)(this)) + { + return; + } + + SimulationStatus status = m_simManager->getStatus(); + + if (key == ' ') + { + // pause simulation + if (status == SimulationStatus::RUNNING) + { + m_simManager->pauseSimulation(); + } + // play simulation + else if (status == SimulationStatus::PAUSED) + { + m_simManager->runSimulation(); + } + // Launch simulation if inactive + if (status == SimulationStatus::INACTIVE) + { + m_simManager->launchSimulation(); + } + } + else if (status != SimulationStatus::INACTIVE && + (key == 'q' || key == 'Q' || key == 'e' || key == 'E')) // end Simulation + { + m_simManager->endSimulation(); + } + else if (key == 'd' || key == 'D') // switch rendering mode + { + if (m_simManager->getViewer()->getRenderingMode() != Renderer::Mode::SIMULATION) + { + m_simManager->getViewer()->setRenderingMode(Renderer::Mode::SIMULATION); + } + else + { + m_simManager->getViewer()->setRenderingMode(Renderer::Mode::DEBUG); + } + } + else if (key == '\u001B') // quit viewer + { + m_simManager->getViewer()->endRenderingLoop(); + } + else if (key == 'p' || key == 'P') // switch framerate display + { + } + else if (key == 'r' || key == 'R') + { + m_simManager->resetSimulation(); + } +} + +void +VulkanInteractorStyle::OnMouseMove(double x, double y) +{ + if (m_onMouseMoveFunction && m_onMouseMoveFunction(this)) + { + return; + } + + if (m_simManager->getStatus() != SimulationStatus::INACTIVE) + { + return; + } + + VulkanBaseInteractorStyle::OnMouseMove(x, y); +} + +void +VulkanInteractorStyle::OnLeftButtonDown() +{ + if (m_onLeftButtonDownFunction && m_onLeftButtonDownFunction(this)) + { + return; + } + + if (m_simManager->getStatus() != SimulationStatus::INACTIVE) + { + return; + } + + VulkanBaseInteractorStyle::OnLeftButtonDown(); +} + +void +VulkanInteractorStyle::OnLeftButtonUp() +{ + if (m_onLeftButtonUpFunction && m_onLeftButtonUpFunction(this)) + { + return; + } + + if (m_simManager->getStatus() != SimulationStatus::INACTIVE) + { + return; + } + + VulkanBaseInteractorStyle::OnLeftButtonUp(); +} + +void +VulkanInteractorStyle::OnMiddleButtonDown() +{ + if (m_onMiddleButtonDownFunction && m_onMiddleButtonDownFunction(this)) + { + return; + } + + if (m_simManager->getStatus() != SimulationStatus::INACTIVE) + { + return; + } + + VulkanBaseInteractorStyle::OnMiddleButtonDown(); +} + +void VulkanInteractorStyle::OnMiddleButtonUp() +{ + if (m_onMiddleButtonUpFunction && m_onMiddleButtonUpFunction(this)) + { + return; + } + + if (m_simManager->getStatus() != SimulationStatus::INACTIVE) + { + return; + } + + VulkanBaseInteractorStyle::OnMiddleButtonUp(); +} + +void +VulkanInteractorStyle::OnRightButtonDown() +{ + if (m_onRightButtonDownFunction && m_onRightButtonDownFunction(this)) + { + return; + } + + if (m_simManager->getStatus() != SimulationStatus::INACTIVE) + { + return; + } + + VulkanBaseInteractorStyle::OnRightButtonDown(); +} + +void +VulkanInteractorStyle::OnRightButtonUp() +{ + if (m_onRightButtonUpFunction && m_onRightButtonUpFunction(this)) + { + return; + } + + if (m_simManager->getStatus() != SimulationStatus::INACTIVE) + { + return; + } + + VulkanBaseInteractorStyle::OnRightButtonUp(); +} + +void +VulkanInteractorStyle::OnMouseWheelForward(double y) +{ + if (m_onMouseWheelForwardFunction && m_onMouseWheelForwardFunction(this)) + { + return; + } + + if (m_simManager->getStatus() != SimulationStatus::INACTIVE) + { + return; + } + + VulkanBaseInteractorStyle::OnMouseWheelForward(y); +} + +void +VulkanInteractorStyle::OnMouseWheelBackward(double y) +{ + if (m_onMouseWheelBackwardFunction && m_onMouseWheelBackwardFunction(this)) + { + return; + } + + if (m_simManager->getStatus() != SimulationStatus::INACTIVE) + { + return; + } + + VulkanBaseInteractorStyle::OnMouseWheelBackward(y); +} +} \ No newline at end of file diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyle.h b/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyle.h new file mode 100644 index 0000000000000000000000000000000000000000..be765a5fd525247ee60f4e6fd492ffef28915ea9 --- /dev/null +++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyle.h @@ -0,0 +1,76 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanInteractorStyle_h +#define imstkVulkanInteractorStyle_h + +#include "GLFW/glfw3.h" + +#include "imstkVulkanInteractorStyleTrackballCamera.h" + +#include <iostream> +#include <unordered_map> +#include <functional> + +namespace imstk +{ +class VulkanInteractorStyle; +class VulkanViewer; + +using VulkanBaseInteractorStyle = VulkanInteractorStyleTrackballCamera; + +using VulkanEventHandlerFunction = std::function< bool(VulkanInteractorStyle * iStyle) >; + +class VulkanInteractorStyle : public VulkanBaseInteractorStyle +{ +public: + VulkanInteractorStyle(); + ~VulkanInteractorStyle(){}; + + virtual void OnTimer(); + virtual void OnChar(int keyID, int type); + virtual void OnMouseMove(double x, double y); + virtual void OnLeftButtonDown(); + virtual void OnLeftButtonUp(); + virtual void OnMiddleButtonDown(); + virtual void OnMiddleButtonUp(); + virtual void OnRightButtonDown(); + virtual void OnRightButtonUp(); + virtual void OnMouseWheelForward(double y); + virtual void OnMouseWheelBackward(double y); + +private: + friend class VulkanViewer; + + std::unordered_map<char, VulkanEventHandlerFunction> m_onCharFunctionMap; + VulkanEventHandlerFunction m_onMouseMoveFunction; + VulkanEventHandlerFunction m_onLeftButtonDownFunction; + VulkanEventHandlerFunction m_onLeftButtonUpFunction; + VulkanEventHandlerFunction m_onMiddleButtonDownFunction; + VulkanEventHandlerFunction m_onMiddleButtonUpFunction; + VulkanEventHandlerFunction m_onRightButtonDownFunction; + VulkanEventHandlerFunction m_onRightButtonUpFunction; + VulkanEventHandlerFunction m_onMouseWheelForwardFunction; + VulkanEventHandlerFunction m_onMouseWheelBackwardFunction; +}; +} + +#endif \ No newline at end of file diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyleTrackballCamera.cpp b/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyleTrackballCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..62e3988ea8d08d56ccf759ae295a5012c9e5254e --- /dev/null +++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyleTrackballCamera.cpp @@ -0,0 +1,259 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanInteractorStyleTrackballCamera.h" + +#include "imstkVulkanViewer.h" +#include "imstkSimulationManager.h" + +namespace imstk +{ +VulkanInteractorStyleTrackballCamera::VulkanInteractorStyleTrackballCamera() +{ +} + +void +VulkanInteractorStyleTrackballCamera::setWindow(GLFWwindow * window, VulkanViewer * viewer) +{ + m_window = window; + m_viewer = viewer; + + glfwSetWindowUserPointer(window, (void *)this); + + glfwSetKeyCallback(m_window, VulkanInteractorStyleTrackballCamera::OnCharInterface); + glfwSetMouseButtonCallback(m_window, VulkanInteractorStyleTrackballCamera::OnMouseButtonInterface); + glfwSetCursorPosCallback(m_window, VulkanInteractorStyleTrackballCamera::OnMouseMoveInterface); + glfwSetScrollCallback(m_window, VulkanInteractorStyleTrackballCamera::OnMouseWheelInterface); + glfwSetWindowSizeCallback(m_window, VulkanInteractorStyleTrackballCamera::OnWindowResizeInterface); + glfwSetFramebufferSizeCallback(m_window, VulkanInteractorStyleTrackballCamera::OnFramebuffersResizeInterface); +} + +void +VulkanInteractorStyleTrackballCamera::OnTimer() +{ +} + +void +VulkanInteractorStyleTrackballCamera::OnCharInterface(GLFWwindow * window, int keyID, int code, int type, int extra) +{ + VulkanInteractorStyleTrackballCamera * style = (VulkanInteractorStyleTrackballCamera *)glfwGetWindowUserPointer(window); + style->OnChar(keyID, type); +} + +void +VulkanInteractorStyleTrackballCamera::OnMouseButtonInterface(GLFWwindow * window, int buttonID, int type, int extra) +{ + VulkanInteractorStyleTrackballCamera * style = (VulkanInteractorStyleTrackballCamera *)glfwGetWindowUserPointer(window); + + switch (buttonID) + { + case GLFW_MOUSE_BUTTON_LEFT: + if (type == GLFW_PRESS) + { + style->OnLeftButtonDown(); + } + else if (type == GLFW_RELEASE) + { + style->OnLeftButtonUp(); + } + break; + case GLFW_MOUSE_BUTTON_RIGHT: + if (type == GLFW_PRESS) + { + style->OnRightButtonDown(); + } + else if (type == GLFW_RELEASE) + { + style->OnRightButtonUp(); + } + break; + case GLFW_MOUSE_BUTTON_MIDDLE: + if (type == GLFW_PRESS) + { + style->OnMiddleButtonDown(); + } + else if (type == GLFW_RELEASE) + { + style->OnMiddleButtonUp(); + } + break; + } +} + +void +VulkanInteractorStyleTrackballCamera::OnMouseMoveInterface(GLFWwindow * window, double x, double y) +{ + VulkanInteractorStyleTrackballCamera * style = (VulkanInteractorStyleTrackballCamera *)glfwGetWindowUserPointer(window); + style->OnMouseMove(x, y); +} + +void +VulkanInteractorStyleTrackballCamera::OnMouseWheelInterface(GLFWwindow * window, double x, double y) +{ + VulkanInteractorStyleTrackballCamera * style = (VulkanInteractorStyleTrackballCamera *)glfwGetWindowUserPointer(window); + if (y < 0) + { + style->OnMouseWheelBackward(y); + } + else + { + style->OnMouseWheelForward(y); + } +} + +void +VulkanInteractorStyleTrackballCamera::OnChar(int keyID, int type) +{ +} + +void +VulkanInteractorStyleTrackballCamera::OnMouseMove(double x, double y) +{ + m_mouseX = (x - m_viewer->m_width / 2) / m_viewer->m_width; + m_mouseY = (y - m_viewer->m_height / 2) / m_viewer->m_height; + auto camera = m_simManager->getActiveScene()->getCamera(); + auto offset = camera->getPosition() - camera->getFocalPoint(); + auto dx = m_mouseX - m_lastMouseX; + auto dy = m_mouseY - m_lastMouseY; + + if (m_state & VulkanInteractorStyleTrackballCamera::LEFT_MOUSE_DOWN) + { + double strength = distance(m_mouseX, m_mouseY); + + auto convertedOffset = glm::vec3(offset.x(), offset.y(), offset.z()); + glm::vec3 rotationAxis(0,1,0); + glm::mat4 rotation; + rotation = glm::rotate(rotation, -(float)dx, rotationAxis); + auto new_position = rotation * glm::vec4(offset.x(), offset.y(), offset.z(), 1); + imstk::Vec3d position(new_position[0], new_position[1], new_position[2]); + camera->setPosition(camera->getFocalPoint() + position); + } + else if (m_state & VulkanInteractorStyleTrackballCamera::MIDDLE_MOUSE_DOWN) + { + auto camera = m_simManager->getActiveScene()->getCamera(); + auto eye = glm::tvec3<float>(camera->getPosition().x(), camera->getPosition().y(), camera->getPosition().z()); + auto center = glm::tvec3<float>(camera->getFocalPoint().x(), camera->getFocalPoint().y(), camera->getFocalPoint().z()); + auto up = glm::tvec3<float>(camera->getViewUp().x(), camera->getViewUp().y(), camera->getViewUp().z()); + + glm::mat4 cameraTranslationMatrix(1); + cameraTranslationMatrix = glm::translate(cameraTranslationMatrix, glm::tvec3<float>(-dx * 10, dy * 10, 0)); + auto cameraMatrix = glm::inverse(glm::lookAt(eye, center, up)); + + auto new_position = cameraMatrix * cameraTranslationMatrix; + auto new_focal_point_offset = glm::mat3(cameraMatrix) * glm::vec3(cameraTranslationMatrix[3]); + imstk::Vec3d position(new_position[3][0], new_position[3][1], new_position[3][2]); + camera->setPosition(position); + auto new_focal_point = center + new_focal_point_offset; + camera->setFocalPoint(Vec3d(new_focal_point[0], new_focal_point[1], new_focal_point[2])); + } + + m_lastMouseX = m_mouseX; + m_lastMouseY = m_mouseY; +} + +void +VulkanInteractorStyleTrackballCamera::OnLeftButtonDown() +{ + m_state |= VulkanInteractorStyleTrackballCamera::LEFT_MOUSE_DOWN; +} + +void +VulkanInteractorStyleTrackballCamera::OnLeftButtonUp() +{ + m_state &= ~VulkanInteractorStyleTrackballCamera::LEFT_MOUSE_DOWN; +} + +void +VulkanInteractorStyleTrackballCamera::OnMiddleButtonDown() +{ + m_state |= VulkanInteractorStyleTrackballCamera::MIDDLE_MOUSE_DOWN; +} + +void VulkanInteractorStyleTrackballCamera::OnMiddleButtonUp() +{ + m_state &= ~VulkanInteractorStyleTrackballCamera::MIDDLE_MOUSE_DOWN; +} + +void +VulkanInteractorStyleTrackballCamera::OnRightButtonDown() +{ + m_state |= VulkanInteractorStyleTrackballCamera::RIGHT_MOUSE_DOWN; +} + +void +VulkanInteractorStyleTrackballCamera::OnRightButtonUp() +{ + m_state &= ~VulkanInteractorStyleTrackballCamera::RIGHT_MOUSE_DOWN; +} + +void +VulkanInteractorStyleTrackballCamera::OnMouseWheelForward(double y) +{ + auto camera = m_simManager->getActiveScene()->getCamera(); + + auto offset = camera->getPosition() - camera->getFocalPoint(); + + auto offsetx = -0.01 * offset.x() * y + camera->getPosition().x(); + auto offsety = -0.01 * offset.y() * y + camera->getPosition().y(); + auto offsetz = -0.01 * offset.z() * y + camera->getPosition().z(); + + camera->setPosition(Vec3d(offsetx, offsety, offsetz)); +} + +void +VulkanInteractorStyleTrackballCamera::OnMouseWheelBackward(double y) +{ + auto camera = m_simManager->getActiveScene()->getCamera(); + + auto offset = camera->getPosition() - camera->getFocalPoint(); + + auto offsetx = -0.01 * offset.x() * y + camera->getPosition().x(); + auto offsety = -0.01 * offset.y() * y + camera->getPosition().y(); + auto offsetz = -0.01 * offset.z() * y + camera->getPosition().z(); + + camera->setPosition(Vec3d(offsetx, offsety, offsetz)); +} + +inline double +VulkanInteractorStyleTrackballCamera::distance(double x, double y) +{ + return sqrt(x * x + y * y); +} + +void +VulkanInteractorStyleTrackballCamera::OnWindowResizeInterface(GLFWwindow * window, int width, int height) +{ + VulkanInteractorStyleTrackballCamera * style = (VulkanInteractorStyleTrackballCamera *)glfwGetWindowUserPointer(window); +} + +void +VulkanInteractorStyleTrackballCamera::OnFramebuffersResizeInterface(GLFWwindow * window, int width, int height) +{ + VulkanInteractorStyleTrackballCamera * style = (VulkanInteractorStyleTrackballCamera *)glfwGetWindowUserPointer(window); + style->OnWindowResize(width, height); +} + +void +VulkanInteractorStyleTrackballCamera::OnWindowResize(int width, int height) +{ + m_viewer->resizeWindow(width, height); +} +} \ No newline at end of file diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyleTrackballCamera.h b/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyleTrackballCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..3171fb7a1f9d6163daa701735a06b8f63fe68060 --- /dev/null +++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanInteractorStyleTrackballCamera.h @@ -0,0 +1,94 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanInteractorStyleTrackballCamera_h +#define imstkVulkanInteractorStyleTrackballCamera_h + +#include "GLFW/glfw3.h" + +#include <iostream> +#include <unordered_map> +#include <functional> + +namespace imstk +{ +class VulkanViewer; +class SimulationManager; + +class VulkanInteractorStyleTrackballCamera +{ +public: + VulkanInteractorStyleTrackballCamera(); + ~VulkanInteractorStyleTrackballCamera(){}; + + void setWindow(GLFWwindow * window, VulkanViewer * viewer); + + virtual void OnTimer(); + virtual void OnChar(int keyID, int type); + virtual void OnMouseMove(double x, double y); + virtual void OnLeftButtonDown(); + virtual void OnLeftButtonUp(); + virtual void OnMiddleButtonDown(); + virtual void OnMiddleButtonUp(); + virtual void OnRightButtonDown(); + virtual void OnRightButtonUp(); + virtual void OnMouseWheelForward(double y); + virtual void OnMouseWheelBackward(double y); + void OnWindowResize(int width, int height); + + // Dispatch function + static void OnCharInterface(GLFWwindow * window, int a, int b, int c, int d); + static void OnMouseButtonInterface(GLFWwindow * window, int a, int b, int c); + static void OnMouseMoveInterface(GLFWwindow * window, double x, double y); + static void OnMouseWheelInterface(GLFWwindow * window, double x, double y); + + static void OnWindowResizeInterface(GLFWwindow * window, int width, int height); + static void OnFramebuffersResizeInterface(GLFWwindow * window, int width, int height); + static void OnFrame(); + +protected: + friend class VulkanViewer; + + GLFWwindow * m_window; + SimulationManager * m_simManager; + VulkanViewer * m_viewer; + + double distance(double x, double y); + + // States + enum + { + LEFT_MOUSE_DOWN = 0x1, + MIDDLE_MOUSE_DOWN = 0x2, + RIGHT_MOUSE_DOWN = 0x4 + }; + + double m_lastMouseX = 0; + double m_lastMouseY = 0; + + double m_mouseX = 0; + double m_mouseY = 0; + + unsigned int m_state = 0; +}; +} + +#endif \ No newline at end of file diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanScreenCaptureUtility.cpp b/Source/SimulationManager/VulkanRenderer/imstkVulkanScreenCaptureUtility.cpp new file mode 100644 index 0000000000000000000000000000000000000000..971fb5e87fcc07b1610b5e46b6c283d3abbbe00d --- /dev/null +++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanScreenCaptureUtility.cpp @@ -0,0 +1,41 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanScreenCaptureUtility.h" + +#include "g3log/g3log.hpp" + +namespace imstk +{ +VulkanScreenCaptureUtility::VulkanScreenCaptureUtility(const std::string prefix /*= "Screenshot-"*/) +{ + m_screenShotNumber = 0; + m_screenShotPrefix = prefix; +} + +void +VulkanScreenCaptureUtility::saveScreenShot() +{ + LOG(WARNING) << "Screen capture not supported\n"; + + m_screenShotNumber++; +} +} // imstk diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanScreenCaptureUtility.h b/Source/SimulationManager/VulkanRenderer/imstkVulkanScreenCaptureUtility.h new file mode 100644 index 0000000000000000000000000000000000000000..c500bb16e817bb57ca28f77359794c7c1d61f70f --- /dev/null +++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanScreenCaptureUtility.h @@ -0,0 +1,58 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanScreenCaptureUtility_h +#define imstkVulkanScreenCaptureUtility_h + +#include "imstkScreenCaptureUtility.h" + +#include <string> + +namespace imstk +{ +/// +/// \class VulkanScreenCaptureUtility +/// +/// \brief Utility class to manage screen capture through Vulkan +/// +class VulkanScreenCaptureUtility : public ScreenCaptureUtility +{ +public: + /// + /// \brief Constructor + /// + VulkanScreenCaptureUtility(const std::string prefix = "Screenshot-"); + + /// + /// \brief Destructor + /// + ~VulkanScreenCaptureUtility() = default; + + /// + /// \brief Saves the screenshot as a png file + /// + virtual void saveScreenShot(); + +protected: +}; +} // imstk + +#endif // ifndef imstkScreenCaptureUtility_h \ No newline at end of file diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a1f63731432932e4119022033323e1bfb5f60e08 --- /dev/null +++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.cpp @@ -0,0 +1,167 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkVulkanViewer.h" + +namespace imstk +{ +VulkanViewer::VulkanViewer(SimulationManager * manager) +{ + m_simManager = manager; +} + +void +VulkanViewer::setActiveScene(std::shared_ptr<Scene>scene) +{ + m_renderer = std::make_shared<VulkanRenderer>(scene); +} + +void +VulkanViewer::startRenderingLoop() +{ + m_running = true; + this->setupWindow(); + m_renderer->initialize(); + this->createWindow(); + + this->setupSwapchain(); + m_renderer->initializeFramebuffers(&m_swapchain); + + while (!glfwWindowShouldClose(m_window)) + { + m_renderer->renderFrame(); + glfwPollEvents(); + m_interactorStyle->OnTimer(); + } + + m_running = false; +} + +void +VulkanViewer::endRenderingLoop() +{ +} + +void +VulkanViewer::setupWindow() +{ + if (!glfwInit()) + { + LOG(FATAL) << "GLFW failed to initialize"; + return; + } + + if (!glfwVulkanSupported()) + { + LOG(FATAL) << "Vulkan is not supported"; + return; + } + + uint32_t tempCount; + const char ** tempExtensions = glfwGetRequiredInstanceExtensions(&tempCount); + for (int i = 0; i < (int)tempCount; i++) + { + m_renderer->m_extensions.push_back((char*)tempExtensions[i]); + } +} + +void +VulkanViewer::createWindow() +{ + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + m_window = glfwCreateWindow(m_width, m_height, "iMSTK", nullptr, nullptr); + VkResult status = glfwCreateWindowSurface(*m_renderer->m_instance, m_window, nullptr, &m_surface); + std::cout << status << std::endl; + + m_interactorStyle = std::make_shared<VulkanInteractorStyle>(); + + m_interactorStyle->setWindow(m_window, this); + m_interactorStyle->m_simManager = m_simManager; +} + +void +VulkanViewer::resizeWindow(int width, int height) +{ + m_width = width; + m_height = height; + vkDeviceWaitIdle(m_renderer->m_renderDevice); + vkDestroySwapchainKHR(m_renderer->m_renderDevice, m_swapchain, nullptr); + this->setupSwapchain(); + + m_renderer->resizeFramebuffers(&m_swapchain, width, height); +} + +void +VulkanViewer::setupSwapchain() +{ + // Build swapchain + VkExtent2D extent; + extent.height = m_height; + extent.width = m_width; + + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_renderer->m_physicalDevices[0], m_surface, &m_physicalCapabilities); + + vkGetPhysicalDeviceSurfaceFormatsKHR(m_renderer->m_physicalDevices[0], m_surface, &m_physicalFormatsCount, nullptr); + m_physicalFormats = new VkSurfaceFormatKHR[(int)m_physicalFormatsCount](); + vkGetPhysicalDeviceSurfaceFormatsKHR(m_renderer->m_physicalDevices[0], m_surface, &m_physicalFormatsCount, m_physicalFormats); + + VkBool32 supported; + vkGetPhysicalDeviceSurfaceSupportKHR(m_renderer->m_physicalDevices[0], 0, m_surface, &supported); + + bool linearColorSpaceSupported = false; + + // Right now linear colorspace is a requirement + for (int i = 0; i < (int)m_physicalFormatsCount; i++) + { + if (m_physicalFormats[i].format == VK_FORMAT_B8G8R8A8_SRGB) + { + linearColorSpaceSupported = true; + } + } + + if (!linearColorSpaceSupported) + { + LOG(FATAL) << "Linear color space not supported"; + } + + VkSwapchainCreateInfoKHR swapchainInfo; + swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + swapchainInfo.pNext = nullptr; + swapchainInfo.flags = 0; + swapchainInfo.surface = m_surface; + swapchainInfo.minImageCount = 3; // triple buffering + swapchainInfo.imageFormat = VK_FORMAT_B8G8R8A8_SRGB; + swapchainInfo.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; + swapchainInfo.imageExtent = extent; + swapchainInfo.imageArrayLayers = 1; + swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchainInfo.queueFamilyIndexCount = 0; + swapchainInfo.pQueueFamilyIndices = nullptr; + swapchainInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + swapchainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + swapchainInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; + swapchainInfo.clipped = VK_TRUE; + swapchainInfo.oldSwapchain = VK_NULL_HANDLE; + + vkCreateSwapchainKHR(m_renderer->m_renderDevice, &swapchainInfo, nullptr, &m_swapchain); +} +} \ No newline at end of file diff --git a/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.h b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.h new file mode 100644 index 0000000000000000000000000000000000000000..da292c8fdd2cacd2cf100c98019ef3b02ccb8639 --- /dev/null +++ b/Source/SimulationManager/VulkanRenderer/imstkVulkanViewer.h @@ -0,0 +1,79 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkVulkanViewer_h +#define imstkVulkanViewer_h + +#include "vulkan/vulkan.h" +#include "GLFW/glfw3.h" +#include "g3log/g3log.hpp" + +#include "imstkVulkanRenderer.h" +#include "imstkViewer.h" +#include "imstkTimer.h" +#include "imstkVulkanInteractorStyle.h" + +namespace imstk +{ +class VulkanInteractorStyle; + +class VulkanViewer : public Viewer { +public: + VulkanViewer(SimulationManager * manager = nullptr); + + virtual void setActiveScene(std::shared_ptr<Scene> scene); + + virtual void startRenderingLoop(); + + virtual void endRenderingLoop(); + + /// + /// \brief Setups up the swapchain + /// + /// A swapchain is basically a queue of backbuffers + /// + void setupSwapchain(); + +protected: + friend class VulkanInteractorStyle; + friend class VulkanInteractorStyleTrackballCamera; + + void setupWindow(); + void createWindow(); + void resizeWindow(int width, int height); + + unsigned int m_width = 1000; + unsigned int m_height = 800; + + std::shared_ptr<VulkanRenderer> m_renderer; + VkSurfaceKHR m_surface; + GLFWwindow * m_window; + SimulationManager * m_simManager; + VkSwapchainKHR m_swapchain; + + VkSurfaceCapabilitiesKHR m_physicalCapabilities; + + uint32_t m_physicalFormatsCount; + VkSurfaceFormatKHR * m_physicalFormats; + std::shared_ptr<VulkanInteractorStyle> m_interactorStyle; +}; +} +#endif \ No newline at end of file diff --git a/Source/SimulationManager/imstkScreenCaptureUtility.cpp b/Source/SimulationManager/imstkScreenCaptureUtility.cpp new file mode 100644 index 0000000000000000000000000000000000000000..893f73222578d9b6da57cbf42be32e0be7a8e371 --- /dev/null +++ b/Source/SimulationManager/imstkScreenCaptureUtility.cpp @@ -0,0 +1,49 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + =========================================================================*/ + +#include "imstkScreenCaptureUtility.h" + +#include "g3log/g3log.hpp" + +namespace imstk +{ +unsigned int +ScreenCaptureUtility::getScreenShotNumber() const +{ + return m_screenShotNumber; +} + +void +ScreenCaptureUtility::setScreenShotPrefix(const std::string newPrefix) +{ + if (m_screenShotPrefix.compare(newPrefix) != 0) + { + m_screenShotPrefix = newPrefix; + m_screenShotNumber = 0; + } +} + +void +ScreenCaptureUtility::resetScreenShotNumber() +{ + m_screenShotNumber = 0; +} +} // imstk diff --git a/Source/SimulationManager/imstkScreenCaptureUtility.h b/Source/SimulationManager/imstkScreenCaptureUtility.h new file mode 100644 index 0000000000000000000000000000000000000000..219fa69488369d9b73bff8c41994aa1456e3c116 --- /dev/null +++ b/Source/SimulationManager/imstkScreenCaptureUtility.h @@ -0,0 +1,71 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkScreenCaptureUtility_h +#define imstkScreenCaptureUtility_h + +#include <string> + +namespace imstk +{ +/// +/// \class ScreenCaptureUtility +/// +/// \brief Utility class to manage screen capture +/// +class ScreenCaptureUtility +{ +public: + /// + /// \brief Saves the screenshot as a png file + /// + virtual void saveScreenShot(){}; + + /// + /// \brief Returns the number of the screenshot + /// + unsigned int getScreenShotNumber() const; + + /// + /// \brief set/reset the prefix amd the count numbers + void setScreenShotPrefix(const std::string newPrefix); + + /// + /// \brief reset the screenshot number indicator + void resetScreenShotNumber(); + +protected: + /// + /// \brief Constructor + /// + ScreenCaptureUtility(){}; + + /// + /// \brief Destructor + /// + ~ScreenCaptureUtility() = default; + + unsigned int m_screenShotNumber; //> screen shot number is added to the file prefix, and incremented everytime a screen shot is taken + std::string m_screenShotPrefix; //> the prefix for the screenshots to be saved +}; +} // imstk + +#endif // ifndef imstkScreenCaptureUtility_h \ No newline at end of file diff --git a/Source/SimulationManager/imstkSimulationManager.cpp b/Source/SimulationManager/imstkSimulationManager.cpp index 49e38684a758a405abc7d562db2acbbe18190b94..b3622dbe139854e1bc5b552650e9b7f8953c21a1 100644 --- a/Source/SimulationManager/imstkSimulationManager.cpp +++ b/Source/SimulationManager/imstkSimulationManager.cpp @@ -27,8 +27,20 @@ namespace imstk { -const SimulationStatus& -SimulationManager::getStatus() const +SimulationManager::SimulationManager() +{ + // Init g3logger + m_logUtil->createLogger("simulation", "./"); + +#ifdef iMSTK_USE_Vulkan + m_viewer = std::make_shared<VulkanViewer>(this); +#else + m_viewer = std::make_shared<VTKViewer>(this); +#endif +} + +const +SimulationStatus& SimulationManager::getStatus() const { return m_status; } @@ -198,7 +210,7 @@ SimulationManager::removeModule(const std::string& moduleName) LOG(INFO) << "Module removed: " << moduleName; } -std::shared_ptr<VTKViewer> +std::shared_ptr<Viewer> SimulationManager::getViewer() const { return m_viewer; @@ -244,14 +256,14 @@ SimulationManager::setActiveScene(const std::string& newSceneName, // render scene in debug, update current scene, and return if (m_status == SimulationStatus::INACTIVE) { - m_viewer->setRenderingMode(VTKRenderer::Mode::DEBUG); + m_viewer->setRenderingMode(Renderer::Mode::DEBUG); m_activeSceneName = newSceneName; return; } // If rendering and simulation active: // render scene in simulation mode, and update simulation - m_viewer->setRenderingMode(VTKRenderer::Mode::SIMULATION); + m_viewer->setRenderingMode(Renderer::Mode::SIMULATION); // Stop/Pause running scene auto oldSceneManager = m_sceneManagerMap.at(m_activeSceneName); @@ -363,7 +375,7 @@ SimulationManager::startSimulation(const bool startSimulationPaused /*= true*/, void SimulationManager::startViewer(const bool debug /*= true*/) { - m_viewer->setRenderingMode(debug ? VTKRenderer::Mode::DEBUG : VTKRenderer::Mode::SIMULATION); + m_viewer->setRenderingMode(debug ? Renderer::Mode::DEBUG : Renderer::Mode::SIMULATION); // Start Rendering if (!m_viewer->isRendering()) @@ -476,7 +488,7 @@ SimulationManager::endSimulation() } // Update Renderer - m_viewer->setRenderingMode(VTKRenderer::Mode::DEBUG); + m_viewer->setRenderingMode(Renderer::Mode::DEBUG); // End modules for(const auto& pair : m_modulesMap) diff --git a/Source/SimulationManager/imstkSimulationManager.h b/Source/SimulationManager/imstkSimulationManager.h index 02187b6801c8c9fa129a7dfdbe498971eb1c15a9..a888fe06484df35a0017214e019bb19765194d54 100644 --- a/Source/SimulationManager/imstkSimulationManager.h +++ b/Source/SimulationManager/imstkSimulationManager.h @@ -27,12 +27,17 @@ #include <thread> #include <memory> -#include "imstkVTKRenderer.h" #include "imstkScene.h" #include "imstkModule.h" #include "imstkSceneManager.h" -#include "imstkVTKViewer.h" #include "imstkLogUtility.h" +#include "imstkViewer.h" + +#ifdef iMSTK_USE_Vulkan +#include "imstkVulkanViewer.h" +#else +#include "imstkVTKViewer.h" +#endif namespace imstk { @@ -49,11 +54,7 @@ public: /// /// \brief Constructor /// - SimulationManager() - { - // Init g3logger - m_logUtil->createLogger("simulation", "./"); - } + SimulationManager(); /// /// \brief Default destructor @@ -131,10 +132,8 @@ public: /// void removeModule(const std::string& moduleName); - /// - /// \brief Returns the vtk viewer - /// - std::shared_ptr<VTKViewer> getViewer() const; + // Viewer + std::shared_ptr<Viewer> getViewer() const; // Simulation @@ -202,7 +201,7 @@ private: std::unordered_map<std::string, std::thread> m_threadMap; - std::shared_ptr<VTKViewer> m_viewer = std::make_shared<VTKViewer>(this); + std::shared_ptr<Viewer> m_viewer; std::shared_ptr<LogUtility> m_logUtil = std::make_shared<LogUtility>(); }; } // imstk diff --git a/Source/SimulationManager/imstkViewer.cpp b/Source/SimulationManager/imstkViewer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..24230e4a2e2d4f4eca0abdf1ef3ed84b4dc44f21 --- /dev/null +++ b/Source/SimulationManager/imstkViewer.cpp @@ -0,0 +1,49 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#include "imstkViewer.h" + +namespace imstk +{ +std::shared_ptr<Scene> +Viewer::getActiveScene() const +{ + return m_activeScene; +} + +std::shared_ptr<Renderer> +Viewer::getActiveRenderer() const +{ + return m_rendererMap.at(m_activeScene); +} + +const bool& +Viewer::isRendering() const +{ + return m_running; +} + +std::shared_ptr<ScreenCaptureUtility> +Viewer::getScreenCaptureUtility() const +{ + return m_screenCapturer; +} +} \ No newline at end of file diff --git a/Source/SimulationManager/imstkViewer.h b/Source/SimulationManager/imstkViewer.h new file mode 100644 index 0000000000000000000000000000000000000000..5874874264ee59b1434470d3d67647b8c28bf4ce --- /dev/null +++ b/Source/SimulationManager/imstkViewer.h @@ -0,0 +1,103 @@ +/*========================================================================= + + Library: iMSTK + + Copyright (c) Kitware, Inc. & Center for Modeling, Simulation, + & Imaging in Medicine, Rensselaer Polytechnic Institute. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0.txt + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=========================================================================*/ + +#ifndef imstkViewer_h +#define imstkViewer_h + +#include <memory> +#include "imstkScene.h" +#include "imstkRenderer.h" +#include "imstkScreenCaptureUtility.h" + +namespace imstk +{ +class SimulationManager; + +class Viewer +{ +public: + + Viewer(){}; + + Viewer(SimulationManager * manager){}; + + /// + /// \brief Get scene currently being rendered + /// + std::shared_ptr<Scene> getActiveScene() const; + + /// + /// \brief Set scene to be rendered + /// + virtual void setActiveScene(std::shared_ptr<Scene>scene){}; + + /// + /// \brief Start rendering + /// + virtual void startRenderingLoop(){}; + + /// + /// \brief Terminate rendering + /// + virtual void endRenderingLoop(){}; + + /// + /// \brief Setup the current renderer to render what's needed + /// based on the mode chosen + /// + virtual void setRenderingMode(Renderer::Mode mode){}; + + /// + /// \brief Get the current renderer's mode + /// + virtual const Renderer::Mode getRenderingMode(){ return Renderer::Mode::EMPTY; }; + + /// + /// \brief Returns true if the Viewer is rendering + /// + const bool& isRendering() const; + + /// + /// \brief Retrieve the renderer associated with the current scene + /// + std::shared_ptr<Renderer> getActiveRenderer() const; + + /// + /// \brief access screen shot utility + /// + std::shared_ptr<ScreenCaptureUtility> getScreenCaptureUtility() const; + + /// + /// \brief Set the coloring of the screen background + /// If 'gradientBackground' is false or not supplied color1 will fill the entire background + /// + virtual void setBackgroundColors(const Vec3d color1, const Vec3d color2 = Vec3d::Zero(), const bool gradientBackground = false){}; + +protected: + std::shared_ptr<Scene> m_activeScene; + + std::unordered_map<std::shared_ptr<Scene>, std::shared_ptr<Renderer>> m_rendererMap; + bool m_running = false; + std::shared_ptr<ScreenCaptureUtility> m_screenCapturer; ///> Screen shot utility +}; +} + +#endif \ No newline at end of file