/* * Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved. * * 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 * * 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. * * SPDX-FileCopyrightText: Copyright (c) 2014-2021 NVIDIA CORPORATION * SPDX-License-Identifier: Apache-2.0 */ // ImGui - standalone example application for Glfw + Vulkan, using programmable // pipeline If you are new to ImGui, see examples/README.txt and documentation // at the top of imgui.cpp. #include #include VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE #include "backends/imgui_impl_glfw.h" #include "imgui.h" #include "hello_vulkan.h" #include "nvh/cameramanipulator.hpp" #include "nvh/fileoperations.hpp" #include "nvpsystem.hpp" #include "nvvk/appbase_vkpp.hpp" #include "nvvk/commands_vk.hpp" #include "nvvk/context_vk.hpp" #include "imgui/imgui_camera_widget.h" #include ////////////////////////////////////////////////////////////////////////// #define UNUSED(x) (void)(x) ////////////////////////////////////////////////////////////////////////// // Default search path for shaders std::vector defaultSearchPaths; // GLFW Callback functions static void onErrorCallback(int error, const char* description) { fprintf(stderr, "GLFW Error %d: %s\n", error, description); } // Extra UI void renderUI(HelloVulkan& helloVk) { bool changed = false; changed |= ImGuiH::CameraWidget(); if(ImGui::CollapsingHeader("Light")) { changed |= ImGui::RadioButton("Point", &helloVk.m_pushConstants.lightType, 0); ImGui::SameLine(); changed |= ImGui::RadioButton("Spot", &helloVk.m_pushConstants.lightType, 1); ImGui::SameLine(); changed |= ImGui::RadioButton("Infinite", &helloVk.m_pushConstants.lightType, 2); if(helloVk.m_pushConstants.lightType < 2) { changed |= ImGui::SliderFloat3("Light Position", &helloVk.m_pushConstants.lightPosition.x, -20.f, 20.f); } if(helloVk.m_pushConstants.lightType > 0) { changed |= ImGui::SliderFloat3("Light Direction", &helloVk.m_pushConstants.lightDirection.x, -1.f, 1.f); } if(helloVk.m_pushConstants.lightType < 2) { changed |= ImGui::SliderFloat("Light Intensity", &helloVk.m_pushConstants.lightIntensity, 0.f, 500.f); } if(helloVk.m_pushConstants.lightType == 1) { float dCutoff = rad2deg(acos(helloVk.m_pushConstants.lightSpotCutoff)); float dOutCutoff = rad2deg(acos(helloVk.m_pushConstants.lightSpotOuterCutoff)); changed |= ImGui::SliderFloat("Cutoff", &dCutoff, 0.f, 45.f); changed |= ImGui::SliderFloat("OutCutoff", &dOutCutoff, 0.f, 45.f); dCutoff = dCutoff > dOutCutoff ? dOutCutoff : dCutoff; helloVk.m_pushConstants.lightSpotCutoff = cos(deg2rad(dCutoff)); helloVk.m_pushConstants.lightSpotOuterCutoff = cos(deg2rad(dOutCutoff)); } } changed |= ImGui::SliderInt("Max Frames", &helloVk.m_maxFrames, 1, 1000); if(changed) helloVk.resetFrame(); } ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// static int const SAMPLE_WIDTH = 1280; static int const SAMPLE_HEIGHT = 720; //-------------------------------------------------------------------------------------------------- // Application Entry // int main(int argc, char** argv) { UNUSED(argc); // Setup GLFW window glfwSetErrorCallback(onErrorCallback); if(!glfwInit()) { return 1; } glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); GLFWwindow* window = glfwCreateWindow(SAMPLE_WIDTH, SAMPLE_HEIGHT, PROJECT_NAME, nullptr, nullptr); // Setup camera CameraManip.setWindowSize(SAMPLE_WIDTH, SAMPLE_HEIGHT); CameraManip.setLookat({8.440, 9.041, -8.973}, {-2.462, 3.661, -0.286}, {0.000, 1.000, 0.000}); // Setup Vulkan if(!glfwVulkanSupported()) { printf("GLFW: Vulkan Not Supported\n"); return 1; } // setup some basic things for the sample, logging file for example NVPSystem system(PROJECT_NAME); // Search path for shaders and other media defaultSearchPaths = { NVPSystem::exePath() + PROJECT_RELDIRECTORY, NVPSystem::exePath() + PROJECT_RELDIRECTORY "..", std::string(PROJECT_NAME), }; // Requesting Vulkan extensions and layers nvvk::ContextCreateInfo contextInfo(true); contextInfo.setVersion(1, 2); contextInfo.addInstanceLayer("VK_LAYER_LUNARG_monitor", true); contextInfo.addInstanceExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, true); contextInfo.addInstanceExtension(VK_KHR_SURFACE_EXTENSION_NAME); #ifdef WIN32 contextInfo.addInstanceExtension(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #else contextInfo.addInstanceExtension(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); contextInfo.addInstanceExtension(VK_KHR_XCB_SURFACE_EXTENSION_NAME); #endif contextInfo.addInstanceExtension(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME); // #VKRay: Activate the ray tracing extension contextInfo.addDeviceExtension(VK_KHR_MAINTENANCE3_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_PIPELINE_LIBRARY_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME); contextInfo.addDeviceExtension(VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME); // #VKRay: Activate the ray tracing extension vk::PhysicalDeviceAccelerationStructureFeaturesKHR accelFeature; contextInfo.addDeviceExtension(VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, false, &accelFeature); vk::PhysicalDeviceRayTracingPipelineFeaturesKHR rtPipelineFeature; contextInfo.addDeviceExtension(VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, false, &rtPipelineFeature); // Creating Vulkan base application nvvk::Context vkctx{}; vkctx.initInstance(contextInfo); // Find all compatible devices auto compatibleDevices = vkctx.getCompatibleDevices(contextInfo); assert(!compatibleDevices.empty()); // Use a compatible device vkctx.initDevice(compatibleDevices[0], contextInfo); // Create example HelloVulkan helloVk; // Window need to be opened to get the surface on which to draw const vk::SurfaceKHR surface = helloVk.getVkSurface(vkctx.m_instance, window); vkctx.setGCTQueueWithPresent(surface); helloVk.setup(vkctx.m_instance, vkctx.m_device, vkctx.m_physicalDevice, vkctx.m_queueGCT.familyIndex); helloVk.createSwapchain(surface, SAMPLE_WIDTH, SAMPLE_HEIGHT); helloVk.createDepthBuffer(); helloVk.createRenderPass(); helloVk.createFrameBuffers(); // Setup Imgui helloVk.initGUI(0); // Using sub-pass 0 // Creating scene helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true)); helloVk.loadModel(nvh::findFile("media/scenes/wuson.obj", defaultSearchPaths, true), nvmath::scale_mat4(nvmath::vec3f(0.5f)) * nvmath::translation_mat4(nvmath::vec3f(0.0f, 0.0f, 6.0f))); std::random_device rd; // Will be used to obtain a seed for the random number engine std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd() std::normal_distribution dis(2.0f, 2.0f); std::normal_distribution disn(0.5f, 0.2f); int wusonIndex = static_cast(helloVk.m_objModel.size() - 1); for(int n = 0; n < 50; ++n) { ObjInstance inst; inst.objIndex = wusonIndex; inst.txtOffset = 0; float scale = fabsf(disn(gen)); nvmath::mat4f mat = nvmath::translation_mat4(nvmath::vec3f{dis(gen), 0.f, dis(gen) + 6}); // mat = mat * nvmath::rotation_mat4_x(dis(gen)); mat = mat * nvmath::scale_mat4(nvmath::vec3f(scale)); inst.transform = mat; inst.transformIT = nvmath::transpose(nvmath::invert((inst.transform))); helloVk.m_objInstance.push_back(inst); } // Creation of implicit geometry MaterialObj mat; // Reflective mat.diffuse = nvmath::vec3f(0, 0, 0); mat.specular = nvmath::vec3f(1.f); mat.shininess = 0.0; mat.illum = 3; helloVk.addImplMaterial(mat); // Transparent mat.diffuse = nvmath::vec3f(0.4, 0.4, 1); mat.illum = 4; mat.dissolve = 0.5; helloVk.addImplMaterial(mat); helloVk.addImplCube({-6.1, 0, -6}, {-6, 10, 6}, 0); helloVk.addImplSphere({1, 2, 4}, 1.f, 1); helloVk.initOffscreen(); Offscreen& offscreen = helloVk.offscreen(); helloVk.createImplictBuffers(); helloVk.createDescriptorSetLayout(); helloVk.createGraphicsPipeline(); helloVk.createUniformBuffer(); helloVk.createSceneDescriptionBuffer(); helloVk.updateDescriptorSet(); // #VKRay helloVk.initRayTracing(); nvmath::vec4f clearColor = nvmath::vec4f(1, 1, 1, 1.00f); bool useRaytracer = true; helloVk.setupGlfwCallbacks(window); ImGui_ImplGlfw_InitForVulkan(window, true); // Main loop while(!glfwWindowShouldClose(window)) { glfwPollEvents(); if(helloVk.isMinimized()) continue; // Start the Dear ImGui frame ImGui_ImplGlfw_NewFrame(); // Show UI window. if(helloVk.showGui()) { ImGui::NewFrame(); ImGuiH::Panel::Begin(); bool changed = false; // Edit 3 floats representing a color changed |= ImGui::ColorEdit3("Clear color", reinterpret_cast(&clearColor)); // Switch between raster and ray tracing changed |= ImGui::Checkbox("Ray Tracer mode", &useRaytracer); if(changed) helloVk.resetFrame(); renderUI(helloVk); ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); ImGuiH::Control::Info("", "", "(F10) Toggle Pane", ImGuiH::Control::Flags::Disabled); ImGuiH::Panel::End(); } // Start rendering the scene helloVk.prepareFrame(); // Start command buffer of this frame auto curFrame = helloVk.getCurFrame(); const vk::CommandBuffer& cmdBuf = helloVk.getCommandBuffers()[curFrame]; cmdBuf.begin({vk::CommandBufferUsageFlagBits::eOneTimeSubmit}); // Updating camera buffer helloVk.updateUniformBuffer(cmdBuf); // Clearing screen std::array clearValues; clearValues[0].setColor( std::array({clearColor[0], clearColor[1], clearColor[2], clearColor[3]})); clearValues[1].setDepthStencil({1.0f, 0}); // Offscreen render pass { vk::RenderPassBeginInfo offscreenRenderPassBeginInfo; offscreenRenderPassBeginInfo.setClearValueCount(2); offscreenRenderPassBeginInfo.setPClearValues(clearValues.data()); offscreenRenderPassBeginInfo.setRenderPass(offscreen.renderPass()); offscreenRenderPassBeginInfo.setFramebuffer(offscreen.frameBuffer()); offscreenRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); // Rendering Scene if(useRaytracer) { helloVk.raytrace(cmdBuf, clearColor); } else { cmdBuf.beginRenderPass(offscreenRenderPassBeginInfo, vk::SubpassContents::eInline); helloVk.rasterize(cmdBuf); cmdBuf.endRenderPass(); } } // 2nd rendering pass: tone mapper, UI { vk::RenderPassBeginInfo postRenderPassBeginInfo; postRenderPassBeginInfo.setClearValueCount(2); postRenderPassBeginInfo.setPClearValues(clearValues.data()); postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass()); postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]); postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()}); cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline); // Rendering tonemapper offscreen.draw(cmdBuf, helloVk.getSize()); // Rendering UI ImGui::Render(); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmdBuf); cmdBuf.endRenderPass(); } // Submit for display cmdBuf.end(); helloVk.submitFrame(); } // Cleanup helloVk.getDevice().waitIdle(); helloVk.destroyResources(); helloVk.destroy(); vkctx.deinit(); glfwDestroyWindow(window); glfwTerminate(); return 0; }