Add vk_ray_trace_indirect_scissor sample
This commit is contained in:
parent
27d8a79ce3
commit
a6690f149a
30 changed files with 4498 additions and 6 deletions
111
ray_tracing_indirect_scissor/CMakeLists.txt
Normal file
111
ray_tracing_indirect_scissor/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
#*****************************************************************************
|
||||
# Copyright 2020 NVIDIA Corporation. All rights reserved.
|
||||
#*****************************************************************************
|
||||
|
||||
cmake_minimum_required(VERSION 3.9.6 FATAL_ERROR)
|
||||
|
||||
#--------------------------------------------------------------------------------------------------
|
||||
# Project setting
|
||||
get_filename_component(PROJNAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
|
||||
SET(PROJNAME vk_${PROJNAME}_KHR)
|
||||
project(${PROJNAME} LANGUAGES C CXX)
|
||||
message(STATUS "-------------------------------")
|
||||
message(STATUS "Processing Project ${PROJNAME}:")
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------------------------------
|
||||
# C++ target and defines
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
add_executable(${PROJNAME})
|
||||
_add_project_definitions(${PROJNAME})
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------------------------------
|
||||
# Source files for this project
|
||||
#
|
||||
file(GLOB SOURCE_FILES *.cpp *.hpp *.inl *.h *.c)
|
||||
file(GLOB EXTRA_COMMON ${TUTO_KHR_DIR}/common/*.*)
|
||||
list(APPEND COMMON_SOURCE_FILES ${EXTRA_COMMON})
|
||||
include_directories(${TUTO_KHR_DIR}/common)
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------------------------------
|
||||
# GLSL to SPIR-V custom build
|
||||
#
|
||||
SET(VULKAN_TARGET_ENV vulkan1.2)
|
||||
UNSET(GLSL_SOURCES)
|
||||
UNSET(SPV_OUTPUT)
|
||||
file(GLOB_RECURSE GLSL_HEADER_FILES "shaders/*.h" "shaders/*.glsl")
|
||||
file(GLOB_RECURSE GLSL_SOURCE_FILES
|
||||
"shaders/*.comp"
|
||||
"shaders/*.frag"
|
||||
"shaders/*.vert"
|
||||
"shaders/*.rchit"
|
||||
"shaders/*.rahit"
|
||||
"shaders/*.rint"
|
||||
"shaders/*.rmiss"
|
||||
"shaders/*.rgen"
|
||||
"shaders/*.rcall"
|
||||
)
|
||||
foreach(GLSL ${GLSL_SOURCE_FILES})
|
||||
get_filename_component(FILE_NAME ${GLSL} NAME)
|
||||
_compile_GLSL(${GLSL} "shaders/${FILE_NAME}.spv" GLSL_SOURCES SPV_OUTPUT)
|
||||
endforeach(GLSL)
|
||||
list(APPEND GLSL_SOURCES ${GLSL_HEADER_FILES})
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------------------------------
|
||||
# Sources
|
||||
target_sources(${PROJNAME} PUBLIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||
target_sources(${PROJNAME} PUBLIC ${COMMON_SOURCE_FILES})
|
||||
target_sources(${PROJNAME} PUBLIC ${PACKAGE_SOURCE_FILES})
|
||||
target_sources(${PROJNAME} PUBLIC ${GLSL_SOURCES})
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------------------------------
|
||||
# Sub-folders in Visual Studio
|
||||
#
|
||||
source_group("Common" FILES ${COMMON_SOURCE_FILES} ${PACKAGE_SOURCE_FILES})
|
||||
source_group("Sources" FILES ${SOURCE_FILES})
|
||||
source_group("Headers" FILES ${HEADER_FILES})
|
||||
source_group("Shader_Files" FILES ${GLSL_SOURCES})
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------------------------------
|
||||
# Linkage
|
||||
#
|
||||
target_link_libraries(${PROJNAME} ${PLATFORM_LIBRARIES} shared_sources)
|
||||
|
||||
foreach(DEBUGLIB ${LIBRARIES_DEBUG})
|
||||
target_link_libraries(${PROJNAME} debug ${DEBUGLIB})
|
||||
endforeach(DEBUGLIB)
|
||||
|
||||
foreach(RELEASELIB ${LIBRARIES_OPTIMIZED})
|
||||
target_link_libraries(${PROJNAME} optimized ${RELEASELIB})
|
||||
endforeach(RELEASELIB)
|
||||
|
||||
#--------------------------------------------------------------------------------------------------
|
||||
# copies binaries that need to be put next to the exe files (ZLib, etc.)
|
||||
#
|
||||
_copy_binaries_to_target( ${PROJNAME} )
|
||||
|
||||
|
||||
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}/shaders")
|
||||
#install(FILES ${SPV_OUTPUT} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}/shaders")
|
||||
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
|
||||
#install(FILES ${CUBIN_SOURCES} CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
|
||||
#install(DIRECTORY "../media" CONFIGURATIONS Release DESTINATION "bin_${ARCH}/${PROJNAME}")
|
||||
#install(DIRECTORY "../media" CONFIGURATIONS Debug DESTINATION "bin_${ARCH}_debug/${PROJNAME}")
|
||||
|
||||
#----------------------------------------------------------------------------------------------------
|
||||
# Copying elements
|
||||
# Media
|
||||
# target_copy_to_output_dir(TARGET ${PROJECT_NAME} FILES "${TUTO_KHR_DIR}/media")
|
||||
# Spir-V Shaders
|
||||
target_copy_to_output_dir(
|
||||
TARGET ${PROJECT_NAME}
|
||||
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEST_SUBFOLDER "${PROJECT_NAME}/"
|
||||
FILES ${SPV_OUTPUT}
|
||||
)
|
||||
|
||||
14
ray_tracing_indirect_scissor/README.md
Normal file
14
ray_tracing_indirect_scissor/README.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# NVIDIA Vulkan Ray Tracing Tutorial
|
||||
|
||||
This example is the result of the ray tracing tutorial.
|
||||
The tutorial is adding ray tracing capability to an OBJ rasterizer in Vulkan
|
||||
|
||||
If you haven't done it, [**Start Ray Tracing Tutorial**](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/).
|
||||
|
||||

|
||||
|
||||
## Going Further
|
||||
|
||||
Once the tutorial completed and the basics of ray tracing are in place, other tuturials are going further from this code base.
|
||||
|
||||
See all other [additional ray tracing tutorials](https://nvpro-samples.github.io/vk_raytracing_tutorial_KHR/vkrt_tuto_further.md.html)
|
||||
1468
ray_tracing_indirect_scissor/hello_vulkan.cpp
Normal file
1468
ray_tracing_indirect_scissor/hello_vulkan.cpp
Normal file
File diff suppressed because it is too large
Load diff
278
ray_tracing_indirect_scissor/hello_vulkan.h
Normal file
278
ray_tracing_indirect_scissor/hello_vulkan.h
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#define NVVK_ALLOC_DEDICATED
|
||||
#include "nvvk/allocator_vk.hpp"
|
||||
#include "nvvk/appbase_vkpp.hpp"
|
||||
#include "nvvk/debug_util_vk.hpp"
|
||||
#include "nvvk/descriptorsets_vk.hpp"
|
||||
|
||||
// #VKRay
|
||||
#include "nvvk/raytraceKHR_vk.hpp"
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Simple rasterizer of OBJ objects
|
||||
// - Each OBJ loaded are stored in an `ObjModel` and referenced by a `ObjInstance`
|
||||
// - It is possible to have many `ObjInstance` referencing the same `ObjModel`
|
||||
// - Rendering is done in an offscreen framebuffer
|
||||
// - The image of the framebuffer is displayed in post-process in a full-screen quad
|
||||
//
|
||||
class HelloVulkan : public nvvk::AppBase
|
||||
{
|
||||
public:
|
||||
void setup(const vk::Instance& instance,
|
||||
const vk::Device& device,
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
uint32_t queueFamily) override;
|
||||
void createDescriptorSetLayout();
|
||||
void createGraphicsPipeline();
|
||||
void loadModel(const std::string& filename, nvmath::mat4f transform = nvmath::mat4f(1));
|
||||
void addLantern(nvmath::vec3f pos, nvmath::vec3f color, float brightness, float radius);
|
||||
void updateDescriptorSet();
|
||||
void createUniformBuffer();
|
||||
void createSceneDescriptionBuffer();
|
||||
void createTextureImages(const vk::CommandBuffer& cmdBuf,
|
||||
const std::vector<std::string>& textures);
|
||||
|
||||
nvmath::mat4 getViewMatrix()
|
||||
{
|
||||
return CameraManip.getMatrix();
|
||||
}
|
||||
|
||||
static constexpr float nearZ = 0.1f;
|
||||
nvmath::mat4 getProjMatrix()
|
||||
{
|
||||
const float aspectRatio = m_size.width / static_cast<float>(m_size.height);
|
||||
return nvmath::perspectiveVK(CameraManip.getFov(), aspectRatio, nearZ, 1000.0f);
|
||||
}
|
||||
|
||||
void updateUniformBuffer(const vk::CommandBuffer&);
|
||||
void onResize(int /*w*/, int /*h*/) override;
|
||||
void destroyResources();
|
||||
void rasterize(const vk::CommandBuffer& cmdBuff);
|
||||
|
||||
// The OBJ model
|
||||
struct ObjModel
|
||||
{
|
||||
uint32_t nbIndices{0};
|
||||
uint32_t nbVertices{0};
|
||||
nvvk::Buffer vertexBuffer; // Device buffer of all 'Vertex'
|
||||
nvvk::Buffer indexBuffer; // Device buffer of the indices forming triangles
|
||||
nvvk::Buffer matColorBuffer; // Device buffer of array of 'Wavefront material'
|
||||
nvvk::Buffer matIndexBuffer; // Device buffer of array of 'Wavefront material'
|
||||
};
|
||||
|
||||
// Instance of the OBJ
|
||||
struct ObjInstance
|
||||
{
|
||||
uint32_t objIndex{0}; // Reference to the `m_objModel`
|
||||
uint32_t txtOffset{0}; // Offset in `m_textures`
|
||||
nvmath::mat4f transform{1}; // Position of the instance
|
||||
nvmath::mat4f transformIT{1}; // Inverse transpose
|
||||
};
|
||||
|
||||
// Information pushed at each draw call
|
||||
struct ObjPushConstant
|
||||
{
|
||||
nvmath::vec3f lightPosition{10.f, 15.f, 8.f};
|
||||
int instanceId{0}; // To retrieve the transformation matrix
|
||||
float lightIntensity{40.f};
|
||||
int lightType{0}; // 0: point, 1: infinite
|
||||
};
|
||||
ObjPushConstant m_pushConstant;
|
||||
|
||||
// Information on each colored lantern illuminating the scene.
|
||||
struct Lantern
|
||||
{
|
||||
nvmath::vec3f position;
|
||||
nvmath::vec3f color;
|
||||
float brightness;
|
||||
float radius; // Max world-space distance that light illuminates.
|
||||
};
|
||||
|
||||
// Information on each colored lantern, plus the info needed for dispatching the
|
||||
// indirect ray trace command used to add its brightness effect.
|
||||
// The dispatched ray trace covers pixels (offsetX, offsetY) to
|
||||
// (offsetX + indirectCommand.width - 1, offsetY + indirectCommand.height - 1).
|
||||
struct LanternIndirectEntry
|
||||
{
|
||||
// Filled in by the device using a compute shader.
|
||||
// NOTE: I rely on indirectCommand being the first member.
|
||||
VkTraceRaysIndirectCommandKHR indirectCommand;
|
||||
int32_t offsetX;
|
||||
int32_t offsetY;
|
||||
|
||||
// Filled in by the host.
|
||||
Lantern lantern;
|
||||
};
|
||||
|
||||
// Array of objects and instances in the scene. Not modifiable after acceleration structure build.
|
||||
std::vector<ObjModel> m_objModel;
|
||||
std::vector<ObjInstance> m_objInstance;
|
||||
|
||||
// Array of lanterns in scene. Not modifiable after acceleration structure build.
|
||||
std::vector<Lantern> m_lanterns;
|
||||
|
||||
// Graphic pipeline
|
||||
vk::PipelineLayout m_pipelineLayout;
|
||||
vk::Pipeline m_graphicsPipeline;
|
||||
nvvk::DescriptorSetBindings m_descSetLayoutBind;
|
||||
vk::DescriptorPool m_descPool;
|
||||
vk::DescriptorSetLayout m_descSetLayout;
|
||||
vk::DescriptorSet m_descSet;
|
||||
|
||||
nvvk::Buffer m_cameraMat; // Device-Host of the camera matrices
|
||||
nvvk::Buffer m_sceneDesc; // Device buffer of the OBJ instances
|
||||
std::vector<nvvk::Texture> m_textures; // vector of all textures of the scene
|
||||
|
||||
nvvk::AllocatorDedicated m_alloc; // Allocator for buffer, images, acceleration structures
|
||||
nvvk::DebugUtil m_debug; // Utility to name objects
|
||||
|
||||
// #Post
|
||||
void createOffscreenRender();
|
||||
void createPostPipeline();
|
||||
void createPostDescriptor();
|
||||
void updatePostDescriptorSet();
|
||||
void drawPost(vk::CommandBuffer cmdBuf);
|
||||
|
||||
nvvk::DescriptorSetBindings m_postDescSetLayoutBind;
|
||||
vk::DescriptorPool m_postDescPool;
|
||||
vk::DescriptorSetLayout m_postDescSetLayout;
|
||||
vk::DescriptorSet m_postDescSet;
|
||||
vk::Pipeline m_postPipeline;
|
||||
vk::PipelineLayout m_postPipelineLayout;
|
||||
vk::RenderPass m_offscreenRenderPass;
|
||||
vk::Framebuffer m_offscreenFramebuffer;
|
||||
nvvk::Texture m_offscreenColor;
|
||||
vk::Format m_offscreenColorFormat{vk::Format::eR32G32B32A32Sfloat};
|
||||
nvvk::Texture m_offscreenDepth;
|
||||
vk::Format m_offscreenDepthFormat{vk::Format::eD32Sfloat};
|
||||
|
||||
// #VKRay
|
||||
void initRayTracing();
|
||||
nvvk::RaytracingBuilderKHR::BlasInput objectToVkGeometryKHR(const ObjModel& model);
|
||||
|
||||
private:
|
||||
void fillLanternVerts(std::vector<nvmath::vec3f>& vertices, std::vector<uint32_t>& indices);
|
||||
void createLanternModel();
|
||||
|
||||
public:
|
||||
void createBottomLevelAS();
|
||||
void createTopLevelAS();
|
||||
void createRtDescriptorSet();
|
||||
void updateRtDescriptorSet();
|
||||
void createRtPipeline();
|
||||
void createLanternIndirectDescriptorSet();
|
||||
void createLanternIndirectCompPipeline();
|
||||
void createRtShaderBindingTable();
|
||||
void createLanternIndirectBuffer();
|
||||
|
||||
void raytrace(const vk::CommandBuffer& cmdBuf, const nvmath::vec4f& clearColor);
|
||||
|
||||
// Used to store lantern model, generated at runtime.
|
||||
const float m_lanternModelRadius = 0.125;
|
||||
nvvk::Buffer m_lanternVertexBuffer;
|
||||
nvvk::Buffer m_lanternIndexBuffer;
|
||||
nvvk::RaytracingBuilderKHR::BlasInput m_lanternBlasInput{};
|
||||
|
||||
// Index of lantern's BLAS in the BLAS array stored in m_rtBuilder.
|
||||
size_t m_lanternBlasId;
|
||||
|
||||
vk::PhysicalDeviceRayTracingPipelinePropertiesKHR m_rtProperties;
|
||||
nvvk::RaytracingBuilderKHR m_rtBuilder;
|
||||
nvvk::DescriptorSetBindings m_rtDescSetLayoutBind;
|
||||
vk::DescriptorPool m_rtDescPool;
|
||||
vk::DescriptorSetLayout m_rtDescSetLayout;
|
||||
vk::DescriptorSet m_rtDescSet;
|
||||
std::vector<vk::RayTracingShaderGroupCreateInfoKHR> m_rtShaderGroups;
|
||||
vk::PipelineLayout m_rtPipelineLayout;
|
||||
vk::Pipeline m_rtPipeline;
|
||||
nvvk::DescriptorSetBindings m_lanternIndirectDescSetLayoutBind;
|
||||
vk::DescriptorPool m_lanternIndirectDescPool;
|
||||
vk::DescriptorSetLayout m_lanternIndirectDescSetLayout;
|
||||
vk::DescriptorSet m_lanternIndirectDescSet;
|
||||
vk::PipelineLayout m_lanternIndirectCompPipelineLayout;
|
||||
vk::Pipeline m_lanternIndirectCompPipeline;
|
||||
nvvk::Buffer m_rtSBTBuffer;
|
||||
|
||||
// Buffer to source vkCmdTraceRaysIndirectKHR indirect parameters and lantern color,
|
||||
// position, etc. from when doing lantern lighting passes.
|
||||
nvvk::Buffer m_lanternIndirectBuffer;
|
||||
VkDeviceSize m_lanternCount = 0; // Set to actual lantern count after TLAS build, as
|
||||
// that is the point no more lanterns may be added.
|
||||
|
||||
// Push constant for ray trace pipeline.
|
||||
struct RtPushConstant
|
||||
{
|
||||
// Background color
|
||||
nvmath::vec4f clearColor;
|
||||
|
||||
// Information on the light in the sky used when lanternPassNumber = -1.
|
||||
nvmath::vec3f lightPosition;
|
||||
float lightIntensity;
|
||||
int32_t lightType;
|
||||
|
||||
// -1 if this is the full-screen pass. Otherwise, this pass is to add light
|
||||
// from lantern number lanternPassNumber. We use this to lookup trace indirect
|
||||
// parameters in m_lanternIndirectBuffer.
|
||||
int32_t lanternPassNumber;
|
||||
|
||||
// Pixel dimensions of the output image.
|
||||
int32_t screenX;
|
||||
int32_t screenY;
|
||||
|
||||
// See m_lanternDebug.
|
||||
int32_t lanternDebug;
|
||||
} m_rtPushConstants;
|
||||
|
||||
// Copied to RtPushConstant::lanternDebug. If true,
|
||||
// make lantern produce constant light regardless of distance
|
||||
// so that I can see the screen rectangle coverage.
|
||||
bool m_lanternDebug = false;
|
||||
|
||||
|
||||
// Push constant for compute shader filling lantern indirect buffer.
|
||||
// Barely fits in 128-byte push constant limit guaranteed by spec.
|
||||
struct LanternIndirectPushConstants
|
||||
{
|
||||
nvmath::vec4 viewRowX; // First 3 rows of view matrix.
|
||||
nvmath::vec4 viewRowY; // Set w=1 implicitly in shader.
|
||||
nvmath::vec4 viewRowZ;
|
||||
|
||||
nvmath::mat4 proj; // Perspective matrix
|
||||
float nearZ; // Near plane used to create projection matrix.
|
||||
|
||||
// Pixel dimensions of output image (needed to scale NDC to screen coordinates).
|
||||
int32_t screenX;
|
||||
int32_t screenY;
|
||||
|
||||
// Length of the LanternIndirectEntry array.
|
||||
int32_t lanternCount;
|
||||
} m_lanternIndirectPushConstants;
|
||||
};
|
||||
324
ray_tracing_indirect_scissor/main.cpp
Normal file
324
ray_tracing_indirect_scissor/main.cpp
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
/* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
||||
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// 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 <array>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_impl_glfw.h"
|
||||
|
||||
#include "hello_vulkan.h"
|
||||
#include "imgui_camera_widget.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"
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
#define UNUSED(x) (void)(x)
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Default search path for shaders
|
||||
std::vector<std::string> 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)
|
||||
{
|
||||
ImGuiH::CameraWidget();
|
||||
if(ImGui::CollapsingHeader("Light"))
|
||||
{
|
||||
ImGui::RadioButton("Point", &helloVk.m_pushConstant.lightType, 0);
|
||||
ImGui::SameLine();
|
||||
ImGui::RadioButton("Infinite", &helloVk.m_pushConstant.lightType, 1);
|
||||
|
||||
ImGui::SliderFloat3("Position", &helloVk.m_pushConstant.lightPosition.x, -20.f, 20.f);
|
||||
ImGui::SliderFloat("Intensity", &helloVk.m_pushConstant.lightIntensity, 0.f, 150.f);
|
||||
ImGui::Checkbox("Lantern Debug", &helloVk.m_lanternDebug);
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
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(nvmath::vec3f(5, 4, -4), nvmath::vec3f(0, 1, 0), nvmath::vec3f(0, 1, 0));
|
||||
|
||||
// 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(argv[0], PROJECT_NAME);
|
||||
|
||||
// Search path for shaders and other media
|
||||
defaultSearchPaths = {
|
||||
PROJECT_ABSDIRECTORY,
|
||||
PROJECT_ABSDIRECTORY "..",
|
||||
NVPSystem::exePath(),
|
||||
NVPSystem::exePath() + "..",
|
||||
NVPSystem::exePath() + 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);
|
||||
// #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);
|
||||
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);
|
||||
|
||||
|
||||
// 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
|
||||
|
||||
// Creation of the example
|
||||
helloVk.loadModel(nvh::findFile("media/scenes/Medieval_building.obj", defaultSearchPaths, true));
|
||||
helloVk.loadModel(nvh::findFile("media/scenes/plane.obj", defaultSearchPaths, true));
|
||||
helloVk.addLantern({ 8.000f, 1.100f, 3.600f}, {1.0f, 0.0f, 0.0f}, 0.4f, 4.0f);
|
||||
helloVk.addLantern({ 8.000f, 0.600f, 3.900f}, {0.0f, 1.0f, 0.0f}, 0.4f, 4.0f);
|
||||
helloVk.addLantern({ 8.000f, 1.100f, 4.400f}, {0.0f, 0.0f, 1.0f}, 0.4f, 4.0f);
|
||||
helloVk.addLantern({ 1.730f, 1.812f, -1.604f}, {0.0f, 0.4f, 0.4f}, 0.4f, 4.0f);
|
||||
helloVk.addLantern({ 1.730f, 1.862f, 1.916f}, {0.0f, 0.2f, 0.4f}, 0.3f, 3.0f);
|
||||
helloVk.addLantern({-2.000f, 1.900f, -0.700f}, {0.8f, 0.8f, 0.6f}, 0.4f, 3.9f);
|
||||
helloVk.addLantern({ 0.100f, 0.080f, -2.392f}, {1.0f, 0.0f, 1.0f}, 0.5f, 5.0f);
|
||||
helloVk.addLantern({ 1.948f, 0.080f, 0.598f}, {1.0f, 1.0f, 1.0f}, 0.6f, 6.0f);
|
||||
helloVk.addLantern({-2.300f, 0.080f, 2.100f}, {0.0f, 0.7f, 0.0f}, 0.6f, 6.0f);
|
||||
helloVk.addLantern({-1.400f, 4.300f, 0.150f}, {1.0f, 1.0f, 0.0f}, 0.7f, 7.0f);
|
||||
|
||||
helloVk.createOffscreenRender();
|
||||
helloVk.createDescriptorSetLayout();
|
||||
helloVk.createGraphicsPipeline();
|
||||
helloVk.createUniformBuffer();
|
||||
helloVk.createSceneDescriptionBuffer();
|
||||
helloVk.updateDescriptorSet();
|
||||
|
||||
// #VKRay
|
||||
helloVk.initRayTracing();
|
||||
helloVk.createBottomLevelAS();
|
||||
helloVk.createTopLevelAS();
|
||||
helloVk.createLanternIndirectBuffer();
|
||||
helloVk.createRtDescriptorSet();
|
||||
helloVk.createRtPipeline();
|
||||
helloVk.createLanternIndirectDescriptorSet();
|
||||
helloVk.createLanternIndirectCompPipeline();
|
||||
helloVk.createRtShaderBindingTable();
|
||||
|
||||
helloVk.createPostDescriptor();
|
||||
helloVk.createPostPipeline();
|
||||
helloVk.updatePostDescriptorSet();
|
||||
|
||||
|
||||
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();
|
||||
ImGui::NewFrame();
|
||||
|
||||
// Show UI window.
|
||||
if(helloVk.showGui())
|
||||
{
|
||||
ImGuiH::Panel::Begin();
|
||||
ImGui::ColorEdit3("Clear color", reinterpret_cast<float*>(&clearColor));
|
||||
ImGui::Checkbox("Ray Tracer mode", &useRaytracer); // Switch between raster and ray tracing
|
||||
|
||||
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
|
||||
vk::ClearValue clearValues[2];
|
||||
clearValues[0].setColor(
|
||||
std::array<float, 4>({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);
|
||||
offscreenRenderPassBeginInfo.setRenderPass(helloVk.m_offscreenRenderPass);
|
||||
offscreenRenderPassBeginInfo.setFramebuffer(helloVk.m_offscreenFramebuffer);
|
||||
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);
|
||||
postRenderPassBeginInfo.setRenderPass(helloVk.getRenderPass());
|
||||
postRenderPassBeginInfo.setFramebuffer(helloVk.getFramebuffers()[curFrame]);
|
||||
postRenderPassBeginInfo.setRenderArea({{}, helloVk.getSize()});
|
||||
|
||||
cmdBuf.beginRenderPass(postRenderPassBeginInfo, vk::SubpassContents::eInline);
|
||||
// Rendering tonemapper
|
||||
helloVk.drawPost(cmdBuf);
|
||||
// Rendering UI
|
||||
ImGui::Render();
|
||||
ImGui::RenderDrawDataVK(cmdBuf, ImGui::GetDrawData());
|
||||
cmdBuf.endRenderPass();
|
||||
}
|
||||
|
||||
// Submit for display
|
||||
cmdBuf.end();
|
||||
helloVk.submitFrame();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
helloVk.getDevice().waitIdle();
|
||||
helloVk.destroyResources();
|
||||
helloVk.destroy();
|
||||
|
||||
vkctx.deinit();
|
||||
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
struct LanternIndirectEntry
|
||||
{
|
||||
// VkTraceRaysIndirectCommandKHR
|
||||
int indirectWidth;
|
||||
int indirectHeight;
|
||||
int indirectDepth;
|
||||
|
||||
// Pixel coordinate of scissor rect upper-left.
|
||||
int offsetX;
|
||||
int offsetY;
|
||||
|
||||
// Lantern starts here:
|
||||
// Can't use vec3 due to alignment.
|
||||
float x, y, z;
|
||||
float red, green, blue;
|
||||
float brightness;
|
||||
float radius;
|
||||
};
|
||||
79
ray_tracing_indirect_scissor/shaders/frag_shader.frag
Normal file
79
ray_tracing_indirect_scissor/shaders/frag_shader.frag
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#version 450
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_EXT_nonuniform_qualifier : enable
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
#extension GL_EXT_scalar_block_layout : enable
|
||||
|
||||
#include "wavefront.glsl"
|
||||
|
||||
|
||||
layout(push_constant) uniform shaderInformation
|
||||
{
|
||||
vec3 lightPosition;
|
||||
uint instanceId;
|
||||
float lightIntensity;
|
||||
int lightType;
|
||||
}
|
||||
pushC;
|
||||
|
||||
// clang-format off
|
||||
// Incoming
|
||||
//layout(location = 0) flat in int matIndex;
|
||||
layout(location = 1) in vec2 fragTexCoord;
|
||||
layout(location = 2) in vec3 fragNormal;
|
||||
layout(location = 3) in vec3 viewDir;
|
||||
layout(location = 4) in vec3 worldPos;
|
||||
// Outgoing
|
||||
layout(location = 0) out vec4 outColor;
|
||||
// Buffers
|
||||
layout(binding = 1, scalar) buffer MatColorBufferObject { WaveFrontMaterial m[]; } materials[];
|
||||
layout(binding = 2, scalar) buffer ScnDesc { sceneDesc i[]; } scnDesc;
|
||||
layout(binding = 3) uniform sampler2D[] textureSamplers;
|
||||
layout(binding = 4, scalar) buffer MatIndex { int i[]; } matIdx[];
|
||||
|
||||
// clang-format on
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
// Object of this instance
|
||||
int objId = scnDesc.i[pushC.instanceId].objId;
|
||||
|
||||
// Material of the object
|
||||
int matIndex = matIdx[nonuniformEXT(objId)].i[gl_PrimitiveID];
|
||||
WaveFrontMaterial mat = materials[nonuniformEXT(objId)].m[matIndex];
|
||||
|
||||
vec3 N = normalize(fragNormal);
|
||||
|
||||
// Vector toward light
|
||||
vec3 L;
|
||||
float lightIntensity = pushC.lightIntensity;
|
||||
if(pushC.lightType == 0)
|
||||
{
|
||||
vec3 lDir = pushC.lightPosition - worldPos;
|
||||
float d = length(lDir);
|
||||
lightIntensity = pushC.lightIntensity / (d * d);
|
||||
L = normalize(lDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
L = normalize(pushC.lightPosition - vec3(0));
|
||||
}
|
||||
|
||||
|
||||
// Diffuse
|
||||
vec3 diffuse = computeDiffuse(mat, L, N);
|
||||
if(mat.textureId >= 0)
|
||||
{
|
||||
int txtOffset = scnDesc.i[pushC.instanceId].txtOffset;
|
||||
uint txtId = txtOffset + mat.textureId;
|
||||
vec3 diffuseTxt = texture(textureSamplers[nonuniformEXT(txtId)], fragTexCoord).xyz;
|
||||
diffuse *= diffuseTxt;
|
||||
}
|
||||
|
||||
// Specular
|
||||
vec3 specular = computeSpecular(mat, viewDir, L, N);
|
||||
|
||||
// Result
|
||||
outColor = vec4(lightIntensity * (diffuse + specular), 1);
|
||||
}
|
||||
23
ray_tracing_indirect_scissor/shaders/lantern.rchit
Normal file
23
ray_tracing_indirect_scissor/shaders/lantern.rchit
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#version 460
|
||||
#extension GL_EXT_ray_tracing : require
|
||||
#extension GL_EXT_nonuniform_qualifier : enable
|
||||
#extension GL_EXT_scalar_block_layout : enable
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
#include "raycommon.glsl"
|
||||
|
||||
// Closest hit shader invoked when a primary ray hits a lantern.
|
||||
|
||||
// clang-format off
|
||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
||||
|
||||
layout(binding = 2, set = 0) buffer LanternArray { LanternIndirectEntry lanterns[]; } lanterns;
|
||||
|
||||
// clang-format on
|
||||
|
||||
void main()
|
||||
{
|
||||
// Just look up this lantern's color. Self-illuminating, so no lighting calculations.
|
||||
LanternIndirectEntry lantern = lanterns.lanterns[nonuniformEXT(gl_InstanceCustomIndexEXT)];
|
||||
prd.hitValue = vec3(lantern.red, lantern.green, lantern.blue);
|
||||
prd.additiveBlending = false;
|
||||
}
|
||||
163
ray_tracing_indirect_scissor/shaders/lanternIndirect.comp
Normal file
163
ray_tracing_indirect_scissor/shaders/lanternIndirect.comp
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
#version 460
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
// Compute shader for filling in raytrace indirect parameters for each lantern
|
||||
// based on the current camera position (passed as view and proj matrix in
|
||||
// push constant).
|
||||
//
|
||||
// Designed to be dispatched with only one work group; it alone fills in
|
||||
// the entire lantern array (of length lanternCount, in also push constant).
|
||||
|
||||
#define LOCAL_SIZE 128
|
||||
layout(local_size_x = LOCAL_SIZE, local_size_y = 1, local_size_z = 1) in;
|
||||
|
||||
#include "LanternIndirectEntry.glsl"
|
||||
|
||||
layout(binding = 0, set = 0) buffer LanternArray { LanternIndirectEntry lanterns[]; } lanterns;
|
||||
|
||||
layout(push_constant) uniform Constants
|
||||
{
|
||||
vec4 viewRowX;
|
||||
vec4 viewRowY;
|
||||
vec4 viewRowZ;
|
||||
mat4 proj;
|
||||
float nearZ;
|
||||
int screenX;
|
||||
int screenY;
|
||||
int lanternCount;
|
||||
}
|
||||
pushC;
|
||||
|
||||
// Copy the technique of "2D Polyhedral Bounds of a Clipped,
|
||||
// Perspective-Projected 3D Sphere" M. Mara M. McGuire
|
||||
// http://jcgt.org/published/0002/02/05/paper.pdf
|
||||
// to compute a screen-space rectangle covering the given Lantern's
|
||||
// light radius-of-effect. Result is in screen (pixel) coordinates.
|
||||
void getScreenCoordBox(in LanternIndirectEntry lantern, out ivec2 lower, out ivec2 upper);
|
||||
|
||||
// Use the xyz and radius of lanterns[i] plus the transformation matrices
|
||||
// in pushC to fill in the offset and indirect parameters of lanterns[i]
|
||||
// (defines the screen rectangle that this lantern's light is bounded in).
|
||||
void fillIndirectEntry(int i)
|
||||
{
|
||||
LanternIndirectEntry lantern = lanterns.lanterns[i];
|
||||
ivec2 lower, upper;
|
||||
getScreenCoordBox(lantern, lower, upper);
|
||||
|
||||
lanterns.lanterns[i].indirectWidth = max(0, upper.x - lower.x);
|
||||
lanterns.lanterns[i].indirectHeight = max(0, upper.y - lower.y);
|
||||
lanterns.lanterns[i].indirectDepth = 1;
|
||||
lanterns.lanterns[i].offsetX = lower.x;
|
||||
lanterns.lanterns[i].offsetY = lower.y;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
for (int i = int(gl_LocalInvocationID.x); i < pushC.lanternCount; i += LOCAL_SIZE)
|
||||
{
|
||||
fillIndirectEntry(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Functions below modified from the paper.
|
||||
float square(float a) { return a*a; }
|
||||
|
||||
void getBoundsForAxis(
|
||||
in bool xAxis,
|
||||
in vec3 center,
|
||||
in float radius,
|
||||
in float nearZ,
|
||||
in mat4 projMatrix,
|
||||
out vec3 U,
|
||||
out vec3 L) {
|
||||
bool trivialAccept = (center.z + radius) < nearZ; // Entirely in back of nearPlane (Trivial Accept)
|
||||
vec3 a = xAxis ? vec3(1, 0, 0) : vec3(0, 1, 0);
|
||||
|
||||
// given in coordinates (a,z), where a is in the direction of the vector a, and z is in the standard z direction
|
||||
vec2 projectedCenter = vec2(dot(a, center), center.z);
|
||||
vec2 bounds_az[2];
|
||||
float tSquared = dot(projectedCenter, projectedCenter) - square(radius);
|
||||
float t, cLength, costheta = 0, sintheta = 0;
|
||||
|
||||
if(tSquared > 0) { // Camera is outside sphere
|
||||
// Distance to the tangent points of the sphere (points where a vector from the camera are tangent to the sphere) (calculated a-z space)
|
||||
t = sqrt(tSquared);
|
||||
cLength = length(projectedCenter);
|
||||
|
||||
// Theta is the angle between the vector from the camera to the center of the sphere and the vectors from the camera to the tangent points
|
||||
costheta = t / cLength;
|
||||
sintheta = radius / cLength;
|
||||
}
|
||||
float sqrtPart = 0.0f;
|
||||
if(!trivialAccept) sqrtPart = sqrt(square(radius) - square(nearZ - projectedCenter.y));
|
||||
|
||||
for(int i = 0; i < 2; ++i){
|
||||
if(tSquared > 0) {
|
||||
float x = costheta * projectedCenter.x + -sintheta * projectedCenter.y;
|
||||
float y = sintheta * projectedCenter.x + costheta * projectedCenter.y;
|
||||
bounds_az[i] = costheta * vec2(x, y);
|
||||
}
|
||||
|
||||
if(!trivialAccept && (tSquared <= 0 || bounds_az[i].y > nearZ)) {
|
||||
bounds_az[i].x = projectedCenter.x + sqrtPart;
|
||||
bounds_az[i].y = nearZ;
|
||||
}
|
||||
sintheta *= -1; // negate theta for B
|
||||
sqrtPart *= -1; // negate sqrtPart for B
|
||||
}
|
||||
U = bounds_az[0].x * a;
|
||||
U.z = bounds_az[0].y;
|
||||
L = bounds_az[1].x * a;
|
||||
L.z = bounds_az[1].y;
|
||||
}
|
||||
|
||||
/** Center is in camera space */
|
||||
void getBoundingBox(
|
||||
in vec3 center,
|
||||
in float radius,
|
||||
in float nearZ,
|
||||
in mat4 projMatrix,
|
||||
out vec2 ndc_low,
|
||||
out vec2 ndc_high) {
|
||||
vec3 maxXHomogenous, minXHomogenous, maxYHomogenous, minYHomogenous;
|
||||
getBoundsForAxis(true, center, radius, nearZ, projMatrix, maxXHomogenous, minXHomogenous);
|
||||
getBoundsForAxis(false, center, radius, nearZ, projMatrix, maxYHomogenous, minYHomogenous);
|
||||
|
||||
vec4 projRow0 = vec4(projMatrix[0][0], projMatrix[1][0], projMatrix[2][0], projMatrix[3][0]);
|
||||
vec4 projRow1 = vec4(projMatrix[0][1], projMatrix[1][1], projMatrix[2][1], projMatrix[3][1]);
|
||||
vec4 projRow3 = vec4(projMatrix[0][3], projMatrix[1][3], projMatrix[2][3], projMatrix[3][3]);
|
||||
|
||||
// We only need one coordinate for each point, so we save computation by only calculating x(or y) and w
|
||||
float maxX_w = dot(vec4(maxXHomogenous, 1.0f), projRow3);
|
||||
float minX_w = dot(vec4(minXHomogenous, 1.0f), projRow3);
|
||||
float maxY_w = dot(vec4(maxYHomogenous, 1.0f), projRow3);
|
||||
float minY_w = dot(vec4(minYHomogenous, 1.0f), projRow3);
|
||||
|
||||
float maxX = dot(vec4(maxXHomogenous, 1.0f), projRow0) / maxX_w;
|
||||
float minX = dot(vec4(minXHomogenous, 1.0f), projRow0) / minX_w;
|
||||
float maxY = dot(vec4(maxYHomogenous, 1.0f), projRow1) / maxY_w;
|
||||
float minY = dot(vec4(minYHomogenous, 1.0f), projRow1) / minY_w;
|
||||
|
||||
// Paper minX, etc. names are misleading, not necessarily min. Fix here.
|
||||
ndc_low = vec2(min(minX, maxX), min(minY, maxY));
|
||||
ndc_high = vec2(max(minX, maxX), max(minY, maxY));
|
||||
}
|
||||
|
||||
void getScreenCoordBox(in LanternIndirectEntry lantern, out ivec2 lower, out ivec2 upper)
|
||||
{
|
||||
vec4 lanternWorldCenter = vec4(lantern.x, lantern.y, lantern.z, 1);
|
||||
vec3 center = vec3(
|
||||
dot(pushC.viewRowX, lanternWorldCenter),
|
||||
dot(pushC.viewRowY, lanternWorldCenter),
|
||||
dot(pushC.viewRowZ, lanternWorldCenter));
|
||||
vec2 ndc_low, ndc_high;
|
||||
float paperNearZ = -abs(pushC.nearZ); // Paper expected negative nearZ, took 2 days to figure out!
|
||||
getBoundingBox(center, lantern.radius, paperNearZ, pushC.proj, ndc_low, ndc_high);
|
||||
|
||||
// Convert NDC [-1,+1]^2 coordinates to screen coordinates, and clamp to stay in bounds.
|
||||
|
||||
lower.x = clamp(int((ndc_low.x * 0.5 + 0.5) * pushC.screenX), 0, pushC.screenX);
|
||||
lower.y = clamp(int((ndc_low.y * 0.5 + 0.5) * pushC.screenY), 0, pushC.screenY);
|
||||
upper.x = clamp(int((ndc_high.x * 0.5 + 0.5) * pushC.screenX), 0, pushC.screenX);
|
||||
upper.y = clamp(int((ndc_high.y * 0.5 + 0.5) * pushC.screenY), 0, pushC.screenY);
|
||||
}
|
||||
12
ray_tracing_indirect_scissor/shaders/lanternShadow.rmiss
Normal file
12
ray_tracing_indirect_scissor/shaders/lanternShadow.rmiss
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#version 460
|
||||
#extension GL_EXT_ray_tracing : require
|
||||
|
||||
// Miss shader invoked when tracing shadow rays (rays towards lantern)
|
||||
// in lantern passes. Misses shouldn't really happen, but if they do,
|
||||
// report we did not hit any lantern by setting hitLanternInstance = -1.
|
||||
layout(location = 2) rayPayloadInEXT int hitLanternInstance;
|
||||
|
||||
void main()
|
||||
{
|
||||
hitLanternInstance = -1;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#version 460
|
||||
#extension GL_EXT_ray_tracing : require
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
#include "raycommon.glsl"
|
||||
|
||||
// During a lantern pass, this closest hit shader is invoked when
|
||||
// shadow rays (rays towards lantern) hit a lantern. Report back
|
||||
// which lantern was hit.
|
||||
|
||||
// clang-format off
|
||||
layout(location = 2) rayPayloadInEXT int hitLanternInstance;
|
||||
|
||||
// clang-format on
|
||||
|
||||
void main()
|
||||
{
|
||||
hitLanternInstance = gl_InstanceCustomIndexEXT;
|
||||
}
|
||||
18
ray_tracing_indirect_scissor/shaders/lanternShadowObj.rchit
Normal file
18
ray_tracing_indirect_scissor/shaders/lanternShadowObj.rchit
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#version 460
|
||||
#extension GL_EXT_ray_tracing : require
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
#include "raycommon.glsl"
|
||||
|
||||
// During a lantern pass, this closest hit shader is invoked when
|
||||
// shadow rays (rays towards lantern) hit a regular OBJ. Report back
|
||||
// that no lantern was hit (-1).
|
||||
|
||||
// clang-format off
|
||||
layout(location = 2) rayPayloadInEXT int hitLanternInstance;
|
||||
|
||||
// clang-format on
|
||||
|
||||
void main()
|
||||
{
|
||||
hitLanternInstance = -1;
|
||||
}
|
||||
15
ray_tracing_indirect_scissor/shaders/passthrough.vert
Normal file
15
ray_tracing_indirect_scissor/shaders/passthrough.vert
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#version 450
|
||||
layout (location = 0) out vec2 outUV;
|
||||
|
||||
|
||||
out gl_PerVertex
|
||||
{
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);
|
||||
gl_Position = vec4(outUV * 2.0f - 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
18
ray_tracing_indirect_scissor/shaders/post.frag
Normal file
18
ray_tracing_indirect_scissor/shaders/post.frag
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
#version 450
|
||||
layout(location = 0) in vec2 outUV;
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
layout(set = 0, binding = 0) uniform sampler2D noisyTxt;
|
||||
|
||||
layout(push_constant) uniform shaderInformation
|
||||
{
|
||||
float aspectRatio;
|
||||
}
|
||||
pushc;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 uv = outUV;
|
||||
float gamma = 1. / 2.2;
|
||||
fragColor = pow(texture(noisyTxt, uv).rgba, vec4(gamma));
|
||||
}
|
||||
20
ray_tracing_indirect_scissor/shaders/raycommon.glsl
Normal file
20
ray_tracing_indirect_scissor/shaders/raycommon.glsl
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "LanternIndirectEntry.glsl"
|
||||
|
||||
struct hitPayload
|
||||
{
|
||||
vec3 hitValue;
|
||||
bool additiveBlending;
|
||||
};
|
||||
|
||||
layout(push_constant) uniform Constants
|
||||
{
|
||||
vec4 clearColor;
|
||||
vec3 lightPosition;
|
||||
float lightIntensity;
|
||||
int lightType; // 0: point, 1: infinite
|
||||
int lanternPassNumber; // -1 if this is the full-screen pass. Otherwise, used to lookup trace indirect parameters.
|
||||
int screenX;
|
||||
int screenY;
|
||||
int lanternDebug;
|
||||
}
|
||||
pushC;
|
||||
175
ray_tracing_indirect_scissor/shaders/raytrace.rchit
Normal file
175
ray_tracing_indirect_scissor/shaders/raytrace.rchit
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
#version 460
|
||||
#extension GL_EXT_ray_tracing : require
|
||||
#extension GL_EXT_nonuniform_qualifier : enable
|
||||
#extension GL_EXT_scalar_block_layout : enable
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
#include "raycommon.glsl"
|
||||
#include "wavefront.glsl"
|
||||
|
||||
hitAttributeEXT vec2 attribs;
|
||||
|
||||
// clang-format off
|
||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
||||
layout(location = 1) rayPayloadEXT bool isShadowed;
|
||||
layout(location = 2) rayPayloadEXT int hitLanternInstance;
|
||||
|
||||
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
|
||||
layout(binding = 2, set = 0) buffer LanternArray { LanternIndirectEntry lanterns[]; } lanterns;
|
||||
|
||||
layout(binding = 1, set = 1, scalar) buffer MatColorBufferObject { WaveFrontMaterial m[]; } materials[];
|
||||
layout(binding = 2, set = 1, scalar) buffer ScnDesc { sceneDesc i[]; } scnDesc;
|
||||
layout(binding = 3, set = 1) uniform sampler2D textureSamplers[];
|
||||
layout(binding = 4, set = 1) buffer MatIndexColorBuffer { int i[]; } matIndex[];
|
||||
layout(binding = 5, set = 1, scalar) buffer Vertices { Vertex v[]; } vertices[];
|
||||
layout(binding = 6, set = 1) buffer Indices { uint i[]; } indices[];
|
||||
|
||||
// clang-format on
|
||||
|
||||
void main()
|
||||
{
|
||||
// Object of this instance
|
||||
uint objId = scnDesc.i[gl_InstanceCustomIndexEXT].objId;
|
||||
|
||||
// Indices of the triangle
|
||||
ivec3 ind = ivec3(indices[nonuniformEXT(objId)].i[3 * gl_PrimitiveID + 0], //
|
||||
indices[nonuniformEXT(objId)].i[3 * gl_PrimitiveID + 1], //
|
||||
indices[nonuniformEXT(objId)].i[3 * gl_PrimitiveID + 2]); //
|
||||
// Vertex of the triangle
|
||||
Vertex v0 = vertices[nonuniformEXT(objId)].v[ind.x];
|
||||
Vertex v1 = vertices[nonuniformEXT(objId)].v[ind.y];
|
||||
Vertex v2 = vertices[nonuniformEXT(objId)].v[ind.z];
|
||||
|
||||
const vec3 barycentrics = vec3(1.0 - attribs.x - attribs.y, attribs.x, attribs.y);
|
||||
|
||||
// Computing the normal at hit position
|
||||
vec3 normal = v0.nrm * barycentrics.x + v1.nrm * barycentrics.y + v2.nrm * barycentrics.z;
|
||||
// Transforming the normal to world space
|
||||
normal = normalize(vec3(scnDesc.i[gl_InstanceCustomIndexEXT].transfoIT * vec4(normal, 0.0)));
|
||||
|
||||
|
||||
// Computing the coordinates of the hit position
|
||||
vec3 worldPos = v0.pos * barycentrics.x + v1.pos * barycentrics.y + v2.pos * barycentrics.z;
|
||||
// Transforming the position to world space
|
||||
worldPos = vec3(scnDesc.i[gl_InstanceCustomIndexEXT].transfo * vec4(worldPos, 1.0));
|
||||
|
||||
// Vector toward the light
|
||||
vec3 L;
|
||||
vec3 colorIntensity = vec3(pushC.lightIntensity);
|
||||
float lightDistance = 100000.0;
|
||||
|
||||
// ray direction is towards lantern, if in lantern pass.
|
||||
if (pushC.lanternPassNumber >= 0)
|
||||
{
|
||||
LanternIndirectEntry lantern = lanterns.lanterns[pushC.lanternPassNumber];
|
||||
vec3 lDir = vec3(lantern.x, lantern.y, lantern.z) - worldPos;
|
||||
lightDistance = length(lDir);
|
||||
vec3 color = vec3(lantern.red, lantern.green, lantern.blue);
|
||||
// Lantern light decreases linearly. Not physically accurate, but looks good
|
||||
// and avoids a hard "edge" at the radius limit. Use a constant value
|
||||
// if lantern debug is enabled to clearly see the covered screen rectangle.
|
||||
float distanceFade =
|
||||
pushC.lanternDebug != 0
|
||||
? 0.3
|
||||
: max(0, (lantern.radius - lightDistance) / lantern.radius);
|
||||
colorIntensity = color * lantern.brightness * distanceFade;
|
||||
L = normalize(lDir);
|
||||
}
|
||||
// Non-lantern pass may have point light...
|
||||
else if(pushC.lightType == 0)
|
||||
{
|
||||
vec3 lDir = pushC.lightPosition - worldPos;
|
||||
lightDistance = length(lDir);
|
||||
colorIntensity = vec3(pushC.lightIntensity / (lightDistance * lightDistance));
|
||||
L = normalize(lDir);
|
||||
}
|
||||
else // or directional light.
|
||||
{
|
||||
L = normalize(pushC.lightPosition - vec3(0));
|
||||
}
|
||||
|
||||
// Material of the object
|
||||
int matIdx = matIndex[nonuniformEXT(objId)].i[gl_PrimitiveID];
|
||||
WaveFrontMaterial mat = materials[nonuniformEXT(objId)].m[matIdx];
|
||||
|
||||
|
||||
// Diffuse
|
||||
vec3 diffuse = computeDiffuse(mat, L, normal);
|
||||
if(mat.textureId >= 0)
|
||||
{
|
||||
uint txtId = mat.textureId + scnDesc.i[gl_InstanceCustomIndexEXT].txtOffset;
|
||||
vec2 texCoord =
|
||||
v0.texCoord * barycentrics.x + v1.texCoord * barycentrics.y + v2.texCoord * barycentrics.z;
|
||||
diffuse *= texture(textureSamplers[nonuniformEXT(txtId)], texCoord).xyz;
|
||||
}
|
||||
|
||||
vec3 specular = vec3(0);
|
||||
float attenuation = 1;
|
||||
|
||||
// Tracing shadow ray only if the light is visible from the surface
|
||||
if(dot(normal, L) > 0)
|
||||
{
|
||||
float tMin = 0.001;
|
||||
float tMax = lightDistance;
|
||||
vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
|
||||
vec3 rayDir = L;
|
||||
|
||||
// Ordinary shadow from the simple tutorial.
|
||||
if (pushC.lanternPassNumber < 0) {
|
||||
isShadowed = true;
|
||||
uint flags = gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT
|
||||
| gl_RayFlagsSkipClosestHitShaderEXT;
|
||||
traceRayEXT(topLevelAS, // acceleration structure
|
||||
flags, // rayFlags
|
||||
0xFF, // cullMask
|
||||
0, // sbtRecordOffset
|
||||
0, // sbtRecordStride
|
||||
1, // missIndex
|
||||
origin, // ray origin
|
||||
tMin, // ray min range
|
||||
rayDir, // ray direction
|
||||
tMax, // ray max range
|
||||
1 // payload (location = 1)
|
||||
);
|
||||
}
|
||||
// Lantern shadow ray. Cast a ray towards the lantern whose lighting is being
|
||||
// added this pass. Only the closest hit shader for lanterns will set
|
||||
// hitLanternInstance (payload 2) to non-negative value.
|
||||
else {
|
||||
// Skip ray if no light would be added anyway.
|
||||
if (colorIntensity == vec3(0)) {
|
||||
isShadowed = true;
|
||||
}
|
||||
else {
|
||||
uint flags = gl_RayFlagsOpaqueEXT;
|
||||
hitLanternInstance = -1;
|
||||
traceRayEXT(topLevelAS, // acceleration structure
|
||||
flags, // rayFlags
|
||||
0xFF, // cullMask
|
||||
2, // sbtRecordOffset : lantern shadow hit groups start at index 2.
|
||||
0, // sbtRecordStride
|
||||
2, // missIndex : lantern shadow miss shader is number 2.
|
||||
origin, // ray origin
|
||||
tMin, // ray min range
|
||||
rayDir, // ray direction
|
||||
tMax, // ray max range
|
||||
2 // payload (location = 2)
|
||||
);
|
||||
// Did we hit the lantern we expected?
|
||||
isShadowed = (hitLanternInstance != pushC.lanternPassNumber);
|
||||
}
|
||||
}
|
||||
|
||||
if(isShadowed)
|
||||
{
|
||||
attenuation = 0.1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Specular
|
||||
specular = computeSpecular(mat, gl_WorldRayDirectionEXT, L, normal);
|
||||
}
|
||||
}
|
||||
|
||||
prd.hitValue = colorIntensity * (attenuation * (diffuse + specular));
|
||||
prd.additiveBlending = true;
|
||||
}
|
||||
71
ray_tracing_indirect_scissor/shaders/raytrace.rgen
Normal file
71
ray_tracing_indirect_scissor/shaders/raytrace.rgen
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
#version 460
|
||||
#extension GL_EXT_ray_tracing : require
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
#include "raycommon.glsl"
|
||||
|
||||
layout(binding = 0, set = 0) uniform accelerationStructureEXT topLevelAS;
|
||||
layout(binding = 1, set = 0, rgba32f) uniform image2D image;
|
||||
|
||||
layout(location = 0) rayPayloadEXT hitPayload prd;
|
||||
|
||||
layout(binding = 0, set = 1) uniform CameraProperties
|
||||
{
|
||||
mat4 view;
|
||||
mat4 proj;
|
||||
mat4 viewInverse;
|
||||
mat4 projInverse;
|
||||
}
|
||||
cam;
|
||||
|
||||
layout(binding = 2, set = 0) buffer LanternArray { LanternIndirectEntry lanterns[]; } lanterns;
|
||||
|
||||
void main()
|
||||
{
|
||||
// Global light pass is a full screen rectangle (lower corner 0,0), but
|
||||
// lantern passes are only run within rectangles that may be offset.
|
||||
ivec2 pixelOffset = ivec2(0);
|
||||
if (pushC.lanternPassNumber >= 0)
|
||||
{
|
||||
pixelOffset.x = lanterns.lanterns[pushC.lanternPassNumber].offsetX;
|
||||
pixelOffset.y = lanterns.lanterns[pushC.lanternPassNumber].offsetY;
|
||||
}
|
||||
|
||||
const ivec2 pixelIntCoord = ivec2(gl_LaunchIDEXT.xy) + pixelOffset;
|
||||
const vec2 pixelCenter = vec2(pixelIntCoord) + vec2(0.5);
|
||||
const vec2 inUV = pixelCenter / vec2(pushC.screenX, pushC.screenY);
|
||||
vec2 d = inUV * 2.0 - 1.0;
|
||||
|
||||
vec4 origin = cam.viewInverse * vec4(0, 0, 0, 1);
|
||||
vec4 target = cam.projInverse * vec4(d.x, d.y, 1, 1);
|
||||
vec4 direction = cam.viewInverse * vec4(normalize(target.xyz), 0);
|
||||
|
||||
uint rayFlags = gl_RayFlagsOpaqueEXT;
|
||||
float tMin = 0.001;
|
||||
float tMax = 10000.0;
|
||||
|
||||
// Lanterns (self-illuminating) and miss shader (constant background color)
|
||||
// do not use additive blending. Only normal OBJ geometry is additive,
|
||||
// OBJ closest hit sets this to true.
|
||||
prd.additiveBlending = false;
|
||||
|
||||
traceRayEXT(topLevelAS, // acceleration structure
|
||||
rayFlags, // rayFlags
|
||||
0xFF, // cullMask
|
||||
0, // sbtRecordOffset
|
||||
0, // sbtRecordStride
|
||||
0, // missIndex
|
||||
origin.xyz, // ray origin
|
||||
tMin, // ray min range
|
||||
direction.xyz, // ray direction
|
||||
tMax, // ray max range
|
||||
0 // payload (location = 0)
|
||||
);
|
||||
|
||||
// Either add to or replace output image color based on prd.additiveBlending.
|
||||
// Global pass always replaces color as it is the first pass.
|
||||
vec3 oldColor = vec3(0);
|
||||
if (prd.additiveBlending && pushC.lanternPassNumber >= 0) {
|
||||
oldColor = imageLoad(image, pixelIntCoord).rgb;
|
||||
}
|
||||
imageStore(image, pixelIntCoord, vec4(prd.hitValue + oldColor, 1.0));
|
||||
}
|
||||
12
ray_tracing_indirect_scissor/shaders/raytrace.rmiss
Normal file
12
ray_tracing_indirect_scissor/shaders/raytrace.rmiss
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#version 460
|
||||
#extension GL_EXT_ray_tracing : require
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
#include "raycommon.glsl"
|
||||
|
||||
layout(location = 0) rayPayloadInEXT hitPayload prd;
|
||||
|
||||
void main()
|
||||
{
|
||||
prd.hitValue = pushC.clearColor.xyz * 0.8;
|
||||
prd.additiveBlending = false;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#version 460
|
||||
#extension GL_EXT_ray_tracing : require
|
||||
|
||||
layout(location = 1) rayPayloadInEXT bool isShadowed;
|
||||
|
||||
void main()
|
||||
{
|
||||
isShadowed = false;
|
||||
}
|
||||
61
ray_tracing_indirect_scissor/shaders/vert_shader.vert
Normal file
61
ray_tracing_indirect_scissor/shaders/vert_shader.vert
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#version 450
|
||||
#extension GL_ARB_separate_shader_objects : enable
|
||||
#extension GL_EXT_scalar_block_layout : enable
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
#include "wavefront.glsl"
|
||||
|
||||
// clang-format off
|
||||
layout(binding = 2, set = 0, scalar) buffer ScnDesc { sceneDesc i[]; } scnDesc;
|
||||
// clang-format on
|
||||
|
||||
layout(binding = 0) uniform UniformBufferObject
|
||||
{
|
||||
mat4 view;
|
||||
mat4 proj;
|
||||
mat4 viewI;
|
||||
}
|
||||
ubo;
|
||||
|
||||
layout(push_constant) uniform shaderInformation
|
||||
{
|
||||
vec3 lightPosition;
|
||||
uint instanceId;
|
||||
float lightIntensity;
|
||||
int lightType;
|
||||
}
|
||||
pushC;
|
||||
|
||||
layout(location = 0) in vec3 inPosition;
|
||||
layout(location = 1) in vec3 inNormal;
|
||||
layout(location = 2) in vec3 inColor;
|
||||
layout(location = 3) in vec2 inTexCoord;
|
||||
|
||||
|
||||
//layout(location = 0) flat out int matIndex;
|
||||
layout(location = 1) out vec2 fragTexCoord;
|
||||
layout(location = 2) out vec3 fragNormal;
|
||||
layout(location = 3) out vec3 viewDir;
|
||||
layout(location = 4) out vec3 worldPos;
|
||||
|
||||
out gl_PerVertex
|
||||
{
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
mat4 objMatrix = scnDesc.i[pushC.instanceId].transfo;
|
||||
mat4 objMatrixIT = scnDesc.i[pushC.instanceId].transfoIT;
|
||||
|
||||
vec3 origin = vec3(ubo.viewI * vec4(0, 0, 0, 1));
|
||||
|
||||
worldPos = vec3(objMatrix * vec4(inPosition, 1.0));
|
||||
viewDir = vec3(worldPos - origin);
|
||||
fragTexCoord = inTexCoord;
|
||||
fragNormal = vec3(objMatrixIT * vec4(inNormal, 0.0));
|
||||
// matIndex = inMatID;
|
||||
|
||||
gl_Position = ubo.proj * ubo.view * vec4(worldPos, 1.0);
|
||||
}
|
||||
58
ray_tracing_indirect_scissor/shaders/wavefront.glsl
Normal file
58
ray_tracing_indirect_scissor/shaders/wavefront.glsl
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
struct Vertex
|
||||
{
|
||||
vec3 pos;
|
||||
vec3 nrm;
|
||||
vec3 color;
|
||||
vec2 texCoord;
|
||||
};
|
||||
|
||||
struct WaveFrontMaterial
|
||||
{
|
||||
vec3 ambient;
|
||||
vec3 diffuse;
|
||||
vec3 specular;
|
||||
vec3 transmittance;
|
||||
vec3 emission;
|
||||
float shininess;
|
||||
float ior; // index of refraction
|
||||
float dissolve; // 1 == opaque; 0 == fully transparent
|
||||
int illum; // illumination model (see http://www.fileformat.info/format/material/)
|
||||
int textureId;
|
||||
};
|
||||
|
||||
struct sceneDesc
|
||||
{
|
||||
int objId;
|
||||
int txtOffset;
|
||||
mat4 transfo;
|
||||
mat4 transfoIT;
|
||||
};
|
||||
|
||||
|
||||
vec3 computeDiffuse(WaveFrontMaterial mat, vec3 lightDir, vec3 normal)
|
||||
{
|
||||
// Lambertian
|
||||
float dotNL = max(dot(normal, lightDir), 0.0);
|
||||
vec3 c = mat.diffuse * dotNL;
|
||||
if(mat.illum >= 1)
|
||||
c += mat.ambient;
|
||||
return c;
|
||||
}
|
||||
|
||||
vec3 computeSpecular(WaveFrontMaterial mat, vec3 viewDir, vec3 lightDir, vec3 normal)
|
||||
{
|
||||
if(mat.illum < 2)
|
||||
return vec3(0);
|
||||
|
||||
// Compute specular only if not in shadow
|
||||
const float kPi = 3.14159265;
|
||||
const float kShininess = max(mat.shininess, 4.0);
|
||||
|
||||
// Specular
|
||||
const float kEnergyConservation = (2.0 + kShininess) / (2.0 * kPi);
|
||||
vec3 V = normalize(-viewDir);
|
||||
vec3 R = reflect(-lightDir, normal);
|
||||
float specular = kEnergyConservation * pow(max(dot(V, R), 0.0), kShininess);
|
||||
|
||||
return vec3(mat.specular * specular);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue