├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── ReSTIRSSS ├── .clang-format ├── .clang-tidy ├── CMakeLists.txt ├── include │ ├── denoiser │ │ └── DenoiserOptiX.h │ └── restirsss │ │ ├── Raydata.h │ │ ├── Rayscenes.h │ │ ├── Raystructs.h │ │ ├── ReSTIRSSS.h │ │ ├── ReSTIRSSSEvaluation.h │ │ ├── ReSTIRSSSEvaluationTiming.h │ │ ├── ReSTIRSSSVideo.h │ │ └── passes │ │ ├── PassDebug.h │ │ ├── PassGBuffer.h │ │ ├── PassPathtrace.h │ │ ├── PassSurface.h │ │ ├── PassTonemapper.h │ │ ├── ReSTIRSSSPassCandidateGeneration.h │ │ ├── ReSTIRSSSPassShade.h │ │ ├── ReSTIRSSSPassSpatialReuse.h │ │ └── ReSTIRSSSPassTemporalReuse.h ├── resources │ ├── environment │ │ └── white.png │ ├── scenes │ │ ├── ajax.xml │ │ ├── ajaxmanylights.xml │ │ ├── asiandragon.xml │ │ ├── flattest.xml │ │ └── lteorb.xml │ └── shaders │ │ ├── arealight.glsl │ │ ├── bxdf │ │ ├── bsdf │ │ │ ├── bsdf.glsl │ │ │ ├── disney_bsdf.glsl │ │ │ ├── disney_diffuse.glsl │ │ │ └── disney_metal.glsl │ │ ├── diffusion │ │ │ ├── sss_diffusion_profile.glsl │ │ │ ├── sss_diffusion_profile_burley.glsl │ │ │ ├── sss_sampling.glsl │ │ │ └── sss_sampling_disk.glsl │ │ └── disney.glsl │ │ ├── defines.glsl │ │ ├── environment.glsl │ │ ├── main │ │ ├── gbuffer.glsl │ │ ├── passes │ │ │ ├── pass_debug.comp │ │ │ ├── pass_gbuffer.comp │ │ │ ├── pass_pathtrace.comp │ │ │ ├── pass_surface.comp │ │ │ ├── pass_tonemapper.comp │ │ │ ├── restirsss_pass_candidate_generation.comp │ │ │ ├── restirsss_pass_shade.comp │ │ │ ├── restirsss_pass_spatial_reuse.comp │ │ │ └── restirsss_pass_temporal_reuse.comp │ │ └── restirsss │ │ │ ├── probinversetest │ │ │ ├── restirsss_shift_test.glsl │ │ │ └── restirsss_target_function_test.glsl │ │ │ ├── restirsss_defines.glsl │ │ │ ├── restirsss_disney_bsdf.glsl │ │ │ ├── restirsss_disney_bssrdf.glsl │ │ │ ├── restirsss_mis.glsl │ │ │ ├── restirsss_pixel_info.glsl │ │ │ ├── restirsss_reservoir.glsl │ │ │ ├── restirsss_shift.glsl │ │ │ ├── restirsss_shift_hybrid_criterion.glsl │ │ │ ├── restirsss_spatial_kernel.glsl │ │ │ └── restirsss_target_function.glsl │ │ ├── material.glsl │ │ ├── raycommon.glsl │ │ ├── raystructs.glsl │ │ ├── trace │ │ ├── trace.glsl │ │ └── trace_rayquery.glsl │ │ ├── utility │ │ ├── colormap.glsl │ │ ├── constants.glsl │ │ ├── normal_mapping.glsl │ │ └── random.glsl │ │ └── visibility │ │ └── visibility.glsl └── src │ ├── bin │ └── main.cpp │ ├── denoiser │ └── DenoiserOptiX.cpp │ └── restirsss │ ├── ReSTIRSSS.cpp │ ├── ReSTIRSSSEvaluation.cpp │ ├── ReSTIRSSSEvaluationTiming.cpp │ └── ReSTIRSSSVideo.cpp ├── VkRaven ├── .clang-format ├── .clang-tidy ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake │ ├── find │ │ └── FindOptix.cmake │ └── setup.cmake ├── lib │ ├── CMakeLists.txt │ └── main.cpp └── raven │ ├── CMakeLists.txt │ ├── include │ └── raven │ │ ├── RavenInclude.h │ │ ├── core │ │ ├── AccelerationStructure.h │ │ ├── Application.h │ │ ├── Buffer.h │ │ ├── GPUContext.h │ │ ├── HeadlessApplication.h │ │ ├── Image.h │ │ ├── Queues.h │ │ ├── RavenVkDynamicLoader.h │ │ ├── Renderer.h │ │ ├── Shader.h │ │ ├── SwapChain.h │ │ ├── Texture.h │ │ ├── TimingHeadlessApplication.h │ │ ├── Uniform.h │ │ ├── VideoHeadlessApplication.h │ │ └── VkDebugUtils.h │ │ ├── passes │ │ ├── ImGuiPass.h │ │ ├── Pass.h │ │ ├── PassCompute.h │ │ ├── PassShader.h │ │ ├── PassShaderCompute.h │ │ └── PassShaderRayTracing.h │ │ ├── rendergraph │ │ ├── RenderGraph.h │ │ ├── RenderGraphPass.h │ │ └── RenderGraphResource.h │ │ ├── scene │ │ ├── ISceneLoader.h │ │ ├── RavenLight.h │ │ ├── RavenMaterial.h │ │ ├── RavenScene.h │ │ ├── RavenSceneNode.h │ │ ├── RavenSceneObject.h │ │ ├── RavenTexture.h │ │ └── loader │ │ │ └── GLTFLoader.h │ │ └── util │ │ ├── AABB.h │ │ ├── Camera.h │ │ ├── ImagePFM.h │ │ ├── Paths.h │ │ ├── Trajectory.h │ │ ├── animation │ │ └── BSpline.h │ │ └── sampling │ │ └── AliasTable.h │ └── src │ └── raven │ └── core │ ├── Application.cpp │ ├── GPUContext.cpp │ ├── HeadlessApplication.cpp │ ├── Queues.cpp │ ├── RavenVkDynamicLoader.cpp │ ├── TimingHeadlessApplication.cpp │ └── VideoHeadlessApplication.cpp ├── screenshot.png └── teaser.png /.gitignore: -------------------------------------------------------------------------------- 1 | # JetBrains IDE 2 | .idea/* 3 | **/.idea/* 4 | *.iws 5 | *.iml 6 | *.eml 7 | 8 | /build/* 9 | **/cmake-build-*/* 10 | 11 | # Visual Studio 12 | /out/ 13 | **/out/ 14 | CmakeSettings.json 15 | /.vs/ 16 | **/.vs/ 17 | 18 | # Shaders 19 | *.spv 20 | 21 | # assets 22 | **/resources/assets/* 23 | **/resources/environment/* 24 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "VkRaven/lib/stb"] 2 | path = VkRaven/lib/stb 3 | url = git@github.com:nothings/stb.git 4 | [submodule "VkRaven/lib/tinyobjloader"] 5 | path = VkRaven/lib/tinyobjloader 6 | url = git@github.com:tinyobjloader/tinyobjloader.git 7 | [submodule "VkRaven/lib/SPIRV-Reflect"] 8 | path = VkRaven/lib/SPIRV-Reflect 9 | url = git@github.com:KhronosGroup/SPIRV-Reflect.git 10 | [submodule "VkRaven/lib/tinygltf"] 11 | path = VkRaven/lib/tinygltf 12 | url = git@github.com:syoyo/tinygltf.git 13 | [submodule "VkRaven/lib/glfw"] 14 | path = VkRaven/lib/glfw 15 | url = git@github.com:glfw/glfw.git 16 | [submodule "VkRaven/lib/glm"] 17 | path = VkRaven/lib/glm 18 | url = git@github.com:g-truc/glm.git 19 | [submodule "VkRaven/lib/imgui"] 20 | path = VkRaven/lib/imgui 21 | url = git@github.com:ocornut/imgui.git 22 | [submodule "VkRaven/lib/pugixml"] 23 | path = VkRaven/lib/pugixml 24 | url = git@github.com:zeux/pugixml.git 25 | [submodule "VkRaven/lib/argparse"] 26 | path = VkRaven/lib/argparse 27 | url = git@github.com:p-ranav/argparse.git 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Mirco Werner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ReSTIR Subsurface Scattering for Real-Time Path Tracing (ReSTIR SSS) 2 | ![](teaser.png) 3 | 4 | ## Introduction 5 | This repository contains the source code for the HPG 2024 paper: 6 | 7 | > [**ReSTIR Subsurface Scattering for Real-Time Path Tracing**](https://doi.org/10.1145/3675372)
8 | > [Mirco Werner](https://github.com/MircoWerner), [Vincent Schüßler](https://cg.ivd.kit.edu/schuessler/staff_index.php), and [Carsten Dachsbacher](https://cg.ivd.kit.edu/dachsbacher/staff_index.php) 9 | 10 | > *Abstract* Subsurface scattering is an important visual cue and in real-time rendering it is often approximated using screen-space algorithms. Path tracing with the diffusion approximation can easily overcome the limitations of these algorithms, but increases image noise. We improve its efficiency by applying reservoir-based spatio-temporal importance resampling (ReSTIR) to subsurface light transport paths. For this, we adopt BSSRDF importance sampling for generating candidates. Further, spatiotemporal reuse requires shifting paths between domains. We observe that different image regions benefit most from either reconnecting through the translucent object (reconnection shift), or one vertex later (delayed reconnection shift). We first introduce a local subsurface scattering specific criterion for a hybrid shift that deterministically selects one of the two shifts for a path. Due to the locality, it cannot always choose the most efficient shift, e.g. near shadow boundaries. Therefore, we additionally propose a novel sequential shift to combine multiple shift mappings: We execute subsequent resampling passes, each one using a different shift, which does not require to deterministically choose a shift for a path. Instead, resampling can pick the most successful shift implicitly. Our method achieves real-time performance and significantly reduces noise and denoising artifacts in regions with visible subsurface scattering compared to standard path tracing with equal render time. 11 | 12 | ## Structure of the Repository 13 | [`ReSTIRSSS/resources/shaders/main/`](./ReSTIRSSS/resources/shaders/main) contains the GLSL shaders for ReSTIR SSS. 14 | - ReSTIR SSS passes: [`restirsss_pass_candidate_generation`](./ReSTIRSSS/resources/shaders/main/passes/restirsss_pass_candidate_generation.comp), [`restirsss_pass_temporal_reuse`](./ReSTIRSSS/resources/shaders/main/passes/restirsss_pass_temporal_reuse.comp), [`restirsss_pass_spatial_reuse`](./ReSTIRSSS/resources/shaders/main/passes/restirsss_pass_spatial_reuse.comp), and [`restirsss_pass_shade`](./ReSTIRSSS/resources/shaders/main/passes/restirsss_pass_shade.comp) 15 | - ReSTIR SSS reservoir: [`restirsss_reservoir`](./ReSTIRSSS/resources/shaders/main/restirsss/restirsss_reservoir.glsl) 16 | - ReSTIR SSS target function: [`restirsss_target_function`](./ReSTIRSSS/resources/shaders/main/restirsss/restirsss_target_function.glsl) 17 | - ReSTIR SSS shifts (reconnection, delayed reconnection, hybrid, sequential) and their Jacobians: [`restirsss_shift`](./ReSTIRSSS/resources/shaders/main/restirsss/restirsss_shift.glsl) 18 | - MIS weights (generalized balance heuristic, streaming pairwise MIS): [`restirsss_mis`](./ReSTIRSSS/resources/shaders/main/restirsss/restirsss_mis.glsl) 19 | 20 | Our sequential shift strategy uses *probabilistic inversion* to draw new random numbers before applying random replay when shifting a path with delayed reconnection (see paper Sec. 4.3 for details). 21 | We also demonstrate the possibility to use probabilistic inversion in ReSTIR in general to use both path and primary sample space shifts for a certain sample by implementing it in a surface reflection case with a path of length 3 (see supplemental document Sec. 3 for details). 22 | This demonstration can be enabled in [`restirsss_defines`](./ReSTIRSSS/resources/shaders/main/restirsss/restirsss_defines.glsl) using the `RESTIRSSS_PROBINVERSETEST_L3PATH` macro. 23 | Also see [`probinversetest`](./ReSTIRSSS/resources/shaders/main/restirsss/probinversetest). 24 | 25 | ## Requirements 26 | - Vulkan 1.3 27 | - GPU with ray tracing support 28 | - (optional) [OptiX](https://developer.nvidia.com/designworks/optix/download) 8.0.0 or higher and [CUDA Toolkit](https://developer.nvidia.com/cuda-downloads) for [denoising](https://developer.nvidia.com/optix-denoiser) 29 | 30 | Other dependencies are included as submodules in [`VkRaven/lib/`](./VkRaven/lib). 31 | 32 | ## Running the Code 33 | Tested on Linux with GCC 14.1.1 and NVIDIA RTX 3070 GPU. 34 | 35 | Windows is not officially supported, however, we get it to run using MinGW and disabling OptiX support in the [CMake configuration](./ReSTIRSSS/CMakeLists.txt). 36 | 37 | ### Clone and Build 38 | ```bash 39 | git clone --recursive git@github.com:MircoWerner/ReSTIR-SSS.git 40 | cd ReSTIR-SSS/ReSTIRSSS 41 | mkdir build 42 | cd build 43 | cmake .. 44 | make 45 | ``` 46 | ### Download Assets 47 | See [ReSTIR SSS Assets](https://github.com/MircoWerner/ReSTIR-SSS-Assets) repository for more details. 48 | ```bash 49 | cd ReSTIR-SSS/ReSTIRSSS/resources 50 | git clone git@github.com:MircoWerner/ReSTIR-SSS-Assets.git assets 51 | cd assets/asiandragon 52 | tar -xf dragon.tar.xz # unpack large file 53 | ``` 54 | ### Run 55 | ```bash 56 | cd ReSTIR-SSS/ReSTIRSSS/build 57 | ./restirsss ajax 58 | ``` 59 | - The provided scenes can be found in [`ReSTIRSSS/resources/scenes/`](./ReSTIRSSS/resources/scenes): `ajax`, `ajaxmanylights`, `asiandragon`, `lteorb`, `flattest`. 60 | - Use `--preset ...` to select the initial rendering mode. This can also be changed during runtime in the UI. 61 | - Use `--evaluate ...` to start the automatic evaluation to generate renderings (to measure errors) or timings as shown in the paper. The video option generates the frames for our short video. 62 | ``` 63 | Usage: restirsss [--help] [--version] [--preset VAR] [--evaluate VAR] scene 64 | 65 | Positional arguments: 66 | scene name of the scene (in resources/scenes/.xml) [required] 67 | 68 | Optional arguments: 69 | -h, --help shows help message and exits 70 | -v, --version prints version information and exits 71 | --preset pathtracing, hybrid, sequential [default: "hybrid"] 72 | --evaluate renderings, timing, video 73 | ``` 74 | 75 | ### Controls 76 | - `WASD` to move the camera 77 | - `Space` or `E` to move the camera up 78 | - `Shift` or `Q` to move the camera down 79 | - Hold `Ctrl` to move faster 80 | - Hold `Right Mouse Button` to look around 81 | - `Esc` to close the application 82 | 83 | ## Acknowledgements 84 | We would like to thank the creators and authors of the used assets and libraries: 85 | - Ajax Bust by Jotero, [Asian Dragon](http://graphics.stanford.edu/data/3Dscanrep/) by XYZ RGB Inc, and [LTE Orb](https://github.com/lighttransport/lighttransportequation-orb) by Yasutoshi Mori (@MirageYM). 86 | - [argsparse](https://github.com/p-ranav/argparse), [glfw](https://github.com/glfw/glfw), [glm](https://github.com/g-truc/glm), [imgui](https://github.com/ocornut/imgui), [pugixml](https://github.com/zeux/pugixml), [SPIRV-Reflect](https://github.com/KhronosGroup/SPIRV-Reflect), [stb](https://github.com/nothings/stb), [tinygltf](https://github.com/syoyo/tinygltf), [tinyobjloader](https://github.com/tinyobjloader/tinyobjloader), and [OptiX](https://developer.nvidia.com/optix-denoiser). 87 | 88 | ![](screenshot.png) -------------------------------------------------------------------------------- /ReSTIRSSS/.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: None 6 | AlignOperands: Align 7 | AllowAllArgumentsOnNextLine: false 8 | AllowAllConstructorInitializersOnNextLine: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: Never 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: All 13 | AllowShortIfStatementsOnASingleLine: Never 14 | AllowShortLambdasOnASingleLine: All 15 | AllowShortLoopsOnASingleLine: true 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BreakBeforeBraces: Custom 19 | BraceWrapping: 20 | AfterCaseLabel: false 21 | AfterClass: false 22 | AfterControlStatement: Never 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterUnion: false 27 | BeforeCatch: false 28 | BeforeElse: false 29 | IndentBraces: false 30 | SplitEmptyFunction: false 31 | SplitEmptyRecord: true 32 | BreakBeforeBinaryOperators: None 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: BeforeColon 36 | ColumnLimit: 0 37 | CompactNamespaces: false 38 | ContinuationIndentWidth: 8 39 | IndentCaseLabels: true 40 | IndentPPDirectives: None 41 | IndentWidth: 4 42 | KeepEmptyLinesAtTheStartOfBlocks: true 43 | MaxEmptyLinesToKeep: 2 44 | NamespaceIndentation: All 45 | ObjCSpaceAfterProperty: false 46 | ObjCSpaceBeforeProtocolList: true 47 | PointerAlignment: Right 48 | ReflowComments: false 49 | SpaceAfterCStyleCast: true 50 | SpaceAfterLogicalNot: false 51 | SpaceAfterTemplateKeyword: false 52 | SpaceBeforeAssignmentOperators: true 53 | SpaceBeforeCpp11BracedList: false 54 | SpaceBeforeCtorInitializerColon: true 55 | SpaceBeforeInheritanceColon: true 56 | SpaceBeforeParens: ControlStatements 57 | SpaceBeforeRangeBasedForLoopColon: false 58 | SpaceInEmptyParentheses: false 59 | SpacesBeforeTrailingComments: 1 60 | SpacesInAngles: false 61 | SpacesInCStyleCastParentheses: false 62 | SpacesInContainerLiterals: false 63 | SpacesInParentheses: false 64 | SpacesInSquareBrackets: false 65 | TabWidth: 4 66 | UseTab: Never 67 | -------------------------------------------------------------------------------- /ReSTIRSSS/.clang-tidy: -------------------------------------------------------------------------------- 1 | # Generated from CLion Inspection settings 2 | --- 3 | Checks: '-*, 4 | bugprone-argument-comment, 5 | bugprone-assert-side-effect, 6 | bugprone-bad-signal-to-kill-thread, 7 | bugprone-branch-clone, 8 | bugprone-copy-constructor-init, 9 | bugprone-dangling-handle, 10 | bugprone-dynamic-static-initializers, 11 | bugprone-fold-init-type, 12 | bugprone-forward-declaration-namespace, 13 | bugprone-forwarding-reference-overload, 14 | bugprone-inaccurate-erase, 15 | bugprone-incorrect-roundings, 16 | bugprone-integer-division, 17 | bugprone-lambda-function-name, 18 | bugprone-macro-parentheses, 19 | bugprone-macro-repeated-side-effects, 20 | bugprone-misplaced-operator-in-strlen-in-alloc, 21 | bugprone-misplaced-pointer-arithmetic-in-alloc, 22 | bugprone-misplaced-widening-cast, 23 | bugprone-move-forwarding-reference, 24 | bugprone-multiple-statement-macro, 25 | bugprone-no-escape, 26 | bugprone-not-null-terminated-result, 27 | bugprone-parent-virtual-call, 28 | bugprone-posix-return, 29 | bugprone-reserved-identifier, 30 | bugprone-sizeof-container, 31 | bugprone-sizeof-expression, 32 | bugprone-spuriously-wake-up-functions, 33 | bugprone-string-constructor, 34 | bugprone-string-integer-assignment, 35 | bugprone-string-literal-with-embedded-nul, 36 | bugprone-suspicious-enum-usage, 37 | bugprone-suspicious-include, 38 | bugprone-suspicious-memset-usage, 39 | bugprone-suspicious-missing-comma, 40 | bugprone-suspicious-semicolon, 41 | bugprone-suspicious-string-compare, 42 | bugprone-suspicious-memory-comparison, 43 | bugprone-suspicious-realloc-usage, 44 | bugprone-swapped-arguments, 45 | bugprone-terminating-continue, 46 | bugprone-throw-keyword-missing, 47 | bugprone-too-small-loop-variable, 48 | bugprone-undefined-memory-manipulation, 49 | bugprone-undelegated-constructor, 50 | bugprone-unhandled-self-assignment, 51 | bugprone-unused-raii, 52 | bugprone-unused-return-value, 53 | bugprone-use-after-move, 54 | bugprone-virtual-near-miss, 55 | cert-dcl21-cpp, 56 | cert-dcl58-cpp, 57 | cert-err34-c, 58 | cert-err52-cpp, 59 | cert-err60-cpp, 60 | cert-flp30-c, 61 | cert-msc50-cpp, 62 | cert-msc51-cpp, 63 | cert-str34-c, 64 | cppcoreguidelines-interfaces-global-init, 65 | cppcoreguidelines-narrowing-conversions, 66 | cppcoreguidelines-pro-type-member-init, 67 | cppcoreguidelines-pro-type-static-cast-downcast, 68 | cppcoreguidelines-slicing, 69 | google-default-arguments, 70 | google-explicit-constructor, 71 | google-runtime-operator, 72 | hicpp-exception-baseclass, 73 | hicpp-multiway-paths-covered, 74 | misc-misplaced-const, 75 | misc-new-delete-overloads, 76 | misc-no-recursion, 77 | misc-non-copyable-objects, 78 | misc-throw-by-value-catch-by-reference, 79 | misc-unconventional-assign-operator, 80 | misc-uniqueptr-reset-release, 81 | modernize-avoid-bind, 82 | modernize-concat-nested-namespaces, 83 | modernize-deprecated-headers, 84 | modernize-deprecated-ios-base-aliases, 85 | modernize-loop-convert, 86 | modernize-make-shared, 87 | modernize-make-unique, 88 | modernize-pass-by-value, 89 | modernize-raw-string-literal, 90 | modernize-redundant-void-arg, 91 | modernize-replace-auto-ptr, 92 | modernize-replace-disallow-copy-and-assign-macro, 93 | modernize-replace-random-shuffle, 94 | modernize-return-braced-init-list, 95 | modernize-shrink-to-fit, 96 | modernize-unary-static-assert, 97 | modernize-use-auto, 98 | modernize-use-bool-literals, 99 | modernize-use-emplace, 100 | modernize-use-equals-default, 101 | modernize-use-equals-delete, 102 | modernize-use-nodiscard, 103 | modernize-use-noexcept, 104 | modernize-use-nullptr, 105 | modernize-use-override, 106 | modernize-use-transparent-functors, 107 | modernize-use-uncaught-exceptions, 108 | mpi-buffer-deref, 109 | mpi-type-mismatch, 110 | openmp-use-default-none, 111 | performance-faster-string-find, 112 | performance-for-range-copy, 113 | performance-implicit-conversion-in-loop, 114 | performance-inefficient-algorithm, 115 | performance-inefficient-string-concatenation, 116 | performance-inefficient-vector-operation, 117 | performance-move-const-arg, 118 | performance-move-constructor-init, 119 | performance-no-automatic-move, 120 | performance-noexcept-move-constructor, 121 | performance-trivially-destructible, 122 | performance-type-promotion-in-math-fn, 123 | performance-unnecessary-copy-initialization, 124 | performance-unnecessary-value-param, 125 | portability-simd-intrinsics, 126 | readability-avoid-const-params-in-decls, 127 | readability-const-return-type, 128 | readability-container-size-empty, 129 | readability-convert-member-functions-to-static, 130 | readability-delete-null-pointer, 131 | readability-deleted-default, 132 | readability-inconsistent-declaration-parameter-name, 133 | readability-make-member-function-const, 134 | readability-misleading-indentation, 135 | readability-misplaced-array-index, 136 | readability-non-const-parameter, 137 | readability-redundant-control-flow, 138 | readability-redundant-declaration, 139 | readability-redundant-function-ptr-dereference, 140 | readability-redundant-smartptr-get, 141 | readability-redundant-string-cstr, 142 | readability-redundant-string-init, 143 | readability-simplify-subscript-expr, 144 | readability-static-accessed-through-instance, 145 | readability-static-definition-in-anonymous-namespace, 146 | readability-string-compare, 147 | readability-uniqueptr-delete-release, 148 | readability-use-anyofallof' -------------------------------------------------------------------------------- /ReSTIRSSS/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | project(restirsss VERSION 0.1.0 DESCRIPTION "ReSTIR Subsurface Scattering" LANGUAGES CXX) 3 | 4 | set(CMAKE_CXX_STANDARD 20) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | 7 | set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) 8 | 9 | find_package(Vulkan REQUIRED) 10 | 11 | #set(GCC_COVERAGE_COMPILE_FLAGS "-fpermissive") 12 | #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}") 13 | 14 | message(STATUS "Compiler Version: ${CMAKE_CXX_COMPILER_ID}") 15 | message(STATUS "Compiler Version: ${CMAKE_CXX_COMPILER_VERSION}") 16 | 17 | # VkRaven Core 18 | if(NOT RAVEN_BASE_DIRECTORY) 19 | message(${CMAKE_CURRENT_SOURCE_DIR}) 20 | find_path(RAVEN_BASE_DIRECTORY 21 | NAMES VkRaven/cmake/setup.cmake 22 | PATHS ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/../.. 23 | REQUIRED 24 | DOC "Directory containing VkRaven" 25 | ) 26 | endif() 27 | if(EXISTS ${RAVEN_BASE_DIRECTORY}/VkRaven) 28 | add_subdirectory(${RAVEN_BASE_DIRECTORY}/VkRaven ${CMAKE_CURRENT_BINARY_DIR}/VkRaven) 29 | else() 30 | message(FATAL_ERROR "Could not find base directory, please set RAVEN_BASE_DIRECTORY to folder containing VkRaven") 31 | endif() 32 | set(RAVEN_CORE_DIR ${RAVEN_BASE_DIRECTORY}/VkRaven) 33 | 34 | SET(ENABLE_OPTIX ON) 35 | if (ENABLE_OPTIX) 36 | find_package(CUDAToolkit) 37 | if (CUDAToolkit_FOUND) 38 | _add_package_Optix() 39 | else() 40 | message(STATUS "CudaToolkit: Not found") 41 | message(STATUS "OptiX: Disabled") 42 | endif () 43 | endif () 44 | 45 | set(RAVENPROJECT_HEADERS 46 | include/restirsss/Raystructs.h include/restirsss/Raydata.h include/restirsss/Rayscenes.h 47 | include/restirsss/passes/PassTonemapper.h 48 | include/denoiser/DenoiserOptiX.h 49 | include/restirsss/ReSTIRSSS.h 50 | include/restirsss/passes/PassGBuffer.h include/restirsss/passes/PassDebug.h include/restirsss/passes/PassSurface.h include/restirsss/passes/PassPathtrace.h 51 | include/restirsss/passes/ReSTIRSSSPassCandidateGeneration.h include/restirsss/passes/ReSTIRSSSPassTemporalReuse.h include/restirsss/passes/ReSTIRSSSPassSpatialReuse.h include/restirsss/passes/ReSTIRSSSPassShade.h 52 | include/restirsss/ReSTIRSSSEvaluation.h include/restirsss/ReSTIRSSSEvaluationTiming.h include/restirsss/ReSTIRSSSVideo.h 53 | ) 54 | 55 | set(RAVENPROJECT_SOURCES 56 | src/bin/main.cpp 57 | src/denoiser/DenoiserOptiX.cpp 58 | src/restirsss/ReSTIRSSS.cpp src/restirsss/ReSTIRSSSEvaluation.cpp src/restirsss/ReSTIRSSSEvaluationTiming.cpp src/restirsss/ReSTIRSSSVideo.cpp 59 | ) 60 | 61 | add_executable(${CMAKE_PROJECT_NAME} ${RAVENPROJECT_HEADERS} ${RAVENPROJECT_SOURCES}) 62 | 63 | target_link_libraries(${CMAKE_PROJECT_NAME} glm Vulkan::Vulkan imgui stb tinyobjloader tinygltf spirv-reflect ravencore glfw pugixml argparse) 64 | if (CUDAToolkit_FOUND) 65 | target_link_libraries(${CMAKE_PROJECT_NAME} CUDA::cudart CUDA::cuda_driver) 66 | endif () 67 | 68 | target_include_directories(${CMAKE_PROJECT_NAME} 69 | PUBLIC 70 | $ 71 | $ 72 | PRIVATE 73 | ${CMAKE_CURRENT_SOURCE_DIR}/src 74 | ) 75 | if (OPTIX_FOUND) 76 | target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE ${OPTIX_INCLUDE_DIR}) 77 | endif () 78 | 79 | target_include_directories(${PROJECT_NAME} PRIVATE ${OPTIX_INCLUDE_DIR}) 80 | 81 | target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE -DVULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1 -DVULKAN_HPP_STORAGE_SHARED=1) 82 | 83 | SET(RESOURCE_DIRECTORY_PATH \"${CMAKE_CURRENT_SOURCE_DIR}/resources\") 84 | if (RESOURCE_DIRECTORY_PATH) 85 | target_compile_definitions(${CMAKE_PROJECT_NAME} PRIVATE RESOURCE_DIRECTORY_PATH=${RESOURCE_DIRECTORY_PATH}) 86 | endif () 87 | 88 | add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD 89 | COMMAND ${CMAKE_COMMAND} -E copy_directory 90 | "${PROJECT_BINARY_DIR}/VkRaven/lib" 91 | "${PROJECT_BINARY_DIR}") 92 | add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD 93 | COMMAND ${CMAKE_COMMAND} -E copy_directory 94 | "${PROJECT_BINARY_DIR}/VkRaven/raven" 95 | "${PROJECT_BINARY_DIR}") -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/Raystructs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace raven { 6 | struct ObjectDescriptor { 7 | uint64_t vertexAddress{}; 8 | uint64_t indexAddress{}; 9 | uint32_t materialId = 0; 10 | 11 | glm::mat4 modelMatrix = glm::mat4(1.f); 12 | glm::mat4 objectToWorldNormal = glm::mat4(1.f); 13 | }; 14 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/ReSTIRSSSEvaluation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ReSTIRSSS.h" 4 | #include "raven/core/HeadlessApplication.h" 5 | 6 | #include 7 | 8 | namespace raven { 9 | class ReSTIRSSSEvaluation { 10 | #ifdef WIN32 11 | #define DEVICE_EXTENSIONS \ 12 | { VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, VK_KHR_RAY_QUERY_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME } 13 | #else 14 | #define DEVICE_EXTENSIONS \ 15 | { VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, VK_KHR_RAY_QUERY_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME } 16 | #endif 17 | 18 | public: 19 | int run() { 20 | if (!initialize()) { 21 | return EXIT_FAILURE; 22 | } 23 | if (!evaluate()) { 24 | return EXIT_FAILURE; 25 | } 26 | return EXIT_SUCCESS; 27 | } 28 | 29 | private: 30 | std::string m_directory; 31 | 32 | const bool m_groundTruth = true; 33 | const bool m_png = true; 34 | const bool m_nonSSSObject = true; 35 | 36 | bool initialize() { 37 | const auto t = std::time(nullptr); 38 | const auto tm = *std::localtime(&t); 39 | std::ostringstream oss; 40 | oss << std::put_time(&tm, "evaluation/%Y-%m-%d-%H-%M-%S"); 41 | m_directory = oss.str(); 42 | 43 | return std::filesystem::create_directories(m_directory); 44 | } 45 | 46 | [[nodiscard]] bool evaluateAjax() const; 47 | 48 | [[nodiscard]] bool evaluateAjaxManyLights() const; 49 | 50 | [[nodiscard]] bool evaluateAjaxIntersectionCount() const; 51 | 52 | [[nodiscard]] bool evaluateAsianDragon(uint32_t sceneMode) const; 53 | 54 | [[nodiscard]] bool evaluateLTEOrb(uint32_t sceneMode) const; 55 | 56 | [[nodiscard]] bool evaluateSpatioTemporalConvergenceAjax() const; 57 | [[nodiscard]] bool evaluateSpatioTemporalConvergenceLTEOrb(uint32_t sceneMode) const; 58 | 59 | [[nodiscard]] bool evaluate() const { 60 | if (!evaluateAjax()) { 61 | return false; 62 | } 63 | 64 | if (!evaluateAjaxManyLights()) { 65 | return false; 66 | } 67 | 68 | if (!evaluateAjaxIntersectionCount()) { 69 | return false; 70 | } 71 | 72 | for (uint32_t i = 0; i < 4; i++) { 73 | if (!evaluateAsianDragon(i)) { 74 | return false; 75 | } 76 | } 77 | 78 | for (uint32_t i = 0; i < 11; i++) { 79 | if (i == 5 || i == 6 || i == 8 || i == 9 || i == 10) { 80 | if (!evaluateLTEOrb(i)) { 81 | return false; 82 | } 83 | } 84 | } 85 | 86 | // if (!evaluateSpatioTemporalConvergenceAjax()) { 87 | // return false; 88 | // } 89 | // if (!evaluateSpatioTemporalConvergenceLTEOrb(6)) { 90 | // return false; 91 | // } 92 | 93 | return true; 94 | } 95 | 96 | static void writeRMSECompare(std::ofstream &compareScript, const std::string &namePrefix, const std::string &nameSuffix) { 97 | compareScript << "printf \"" << namePrefix << nameSuffix << ".png\\n\" 2>&1 | tee -a rmse.txt\n"; 98 | compareScript << "compare -metric RMSE " << namePrefix << "ground_truth.png " << namePrefix << nameSuffix << ".png null: 2>&1 | tee -a rmse.txt\n"; 99 | compareScript << "printf \"\\n\" 2>&1 | tee -a rmse.txt\n"; 100 | } 101 | 102 | static void writeHDRRMSECompare(std::ofstream &compareScript, const std::string &namePrefix, const std::string &nameSuffix) { 103 | compareScript << "printf \"" << namePrefix << nameSuffix << ".hdr\\n\" 2>&1 | tee -a hdr_rmse.txt\n"; 104 | compareScript << "./hdr_rmse.sh " << namePrefix << "ground_truth.hdr " << namePrefix << nameSuffix << ".hdr null: 2>&1 | tee -a hdr_rmse.txt\n"; 105 | compareScript << "printf \"\\n\" 2>&1 | tee -a hdr_rmse.txt\n"; 106 | } 107 | 108 | static void writeMSECompare(std::ofstream &compareScript, const std::string &namePrefix, const std::string &nameSuffix) { 109 | compareScript << "printf \"" << namePrefix << nameSuffix << ".png\\n\" 2>&1 | tee -a mse.txt\n"; 110 | compareScript << "compare -metric MSE " << namePrefix << "ground_truth.png " << namePrefix << nameSuffix << ".png null: 2>&1 | tee -a mse.txt\n"; 111 | compareScript << "printf \"\\n\" 2>&1 | tee -a mse.txt\n"; 112 | } 113 | 114 | static void writeFLIPCompare(std::ofstream &compareScript, const std::string &namePrefix, const std::string &nameSuffix) { 115 | compareScript << "printf \"" << namePrefix << nameSuffix << ".png\\n\" 2>&1 | tee -a flip.txt\n"; 116 | compareScript << "./flip.sh " << namePrefix << "ground_truth.png " << namePrefix << nameSuffix << ".png 2>&1 | tee -a flip.txt\n"; 117 | compareScript << "printf \"\\n\" 2>&1 | tee -a flip.txt\n"; 118 | } 119 | }; 120 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/ReSTIRSSSEvaluationTiming.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ReSTIRSSS.h" 4 | #include "raven/core/TimingHeadlessApplication.h" 5 | 6 | namespace raven { 7 | class ReSTIRSSSEvaluationTiming { 8 | #ifdef WIN32 9 | #define DEVICE_EXTENSIONS \ 10 | { VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, VK_KHR_RAY_QUERY_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME } 11 | #else 12 | #define DEVICE_EXTENSIONS \ 13 | { VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, VK_KHR_RAY_QUERY_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME } 14 | #endif 15 | 16 | public: 17 | int run() { 18 | if (!initialize()) { 19 | return EXIT_FAILURE; 20 | } 21 | if (!evaluate()) { 22 | return EXIT_FAILURE; 23 | } 24 | return EXIT_SUCCESS; 25 | } 26 | 27 | private: 28 | std::string m_directory; 29 | 30 | bool initialize() { 31 | const auto t = std::time(nullptr); 32 | const auto tm = *std::localtime(&t); 33 | std::ostringstream oss; 34 | oss << std::put_time(&tm, "evaluation-timing/%Y-%m-%d-%H-%M-%S"); 35 | m_directory = oss.str(); 36 | 37 | return std::filesystem::create_directories(m_directory); 38 | } 39 | 40 | [[nodiscard]] bool evaluateAjax() const; 41 | 42 | [[nodiscard]] bool evaluateAjaxManyLights() const; 43 | 44 | [[nodiscard]] bool evaluateAsianDragon(uint32_t sceneMode) const; 45 | 46 | [[nodiscard]] bool evaluateLTEOrb(uint32_t sceneMode) const; 47 | 48 | [[nodiscard]] bool evaluate() const { 49 | if (!evaluateAjax()) { 50 | return false; 51 | } 52 | 53 | if (!evaluateAjaxManyLights()) { 54 | return false; 55 | } 56 | 57 | for (uint32_t i = 0; i < 4; i++) { 58 | if (!evaluateAsianDragon(i)) { 59 | return false; 60 | } 61 | } 62 | 63 | for (uint32_t i = 0; i < 11; i++) { 64 | if (i == 5 || i == 6 || i == 8 || i == 9 || i == 10) { 65 | if (!evaluateLTEOrb(i)) { 66 | return false; 67 | } 68 | } 69 | } 70 | 71 | return true; 72 | } 73 | }; 74 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/ReSTIRSSSVideo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ReSTIRSSS.h" 4 | 5 | #include 6 | 7 | namespace raven { 8 | class ReSTIRSSSVideo { 9 | #ifdef WIN32 10 | #define DEVICE_EXTENSIONS \ 11 | { VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, VK_KHR_RAY_QUERY_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME } 12 | #else 13 | #define DEVICE_EXTENSIONS \ 14 | { VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, VK_KHR_RAY_QUERY_EXTENSION_NAME, VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME } 15 | #endif 16 | 17 | public: 18 | int run() { 19 | if (!initialize()) { 20 | return EXIT_FAILURE; 21 | } 22 | if (!evaluate()) { 23 | return EXIT_FAILURE; 24 | } 25 | return EXIT_SUCCESS; 26 | } 27 | 28 | private: 29 | std::string m_directory; 30 | 31 | bool initialize() { 32 | const auto t = std::time(nullptr); 33 | const auto tm = *std::localtime(&t); 34 | std::ostringstream oss; 35 | oss << std::put_time(&tm, "video/%Y-%m-%d-%H-%M-%S"); 36 | m_directory = oss.str(); 37 | 38 | return std::filesystem::create_directories(m_directory); 39 | } 40 | 41 | [[nodiscard]] bool videoAjaxReference() const; 42 | [[nodiscard]] bool videoAjaxPT1SPP() const; 43 | [[nodiscard]] bool videoAjaxPT1SPPDenoised() const; 44 | [[nodiscard]] bool videoAjaxPT6SPP() const; 45 | [[nodiscard]] bool videoAjaxPT6SPPDenoised() const; 46 | [[nodiscard]] bool videoAjaxPT12SPP() const; 47 | [[nodiscard]] bool videoAjaxPT12SPPDenoised() const; 48 | [[nodiscard]] bool videoAjaxSequential() const; 49 | [[nodiscard]] bool videoAjaxSequentialDenoised() const; 50 | 51 | [[nodiscard]] bool videoAsianDragonSpatiotemporalSequential() const; 52 | 53 | [[nodiscard]] bool evaluate() const { 54 | if (!videoAjaxReference()) { 55 | return false; 56 | } 57 | if (!videoAjaxPT1SPP()) { 58 | return false; 59 | } 60 | if (!videoAjaxPT1SPPDenoised()) { 61 | return false; 62 | } 63 | // if (!videoAjaxPT6SPP()) { 64 | // return false; 65 | // } 66 | // if (!videoAjaxPT6SPPDenoised()) { 67 | // return false; 68 | // } 69 | // if (!videoAjaxPT12SPP()) { 70 | // return false; 71 | // } 72 | // if (!videoAjaxPT12SPPDenoised()) { 73 | // return false; 74 | // } 75 | if (!videoAjaxSequential()) { 76 | return false; 77 | } 78 | if (!videoAjaxSequentialDenoised()) { 79 | return false; 80 | } 81 | 82 | // if (!videoAsianDragonSpatiotemporalSequential()) { 83 | // return false; 84 | // } 85 | 86 | return true; 87 | } 88 | }; 89 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/passes/PassDebug.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "raven/passes/PassShaderCompute.h" 4 | #include "raven/util/Paths.h" 5 | 6 | namespace raven { 7 | class PassDebug final : public PassShaderCompute { 8 | public: 9 | explicit PassDebug(GPUContext *gpuContext) : PassShaderCompute(gpuContext, "PassDebug") { 10 | } 11 | 12 | struct PushConstants { 13 | glm::ivec2 g_pixels; 14 | 15 | glm::vec3 g_ray_origin; 16 | glm::vec3 g_ray_left_bottom; 17 | glm::vec3 g_ray_left_top; 18 | glm::vec3 g_ray_right_bottom; 19 | glm::vec3 g_ray_right_top; 20 | 21 | uint32_t g_frame = 0; 22 | 23 | uint32_t g_rng_init; 24 | uint32_t g_rng_init_offset; 25 | }; 26 | 27 | PushConstants m_pushConstants = {}; 28 | 29 | protected: 30 | std::vector> createShaders() override { 31 | constexpr auto workGroupSize = vk::Extent3D{8, 8, 1}; 32 | auto specializationMapEntries = std::vector{vk::SpecializationMapEntry{0, 0, sizeof(uint32_t)}, 33 | vk::SpecializationMapEntry{1, 4, sizeof(uint32_t)}, 34 | vk::SpecializationMapEntry{2, 8, sizeof(uint32_t)}}; 35 | auto specializationData = std::vector{workGroupSize.width, workGroupSize.height, workGroupSize.depth}; 36 | return {std::make_shared(m_gpuContext, Paths::m_resourceDirectoryPath + "/shaders/main/passes", "pass_debug.comp", vk::ShaderStageFlagBits::eCompute, workGroupSize, specializationMapEntries, specializationData)}; 37 | } 38 | 39 | uint32_t getPushConstantRangeSize() override { 40 | return sizeof(PushConstants); 41 | } 42 | }; 43 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/passes/PassGBuffer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "raven/passes/PassShaderCompute.h" 4 | #include "raven/util/Paths.h" 5 | 6 | namespace raven { 7 | class PassGBuffer final : public PassShaderCompute { 8 | public: 9 | explicit PassGBuffer(GPUContext *gpuContext) : PassShaderCompute(gpuContext, "PassGBuffer") { 10 | } 11 | 12 | struct PushConstants { 13 | glm::ivec2 g_pixels; 14 | 15 | glm::vec3 g_ray_origin; 16 | glm::vec3 g_ray_left_bottom; 17 | glm::vec3 g_ray_left_top; 18 | glm::vec3 g_ray_right_bottom; 19 | glm::vec3 g_ray_right_top; 20 | 21 | uint32_t g_frame = 0; 22 | 23 | uint32_t g_rng_init; 24 | uint32_t g_rng_init_offset; 25 | }; 26 | 27 | PushConstants m_pushConstants = {}; 28 | 29 | protected: 30 | std::vector> createShaders() override { 31 | constexpr auto workGroupSize = vk::Extent3D{8, 8, 1}; 32 | auto specializationMapEntries = std::vector{vk::SpecializationMapEntry{0, 0, sizeof(uint32_t)}, 33 | vk::SpecializationMapEntry{1, 4, sizeof(uint32_t)}, 34 | vk::SpecializationMapEntry{2, 8, sizeof(uint32_t)}}; 35 | auto specializationData = std::vector{workGroupSize.width, workGroupSize.height, workGroupSize.depth}; 36 | return {std::make_shared(m_gpuContext, Paths::m_resourceDirectoryPath + "/shaders/main/passes", "pass_gbuffer.comp", vk::ShaderStageFlagBits::eCompute, workGroupSize, specializationMapEntries, specializationData)}; 37 | } 38 | 39 | uint32_t getPushConstantRangeSize() override { 40 | return sizeof(PushConstants); 41 | } 42 | }; 43 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/passes/PassPathtrace.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "raven/passes/PassShaderCompute.h" 4 | #include "raven/util/Paths.h" 5 | 6 | namespace raven { 7 | class PassPathtrace final : public PassShaderCompute { 8 | public: 9 | explicit PassPathtrace(GPUContext *gpuContext) : PassShaderCompute(gpuContext, "PassPathtrace") { 10 | } 11 | 12 | struct PushConstants { 13 | glm::ivec2 g_pixels; 14 | 15 | glm::vec3 g_ray_origin; 16 | glm::vec3 g_ray_left_bottom; 17 | glm::vec3 g_ray_left_top; 18 | glm::vec3 g_ray_right_bottom; 19 | glm::vec3 g_ray_right_top; 20 | 21 | uint32_t g_frame = 0; 22 | 23 | uint32_t g_rng_init; 24 | uint32_t g_rng_init_offset; 25 | }; 26 | 27 | PushConstants m_pushConstants = {}; 28 | 29 | protected: 30 | std::vector> createShaders() override { 31 | constexpr auto workGroupSize = vk::Extent3D{8, 8, 1}; 32 | auto specializationMapEntries = std::vector{vk::SpecializationMapEntry{0, 0, sizeof(uint32_t)}, 33 | vk::SpecializationMapEntry{1, 4, sizeof(uint32_t)}, 34 | vk::SpecializationMapEntry{2, 8, sizeof(uint32_t)}}; 35 | auto specializationData = std::vector{workGroupSize.width, workGroupSize.height, workGroupSize.depth}; 36 | return {std::make_shared(m_gpuContext, Paths::m_resourceDirectoryPath + "/shaders/main/passes", "pass_pathtrace.comp", vk::ShaderStageFlagBits::eCompute, workGroupSize, specializationMapEntries, specializationData)}; 37 | } 38 | 39 | uint32_t getPushConstantRangeSize() override { 40 | return sizeof(PushConstants); 41 | } 42 | }; 43 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/passes/PassSurface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "raven/passes/PassShaderCompute.h" 4 | #include "raven/util/Paths.h" 5 | 6 | namespace raven { 7 | class PassSurface final : public PassShaderCompute { 8 | public: 9 | explicit PassSurface(GPUContext *gpuContext) : PassShaderCompute(gpuContext, "PassSurface") { 10 | } 11 | 12 | struct PushConstants { 13 | glm::ivec2 g_pixels; 14 | 15 | glm::vec3 g_ray_origin; 16 | glm::vec3 g_ray_left_bottom; 17 | glm::vec3 g_ray_left_top; 18 | glm::vec3 g_ray_right_bottom; 19 | glm::vec3 g_ray_right_top; 20 | 21 | uint32_t g_frame = 0; 22 | 23 | uint32_t g_rng_init; 24 | uint32_t g_rng_init_offset; 25 | }; 26 | 27 | PushConstants m_pushConstants = {}; 28 | 29 | protected: 30 | std::vector> createShaders() override { 31 | constexpr auto workGroupSize = vk::Extent3D{8, 8, 1}; 32 | auto specializationMapEntries = std::vector{vk::SpecializationMapEntry{0, 0, sizeof(uint32_t)}, 33 | vk::SpecializationMapEntry{1, 4, sizeof(uint32_t)}, 34 | vk::SpecializationMapEntry{2, 8, sizeof(uint32_t)}}; 35 | auto specializationData = std::vector{workGroupSize.width, workGroupSize.height, workGroupSize.depth}; 36 | return {std::make_shared(m_gpuContext, Paths::m_resourceDirectoryPath + "/shaders/main/passes", "pass_surface.comp", vk::ShaderStageFlagBits::eCompute, workGroupSize, specializationMapEntries, specializationData)}; 37 | } 38 | 39 | uint32_t getPushConstantRangeSize() override { 40 | return sizeof(PushConstants); 41 | } 42 | }; 43 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/passes/PassTonemapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "raven/passes/PassShaderCompute.h" 4 | #include "raven/util/Paths.h" 5 | 6 | namespace raven { 7 | class PassTonemapper final : public PassShaderCompute { 8 | public: 9 | explicit PassTonemapper(GPUContext *gpuContext) : PassShaderCompute(gpuContext, "PassTonemapper") { 10 | } 11 | 12 | struct PushConstants { 13 | glm::ivec2 g_pixels; 14 | 15 | uint32_t g_tonemapper; 16 | }; 17 | 18 | PushConstants m_pushConstants = {}; 19 | 20 | protected: 21 | std::vector> createShaders() override { 22 | constexpr auto workGroupSize = vk::Extent3D{8, 8, 1}; 23 | auto specializationMapEntries = std::vector{vk::SpecializationMapEntry{0, 0, sizeof(uint32_t)}, 24 | vk::SpecializationMapEntry{1, 4, sizeof(uint32_t)}, 25 | vk::SpecializationMapEntry{2, 8, sizeof(uint32_t)}}; 26 | auto specializationData = std::vector{workGroupSize.width, workGroupSize.height, workGroupSize.depth}; 27 | return {std::make_shared(m_gpuContext, Paths::m_resourceDirectoryPath + "/shaders/main/passes", "pass_tonemapper.comp", vk::ShaderStageFlagBits::eCompute, workGroupSize, specializationMapEntries, specializationData)}; 28 | } 29 | 30 | uint32_t getPushConstantRangeSize() override { 31 | return sizeof(PushConstants); 32 | } 33 | }; 34 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/passes/ReSTIRSSSPassCandidateGeneration.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "raven/passes/PassShaderCompute.h" 4 | #include "raven/util/Paths.h" 5 | 6 | namespace raven { 7 | class ReSTIRSSSPassCandidateGeneration final : public PassShaderCompute { 8 | public: 9 | explicit ReSTIRSSSPassCandidateGeneration(GPUContext *gpuContext) : PassShaderCompute(gpuContext, "ReSTIRSSSPassCandidateGeneration") { 10 | } 11 | 12 | struct PushConstants { 13 | glm::ivec2 g_pixels; 14 | 15 | glm::vec3 g_ray_origin; 16 | glm::vec3 g_ray_left_bottom; 17 | glm::vec3 g_ray_left_top; 18 | glm::vec3 g_ray_right_bottom; 19 | glm::vec3 g_ray_right_top; 20 | 21 | uint32_t g_frame = 0; 22 | 23 | uint32_t g_rng_init; 24 | uint32_t g_rng_init_offset; 25 | }; 26 | 27 | PushConstants m_pushConstants = {}; 28 | 29 | protected: 30 | std::vector> createShaders() override { 31 | constexpr auto workGroupSize = vk::Extent3D{8, 8, 1}; 32 | auto specializationMapEntries = std::vector{vk::SpecializationMapEntry{0, 0, sizeof(uint32_t)}, 33 | vk::SpecializationMapEntry{1, 4, sizeof(uint32_t)}, 34 | vk::SpecializationMapEntry{2, 8, sizeof(uint32_t)}}; 35 | auto specializationData = std::vector{workGroupSize.width, workGroupSize.height, workGroupSize.depth}; 36 | return {std::make_shared(m_gpuContext, Paths::m_resourceDirectoryPath + "/shaders/main/passes", "restirsss_pass_candidate_generation.comp", vk::ShaderStageFlagBits::eCompute, workGroupSize, specializationMapEntries, specializationData)}; 37 | } 38 | 39 | uint32_t getPushConstantRangeSize() override { 40 | return sizeof(PushConstants); 41 | } 42 | }; 43 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/passes/ReSTIRSSSPassShade.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "raven/passes/PassShaderCompute.h" 4 | #include "raven/util/Paths.h" 5 | 6 | namespace raven { 7 | class ReSTIRSSSPassShade final : public PassShaderCompute { 8 | public: 9 | explicit ReSTIRSSSPassShade(GPUContext *gpuContext) : PassShaderCompute(gpuContext, "ReSTIRSSSPassShade") { 10 | } 11 | 12 | struct PushConstants { 13 | glm::ivec2 g_pixels; 14 | 15 | glm::vec3 g_ray_origin; 16 | glm::vec3 g_ray_left_bottom; 17 | glm::vec3 g_ray_left_top; 18 | glm::vec3 g_ray_right_bottom; 19 | glm::vec3 g_ray_right_top; 20 | 21 | uint32_t g_frame = 0; 22 | 23 | uint32_t g_rng_init; 24 | uint32_t g_rng_init_offset; 25 | }; 26 | 27 | PushConstants m_pushConstants = {}; 28 | 29 | protected: 30 | std::vector> createShaders() override { 31 | constexpr auto workGroupSize = vk::Extent3D{8, 8, 1}; 32 | auto specializationMapEntries = std::vector{vk::SpecializationMapEntry{0, 0, sizeof(uint32_t)}, 33 | vk::SpecializationMapEntry{1, 4, sizeof(uint32_t)}, 34 | vk::SpecializationMapEntry{2, 8, sizeof(uint32_t)}}; 35 | auto specializationData = std::vector{workGroupSize.width, workGroupSize.height, workGroupSize.depth}; 36 | return {std::make_shared(m_gpuContext, Paths::m_resourceDirectoryPath + "/shaders/main/passes", "restirsss_pass_shade.comp", vk::ShaderStageFlagBits::eCompute, workGroupSize, specializationMapEntries, specializationData)}; 37 | } 38 | 39 | uint32_t getPushConstantRangeSize() override { 40 | return sizeof(PushConstants); 41 | } 42 | }; 43 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/passes/ReSTIRSSSPassSpatialReuse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "raven/passes/PassShaderCompute.h" 4 | #include "raven/util/Paths.h" 5 | 6 | namespace raven { 7 | class ReSTIRSSSPassSpatialReuse final : public PassShaderCompute { 8 | public: 9 | explicit ReSTIRSSSPassSpatialReuse(GPUContext *gpuContext, const uint32_t spatialCount) : PassShaderCompute(gpuContext, "ReSTIRSSSPassSpatialReuse"), m_spatialCount(spatialCount) { 10 | } 11 | 12 | struct PushConstants { 13 | glm::ivec2 g_pixels; 14 | 15 | glm::vec3 g_ray_origin; 16 | glm::vec3 g_ray_left_bottom; 17 | glm::vec3 g_ray_left_top; 18 | glm::vec3 g_ray_right_bottom; 19 | glm::vec3 g_ray_right_top; 20 | 21 | uint32_t g_frame = 0; 22 | 23 | uint32_t g_rng_init; 24 | uint32_t g_rng_init_offset; 25 | }; 26 | 27 | PushConstants m_pushConstants = {}; 28 | 29 | void updateSpecializationConstant3(const uint32_t value) { 30 | m_spatialCount = value; 31 | auto specializationMapEntries = std::vector{vk::SpecializationMapEntry{0, 0, sizeof(uint32_t)}, 32 | vk::SpecializationMapEntry{1, 4, sizeof(uint32_t)}, 33 | vk::SpecializationMapEntry{2, 8, sizeof(uint32_t)}, 34 | vk::SpecializationMapEntry{3, 12, sizeof(uint32_t)}}; 35 | auto specializationData = std::vector{workGroupSize.width, workGroupSize.height, workGroupSize.depth, m_spatialCount}; 36 | updateSpecializationConstants(0, specializationMapEntries, specializationData); 37 | } 38 | 39 | protected: 40 | const vk::Extent3D workGroupSize = vk::Extent3D{8, 8, 1}; 41 | uint32_t m_spatialCount = 0; 42 | 43 | std::vector> createShaders() override { 44 | auto specializationMapEntries = std::vector{vk::SpecializationMapEntry{0, 0, sizeof(uint32_t)}, 45 | vk::SpecializationMapEntry{1, 4, sizeof(uint32_t)}, 46 | vk::SpecializationMapEntry{2, 8, sizeof(uint32_t)}, 47 | vk::SpecializationMapEntry{3, 12, sizeof(uint32_t)}}; 48 | auto specializationData = std::vector{workGroupSize.width, workGroupSize.height, workGroupSize.depth, m_spatialCount}; 49 | return {std::make_shared(m_gpuContext, Paths::m_resourceDirectoryPath + "/shaders/main/passes", "restirsss_pass_spatial_reuse.comp", vk::ShaderStageFlagBits::eCompute, workGroupSize, specializationMapEntries, specializationData)}; 50 | } 51 | 52 | uint32_t getPushConstantRangeSize() override { 53 | return sizeof(PushConstants); 54 | } 55 | }; 56 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/include/restirsss/passes/ReSTIRSSSPassTemporalReuse.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "raven/passes/PassShaderCompute.h" 4 | #include "raven/util/Paths.h" 5 | 6 | namespace raven { 7 | class ReSTIRSSSPassTemporalReuse final : public PassShaderCompute { 8 | public: 9 | explicit ReSTIRSSSPassTemporalReuse(GPUContext *gpuContext) : PassShaderCompute(gpuContext, "ReSTIRSSSPassTemporalReuse") { 10 | } 11 | 12 | struct PushConstants { 13 | glm::ivec2 g_pixels; 14 | 15 | glm::vec3 g_ray_origin; 16 | glm::vec3 g_ray_left_bottom; 17 | glm::vec3 g_ray_left_top; 18 | glm::vec3 g_ray_right_bottom; 19 | glm::vec3 g_ray_right_top; 20 | 21 | uint32_t g_frame = 0; 22 | 23 | uint32_t g_rng_init; 24 | uint32_t g_rng_init_offset; 25 | }; 26 | 27 | PushConstants m_pushConstants = {}; 28 | 29 | protected: 30 | std::vector> createShaders() override { 31 | constexpr auto workGroupSize = vk::Extent3D{8, 8, 1}; 32 | auto specializationMapEntries = std::vector{vk::SpecializationMapEntry{0, 0, sizeof(uint32_t)}, 33 | vk::SpecializationMapEntry{1, 4, sizeof(uint32_t)}, 34 | vk::SpecializationMapEntry{2, 8, sizeof(uint32_t)}}; 35 | auto specializationData = std::vector{workGroupSize.width, workGroupSize.height, workGroupSize.depth}; 36 | return {std::make_shared(m_gpuContext, Paths::m_resourceDirectoryPath + "/shaders/main/passes", "restirsss_pass_temporal_reuse.comp", vk::ShaderStageFlagBits::eCompute, workGroupSize, specializationMapEntries, specializationData)}; 37 | } 38 | 39 | uint32_t getPushConstantRangeSize() override { 40 | return sizeof(PushConstants); 41 | } 42 | }; 43 | } // namespace raven -------------------------------------------------------------------------------- /ReSTIRSSS/resources/environment/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MircoWerner/ReSTIR-SSS/c209f2b72b85cc51aa2577c14534952154ae4313/ReSTIRSSS/resources/environment/white.png -------------------------------------------------------------------------------- /ReSTIRSSS/resources/scenes/ajax.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 23 | -------------------------------------------------------------------------------- /ReSTIRSSS/resources/scenes/ajaxmanylights.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 23 | -------------------------------------------------------------------------------- /ReSTIRSSS/resources/scenes/asiandragon.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 22 | -------------------------------------------------------------------------------- /ReSTIRSSS/resources/scenes/flattest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /ReSTIRSSS/resources/scenes/lteorb.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 13 | -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/arealight.glsl: -------------------------------------------------------------------------------- 1 | #ifndef AREALIGHT_GLSL 2 | #define AREALIGHT_GLSL 3 | 4 | float arealight_areaTriangle(in const vec3 p0, in const vec3 p1, in const vec3 p2) { 5 | return 0.5 * length(cross(p1 - p0, p2 - p0)); 6 | } 7 | 8 | float arealight_pdf_vam(in const float numLights, in const vec3 p0World, in const vec3 p1World, in const vec3 p2World) { 9 | // pdf in solid angle by dividing by the geometry term 10 | return 1.0 / (numLights * arealight_areaTriangle(p0World, p1World, p2World)); 11 | } 12 | 13 | void arealight_sample_vam(in const uint xi1, in const float xi2, in const float xi3, in const vec3 vertexPositionWorld, out int objectDescriptorId, out int triangleId, out vec2 barycentrics, out vec3 position, out vec3 normal, out vec3 emission, out float pdf) { 14 | const Light light = g_lights[xi1];// introduces 1 / numLights pdf 15 | 16 | objectDescriptorId = int(light.objectDescriptorId); 17 | triangleId = int(light.triangleId); 18 | 19 | ObjectDescriptor objDesc = g_objectDescriptors[light.objectDescriptorId]; 20 | Indices indices = Indices(objDesc.indexAddress); 21 | Vertices vertices = Vertices(objDesc.vertexAddress); 22 | 23 | const ivec3 ind = indices.i[light.triangleId]; 24 | const Vertex v0 = vertices.v[ind.x]; 25 | const Vertex v1 = vertices.v[ind.y]; 26 | const Vertex v2 = vertices.v[ind.z]; 27 | 28 | const vec3 p0 = vec3(v0.position_x, v0.position_y, v0.position_z); 29 | const vec3 p1 = vec3(v1.position_x, v1.position_y, v1.position_z); 30 | const vec3 p2 = vec3(v2.position_x, v2.position_y, v2.position_z); 31 | 32 | const vec3 p0World = (objDesc.objectToWorld * vec4(p0, 1.0)).xyz; 33 | const vec3 p1World = (objDesc.objectToWorld * vec4(p1, 1.0)).xyz; 34 | const vec3 p2World = (objDesc.objectToWorld * vec4(p2, 1.0)).xyz; 35 | 36 | // generate point on the triangle 37 | const float s = 1 - sqrt(1 - xi2); 38 | const float t = (1 - s) * xi3; 39 | position = p0World + s * (p1World - p0World) + t * (p2World - p0World); 40 | 41 | const vec3 normalWorld = normalize(cross(p1World - p0World, p2World - p0World)); 42 | normal = dot(normalWorld, normalize(vertexPositionWorld - position)) >= 0.0 ? normalWorld : -normalWorld;// align normal in correct direction 43 | 44 | emission = light.emission; 45 | 46 | // pdf in area measure 47 | pdf = arealight_pdf_vam(g_num_lights, p0World, p1World, p2World); 48 | 49 | // barycentrics from positions 50 | const float area = arealight_areaTriangle(p0World, p1World, p2World); 51 | barycentrics.x = arealight_areaTriangle(p0World, position, p2World) / area;// barycentricsY 52 | barycentrics.y = arealight_areaTriangle(p0World, p1World, position) / area;// barycentricsZ 53 | } 54 | 55 | void arealight_sample_vam(in const uint xi1, in const float xi2, in const float xi3, out int objectDescriptorId, out int triangleId, out vec2 barycentrics, out vec3 position, out vec3 unalignedNormal, out vec3 emission, out float pdf) { 56 | const Light light = g_lights[xi1];// introduces 1 / numLights pdf 57 | 58 | objectDescriptorId = int(light.objectDescriptorId); 59 | triangleId = int(light.triangleId); 60 | 61 | ObjectDescriptor objDesc = g_objectDescriptors[light.objectDescriptorId]; 62 | Indices indices = Indices(objDesc.indexAddress); 63 | Vertices vertices = Vertices(objDesc.vertexAddress); 64 | 65 | const ivec3 ind = indices.i[light.triangleId]; 66 | const Vertex v0 = vertices.v[ind.x]; 67 | const Vertex v1 = vertices.v[ind.y]; 68 | const Vertex v2 = vertices.v[ind.z]; 69 | 70 | const vec3 p0 = vec3(v0.position_x, v0.position_y, v0.position_z); 71 | const vec3 p1 = vec3(v1.position_x, v1.position_y, v1.position_z); 72 | const vec3 p2 = vec3(v2.position_x, v2.position_y, v2.position_z); 73 | 74 | const vec3 p0World = (objDesc.objectToWorld * vec4(p0, 1.0)).xyz; 75 | const vec3 p1World = (objDesc.objectToWorld * vec4(p1, 1.0)).xyz; 76 | const vec3 p2World = (objDesc.objectToWorld * vec4(p2, 1.0)).xyz; 77 | 78 | // generate point on the triangle 79 | const float s = 1 - sqrt(1 - xi2); 80 | const float t = (1 - s) * xi3; 81 | position = p0World + s * (p1World - p0World) + t * (p2World - p0World); 82 | 83 | unalignedNormal = normalize(cross(p1World - p0World, p2World - p0World)); 84 | 85 | emission = light.emission; 86 | 87 | // pdf in area measure 88 | pdf = arealight_pdf_vam(g_num_lights, p0World, p1World, p2World); 89 | 90 | // barycentrics from positions 91 | const float area = arealight_areaTriangle(p0World, p1World, p2World); 92 | barycentrics.x = arealight_areaTriangle(p0World, position, p2World) / area;// barycentricsY 93 | barycentrics.y = arealight_areaTriangle(p0World, p1World, position) / area;// barycentricsZ 94 | } 95 | 96 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/bxdf/bsdf/bsdf.glsl: -------------------------------------------------------------------------------- 1 | #ifndef BSDF_GLSL 2 | #define BSDF_GLSL 3 | 4 | #include "../../utility/constants.glsl" 5 | #include "../../material.glsl" 6 | #include "../diffusion/sss_diffusion_profile.glsl" 7 | 8 | struct BSDFVertex { 9 | // vec3 position; 10 | vec3 geometricNormal; 11 | }; 12 | 13 | struct BSDFFrame { 14 | vec3 t; 15 | vec3 b; 16 | vec3 n; 17 | }; 18 | 19 | struct BSDFMaterial { 20 | vec3 baseColor; 21 | float roughness; 22 | float anisotropic; 23 | float metallic; 24 | float subsurface; 25 | vec3 scatterDistance; 26 | }; 27 | 28 | BSDFMaterial bsdfMaterialInit(in const Material material, in const vec2 uv) { 29 | BSDFMaterial bsdfMaterial; 30 | bsdfMaterial.baseColor = material_getAlbedo(material, uv); 31 | bsdfMaterial.roughness = material_getRoughness(material, uv); 32 | bsdfMaterial.anisotropic = 0.0; 33 | bsdfMaterial.metallic = material_getMetallic(material, uv); 34 | bsdfMaterial.subsurface = material.subsurface; 35 | bsdfMaterial.scatterDistance = material.subsurface * material.meanFreePath / sss_diffusion_profile_scatterDistance(bsdfMaterial.baseColor); 36 | return bsdfMaterial; 37 | } 38 | 39 | /// Project a vector to a frame's local coordinates. 40 | vec3 toLocal(in const BSDFFrame frame, in const vec3 v) { 41 | return vec3(dot(v, frame.t), dot(v, frame.b), dot(v, frame.n)); 42 | } 43 | 44 | /// Convert a vector in a frame's local coordinates to the reference coordinate the frame is in. 45 | vec3 toWorld(in const BSDFFrame frame, in const vec3 v) { 46 | return frame.t * v[0] + frame.b * v[1] + frame.n * v[2]; 47 | } 48 | 49 | /// Given a vector n, outputs two vectors such that all three vectors are 50 | /// orthogonal to each other. 51 | /// The approach here is based on Frisvad's paper 52 | /// "Building an Orthonormal Basis from a 3D Unit Vector Without Normalization" 53 | /// https://backend.orbit.dtu.dk/ws/portalfiles/portal/126824972/onb_frisvad_jgt2012_v2.pdf 54 | BSDFFrame coordinateSystem(in const vec3 n) { 55 | BSDFFrame frame; 56 | frame.n = n; 57 | if (n[2] < (-1 + 1e-6)) { 58 | frame.t = vec3(0, -1, 0); 59 | frame.b = vec3(-1, 0, 0); 60 | } else { 61 | float a = 1 / (1 + n[2]); 62 | float b = -n[0] * n[1] * a; 63 | frame.t = vec3(1 - n[0] * n[0] * a, b, -n[0]); 64 | frame.b = vec3(b, 1 - n[1] * n[1] * a, -n[1]); 65 | } 66 | return frame; 67 | } 68 | 69 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/bxdf/bsdf/disney_bsdf.glsl: -------------------------------------------------------------------------------- 1 | #ifndef BSDF_DISNEYA_GLSL 2 | #define BSDF_DISNEYA_GLSL 3 | 4 | #include "bsdf.glsl" 5 | #include "disney_diffuse.glsl" 6 | #include "disney_metal.glsl" 7 | 8 | float bsdf_disney_lobe_weight(in const BSDFMaterial material, in const float rndLobe) { 9 | const float metallic = material.metallic; 10 | const float diffuseWeight = 1.0 - metallic; 11 | const float metalWeight = metallic; 12 | const float sumWeights = diffuseWeight + metalWeight; 13 | 14 | if (rndLobe < diffuseWeight / sumWeights) { 15 | return diffuseWeight / sumWeights; 16 | } else { 17 | return metalWeight / sumWeights; 18 | } 19 | } 20 | 21 | uint bsdf_disney_lobe_index(in const BSDFMaterial material, in const float rndLobe) { 22 | const float metallic = material.metallic; 23 | const float diffuseWeight = 1.0 - metallic; 24 | const float metalWeight = metallic; 25 | const float sumWeights = diffuseWeight + metalWeight; 26 | 27 | if (rndLobe < diffuseWeight / sumWeights) { 28 | return 0; 29 | } else { 30 | return 1; 31 | } 32 | } 33 | 34 | vec3 bsdf_disney_evaluate(in const BSDFVertex vertex, in const BSDFFrame frame, in const BSDFMaterial material, in const vec3 dirIn, in const vec3 dirOut) { 35 | const vec3 diffuse = bsdf_disney_diffuse_evaluate(vertex, frame, material, dirIn, dirOut); 36 | const vec3 metal = bsdf_disney_metal_evaluate(vertex, frame, material, dirIn, dirOut); 37 | 38 | const float metallic = material.metallic; 39 | 40 | return (1.0 - metallic) * diffuse + metallic * metal; 41 | } 42 | 43 | bool bsdf_disney_sample(in const BSDFVertex vertex, in const BSDFFrame frame, in const BSDFMaterial material, in const vec3 dirIn, out vec3 dirOut, in const uint lobe, in const vec2 rndParam) { 44 | if (lobe == 0) { 45 | return bsdf_disney_diffuse_sample(vertex, frame, material, dirIn, dirOut, rndParam); 46 | } else { 47 | return bsdf_disney_metal_sample(vertex, frame, material, dirIn, dirOut, rndParam); 48 | } 49 | } 50 | 51 | float bsdf_disney_pdf(in const BSDFVertex vertex, in const BSDFFrame frame, in const BSDFMaterial material, in const vec3 dirIn, in const vec3 dirOut) { 52 | const float diffusePDF = bsdf_disney_diffuse_pdf(vertex, frame, material, dirIn, dirOut); 53 | const float metalPDF = bsdf_disney_metal_pdf(vertex, frame, material, dirIn, dirOut); 54 | 55 | const float metallic = material.metallic; 56 | const float diffuseWeight = 1.0 - metallic; 57 | const float metalWeight = metallic; 58 | const float sumWeights = diffuseWeight + metalWeight; 59 | 60 | return (diffuseWeight * diffusePDF + metalWeight * metalPDF) / sumWeights; 61 | } 62 | 63 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/bxdf/bsdf/disney_diffuse.glsl: -------------------------------------------------------------------------------- 1 | #ifndef BSDF_DISNEY_DIFFUSE_GLSL 2 | #define BSDF_DISNEY_DIFFUSE_GLSL 3 | 4 | #include "bsdf.glsl" 5 | 6 | float fresnelDiffuse90(in const float roughness, in const vec3 dirOut, in const vec3 halfVector) { 7 | return 0.5 + 2.0 * roughness * dot(halfVector, dirOut) * dot(halfVector, dirOut); 8 | } 9 | 10 | float fresnelDiffuse(in const float fd90, in const BSDFFrame frame, in const vec3 omega) { 11 | return 1.0 + (fd90 - 1.0) * pow(1.0 - max(dot(frame.n, omega), 0), 5); 12 | } 13 | 14 | vec3 sampleCosHemisphere(in const vec2 rndParam) { 15 | // float tmp = sqrt(clamp(1 - rndParam[0], 0, 1)); 16 | // float phi = TWO_PI * rndParam[1]; 17 | // return vec3(cos(phi) * tmp, sin(phi) * tmp, sqrt(clamp(rndParam[0], 0, 1))); 18 | float theta = acos(sqrt(1 - rndParam[0])); 19 | float phi = TWO_PI * rndParam[1]; 20 | vec3 omegaLocal = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); 21 | return omegaLocal; 22 | } 23 | 24 | vec2 reverseSampleCosHemisphere(in const vec3 omegaLocal) { 25 | float cosTheta = omegaLocal.z; 26 | const float reverseXi1 = 1 - cosTheta * cosTheta; 27 | float sinTheta = sqrt(1 - cosTheta * cosTheta); 28 | float sinPhi = omegaLocal.y / sinTheta; 29 | float cosPhi = omegaLocal.x / sinTheta; 30 | // get angle in [0,2Pi] 31 | float reversePhi = atan(sinPhi, cosPhi); 32 | reversePhi = reversePhi >= 0 ? reversePhi : reversePhi + 2 * PI; 33 | const float reverseXi2 = reversePhi / (2 * PI); 34 | return vec2(reverseXi1, reverseXi2); 35 | } 36 | 37 | //#undef ALPHA 38 | //#define ALPHA 2 39 | //vec3 sampleCosHemisphere(in vec2 rndParam) { 40 | // // float tmp = sqrt(clamp(1 - rndParam[0], 0, 1)); 41 | // // float phi = TWO_PI * rndParam[1]; 42 | // // return vec3(cos(phi) * tmp, sin(phi) * tmp, sqrt(clamp(rndParam[0], 0, 1))); 43 | // float theta = acos(pow(1 - rndParam[0], 1.0 / (ALPHA + 1.0))); 44 | // float phi = TWO_PI * rndParam[1]; 45 | // vec3 omegaLocal = vec3(sin(theta) * cos(phi), sin(theta) * sin(phi), cos(theta)); 46 | // return omegaLocal; 47 | //} 48 | // 49 | //vec2 reverseSampleCosHemisphere(in vec3 omegaLocal) { 50 | // float cosTheta = omegaLocal.z; 51 | // const float reverseXi1 = 1 - pow(cosTheta, ALPHA + 1); 52 | // float sinTheta = sqrt(1 - pow(cosTheta, ALPHA + 1)); 53 | // float sinPhi = omegaLocal.y / sinTheta; 54 | // float cosPhi = omegaLocal.x / sinTheta; 55 | // // get angle in [0,2Pi] 56 | // float reversePhi = atan(sinPhi, cosPhi); 57 | // reversePhi = reversePhi >= 0 ? reversePhi : reversePhi + 2 * PI; 58 | // const float reverseXi2 = reversePhi / (2 * PI); 59 | // return vec2(reverseXi1, reverseXi2); 60 | //} 61 | 62 | vec3 bsdf_disney_diffuse_evaluate(in const BSDFVertex vertex, in BSDFFrame frame, in const BSDFMaterial material, in const vec3 dirIn, in const vec3 dirOut) { 63 | if (dot(vertex.geometricNormal, dirIn) < 0 || 64 | dot(vertex.geometricNormal, dirOut) < 0) { 65 | // No light below the surface 66 | return vec3(0); 67 | } 68 | 69 | // Flip the shading frame if it is inconsistent with the geometry normal 70 | if (dot(frame.n, dirIn) < 0) { 71 | frame.t = -frame.t; 72 | frame.b = -frame.b; 73 | frame.n = -frame.n; 74 | } 75 | 76 | const vec3 halfVector = normalize(dirIn + dirOut); 77 | 78 | // base diffuse 79 | const float fd90 = fresnelDiffuse90(material.roughness, dirOut, halfVector); 80 | const vec3 baseDiffuse = material.baseColor / PI 81 | * fresnelDiffuse(fd90, frame, dirIn) * fresnelDiffuse(fd90, frame, dirOut) 82 | * max(dot(frame.n, dirOut), 0); 83 | 84 | return baseDiffuse; 85 | } 86 | 87 | bool bsdf_disney_diffuse_sample(in const BSDFVertex vertex, in BSDFFrame frame, in const BSDFMaterial material, in const vec3 dirIn, out vec3 dirOut, in const vec2 rndParam) { 88 | if (dot(vertex.geometricNormal, dirIn) < 0) { 89 | // No light below the surface 90 | return false; 91 | } 92 | 93 | // Flip the shading frame if it is inconsistent with the geometry normal 94 | if (dot(frame.n, dirIn) < 0) { 95 | frame.t = -frame.t; 96 | frame.b = -frame.b; 97 | frame.n = -frame.n; 98 | } 99 | 100 | dirOut = toWorld(frame, sampleCosHemisphere(rndParam)); 101 | return true; 102 | } 103 | 104 | float bsdf_disney_diffuse_pdf(in const BSDFVertex vertex, in BSDFFrame frame, in const BSDFMaterial material, in const vec3 dirIn, in const vec3 dirOut) { 105 | if (dot(vertex.geometricNormal, dirIn) < 0 || 106 | dot(vertex.geometricNormal, dirOut) < 0) { 107 | // No light below the surface 108 | return 0; 109 | } 110 | 111 | // Flip the shading frame if it is inconsistent with the geometry normal 112 | if (dot(frame.n, dirIn) < 0) { 113 | frame.t = -frame.t; 114 | frame.b = -frame.b; 115 | frame.n = -frame.n; 116 | } 117 | 118 | return max(dot(frame.n, dirOut), 0) / PI; 119 | // return (ALPHA + 1.0) * pow(max(0, dot(dirOut, frame.n)), ALPHA) / (2.0 * PI); 120 | } 121 | 122 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/bxdf/diffusion/sss_diffusion_profile.glsl: -------------------------------------------------------------------------------- 1 | #ifndef SSS_DIFFUSION_PROFILE_GLSL 2 | #define SSS_DIFFUSION_PROFILE_GLSL 3 | 4 | vec3 sss_diffusion_profile_scatterDistance(in const vec3 surfaceAlbedo); 5 | 6 | vec3 sss_diffusion_profile_evaluate(in const float radius, in const vec3 scatterDistance); 7 | 8 | float sss_diffusion_profile_pdf(in const float radius, in const float scatterDistance); 9 | vec3 sss_diffusion_profile_pdf_vectorized(in const float radius, in const vec3 scatterDistance); 10 | 11 | float sss_diffusion_profile_sample(in const float xi, in const float scatterDistance); 12 | 13 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/bxdf/diffusion/sss_diffusion_profile_burley.glsl: -------------------------------------------------------------------------------- 1 | #ifndef SSS_DIFFUSION_PROFILE_BURLEY_GLSL 2 | #define SSS_DIFFUSION_PROFILE_BURLEY_GLSL 3 | 4 | #include "sss_diffusion_profile.glsl" 5 | 6 | // d = l / s <- mfp / scaling 7 | float sss_diffusion_profile_burley_cdfDiffusion(in const float r, in const float d) { 8 | return 1.0 - 0.25 * exp(-r / d) - 0.75 * exp(-r / (3.0 * d)); 9 | } 10 | 11 | float sss_diffusion_profile_burley_cdfFirstDerivativeDiffusion(in const float r, in const float d) { 12 | return 0.25 / d * (exp(-r / d) + exp(-r / (3.0 * d))); 13 | } 14 | 15 | float sss_diffusion_profile_burley_cdfSecondDerivativeDiffusion(in const float r, in const float d) { 16 | return -0.25 / (d * d) * (exp(-r / d) + exp(-r / (3.0 * d)) / 3.0); 17 | } 18 | 19 | vec3 sss_diffusion_profile_scatterDistance(in const vec3 surfaceAlbedo) { 20 | const vec3 a = surfaceAlbedo - vec3(0.8); 21 | return 1.9 - surfaceAlbedo + 3.5 * a * a; 22 | } 23 | 24 | vec3 sss_diffusion_profile_evaluate(in const float radius, in const vec3 scatterDistance) { 25 | if (radius <= 0) { 26 | return vec3(0.25 / PI) / max(vec3(0.000001), scatterDistance); 27 | } 28 | const vec3 rd = radius / scatterDistance; 29 | return (exp(-rd) + exp(-rd / 3.0)) / max(vec3(0.000001), (8.0 * PI * scatterDistance * radius)); 30 | } 31 | 32 | float sss_diffusion_profile_pdf(in const float radius, in const float scatterDistance) { 33 | if (radius <= 0) { 34 | return (0.25 / PI) / max(0.000001, scatterDistance); 35 | } 36 | const float rd = radius / scatterDistance; 37 | return (exp(-rd) + exp(-rd / 3.0)) / max(0.000001, (8.0 * PI * scatterDistance * radius));// divide by r to convert from polar to cartesian 38 | } 39 | 40 | vec3 sss_diffusion_profile_pdf_vectorized(in const float radius, in const vec3 scatterDistance) { 41 | if (radius <= 0) { 42 | return (0.25 / PI) / max(vec3(0.000001), scatterDistance); 43 | } 44 | const vec3 rd = radius / scatterDistance; 45 | return (exp(-rd) + exp(-rd / 3.0)) / max(vec3(0.000001), (8.0 * PI * scatterDistance * radius));// divide by r to convert from polar to cartesian 46 | } 47 | 48 | #define LOG2_E 1.44269504089 49 | //// https://zero-radiance.github.io/post/sampling-diffusion/ 50 | //// Performs sampling of a Normalized Burley diffusion profile in polar coordinates. 51 | //// 'u' is the random number (the value of the CDF): [0, 1). 52 | //// rcp(s) = 1 / ShapeParam = ScatteringDistance. 53 | //// 'r' is the sampled radial distance, s.t. (u = 0 -> r = 0) and (u = 1 -> r = Inf). 54 | //// rcp(Pdf) is the reciprocal of the corresponding PDF value. 55 | float sampleBurleyDiffusionProfileAnalytical(in float u, in const float rcpS) { 56 | u = 1 - u;// Convert CDF to CCDF; the resulting value of (u != 0) 57 | 58 | const float g = 1 + (4 * u) * (2 * u + sqrt(1 + (4 * u) * u)); 59 | const float n = exp2(log2(g) * (-1.0/3.0));// g^(-1/3) 60 | const float p = (g * n) * n;// g^(+1/3) 61 | const float c = 1 + p + n;// 1 + g^(+1/3) + g^(-1/3) 62 | const float x = (3 / LOG2_E) * log2(c / (4 * u));// 3 * Log[c / (4 * u)] 63 | 64 | // x = s * r 65 | // exp_13 = Exp[-x/3] = Exp[-1/3 * 3 * Log[c / (4 * u)]] 66 | // exp_13 = Exp[-Log[c / (4 * u)]] = (4 * u) / c 67 | // exp_1 = Exp[-x] = exp_13 * exp_13 * exp_13 68 | // expSum = exp_1 + exp_13 = exp_13 * (1 + exp_13 * exp_13) 69 | // rcpExp = rcp(expSum) = c^3 / ((4 * u) * (c^2 + 16 * u^2)) 70 | const float rcpExp = ((c * c) * c) / ((4 * u) * ((c * c) + (4 * u) * (4 * u))); 71 | 72 | return x * rcpS; // r 73 | } 74 | 75 | 76 | float sss_diffusion_profile_sample(in const float xi, in const float scatterDistance) { 77 | return sampleBurleyDiffusionProfileAnalytical(xi, scatterDistance); 78 | 79 | // SOLVE for r: xi = cdf(r,d) 80 | // use Halley's method to perform numerical inversion (converges in 2-4 iterations) -> https://en.wikipedia.org/wiki/Halley%27s_method 81 | // this is suggested by https://advances.realtimerendering.com/s2018/Efficient%20screen%20space%20subsurface%20scattering%20Siggraph%202018.pdf 82 | 83 | // // xi = cdf(r,d) <=> 0 = cdf(r,d) - xi =: f 84 | // float r = 0.0; 85 | // for (int i = 0; i < 4; i++) { 86 | // float f = sss_diffusion_profile_burley_cdfDiffusion(r, scatterDistance) - xi; 87 | // float df = sss_diffusion_profile_burley_cdfFirstDerivativeDiffusion(r, scatterDistance); 88 | // float ddf = sss_diffusion_profile_burley_cdfSecondDerivativeDiffusion(r, scatterDistance); 89 | // 90 | // r = r - 2.0 * f * df / (2.0 * df * df - f * ddf); 91 | // } 92 | // 93 | // return r; 94 | } 95 | 96 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/bxdf/diffusion/sss_sampling.glsl: -------------------------------------------------------------------------------- 1 | #ifndef SSS_SAMPLING_GLSL 2 | #define SSS_SAMPLING_GLSL 3 | 4 | struct SSSInfo { 5 | vec3 position; 6 | 7 | int objectDescriptorId; 8 | 9 | vec3 scatterDistance; 10 | 11 | uint intersection; 12 | }; 13 | 14 | struct SSSSample { 15 | int objectDescriptorId; 16 | int triangleId; 17 | vec2 barycentrics; 18 | 19 | vec3 position; 20 | vec3 geometricNormal; 21 | vec3 normal; 22 | 23 | uint intersection; 24 | }; 25 | 26 | bool sss_sampling(inout uint rngState, in const SSSInfo sssInfo, out SSSSample sssSample, out float pdf); 27 | 28 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/bxdf/disney.glsl: -------------------------------------------------------------------------------- 1 | #ifndef BSDF_DISNEY_GLSL 2 | #define BSDF_DISNEY_GLSL 3 | 4 | #include "diffusion/sss_diffusion_profile_burley.glsl" 5 | #include "diffusion/sss_sampling_disk.glsl" 6 | 7 | #include "bsdf/bsdf.glsl" 8 | #include "bsdf/disney_bsdf.glsl" 9 | 10 | #define SCATTERING_TYPE_BSDF 0x1 11 | #define SCATTERING_TYPE_BSSRDF 0x2 12 | 13 | // === SCATTERING TYPE === 14 | uint disney_sampleScatteringType(inout uint rngState, in const bool sss, in const uint bounce, in const float sssFactor, out float pdf) { 15 | if (!sss || bounce > 0) { 16 | pdf = 1.0; 17 | return SCATTERING_TYPE_BSDF; 18 | } 19 | if (sssFactor > 0) { 20 | pdf = 1.0; 21 | return SCATTERING_TYPE_BSSRDF; 22 | } 23 | pdf = 1.0; 24 | return SCATTERING_TYPE_BSDF; 25 | } 26 | 27 | uint disney_sampleScatteringTypeWOSSS(inout uint rngState, in const bool sss, in const uint bounce, in const float sssFactor, out float pdf) { 28 | pdf = 1.0; 29 | return SCATTERING_TYPE_BSDF; 30 | } 31 | 32 | // === UTILITY === 33 | float disney_schlickWeight(in const float a) { 34 | const float b = clamp(1.0 - a, 0.0, 1.0); 35 | const float bb = b * b; 36 | return bb * bb * b; 37 | } 38 | 39 | float disney_diffuseLambertWeight(in const float fv, in const float fl) { 40 | return (1.0 - 0.5 * fl) * (1.0 - 0.5 * fv); 41 | } 42 | 43 | float disney_diffuseLambertWeightSingle(in const float f) { 44 | return 1.0 - 0.5 * f; 45 | } 46 | 47 | // === BSSRDF === 48 | vec3 disney_bssrdf_fresnel_evaluate(in const vec3 normal, in const vec3 direction) { 49 | // return vec3(1); // setting this to 1 ensures smooth transition to Lambert diffuse 50 | 51 | const float dotND = dot(normal, direction); 52 | const float schlick = disney_schlickWeight(dotND); 53 | const float lambertWeight = disney_diffuseLambertWeightSingle(schlick); 54 | return vec3(lambertWeight); 55 | } 56 | 57 | void disney_bssrdf_evaluate(in const vec3 normal, in const vec3 v, in const float distance, in const vec3 scatterDistance, in const vec3 surfaceAlbedo, out vec3 bssrdf) { 58 | const vec3 diffusionProfile = surfaceAlbedo * sss_diffusion_profile_evaluate(distance, scatterDistance); 59 | 60 | bssrdf = diffusionProfile / PI * disney_bssrdf_fresnel_evaluate(normal, v); 61 | } 62 | 63 | void disney_bssrdf_evaluate(in const vec3 normal, in const vec3 v, in const vec3 normalSample, in const vec3 l, in const float distance, in const vec3 scatterDistance, in const vec3 surfaceAlbedo, out vec3 bssrdf, out vec3 bsdf) { 64 | const vec3 diffusionProfile = surfaceAlbedo * sss_diffusion_profile_evaluate(distance, scatterDistance); 65 | 66 | bssrdf = diffusionProfile / PI * disney_bssrdf_fresnel_evaluate(normal, v); 67 | bsdf = disney_bssrdf_fresnel_evaluate(normalSample, l); 68 | } 69 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/defines.glsl: -------------------------------------------------------------------------------- 1 | #ifndef DEFINES_GLSL 2 | #define DEFINES_GLSL 3 | 4 | #define NUM_TEXTURES 8 5 | //#define GEOMETRIC_NORMAL 6 | 7 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/environment.glsl: -------------------------------------------------------------------------------- 1 | #ifndef ENVIRONMENT_GLSL 2 | #define ENVIRONMENT_GLSL 3 | 4 | vec3 environment_evaluate(in const vec3 direction) { 5 | if (g_environment_map == 0) { 6 | return g_sky_color; 7 | } 8 | const vec2 longitudeLatitude = vec2((atan(direction.x, direction.z) / PI + 1.0) * 0.5 + g_environment_map_rotation.x, asin(-direction.y) / PI + 0.5 + g_environment_map_rotation.y); 9 | return texture(textureEnvironment, longitudeLatitude).rgb; 10 | } 11 | 12 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/main/gbuffer.glsl: -------------------------------------------------------------------------------- 1 | #ifndef GBUFFER_GLSL 2 | #define GBUFFER_GLSL 3 | 4 | #include "../defines.glsl" 5 | #include "../utility/normal_mapping.glsl" 6 | #include "../material.glsl" 7 | #include "../trace/trace.glsl" 8 | 9 | bool pixelInfoFromGBuffer(in const vec3 origin, in const GBuffer gBuffer, out ReSTIRPixelInfo pixelInfo) { 10 | // handle error or sky hit 11 | if (gBuffer.objectDescriptorId == GBUFFER_NULL || gBuffer.triangleId == GBUFFER_NULL) { 12 | return false; 13 | } 14 | 15 | // intersection info 16 | const HitPayload payload = HitPayload(int(gBuffer.objectDescriptorId), int(gBuffer.triangleId), 0, vec2(gBuffer.barycentricsY, gBuffer.barycentricsZ), gl_HitKindFrontFacingTriangleEXT); 17 | intersectionInfo(payload, origin, pixelInfo.position, pixelInfo.geometricNormal, pixelInfo.normal, pixelInfo.material); 18 | pixelInfo.v = normalize(origin - pixelInfo.position); 19 | 20 | return true; 21 | } 22 | 23 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/main/passes/pass_surface.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive: enable 3 | #extension GL_EXT_nonuniform_qualifier: enable 4 | #extension GL_EXT_scalar_block_layout: enable 5 | #extension GL_EXT_shader_explicit_arithmetic_types_int64: require 6 | #extension GL_EXT_buffer_reference2: require 7 | #extension GL_EXT_ray_query : require 8 | 9 | #include "../../defines.glsl" 10 | 11 | #include "../../utility/constants.glsl" 12 | #include "../../utility/random.glsl" 13 | #include "../../raystructs.glsl" 14 | #include "../../raycommon.glsl" 15 | 16 | layout (local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in; 17 | 18 | layout (push_constant, std430) uniform PushConstants { 19 | int g_pixels_x; 20 | int g_pixels_y; 21 | 22 | float g_ray_origin_x; 23 | float g_ray_origin_y; 24 | float g_ray_origin_z; 25 | float g_ray_left_bottom_x; 26 | float g_ray_left_bottom_y; 27 | float g_ray_left_bottom_z; 28 | float g_ray_left_top_x; 29 | float g_ray_left_top_y; 30 | float g_ray_left_top_z; 31 | float g_ray_right_bottom_x; 32 | float g_ray_right_bottom_y; 33 | float g_ray_right_bottom_z; 34 | float g_ray_right_top_x; 35 | float g_ray_right_top_y; 36 | float g_ray_right_top_z; 37 | 38 | uint g_frame; 39 | 40 | uint g_rng_init; 41 | uint g_rng_init_offset; 42 | }; 43 | 44 | layout (set = 0, binding = 0) uniform accelerationStructureEXT topLevelAS; 45 | layout (set = 0, binding = 1, rgba32f) uniform image2D framebuffer; 46 | layout (set = 0, binding = 2, rgba32f) uniform image2D accumulationBuffer; 47 | 48 | layout (std430, set = 0, binding = 3) uniform options_pass_surface { 49 | uint g_num_lights; 50 | 51 | uint g_normal_mapping; 52 | uint g_sss; 53 | }; 54 | 55 | // SCENE 56 | layout (set = 0, binding = 10, scalar) readonly buffer buffer_object_descriptor { ObjectDescriptor g_objectDescriptors[]; }; 57 | layout (set = 0, binding = 11, scalar) readonly buffer buffer_material { Material g_materials[]; }; 58 | layout (set = 0, binding = 12, scalar) readonly buffer buffer_light { Light g_lights[]; }; 59 | 60 | layout (buffer_reference, scalar) readonly buffer Indices { ivec3 i[]; }; 61 | layout (buffer_reference, scalar) readonly buffer Vertices { Vertex v[]; }; 62 | 63 | layout (set = 0, binding = 20) uniform sampler2D textures[NUM_TEXTURES]; 64 | layout (set = 0, binding = 21) uniform sampler2D textureEnvironment; 65 | 66 | // G-BUFFER 67 | //layout (set = 0, binding = 30, scalar) readonly buffer buffer_g_buffers { GBuffer g_gBuffers[]; }; 68 | layout (set = 0, binding = 30, rgba32f) readonly uniform image2D g_gBuffers; 69 | 70 | #include "../restirsss/restirsss_pixel_info.glsl" 71 | 72 | #include "../gbuffer.glsl" 73 | #include "../../arealight.glsl" 74 | #include "../../visibility/visibility.glsl" 75 | #include "../../bxdf/disney.glsl" 76 | 77 | vec3 generateSampleBSDFWithLightSourceSampling(inout uint rngState, in ReSTIRPixelInfo pixelInfo) { 78 | // sample light candidate 79 | int lightObjectDescriptor; 80 | int lightTriangleId; 81 | vec2 lightBarycentrics; 82 | vec3 lightPosition; 83 | vec3 lightNormalUnaligned; 84 | vec3 lightEmission; 85 | float lightPDFVAM; 86 | arealight_sample_vam(nextUInt(rngState, g_num_lights - 1), nextFloat(rngState), nextFloat(rngState), lightObjectDescriptor, lightTriangleId, lightBarycentrics, lightPosition, lightNormalUnaligned, lightEmission, lightPDFVAM); 87 | 88 | const vec3 lightToSurface = pixelInfo.position - lightPosition; 89 | const vec3 lightToSurfaceNormalized = normalize(lightToSurface); 90 | const vec3 lightNormal = dot(lightNormalUnaligned, lightToSurfaceNormalized) >= 0.0 ? lightNormalUnaligned : -lightNormalUnaligned;// align normal in correct direction 91 | const float cosAtLight = max(0, dot(lightNormal, lightToSurfaceNormalized)); 92 | const float geometryTermSolidAngle = cosAtLight / dot(lightToSurface, lightToSurface); 93 | const float lightPDF = lightPDFVAM / geometryTermSolidAngle; 94 | if (lightPDF <= 0.0) { 95 | return vec3(0); 96 | } 97 | 98 | if (!visibility_shadowRay(pixelInfo.position, pixelInfo.geometricNormal, -lightToSurfaceNormalized, length(lightToSurface), lightObjectDescriptor, lightTriangleId)) { 99 | return vec3(0); 100 | } 101 | 102 | // evaluate bsdf 103 | const BSDFVertex vertex = BSDFVertex(pixelInfo.geometricNormal); 104 | const BSDFFrame frame = coordinateSystem(pixelInfo.normal); 105 | const vec3 bsdf = bsdf_disney_evaluate(vertex, frame, pixelInfo.material, pixelInfo.v, -lightToSurfaceNormalized); 106 | 107 | const float cosAtSurface = max(0, dot(pixelInfo.normal, -lightToSurfaceNormalized)); 108 | 109 | return bsdf * cosAtSurface * lightEmission / lightPDF; 110 | } 111 | 112 | vec3 pathtraceSingle(inout uint rngState, in const ReSTIRPixelInfo pixelInfo) { 113 | if (g_num_lights <= 0) { 114 | return vec3(0); 115 | } 116 | 117 | // bsdf 118 | return generateSampleBSDFWithLightSourceSampling(rngState, pixelInfo); 119 | } 120 | 121 | void shade(inout uint rngState, in const ivec2 pixel) { 122 | const int pixelIndex = pixel.y * g_pixels_x + pixel.x; 123 | 124 | // load g-buffer 125 | // const GBuffer gBuffer = g_gBuffers[pixelIndex]; 126 | const vec4 gBufferRaw = imageLoad(g_gBuffers, pixel); 127 | const GBuffer gBuffer = GBuffer(uint(gBufferRaw[0]), uint(gBufferRaw[1]), gBufferRaw[2], gBufferRaw[3]); 128 | 129 | // pixel info 130 | ReSTIRPixelInfo pixelInfo; 131 | if (!pixelInfoFromGBuffer(vec3(g_ray_origin_x, g_ray_origin_y, g_ray_origin_z), gBuffer, pixelInfo)) { 132 | return; 133 | } 134 | 135 | const bool pathSSS = restirsss_pixel_info_isSSS(pixelInfo); 136 | if (pathSSS) { 137 | return; 138 | } 139 | 140 | const vec3 color = pathtraceSingle(rngState, pixelInfo); 141 | 142 | // accumulate and write framebuffer 143 | const vec3 newColor = mix(imageLoad(accumulationBuffer, pixel).rgb, color, 1.0 / float(g_frame + 1)); 144 | imageStore(accumulationBuffer, pixel, vec4(newColor, 1.0)); 145 | imageStore(framebuffer, pixel, vec4(newColor, 1.0)); 146 | } 147 | 148 | void main() { 149 | const ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); 150 | if (any(greaterThanEqual(pixel, ivec2(g_pixels_x, g_pixels_y)))) { 151 | return; 152 | } 153 | 154 | // load rng 155 | uint rngState = (g_rng_init + 1) * g_pixels_x * (pixel.y + 1) + pixel.x + g_rng_init_offset;// add offset to avoid same seed as other passes (otherwise, visible artifacts possible) 156 | 157 | shade(rngState, pixel); 158 | } -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/main/passes/pass_tonemapper.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive: enable 3 | 4 | layout (local_size_x_id = 0, local_size_y_id = 1, local_size_z_id = 2) in; 5 | 6 | layout (push_constant, std430) uniform PushConstants { 7 | int g_pixels_x; 8 | int g_pixels_y; 9 | 10 | uint g_tonemapper; 11 | }; 12 | 13 | layout (set = 0, binding = 0, rgba32f) uniform image2D image; 14 | 15 | #define TONEMAPPER_OFF 0 16 | #define TONEMAPPER_GAMMA 1 17 | 18 | void main() { 19 | if (g_tonemapper == TONEMAPPER_OFF) { 20 | return; 21 | } 22 | 23 | const ivec2 pixel = ivec2(gl_GlobalInvocationID.xy); 24 | if (any(greaterThanEqual(pixel, ivec2(g_pixels_x, g_pixels_y)))) { 25 | return; 26 | } 27 | 28 | const vec3 colorIn = imageLoad(image, pixel).rgb; 29 | 30 | vec3 colorOut = colorIn; 31 | if (g_tonemapper == TONEMAPPER_GAMMA) { 32 | // colorOut = pow(colorIn, vec3(1.0 / 2.2)); 33 | colorOut = /*colorIn == vec3(1) ? vec3(1) :*/ pow(colorIn / (colorIn + vec3(1.0)), vec3(1.0 / 2.2)); // we use reinhard tonemapping here 34 | } 35 | 36 | imageStore(image, pixel, vec4(colorOut, 1.0)); 37 | } -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/main/restirsss/probinversetest/restirsss_target_function_test.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RESTIRSSS_TARGET_FUNCTION_TEST_GLSL 2 | #define RESTIRSSS_TARGET_FUNCTION_TEST_GLSL 3 | 4 | float restirsss_target_function_evaluate(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample); 5 | 6 | /** 7 | * Used to combine multiple reservoirs. 8 | * Either the same as the default restir_target_function_evaluate or include additional checks, e.g. visibility check for ReSTIR DI, to stay unbiased. 9 | */ 10 | float restirsss_target_function_resampleEvaluate(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample, in const bool visibilityCheck); 11 | 12 | // PRIVATE 13 | #include "../../bxdf/disney.glsl" 14 | #include "../../visibility/visibility.glsl" 15 | #include "../../material.glsl" 16 | 17 | vec3 restirsss_target_function_unshadowedLightContribution(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample) { 18 | if (restirsss_reservoir_isNullSample(evalSample)) { 19 | return vec3(0); 20 | } 21 | 22 | const vec3 x1x2 = evalSample.samplePosition - pixelInfo.position;// visibile point -> x2 23 | const vec3 x1x2Normalized = normalize(x1x2); 24 | const vec3 x2x3 = evalSample.lightPosition - evalSample.samplePosition;// x2 -> light source 25 | const vec3 x2x3Normalized = normalize(x2x3); 26 | 27 | vec3 unshadowedLightContribution = vec3(1); 28 | 29 | const BSDFVertex vertex = BSDFVertex(pixelInfo.geometricNormal); 30 | const BSDFFrame frame = coordinateSystem(pixelInfo.normal); 31 | // bsdf at x1 32 | unshadowedLightContribution *= bsdf_disney_evaluate(vertex, frame, pixelInfo.material, pixelInfo.v, x1x2Normalized); 33 | 34 | // bsdf at x2 35 | BSDFVertex vertexAtX2; 36 | BSDFFrame frameAtX2; 37 | BSDFMaterial materialAtX2; 38 | { 39 | const ObjectDescriptor objDesc = g_objectDescriptors[evalSample.sampleObjectDescriptor]; 40 | Indices indices = Indices(objDesc.indexAddress); 41 | Vertices vertices = Vertices(objDesc.vertexAddress); 42 | const Material material = g_materials[objDesc.materialId]; 43 | 44 | const ivec3 ind = indices.i[evalSample.sampleTriangleId]; 45 | const Vertex v0 = vertices.v[ind.x]; 46 | const Vertex v1 = vertices.v[ind.y]; 47 | const Vertex v2 = vertices.v[ind.z]; 48 | 49 | const vec2 uv0 = vec2(v0.texCoord_u, v0.texCoord_v); 50 | const vec2 uv1 = vec2(v1.texCoord_u, v1.texCoord_v); 51 | const vec2 uv2 = vec2(v2.texCoord_u, v2.texCoord_v); 52 | 53 | const vec3 barycentrics = vec3(1.0 - evalSample.sampleBarycentrics.x - evalSample.sampleBarycentrics.y, evalSample.sampleBarycentrics.x, evalSample.sampleBarycentrics.y); 54 | 55 | // UV 56 | const vec2 uv = uv0 * barycentrics.x + uv1 * barycentrics.y + uv2 * barycentrics.z; 57 | 58 | vertexAtX2 = BSDFVertex(evalSample.sampleGeometricNormal); 59 | frameAtX2 = coordinateSystem(evalSample.sampleNormal); 60 | materialAtX2 = bsdfMaterialInit(material, uv); 61 | } 62 | unshadowedLightContribution *= bsdf_disney_evaluate(vertexAtX2, frameAtX2, materialAtX2, -x1x2Normalized, x2x3Normalized); 63 | 64 | // light 65 | const float cosAtSurface = max(0, dot(evalSample.sampleNormal, x2x3Normalized)); 66 | // float cosAtLight = max(0, dot(evalSample.lightNormal, -x2x3Normalized)); 67 | // float geometryTerm = cosAtSurface * cosAtLight / dot(x2x3, x2x3); 68 | unshadowedLightContribution *= evalSample.lightEmission;// * cosAtSurface /** geometryTerm*/; 69 | 70 | return unshadowedLightContribution; 71 | } 72 | 73 | vec3 restirsss_measurementContributionFunction(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample) { 74 | const vec3 color = restirsss_target_function_unshadowedLightContribution(pixelInfo, evalSample); 75 | 76 | // if (g_restir_visibility == 0) { 77 | // // no visibility pass, check if chosen light is visible from the chosen sample position 78 | // vec3 surfaceToLightNormalized = normalize(evalSample.lightPosition - evalSample.samplePosition); 79 | // color *= visibility_shadowRay(evalSample.samplePosition, evalSample.sampleGeometricNormal, surfaceToLightNormalized, evalSample.lightObjectDescriptor, evalSample.lightTriangleId); 80 | // } 81 | return color; 82 | } 83 | 84 | float calcLuminance(in const vec3 color) { 85 | return dot(color.xyz, vec3(0.299f, 0.587f, 0.114f)); 86 | } 87 | 88 | // implement "base class" 89 | float restirsss_target_function_evaluate(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample) { 90 | const vec3 unshadowedLightContribution = restirsss_target_function_unshadowedLightContribution(pixelInfo, evalSample); 91 | 92 | // float targetFunction = length(unshadowedLightContribution);// ^p(X_i) 93 | // targetFunction = (isnan(targetFunction) || isinf(targetFunction)) ? 0 : targetFunction; 94 | const float targetFunction = calcLuminance(unshadowedLightContribution); 95 | 96 | return targetFunction; 97 | } 98 | 99 | // implement "base class" 100 | float restirsss_target_function_resampleEvaluate(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample, in const bool visibilityCheck) { 101 | if (restirsss_reservoir_isNullSample(evalSample)) { 102 | return 0; 103 | } 104 | 105 | /*if (g_restir_shift == RESTIRSSS_SHIFT_RECONNECTION || g_restir_shift == RESTIRSSS_SHIFT_SEQUENTIAL_RECONNECTION)*/ /* unoptimized but ok for this debug case */ { 106 | // the proposal function ensures that [x1,x2] is visible, so we have to ensure this for resampling as well to stay unbiased 107 | const vec3 surfaceToX2 = evalSample.samplePosition - pixelInfo.position; 108 | const vec3 surfaceToX2Normalized = normalize(surfaceToX2); 109 | if (!visibility_shadowRay(pixelInfo.position, pixelInfo.geometricNormal, surfaceToX2Normalized, length(surfaceToX2), evalSample.sampleObjectDescriptor, evalSample.sampleTriangleId)) { 110 | return 0; 111 | } 112 | } 113 | if (visibilityCheck) { 114 | const vec3 surfaceToLight = evalSample.lightPosition - evalSample.samplePosition; 115 | const vec3 surfaceToLightNormalized = normalize(surfaceToLight); 116 | if (!visibility_shadowRay(evalSample.samplePosition, evalSample.sampleGeometricNormal, surfaceToLightNormalized, length(surfaceToLight), evalSample.lightObjectDescriptor, evalSample.lightTriangleId)) { 117 | return 0; 118 | } 119 | } 120 | return restirsss_target_function_evaluate(pixelInfo, evalSample); 121 | } 122 | 123 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/main/restirsss/restirsss_defines.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RESTIRSSS_DEFINES_GLSL 2 | #define RESTIRSSS_DEFINES_GLSL 3 | 4 | // shifts 5 | #define RESTIRSSS_SHIFT_RECONNECTION 0 6 | #define RESTIRSSS_SHIFT_DELAYED_RECONNECTION 1 7 | 8 | #define RESTIRSSS_SHIFT_HYBRID 2 9 | 10 | #define RESTIRSSS_SHIFT_SEQUENTIAL_RECONNECTION 3 11 | #define RESTIRSSS_SHIFT_SEQUENTIAL_DELAYED_RECONNECTION 4 12 | 13 | // sequential shift performance optimization (introduces small bias): calculate intersection id for the selected sample only after the resampling pass and possibly set intersection id to an unknown state (see paper Sec. 4.3 for details) 14 | #define RESTIRSSS_RECONNECTION_INTERSECTIONID_DELAYED 15 | 16 | // sample a light source per candidate and share between all intersections (performance) or sample light source for each found intersection (less variance possible) 17 | #define RESTIRSSS_LIGHT_PER_CANDIDATE 18 | 19 | //#define RESTIRSSS_PROBINVERSETEST_L3PATH 20 | 21 | //#define RESTIRSSS_WRITE_DEBUG_IMAGES 22 | 23 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/main/restirsss/restirsss_pixel_info.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RESTIR_RESERVOIR_GLSL 2 | #define RESTIR_RESERVOIR_GLSL 3 | 4 | #include "../../utility/random.glsl" 5 | #include "../../bxdf/bsdf/bsdf.glsl" 6 | 7 | struct ReSTIRPixelInfo { 8 | BSDFMaterial material; 9 | vec3 v;// inverse ray direction, i.e. from surface to camera or previous bounce 10 | vec3 position; 11 | vec3 geometricNormal; 12 | vec3 normal; 13 | }; 14 | 15 | bool restirsss_pixel_info_isSSS(in const ReSTIRPixelInfo pixelInfo) { 16 | return g_sss > 0 && pixelInfo.material.subsurface > 0; 17 | } 18 | 19 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/main/restirsss/restirsss_shift_hybrid_criterion.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RESTIRSSS_SHIFT_HYBRID_CRITERION_GLSL 2 | #define RESTIRSSS_SHIFT_HYBRID_CRITERION_GLSL 3 | 4 | // true if vertex x_2 is connectable from vertex x_1 (or y_1) 5 | bool restirsss_shift_connectable(in const vec3 x1Position, in const vec3 x1Normal, in const vec3 x2Position, in const vec3 x2Normal, in const vec3 scatterDistance) { 6 | // connectable if the angle between the normals is less than 60 degrees or the distance is greater than 2 times the maximum scatter distance 7 | return dot(x1Normal, x2Normal) <= 0.5 || distance(x1Position, x2Position) >= 2.0 * max(scatterDistance.r, max(scatterDistance.g, scatterDistance.b)); 8 | } 9 | 10 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/main/restirsss/restirsss_spatial_kernel.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RESTIR_SPATIAL_KERNEL_GLSL 2 | #define RESTIR_SPATIAL_KERNEL_GLSL 3 | 4 | #include "../../utility/random.glsl" 5 | #include "../../utility/constants.glsl" 6 | #include "../../bxdf/diffusion/sss_diffusion_profile.glsl" 7 | 8 | ivec2 restirsss_spatial_kernel_uniform(inout uint rngState, in const float maxRadius) { 9 | const float radius = maxRadius * sqrt(nextFloat(rngState)); 10 | const float angle = 2.0 * PI * nextFloat(rngState); 11 | 12 | const vec2 offset = vec2(radius * cos(angle), radius * sin(angle)); 13 | 14 | return ivec2(round(offset)); 15 | } 16 | 17 | float restirsss_spatial_kernel_maxSearchRadiusDiffusion(in const vec3 scatterDistance, in const vec3 position, in const ivec2 pixel, in const vec2 size) { 18 | const float maxRadius = 2.0 * max(scatterDistance.r, max(scatterDistance.g, scatterDistance.b)); 19 | 20 | const mat4 g_view_to_world_space = inverse(g_world_to_view_space); 21 | // transform screen space axes into world space 22 | const vec3 worldSpaceE1 = (g_view_to_world_space * vec4(1.0, 0.0, 0.0, 0.0)).xyz; 23 | const vec3 worldSpaceE2 = (g_view_to_world_space * vec4(0.0, 1.0, 0.0, 0.0)).xyz; 24 | 25 | // maximum offset positions in world space 26 | const vec3 worldSpaceOffsetPositionRight = position + maxRadius * worldSpaceE1; 27 | const vec3 worldSpaceOffsetPositionUp = position + maxRadius * worldSpaceE2; 28 | // transform back to screen space 29 | const vec3 screenSpaceOffsetPositionRight = (g_world_to_view_space * vec4(worldSpaceOffsetPositionRight, 1.0)).xyz; 30 | const vec3 screenSpaceOffsetPositionUp = (g_world_to_view_space * vec4(worldSpaceOffsetPositionUp, 1.0)).xyz; 31 | // project to clip space 32 | const vec3 clipSpaceOffsetPositionRight = (g_view_to_clip_space * vec4(screenSpaceOffsetPositionRight, 1.0)).xyz; // [-1,1] 33 | const vec3 clipSpaceOffsetPositionUp = (g_view_to_clip_space * vec4(screenSpaceOffsetPositionUp, 1.0)).xyz; // [-1,1] 34 | const vec2 clipSpaceProjectedOffsetPositionRight = clipSpaceOffsetPositionRight.xy / clipSpaceOffsetPositionRight.z; 35 | const vec2 clipSpaceProjectedOffsetPositionUp = clipSpaceOffsetPositionUp.xy / clipSpaceOffsetPositionUp.z; 36 | // convert to NDC 37 | const vec2 ndcOffsetPositionRight = clipSpaceProjectedOffsetPositionRight * 0.5 + 0.5; // [0,1] 38 | const vec2 ndcOffsetPositionUp = clipSpaceProjectedOffsetPositionUp * 0.5 + 0.5; // [0,1] 39 | 40 | const vec2 pixelRight = round(ndcOffsetPositionRight * vec2(size)); 41 | const vec2 pixelUp = round(ndcOffsetPositionUp * vec2(size)); 42 | 43 | const float searchRadiusRight = distance(vec2(pixel), pixelRight); 44 | const float searchRadiusUp = distance(vec2(pixel), pixelUp); 45 | 46 | return clamp(max(searchRadiusRight, searchRadiusUp), 5, 30); 47 | } 48 | 49 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/main/restirsss/restirsss_target_function.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RESTIRSSS_TARGET_FUNCTION_GLSL 2 | #define RESTIRSSS_TARGET_FUNCTION_GLSL 3 | 4 | float restirsss_target_function_evaluate(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample); 5 | 6 | /** 7 | * Used to combine multiple reservoirs. 8 | * Either the same as the default restir_target_function_evaluate or include additional checks, e.g. visibility check for ReSTIR DI, to stay unbiased. 9 | */ 10 | float restirsss_target_function_resampleEvaluate(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample, in const bool visibilityCheck); 11 | 12 | // PRIVATE 13 | #include "../../bxdf/disney.glsl" 14 | #include "../../visibility/visibility.glsl" 15 | 16 | vec3 restirsss_target_function_unshadowedLightContribution(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample) { 17 | if (restirsss_reservoir_isNullSample(evalSample)) { 18 | return vec3(0); 19 | } 20 | 21 | vec3 unshadowedLightContribution = vec3(1); 22 | 23 | if (restirsss_pixel_info_isSSS(pixelInfo)) { 24 | // bssrdf 25 | const float actualDistance = distance(pixelInfo.position, evalSample.samplePosition); 26 | 27 | const vec3 surfaceToLight = evalSample.lightPosition - evalSample.samplePosition; 28 | const vec3 surfaceToLightNormalized = normalize(surfaceToLight); 29 | 30 | vec3 bssrdf; 31 | vec3 bsdf; 32 | disney_bssrdf_evaluate(pixelInfo.normal, pixelInfo.v, evalSample.sampleNormal, surfaceToLightNormalized, actualDistance, pixelInfo.material.scatterDistance, pixelInfo.material.baseColor, bssrdf, bsdf); 33 | 34 | const float cosAtSurface = max(0, dot(evalSample.sampleNormal, surfaceToLightNormalized)); 35 | 36 | unshadowedLightContribution *= bssrdf * bsdf * cosAtSurface * evalSample.lightEmission; 37 | } else { 38 | // bsdf 39 | const vec3 surfaceToLight = evalSample.lightPosition - pixelInfo.position; 40 | const vec3 surfaceToLightNormalized = normalize(surfaceToLight); 41 | 42 | const BSDFVertex vertex = BSDFVertex(pixelInfo.geometricNormal); 43 | const BSDFFrame frame = coordinateSystem(pixelInfo.normal); 44 | const vec3 bsdf = bsdf_disney_evaluate(vertex, frame, pixelInfo.material, pixelInfo.v, surfaceToLightNormalized); 45 | 46 | const float cosAtSurface = max(0, dot(pixelInfo.normal, surfaceToLightNormalized)); 47 | 48 | unshadowedLightContribution *= bsdf * cosAtSurface * evalSample.lightEmission; 49 | } 50 | 51 | // unshadowedLightContribution *= visibility_shadowRay(evalSample.samplePosition, evalSample.sampleGeometricNormal, surfaceToLightNormalized, evalSample.lightObjectDescriptor, evalSample.lightTriangleId); 52 | 53 | return unshadowedLightContribution; 54 | } 55 | 56 | vec3 restirsss_measurementContributionFunction(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample) { 57 | const vec3 color = restirsss_target_function_unshadowedLightContribution(pixelInfo, evalSample); 58 | 59 | // if (g_restir_visibility == 0) { 60 | // // no visibility pass, check if chosen light is visible from the chosen sample position 61 | // vec3 surfacePosition; 62 | // vec3 surfaceGeometricNormal; 63 | // vec3 surfaceToLightNormalized; 64 | // if (restirsss_pixel_info_isSSS(pixelInfo)) { 65 | // surfacePosition = evalSample.samplePosition; 66 | // surfaceGeometricNormal = evalSample.sampleGeometricNormal; 67 | // surfaceToLightNormalized = normalize(evalSample.lightPosition - evalSample.samplePosition); 68 | // } else { 69 | // surfacePosition = pixelInfo.position; 70 | // surfaceGeometricNormal = pixelInfo.geometricNormal; 71 | // surfaceToLightNormalized = normalize(evalSample.lightPosition - pixelInfo.position); 72 | // } 73 | // color *= visibility_shadowRay(surfacePosition, surfaceGeometricNormal, surfaceToLightNormalized, evalSample.lightObjectDescriptor, evalSample.lightTriangleId); 74 | // } 75 | return color; 76 | } 77 | 78 | float calcLuminance(in const vec3 color) { 79 | return dot(color.xyz, vec3(0.299f, 0.587f, 0.114f)); 80 | } 81 | 82 | // implement "base class" 83 | float restirsss_target_function_evaluate(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample) { 84 | const vec3 unshadowedLightContribution = restirsss_target_function_unshadowedLightContribution(pixelInfo, evalSample); 85 | 86 | // float targetFunction = length(unshadowedLightContribution);// ^p(X_i) 87 | // targetFunction = (isnan(targetFunction) || isinf(targetFunction)) ? 0 : targetFunction; 88 | const float targetFunction = calcLuminance(unshadowedLightContribution); 89 | 90 | return targetFunction; 91 | } 92 | 93 | // implement "base class" 94 | float restirsss_target_function_resampleEvaluate(in const ReSTIRPixelInfo pixelInfo, in const ReSTIRSSSSample evalSample, in const bool visibilityCheck) { 95 | if (visibilityCheck) { 96 | vec3 surfacePosition; 97 | vec3 surfaceGeometricNormal; 98 | vec3 surfaceToLightNormalized; 99 | float tMax = 0; 100 | if (restirsss_pixel_info_isSSS(pixelInfo)) { 101 | surfacePosition = evalSample.samplePosition; 102 | surfaceGeometricNormal = evalSample.sampleGeometricNormal; 103 | const vec3 d = evalSample.lightPosition - evalSample.samplePosition; 104 | surfaceToLightNormalized = normalize(d); 105 | tMax = length(d); 106 | } else { 107 | surfacePosition = pixelInfo.position; 108 | surfaceGeometricNormal = pixelInfo.geometricNormal; 109 | const vec3 d = evalSample.lightPosition - pixelInfo.position; 110 | surfaceToLightNormalized = normalize(d); 111 | tMax = length(d); 112 | } 113 | if (!visibility_shadowRay(surfacePosition, surfaceGeometricNormal, surfaceToLightNormalized, tMax, evalSample.lightObjectDescriptor, evalSample.lightTriangleId)) { 114 | return 0; 115 | } 116 | } 117 | return restirsss_target_function_evaluate(pixelInfo, evalSample); 118 | } 119 | 120 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/material.glsl: -------------------------------------------------------------------------------- 1 | #ifndef MATERIAL_GLSL 2 | #define MATERIAL_GLSL 3 | 4 | vec3 material_getAlbedo(in const Material material, in const vec2 uv) { 5 | return material.baseColorTexture >= 0 ? texture(textures[material.baseColorTexture], uv).rgb : material.baseColorFactor.rgb; 6 | } 7 | 8 | float material_getMetallic(in const Material material, in const vec2 uv) { 9 | return material.metallicRoughnessTexture >= 0 ? texture(textures[material.metallicRoughnessTexture], uv).b : material.metallicFactor; 10 | } 11 | 12 | float material_getRoughness(in const Material material, in const vec2 uv) { 13 | return material.metallicRoughnessTexture >= 0 ? texture(textures[material.metallicRoughnessTexture], uv).g : material.roughnessFactor; 14 | } 15 | 16 | bool material_isLightSource(in const Material material) { 17 | return any(greaterThan(material.emission, vec3(0))); 18 | } 19 | 20 | bool material_isTranslucent(in const Material material) { 21 | return material.subsurface > 0.0; 22 | } 23 | 24 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/raycommon.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RAYCOMMON_GLSL 2 | #define RAYCOMMON_GLSL 3 | 4 | struct HitPayload { 5 | int objectDescriptorId; // gl_InstanceCustomIndexEXT 6 | int triangleId; // gl_PrimitiveID 7 | float t; // distance 8 | vec2 barycentrics; // encodes vec3(1.0 - barycentrics.x - barycentrics.y, barycentrics.x, barycentrics.y) 9 | uint face; // gl_HitKindFrontFacingTriangleEXT or gl_HitKindBackFacingTriangleEXT 10 | }; 11 | 12 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/raystructs.glsl: -------------------------------------------------------------------------------- 1 | #ifndef RAYSTRUCTS_GLSL 2 | #define RAYSTRUCTS_GLSL 3 | 4 | struct ObjectDescriptor { 5 | uint64_t vertexAddress; 6 | uint64_t indexAddress; 7 | uint materialId; 8 | 9 | mat4 objectToWorld; 10 | mat4 objectToWorldNormal; // == transpose(inverse(objectToWorld)) 11 | }; 12 | 13 | struct Vertex { 14 | float position_x; 15 | float position_y; 16 | float position_z; 17 | float normal_x; 18 | float normal_y; 19 | float normal_z; 20 | float tangent_x; 21 | float tangent_y; 22 | float tangent_z; 23 | float tangent_w; 24 | float texCoord_u; 25 | float texCoord_v; 26 | }; 27 | 28 | struct Material { 29 | vec3 baseColorFactor; 30 | int baseColorTexture; 31 | float metallicFactor; 32 | float roughnessFactor; 33 | int metallicRoughnessTexture; 34 | 35 | int normalTexture; 36 | 37 | vec3 emission; 38 | 39 | float subsurface; 40 | vec3 meanFreePath; 41 | }; 42 | 43 | struct Light { 44 | uint type; 45 | 46 | uint objectDescriptorId; 47 | uint triangleId; 48 | 49 | vec3 position; 50 | vec3 emission; 51 | }; 52 | 53 | #define GBUFFER_NULL 0xFFFFFFFFu 54 | 55 | struct GBuffer { 56 | uint objectDescriptorId; // gl_InstanceCustomIndexEXT 57 | uint triangleId; // gl_PrimitiveID 58 | float barycentricsY; // encodes vec3(1.0 - barycentricsY - barycentricsZ, barycentricsY, barycentricsZ) 59 | float barycentricsZ; // encodes vec3(1.0 - barycentricsY - barycentricsZ, barycentricsY, barycentricsZ) 60 | }; 61 | 62 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/trace/trace_rayquery.glsl: -------------------------------------------------------------------------------- 1 | #ifndef TRACE_RAYQUERY_GLSL 2 | #define TRACE_RAYQUERY_GLSL 3 | 4 | #include "../raycommon.glsl" 5 | #include "trace.glsl" 6 | 7 | bool trace(in const vec3 origin, in const vec3 direction, in const float tMin, in const float tMax, out HitPayload hitPayload) { 8 | rayQueryEXT rayQuery; 9 | rayQueryInitializeEXT(rayQuery, 10 | topLevelAS, 11 | gl_RayFlagsOpaqueEXT, 12 | 0xFF, 13 | origin, 14 | tMin + 0.001, 15 | direction, 16 | tMax); 17 | 18 | while(rayQueryProceedEXT(rayQuery)){ 19 | } 20 | 21 | if (rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT) { 22 | return false; 23 | } 24 | 25 | hitPayload.objectDescriptorId = rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, true); 26 | hitPayload.triangleId = rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true); 27 | hitPayload.t = rayQueryGetIntersectionTEXT(rayQuery, true); 28 | hitPayload.barycentrics = rayQueryGetIntersectionBarycentricsEXT(rayQuery, true); 29 | hitPayload.face = rayQueryGetIntersectionFrontFaceEXT(rayQuery, true) ? gl_HitKindFrontFacingTriangleEXT : gl_HitKindBackFacingTriangleEXT; 30 | return true; 31 | } 32 | 33 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/utility/colormap.glsl: -------------------------------------------------------------------------------- 1 | #ifndef UTILITY_COLORMAP_GLSL 2 | #define UTILITY_COLORMAP_GLSL 3 | 4 | // https://www.shadertoy.com/view/WlfXRN 5 | 6 | vec3 colormap_viridis(in const float t) { 7 | const vec3 c0 = vec3(0.2777273272234177, 0.005407344544966578, 0.3340998053353061); 8 | const vec3 c1 = vec3(0.1050930431085774, 1.404613529898575, 1.384590162594685); 9 | const vec3 c2 = vec3(-0.3308618287255563, 0.214847559468213, 0.09509516302823659); 10 | const vec3 c3 = vec3(-4.634230498983486, -5.799100973351585, -19.33244095627987); 11 | const vec3 c4 = vec3(6.228269936347081, 14.17993336680509, 56.69055260068105); 12 | const vec3 c5 = vec3(4.776384997670288, -13.74514537774601, -65.35303263337234); 13 | const vec3 c6 = vec3(-5.435455855934631, 4.645852612178535, 26.3124352495832); 14 | 15 | return c0+t*(c1+t*(c2+t*(c3+t*(c4+t*(c5+t*c6))))); 16 | } 17 | 18 | vec3 colormap_plasma(in const float t) { 19 | const vec3 c0 = vec3(0.05873234392399702, 0.02333670892565664, 0.5433401826748754); 20 | const vec3 c1 = vec3(2.176514634195958, 0.2383834171260182, 0.7539604599784036); 21 | const vec3 c2 = vec3(-2.689460476458034, -7.455851135738909, 3.110799939717086); 22 | const vec3 c3 = vec3(6.130348345893603, 42.3461881477227, -28.51885465332158); 23 | const vec3 c4 = vec3(-11.10743619062271, -82.66631109428045, 60.13984767418263); 24 | const vec3 c5 = vec3(10.02306557647065, 71.41361770095349, -54.07218655560067); 25 | const vec3 c6 = vec3(-3.658713842777788, -22.93153465461149, 18.19190778539828); 26 | 27 | return c0+t*(c1+t*(c2+t*(c3+t*(c4+t*(c5+t*c6))))); 28 | } 29 | 30 | vec3 colormap_magma(in const float t) { 31 | const vec3 c0 = vec3(-0.002136485053939582, -0.000749655052795221, -0.005386127855323933); 32 | const vec3 c1 = vec3(0.2516605407371642, 0.6775232436837668, 2.494026599312351); 33 | const vec3 c2 = vec3(8.353717279216625, -3.577719514958484, 0.3144679030132573); 34 | const vec3 c3 = vec3(-27.66873308576866, 14.26473078096533, -13.64921318813922); 35 | const vec3 c4 = vec3(52.17613981234068, -27.94360607168351, 12.94416944238394); 36 | const vec3 c5 = vec3(-50.76852536473588, 29.04658282127291, 4.23415299384598); 37 | const vec3 c6 = vec3(18.65570506591883, -11.48977351997711, -5.601961508734096); 38 | 39 | return c0+t*(c1+t*(c2+t*(c3+t*(c4+t*(c5+t*c6))))); 40 | } 41 | 42 | vec3 colormap_inferno(in const float t) { 43 | const vec3 c0 = vec3(0.0002189403691192265, 0.001651004631001012, -0.01948089843709184); 44 | const vec3 c1 = vec3(0.1065134194856116, 0.5639564367884091, 3.932712388889277); 45 | const vec3 c2 = vec3(11.60249308247187, -3.972853965665698, -15.9423941062914); 46 | const vec3 c3 = vec3(-41.70399613139459, 17.43639888205313, 44.35414519872813); 47 | const vec3 c4 = vec3(77.162935699427, -33.40235894210092, -81.80730925738993); 48 | const vec3 c5 = vec3(-71.31942824499214, 32.62606426397723, 73.20951985803202); 49 | const vec3 c6 = vec3(25.13112622477341, -12.24266895238567, -23.07032500287172); 50 | 51 | return c0+t*(c1+t*(c2+t*(c3+t*(c4+t*(c5+t*c6))))); 52 | } 53 | 54 | vec3 colormap_inverse_tonemapper_gamma(in vec3 color) { 55 | color = pow(color, vec3(2.2)); 56 | return color / (1 - color); 57 | } 58 | 59 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/utility/constants.glsl: -------------------------------------------------------------------------------- 1 | #ifndef UTILITY_CONSTANTS_GLSL 2 | #define UTILITY_CONSTANTS_GLSL 3 | 4 | #define PI 3.14159265359 5 | #define TWO_PI 6.28318530718 6 | #define INV_PI 0.31830988618 7 | 8 | #define INFINITY 1000000000.0 9 | 10 | #define INVALID_UINT_VALUE 0xFFFFFFFFu 11 | #define ERROR_UINT_VALUE 0xFFFFFFFEu 12 | 13 | #define RENDER_MODE_POSITION 0 14 | #define RENDER_MODE_NORMAL 1 15 | #define RENDER_MODE_GEOMETRIC_NORMAL 2 16 | #define RENDER_MODE_UV 3 17 | #define RENDER_MODE_BASE_COLOR 4 18 | #define RENDER_MODE_NORMAL_MAP 5 19 | #define RENDER_MODE_TANGENT 6 20 | #define RENDER_MODE_BI_TANGENT 7 21 | #define RENDER_MODE_OBJECT_DESCRIPTOR 8 22 | #define RENDER_MODE_TRIANGLE 9 23 | #define RENDER_MODE_MOTION 10 24 | #define RENDER_MODE_FACE 11 25 | #define RENDER_MODE_COLORMAP 12 26 | #define RENDER_MODE_DISK_BASED_SAMPLING_INTERSECTIONS 13 27 | #define RENDER_MODE_RESTIRSSS_SEARCH_RADIUS 14 28 | 29 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/utility/normal_mapping.glsl: -------------------------------------------------------------------------------- 1 | #ifndef UTILITY_NORMAL_MAPPING_GLSL 2 | #define UTILITY_NORMAL_MAPPING_GLSL 3 | 4 | mat3 tangentSpaceMatrix(in const vec3 tangent, in const vec3 bitangent, in const vec3 normal) { 5 | return transpose(inverse(mat3(tangent, bitangent, normal))); 6 | // return mat3(tangent, bitangent, normal); 7 | } 8 | 9 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/utility/random.glsl: -------------------------------------------------------------------------------- 1 | #ifndef UTILITY_RANDOM_GLSL 2 | #define UTILITY_RANDOM_GLSL 3 | 4 | #include "constants.glsl" 5 | 6 | /** 7 | * Random number in [0,1]. 8 | * https://www.shadertoy.com/view/XlGcRh 9 | */ 10 | float pcg(inout uint state) { 11 | state = state * 747796405u + 2891336453u; 12 | uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; 13 | word = (word >> 22u) ^ word; 14 | return word / 4294967295.0; 15 | } 16 | 17 | // https://github.com/nvpro-samples/vk_mini_path_tracer/blob/main/vk_mini_path_tracer/shaders/raytrace.comp.glsl#L25 18 | // Steps the RNG and returns a floating-point value between 0 and 1 inclusive. 19 | float nextFloat(inout uint rngState) { 20 | // Condensed version of pcg_output_rxs_m_xs_32_32, with simple conversion to floating-point [0,1]. 21 | rngState = rngState * 747796405 + 1; 22 | uint word = ((rngState >> ((rngState >> 28) + 4)) ^ rngState) * 277803737; 23 | word = (word >> 22) ^ word; 24 | return float(word) / 4294967295.0f; 25 | } 26 | 27 | // [0, maxUInt] 28 | // maxUInt inclusive! 29 | uint nextUInt(inout uint rngState, uint maxUInt) { 30 | rngState = rngState * 747796405 + 1; 31 | uint word = ((rngState >> ((rngState >> 28) + 4)) ^ rngState) * 277803737; 32 | word = (word >> 22) ^ word; 33 | return word % (maxUInt + 1); 34 | } 35 | 36 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/resources/shaders/visibility/visibility.glsl: -------------------------------------------------------------------------------- 1 | #ifndef VISIBILITY_GLSL 2 | #define VISIBILITY_GLSL 3 | 4 | bool visibility_shadowRay(in const vec3 positionWorld, in const vec3 geometricNormalWorld, in const vec3 lightDirection, in const float tMax, in const uint objectDescriptor, in const uint triangleId) { 5 | rayQueryEXT rayQuery; 6 | rayQueryInitializeEXT(rayQuery, 7 | topLevelAS, 8 | // gl_RayFlagsOpaqueEXT, 9 | gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT | gl_RayFlagsSkipClosestHitShaderEXT, 10 | 0xFF, 11 | positionWorld, 12 | 0.001, 13 | lightDirection, 14 | tMax - 0.001); 15 | 16 | // while(rayQueryProceedEXT(rayQuery)){ 17 | // } 18 | // 19 | // bool hit = (rayQueryGetIntersectionTypeEXT(rayQuery, true) != gl_RayQueryCommittedIntersectionNoneEXT); 20 | // if (!hit || rayQueryGetIntersectionInstanceCustomIndexEXT(rayQuery, true) == objectDescriptor && rayQueryGetIntersectionPrimitiveIndexEXT(rayQuery, true) == triangleId) { 21 | // return 1.0; 22 | // } 23 | // return 0.0; 24 | rayQueryProceedEXT(rayQuery); 25 | return rayQueryGetIntersectionTypeEXT(rayQuery, true) == gl_RayQueryCommittedIntersectionNoneEXT; 26 | } 27 | 28 | #endif -------------------------------------------------------------------------------- /ReSTIRSSS/src/bin/main.cpp: -------------------------------------------------------------------------------- 1 | #define STB_IMAGE_IMPLEMENTATION 2 | #define STB_IMAGE_WRITE_IMPLEMENTATION 3 | #define TINYOBJLOADER_IMPLEMENTATION 4 | 5 | #include "raven/core/RavenVkDynamicLoader.h" 6 | 7 | #include "raven/core/Application.h" 8 | #include "raven/core/HeadlessApplication.h" 9 | #include "raven/util/Paths.h" 10 | 11 | #include "restirsss/ReSTIRSSS.h" 12 | #include "restirsss/ReSTIRSSSEvaluation.h" 13 | #include "restirsss/ReSTIRSSSEvaluationTiming.h" 14 | #include "restirsss/ReSTIRSSSVideo.h" 15 | 16 | #include "argparse/include/argparse/argparse.hpp" 17 | 18 | int main(const int argc, char *argv[]) { 19 | #ifdef RESOURCE_DIRECTORY_PATH 20 | raven::Paths::m_resourceDirectoryPath = RESOURCE_DIRECTORY_PATH; 21 | #endif 22 | 23 | argparse::ArgumentParser program("restirsss"); 24 | program.add_argument("scene") 25 | .help("name of the scene (in resources/scenes/.xml)") 26 | .required(); 27 | program.add_argument("--preset") 28 | .nargs(1) 29 | .help("pathtracing, hybrid, sequential") 30 | .choices("pathtracing", "hybrid", "sequential") 31 | .default_value("hybrid"); 32 | program.add_argument("--evaluate") 33 | .nargs(1) 34 | .help("renderings, timing, video") 35 | .choices("renderings", "timing", "video"); 36 | 37 | try { 38 | program.parse_args(argc, argv); 39 | } catch (const std::exception &err) { 40 | std::cerr << err.what() << std::endl; 41 | std::cerr << program; 42 | return 1; 43 | } 44 | 45 | if (program.present("--evaluate")) { 46 | if (program.get("--evaluate") == "renderings") { 47 | return raven::ReSTIRSSSEvaluation().run(); 48 | } 49 | if (program.get("--evaluate") == "timing") { 50 | return raven::ReSTIRSSSEvaluationTiming().run(); 51 | } 52 | if (program.get("--evaluate") == "video") { 53 | return raven::ReSTIRSSSVideo().run(); 54 | } 55 | } 56 | 57 | auto rendererSettings = raven::ReSTIRSSS::ReSTIRSSSSettings{.m_scene = raven::Rayscenes::UNDEFINED}; 58 | const auto renderer = std::make_shared(rendererSettings, program.get("scene"), program.get("--preset")); 59 | std::string appName = "ReSTIR Subsurface Scattering for Real-Time Path Tracing"; 60 | 61 | #ifdef WIN32 62 | auto settings = raven::Application::ApplicationSettings{.m_msaaSamples = vk::SampleCountFlagBits::e1, 63 | .m_deviceExtensions = {VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, VK_KHR_RAY_QUERY_EXTENSION_NAME, 64 | VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME}}; 65 | #else 66 | auto settings = raven::Application::ApplicationSettings{.m_msaaSamples = vk::SampleCountFlagBits::e1, 67 | .m_deviceExtensions = {VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME, VK_KHR_RAY_QUERY_EXTENSION_NAME, 68 | VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME}}; 69 | #endif 70 | raven::Application app(appName, settings, renderer, raven::Queues::QueueFamilies::COMPUTE_FAMILY | raven::Queues::QueueFamilies::GRAPHICS_FAMILY | raven::Queues::TRANSFER_FAMILY); 71 | app.setVSync(true); 72 | 73 | try { 74 | app.run(); 75 | } catch (const std::exception &e) { 76 | std::cerr << e.what() << std::endl; 77 | return EXIT_FAILURE; 78 | } 79 | 80 | return EXIT_SUCCESS; 81 | } -------------------------------------------------------------------------------- /VkRaven/.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: None 6 | AlignOperands: Align 7 | AllowAllArgumentsOnNextLine: false 8 | AllowAllConstructorInitializersOnNextLine: false 9 | AllowAllParametersOfDeclarationOnNextLine: false 10 | AllowShortBlocksOnASingleLine: Never 11 | AllowShortCaseLabelsOnASingleLine: false 12 | AllowShortFunctionsOnASingleLine: All 13 | AllowShortIfStatementsOnASingleLine: Never 14 | AllowShortLambdasOnASingleLine: All 15 | AllowShortLoopsOnASingleLine: true 16 | AlwaysBreakAfterReturnType: None 17 | AlwaysBreakTemplateDeclarations: Yes 18 | BreakBeforeBraces: Custom 19 | BraceWrapping: 20 | AfterCaseLabel: false 21 | AfterClass: false 22 | AfterControlStatement: Never 23 | AfterEnum: false 24 | AfterFunction: false 25 | AfterNamespace: false 26 | AfterUnion: false 27 | BeforeCatch: false 28 | BeforeElse: false 29 | IndentBraces: false 30 | SplitEmptyFunction: false 31 | SplitEmptyRecord: true 32 | BreakBeforeBinaryOperators: None 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeColon 35 | BreakInheritanceList: BeforeColon 36 | ColumnLimit: 0 37 | CompactNamespaces: false 38 | ContinuationIndentWidth: 8 39 | IndentCaseLabels: true 40 | IndentPPDirectives: None 41 | IndentWidth: 4 42 | KeepEmptyLinesAtTheStartOfBlocks: true 43 | MaxEmptyLinesToKeep: 2 44 | NamespaceIndentation: All 45 | ObjCSpaceAfterProperty: false 46 | ObjCSpaceBeforeProtocolList: true 47 | PointerAlignment: Right 48 | ReflowComments: false 49 | SpaceAfterCStyleCast: true 50 | SpaceAfterLogicalNot: false 51 | SpaceAfterTemplateKeyword: false 52 | SpaceBeforeAssignmentOperators: true 53 | SpaceBeforeCpp11BracedList: false 54 | SpaceBeforeCtorInitializerColon: true 55 | SpaceBeforeInheritanceColon: true 56 | SpaceBeforeParens: ControlStatements 57 | SpaceBeforeRangeBasedForLoopColon: false 58 | SpaceInEmptyParentheses: false 59 | SpacesBeforeTrailingComments: 1 60 | SpacesInAngles: false 61 | SpacesInCStyleCastParentheses: false 62 | SpacesInContainerLiterals: false 63 | SpacesInParentheses: false 64 | SpacesInSquareBrackets: false 65 | TabWidth: 4 66 | UseTab: Never 67 | -------------------------------------------------------------------------------- /VkRaven/.clang-tidy: -------------------------------------------------------------------------------- 1 | # Generated from CLion Inspection settings 2 | --- 3 | Checks: '-*, 4 | bugprone-argument-comment, 5 | bugprone-assert-side-effect, 6 | bugprone-bad-signal-to-kill-thread, 7 | bugprone-branch-clone, 8 | bugprone-copy-constructor-init, 9 | bugprone-dangling-handle, 10 | bugprone-dynamic-static-initializers, 11 | bugprone-fold-init-type, 12 | bugprone-forward-declaration-namespace, 13 | bugprone-forwarding-reference-overload, 14 | bugprone-inaccurate-erase, 15 | bugprone-incorrect-roundings, 16 | bugprone-integer-division, 17 | bugprone-lambda-function-name, 18 | bugprone-macro-parentheses, 19 | bugprone-macro-repeated-side-effects, 20 | bugprone-misplaced-operator-in-strlen-in-alloc, 21 | bugprone-misplaced-pointer-arithmetic-in-alloc, 22 | bugprone-misplaced-widening-cast, 23 | bugprone-move-forwarding-reference, 24 | bugprone-multiple-statement-macro, 25 | bugprone-no-escape, 26 | bugprone-not-null-terminated-result, 27 | bugprone-parent-virtual-call, 28 | bugprone-posix-return, 29 | bugprone-reserved-identifier, 30 | bugprone-sizeof-container, 31 | bugprone-sizeof-expression, 32 | bugprone-spuriously-wake-up-functions, 33 | bugprone-string-constructor, 34 | bugprone-string-integer-assignment, 35 | bugprone-string-literal-with-embedded-nul, 36 | bugprone-suspicious-enum-usage, 37 | bugprone-suspicious-include, 38 | bugprone-suspicious-memset-usage, 39 | bugprone-suspicious-missing-comma, 40 | bugprone-suspicious-semicolon, 41 | bugprone-suspicious-string-compare, 42 | bugprone-suspicious-memory-comparison, 43 | bugprone-suspicious-realloc-usage, 44 | bugprone-swapped-arguments, 45 | bugprone-terminating-continue, 46 | bugprone-throw-keyword-missing, 47 | bugprone-too-small-loop-variable, 48 | bugprone-undefined-memory-manipulation, 49 | bugprone-undelegated-constructor, 50 | bugprone-unhandled-self-assignment, 51 | bugprone-unused-raii, 52 | bugprone-unused-return-value, 53 | bugprone-use-after-move, 54 | bugprone-virtual-near-miss, 55 | cert-dcl21-cpp, 56 | cert-dcl58-cpp, 57 | cert-err34-c, 58 | cert-err52-cpp, 59 | cert-err60-cpp, 60 | cert-flp30-c, 61 | cert-msc50-cpp, 62 | cert-msc51-cpp, 63 | cert-str34-c, 64 | cppcoreguidelines-interfaces-global-init, 65 | cppcoreguidelines-narrowing-conversions, 66 | cppcoreguidelines-pro-type-member-init, 67 | cppcoreguidelines-pro-type-static-cast-downcast, 68 | cppcoreguidelines-slicing, 69 | google-default-arguments, 70 | google-explicit-constructor, 71 | google-runtime-operator, 72 | hicpp-exception-baseclass, 73 | hicpp-multiway-paths-covered, 74 | misc-misplaced-const, 75 | misc-new-delete-overloads, 76 | misc-no-recursion, 77 | misc-non-copyable-objects, 78 | misc-throw-by-value-catch-by-reference, 79 | misc-unconventional-assign-operator, 80 | misc-uniqueptr-reset-release, 81 | modernize-avoid-bind, 82 | modernize-concat-nested-namespaces, 83 | modernize-deprecated-headers, 84 | modernize-deprecated-ios-base-aliases, 85 | modernize-loop-convert, 86 | modernize-make-shared, 87 | modernize-make-unique, 88 | modernize-pass-by-value, 89 | modernize-raw-string-literal, 90 | modernize-redundant-void-arg, 91 | modernize-replace-auto-ptr, 92 | modernize-replace-disallow-copy-and-assign-macro, 93 | modernize-replace-random-shuffle, 94 | modernize-return-braced-init-list, 95 | modernize-shrink-to-fit, 96 | modernize-unary-static-assert, 97 | modernize-use-auto, 98 | modernize-use-bool-literals, 99 | modernize-use-emplace, 100 | modernize-use-equals-default, 101 | modernize-use-equals-delete, 102 | modernize-use-nodiscard, 103 | modernize-use-noexcept, 104 | modernize-use-nullptr, 105 | modernize-use-override, 106 | modernize-use-transparent-functors, 107 | modernize-use-uncaught-exceptions, 108 | mpi-buffer-deref, 109 | mpi-type-mismatch, 110 | openmp-use-default-none, 111 | performance-faster-string-find, 112 | performance-for-range-copy, 113 | performance-implicit-conversion-in-loop, 114 | performance-inefficient-algorithm, 115 | performance-inefficient-string-concatenation, 116 | performance-inefficient-vector-operation, 117 | performance-move-const-arg, 118 | performance-move-constructor-init, 119 | performance-no-automatic-move, 120 | performance-noexcept-move-constructor, 121 | performance-trivially-destructible, 122 | performance-type-promotion-in-math-fn, 123 | performance-unnecessary-copy-initialization, 124 | performance-unnecessary-value-param, 125 | portability-simd-intrinsics, 126 | readability-avoid-const-params-in-decls, 127 | readability-const-return-type, 128 | readability-container-size-empty, 129 | readability-convert-member-functions-to-static, 130 | readability-delete-null-pointer, 131 | readability-deleted-default, 132 | readability-inconsistent-declaration-parameter-name, 133 | readability-make-member-function-const, 134 | readability-misleading-indentation, 135 | readability-misplaced-array-index, 136 | readability-non-const-parameter, 137 | readability-redundant-control-flow, 138 | readability-redundant-declaration, 139 | readability-redundant-function-ptr-dereference, 140 | readability-redundant-smartptr-get, 141 | readability-redundant-string-cstr, 142 | readability-redundant-string-init, 143 | readability-simplify-subscript-expr, 144 | readability-static-accessed-through-instance, 145 | readability-static-definition-in-anonymous-namespace, 146 | readability-string-compare, 147 | readability-uniqueptr-delete-release, 148 | readability-use-anyofallof' -------------------------------------------------------------------------------- /VkRaven/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | project(raven VERSION 0.1.0 DESCRIPTION "VkRaven - Vulkan Render and Visualization Engine" LANGUAGES C CXX) 3 | 4 | set(CMAKE_CXX_STANDARD 20) 5 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 6 | 7 | set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) 8 | 9 | find_package(Vulkan REQUIRED) 10 | 11 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/find/" PARENT_SCOPE) 12 | include(cmake/setup.cmake) 13 | 14 | if (MSVC) 15 | SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:mainCRTStartup" PARENT_SCOPE) 16 | endif () 17 | 18 | add_subdirectory(lib) 19 | add_subdirectory(raven) 20 | -------------------------------------------------------------------------------- /VkRaven/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Mirco Werner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /VkRaven/README.md: -------------------------------------------------------------------------------- 1 | # VkRaven 2 | **V**ul**k**an **R**ender **a**nd **V**isualization **En**gine 3 | -------------------------------------------------------------------------------- /VkRaven/cmake/find/FindOptix.cmake: -------------------------------------------------------------------------------- 1 | # taken from https://github.com/nvpro-samples/nvpro_core/blob/master/cmake/find/FindOptix7.cmake, adjusted 2 | 3 | # Try to find OptiX project dll/so and headers 4 | # 5 | 6 | # outputs 7 | unset(OPTIX_DLL CACHE) 8 | unset(OPTIX_LIB CACHE) 9 | unset(OPTIX_FOUND CACHE) 10 | unset(OPTIX_INCLUDE_DIR CACHE) 11 | 12 | # OPTIX_LOCATION can be setup to search versions somewhere else 13 | 14 | macro(folder_list result curdir substring) 15 | FILE(GLOB children RELATIVE ${curdir} ${curdir}/*${substring}*) 16 | SET(dirlist "") 17 | foreach (child ${children}) 18 | IF (IS_DIRECTORY ${curdir}/${child}) 19 | LIST(APPEND dirlist ${child}) 20 | ENDIF () 21 | ENDFOREACH () 22 | SET(${result} ${dirlist}) 23 | ENDMACRO() 24 | 25 | macro(_find_version_path targetVersion targetPath rootName searchList) 26 | unset(targetVersion) 27 | unset(targetPath) 28 | SET(bestver "0.0.0") 29 | SET(bestpath "") 30 | foreach (basedir ${searchList}) 31 | folder_list(dirList ${basedir} ${rootName}) 32 | foreach (checkdir ${dirList}) 33 | string(REGEX MATCH "${rootName}(.*)([0-9]+)\\.([0-9]+)\\.([0-9]+)(.*)$" result "${checkdir}") 34 | if ("${result}" STREQUAL "${checkdir}") 35 | # found a path with versioning 36 | SET(ver "${CMAKE_MATCH_2}.${CMAKE_MATCH_3}.${CMAKE_MATCH_4}") 37 | if (ver VERSION_GREATER bestver) 38 | SET(bestver ${ver}) 39 | SET(bestmajorver ${CMAKE_MATCH_2}) 40 | SET(bestminorver ${CMAKE_MATCH_3}) 41 | SET(bestpath "${basedir}/${checkdir}") 42 | endif () 43 | endif () 44 | endforeach () 45 | endforeach () 46 | if ("${bestver}" STREQUAL "0.0.0") 47 | foreach (basedir ${searchList}) 48 | if (EXISTS "${basedir}/optix/include/optix.h") 49 | SET(bestver "unknown") 50 | SET(bestpath "${basedir}/optix") 51 | endif () 52 | endforeach () 53 | endif () 54 | SET(${targetVersion} "${bestver}") 55 | SET(${targetPath} "${bestpath}") 56 | endmacro() 57 | 58 | macro(_find_files targetVar incDir dllName dllName64 folder) 59 | unset(fileList) 60 | if (ARCH STREQUAL "x86") 61 | file(GLOB fileList "${${incDir}}/../${folder}${dllName}") 62 | list(LENGTH fileList NUMLIST) 63 | if (NUMLIST EQUAL 0) 64 | file(GLOB fileList "${${incDir}}/${folder}${dllName}") 65 | endif () 66 | else () 67 | file(GLOB fileList "${${incDir}}/../${folder}${dllName64}") 68 | list(LENGTH fileList NUMLIST) 69 | if (NUMLIST EQUAL 0) 70 | file(GLOB fileList "${${incDir}}/${folder}${dllName64}") 71 | endif () 72 | endif () 73 | list(LENGTH fileList NUMLIST) 74 | if (NUMLIST EQUAL 0) 75 | message(STATUS "MISSING: unable to find ${targetVar} files (${folder}${dllName}, ${folder}${dllName64})") 76 | set(${targetVar} "NOTFOUND") 77 | endif () 78 | list(APPEND ${targetVar} ${fileList}) 79 | 80 | # message ( "File list: ${${targetVar}}" ) #-- debugging 81 | endmacro() 82 | 83 | if (DEFINED OPTIX_LOCATION OR DEFINED ENV{OPTIX_LOCATION}) 84 | Message(STATUS "OptiX: Using OPTIX_LOCATION (${OPTIX_LOCATION})...") 85 | if (NOT DEFINED OPTIX_LOCATION) 86 | if (DEFINED ENV{OPTIX_LOCATION}) 87 | set(OPTIX_LOCATION $ENV{OPTIX_LOCATION}) 88 | endif () 89 | endif () 90 | # Locate by version failed. Handle user override for OPTIX_LOCATION. 91 | string(REGEX MATCH ".*([0-9]+).([0-9]+).([0-9]+)(.*)$" result "${OPTIX_LOCATION}") 92 | if ("${result}" STREQUAL "${OPTIX_LOCATION}") 93 | SET(bestver "${CMAKE_MATCH_1}.${CMAKE_MATCH_2}.${CMAKE_MATCH_3}") 94 | SET(bestmajorver ${CMAKE_MATCH_1}) 95 | SET(bestminorver ${CMAKE_MATCH_2}) 96 | Message(STATUS "OptiX: Version ${bestver}") 97 | SET(OPTIX_VERSION "${bestver}") 98 | else () 99 | Message(WARNING "Could NOT extract the version from OPTIX folder : ${result}") 100 | endif () 101 | find_path(OPTIX_INCLUDE_DIR optix.h ${OPTIX_LOCATION}/include) 102 | if (OPTIX_INCLUDE_DIR) 103 | set(OPTIX_ROOT_DIR ${OPTIX_INCLUDE_DIR}/../) 104 | endif () 105 | endif () 106 | if (NOT DEFINED OPTIX_ROOT_DIR) 107 | # Locate OptiX by version 108 | set(SEARCH_PATHS 109 | $ENV{OPTIX_LOCATION} 110 | ${OPTIX_LOCATION} 111 | ${PROJECT_SOURCE_DIR}/../LocalPackages/Optix 112 | ${PROJECT_SOURCE_DIR}/../../LocalPackages/Optix 113 | ${PROJECT_SOURCE_DIR}/../../../LocalPackages/Optix 114 | C:/ProgramData/NVIDIA\ Corporation 115 | /opt 116 | ) 117 | 118 | _find_version_path(OPTIX_VERSION OPTIX_ROOT_DIR "OptiX" "${SEARCH_PATHS}") 119 | 120 | message(STATUS "OptiX version: ${OPTIX_VERSION}") 121 | endif () 122 | 123 | if (OPTIX_ROOT_DIR) 124 | #-------- Locate HEADERS 125 | _find_files(OPTIX_HEADERS OPTIX_ROOT_DIR "optix.h" "optix.h" "include/") 126 | 127 | include(FindPackageHandleStandardArgs) 128 | 129 | SET(OPTIX_INCLUDE_DIR "${OPTIX_ROOT_DIR}/include" CACHE PATH "path") 130 | add_definitions("-DOPTIX_PATH=R\"(${OPTIX_ROOT_DIR})\"") 131 | # add_definitions("-DOPTIX_VERSION=\"${OPTIX_VERSION}\"") 132 | 133 | else (OPTIX_ROOT_DIR) 134 | 135 | message(WARNING " 136 | OPTIX not found. 137 | The OPTIX folder you would specify with OPTIX_LOCATION should contain: 138 | - lib[64] folder: containing the Optix[64_]*.dll or *.so 139 | - include folder: containing the include files" 140 | ) 141 | endif (OPTIX_ROOT_DIR) 142 | 143 | find_package_handle_standard_args(Optix DEFAULT_MSG OPTIX_ROOT_DIR) 144 | mark_as_advanced(OPTIX_FOUND) -------------------------------------------------------------------------------- /VkRaven/cmake/setup.cmake: -------------------------------------------------------------------------------- 1 | macro(_add_package_Optix) 2 | find_package(Optix) 3 | if (OPTIX_FOUND) 4 | Message(STATUS "OptiX: Enabled") 5 | add_definitions(-DOPTIX_SUPPORT) 6 | include_directories(${OPTIX_INCLUDE_DIR}) 7 | LIST(APPEND PACKAGE_SOURCE_FILES ${OPTIX_HEADERS}) 8 | source_group(OPTIX FILES ${OPTIX_HEADERS}) 9 | set(USING_OPTIX "YES") 10 | else () 11 | Message(STATUS "OptiX: Disabled") 12 | endif () 13 | endmacro() -------------------------------------------------------------------------------- /VkRaven/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ### GLFW ### 2 | set(GLFW_BUILD_DOCS OFF CACHE BOOL "GLFW lib only") 3 | set(GLFW_INSTALL OFF CACHE BOOL "GLFW lib only") 4 | add_subdirectory(glfw) 5 | 6 | ### glm ### 7 | add_subdirectory(glm) 8 | 9 | ### imgui ### 10 | if (WIN32) 11 | add_library(imgui STATIC ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imconfig.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_demo.cpp 12 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_draw.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends/imgui_impl_glfw.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends/imgui_impl_glfw.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends/imgui_impl_vulkan.cpp 13 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends/imgui_impl_vulkan.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_internal.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_tables.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_widgets.cpp 14 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imstb_rectpack.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imstb_textedit.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imstb_truetype.h 15 | main.cpp) 16 | else () 17 | add_library(imgui SHARED ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imconfig.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_demo.cpp 18 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_draw.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends/imgui_impl_glfw.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends/imgui_impl_glfw.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends/imgui_impl_vulkan.cpp 19 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui/backends/imgui_impl_vulkan.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_internal.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_tables.cpp ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imgui_widgets.cpp 20 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imstb_rectpack.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imstb_textedit.h ${CMAKE_CURRENT_SOURCE_DIR}/imgui/imstb_truetype.h 21 | main.cpp) 22 | endif () 23 | set_target_properties(imgui PROPERTIES LINKER_LANGUAGE CXX) 24 | target_include_directories(imgui 25 | PUBLIC 26 | $ 27 | ${CMAKE_CURRENT_SOURCE_DIR}/imgui 28 | ) 29 | target_link_libraries(imgui Vulkan::Vulkan glfw) 30 | install(TARGETS imgui LIBRARY DESTINATION lib) 31 | 32 | ### stb ### 33 | add_library(stb SHARED ${CMAKE_CURRENT_SOURCE_DIR}/stb/stb_image.h ${CMAKE_CURRENT_SOURCE_DIR}/stb/stb_image_write.h main.cpp) 34 | set_target_properties(stb PROPERTIES LINKER_LANGUAGE CXX) 35 | install(TARGETS stb LIBRARY DESTINATION lib) 36 | 37 | ### tinyobjloader ### 38 | add_library(tinyobjloader SHARED ${CMAKE_CURRENT_SOURCE_DIR}/tinyobjloader/tiny_obj_loader.h main.cpp) 39 | set_target_properties(tinyobjloader PROPERTIES LINKER_LANGUAGE CXX) 40 | install(TARGETS tinyobjloader LIBRARY DESTINATION lib) 41 | 42 | ### tinygltf ### 43 | add_library(tinygltf SHARED ${CMAKE_CURRENT_SOURCE_DIR}/tinygltf/tiny_gltf.h ${CMAKE_CURRENT_SOURCE_DIR}/tinygltf/tiny_gltf.cc) 44 | set_target_properties(tinygltf PROPERTIES LINKER_LANGUAGE CXX) 45 | install(TARGETS tinygltf LIBRARY DESTINATION lib) 46 | 47 | ### SPIRV-Reflect ### 48 | add_library(spirv-reflect SHARED ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Reflect/spirv_reflect.h ${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Reflect/spirv_reflect.cpp) 49 | set_target_properties(spirv-reflect PROPERTIES LINKER_LANGUAGE CXX) 50 | install(TARGETS spirv-reflect LIBRARY DESTINATION lib) 51 | 52 | ### pugixml ### 53 | add_library(pugixml SHARED ${CMAKE_CURRENT_SOURCE_DIR}/pugixml/src/pugiconfig.hpp ${CMAKE_CURRENT_SOURCE_DIR}/pugixml/src/pugixml.hpp ${CMAKE_CURRENT_SOURCE_DIR}/pugixml/src/pugixml.cpp) 54 | set_target_properties(pugixml PROPERTIES LINKER_LANGUAGE CXX) 55 | install(TARGETS pugixml LIBRARY DESTINATION lib) 56 | 57 | ### argparse ### 58 | add_library(argparse SHARED ${CMAKE_CURRENT_SOURCE_DIR}/argparse/include/argparse/argparse.hpp main.cpp) 59 | set_target_properties(argparse PROPERTIES LINKER_LANGUAGE CXX) 60 | install(TARGETS argparse LIBRARY DESTINATION lib) -------------------------------------------------------------------------------- /VkRaven/lib/main.cpp: -------------------------------------------------------------------------------- 1 | int main() { 2 | return 0; 3 | } -------------------------------------------------------------------------------- /VkRaven/raven/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.18) 2 | project(ravencore VERSION 0.1.0 DESCRIPTION "VkRaven Core - Vulkan Render and Visualization Engine Core" LANGUAGES CXX) 3 | 4 | set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) 5 | 6 | find_package(Vulkan REQUIRED) 7 | 8 | set(RAVENCORE_HEADERS 9 | include/raven/RavenInclude.h 10 | include/raven/core/Renderer.h 11 | include/raven/core/Application.h include/raven/core/HeadlessApplication.h include/raven/core/TimingHeadlessApplication.h include/raven/core/VideoHeadlessApplication.h 12 | include/raven/core/GPUContext.h include/raven/core/Queues.h include/raven/core/Shader.h 13 | include/raven/core/RavenVkDynamicLoader.h 14 | include/raven/util/AABB.h include/raven/util/Paths.h include/raven/core/Buffer.h include/raven/core/Image.h include/raven/core/Texture.h include/raven/passes/ImGuiPass.h include/raven/core/Uniform.h 15 | include/raven/core/SwapChain.h include/raven/util/Camera.h include/raven/core/VkDebugUtils.h include/raven/core/AccelerationStructure.h 16 | include/raven/scene/RavenScene.h include/raven/scene/RavenSceneNode.h include/raven/scene/RavenSceneObject.h include/raven/scene/RavenMaterial.h include/raven/scene/RavenLight.h include/raven/scene/RavenTexture.h include/raven/scene/ISceneLoader.h include/raven/scene/loader/GLTFLoader.h 17 | include/raven/rendergraph/RenderGraph.h 18 | include/raven/rendergraph/RenderGraphPass.h 19 | include/raven/rendergraph/RenderGraphResource.h 20 | include/raven/util/sampling/AliasTable.h 21 | include/raven/passes/PassShader.h include/raven/passes/PassShaderCompute.h include/raven/passes/PassShaderRayTracing.h 22 | include/raven/passes/Pass.h include/raven/passes/PassCompute.h 23 | include/raven/util/Trajectory.h 24 | include/raven/util/ImagePFM.h 25 | include/raven/util/animation/BSpline.h 26 | include/raven/RavenInclude.h 27 | ) 28 | 29 | set(RAVENCORE_SOURCES 30 | src/raven/core/Application.cpp src/raven/core/HeadlessApplication.cpp src/raven/core/TimingHeadlessApplication.cpp src/raven/core/VideoHeadlessApplication.cpp 31 | src/raven/core/GPUContext.cpp src/raven/core/Queues.cpp src/raven/core/RavenVkDynamicLoader.cpp 32 | ) 33 | 34 | add_library(ravencore SHARED ${RAVENCORE_HEADERS} ${RAVENCORE_SOURCES}) 35 | add_library(ravencore::ravencore ALIAS ravencore) 36 | 37 | set_target_properties(ravencore PROPERTIES LINKER_LANGUAGE CXX) 38 | 39 | target_compile_definitions(ravencore PRIVATE -DVULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1) 40 | target_compile_definitions(ravencore PRIVATE -DVULKAN_HPP_STORAGE_SHARED_EXPORT=1) 41 | target_compile_definitions(ravencore PRIVATE -DVULKAN_HPP_STORAGE_SHARED=1) 42 | 43 | target_include_directories(ravencore 44 | PUBLIC 45 | $ 46 | $ 47 | $ 48 | $ 49 | $ 50 | PRIVATE 51 | ${CMAKE_CURRENT_SOURCE_DIR}/src 52 | ) 53 | 54 | target_link_libraries(ravencore Vulkan::Vulkan glfw imgui stb) 55 | 56 | install(TARGETS ravencore LIBRARY DESTINATION raven) -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/RavenInclude.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef WIN32 4 | #include 5 | #define VK_USE_PLATFORM_WIN32_KHR 6 | #include 7 | #include 8 | #include 9 | #else 10 | #include 11 | #endif -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/core/GPUContext.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "raven/RavenInclude.h" 12 | 13 | //#include "raven/core/VkExtensions.h" 14 | 15 | #include "Queues.h" 16 | #include "VkDebugUtils.h" 17 | #include "raven/util/Camera.h" 18 | 19 | namespace raven { 20 | class GPUContext { 21 | public: 22 | explicit GPUContext(uint32_t requiredQueueFamilies); 23 | 24 | virtual void init(); 25 | 26 | virtual void shutdown(); 27 | 28 | vk::PhysicalDevice m_physicalDevice = VK_NULL_HANDLE; // will be destroyed implicitly when instance is destroyed 29 | 30 | vk::Device m_device{}; 31 | std::shared_ptr m_queues; 32 | 33 | uint32_t m_activeIndex = 0; 34 | 35 | [[nodiscard]] uint32_t getMultiBufferedCount() const { 36 | return MAX_FRAMES_IN_FLIGHT; 37 | } 38 | 39 | [[nodiscard]] uint32_t getActiveIndex() const { 40 | return m_activeIndex; 41 | } 42 | 43 | vk::CommandPool m_graphicsCommandPool{}; 44 | vk::CommandPool m_computeCommandPool{}; 45 | vk::CommandPool m_transferCommandPool{}; 46 | 47 | void executeCommands(const std::function &recordCommands, Queues::Queue queue = Queues::Queue::TRANSFER, uint32_t awaitBeforeExecutionCount = 0, vk::Semaphore *awaitBeforeExecution = nullptr, vk::PipelineStageFlags *awaitBeforeExecutionStages = nullptr) { 48 | vk::CommandBuffer commandBuffer; 49 | switch (queue) { 50 | case Queues::GRAPHICS: 51 | commandBuffer = m_graphicsCommandBuffers[m_activeIndex]; 52 | break; 53 | case Queues::COMPUTE: 54 | commandBuffer = m_computeCommandBuffers[m_activeIndex]; 55 | break; 56 | case Queues::TRANSFER: 57 | commandBuffer = m_transferCommandBuffers[m_activeIndex]; 58 | break; 59 | default: 60 | throw std::runtime_error("Execute command does not support other queues!"); 61 | } 62 | 63 | vk::CommandBufferBeginInfo beginInfo{}; 64 | beginInfo.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit; 65 | 66 | if (commandBuffer.begin(&beginInfo) != vk::Result::eSuccess) { 67 | throw std::runtime_error("Failed to begin command buffer!"); 68 | } 69 | 70 | recordCommands(commandBuffer); 71 | 72 | vkEndCommandBuffer(commandBuffer); 73 | 74 | vk::SubmitInfo submitInfo{}; 75 | submitInfo.commandBufferCount = 1; 76 | submitInfo.pCommandBuffers = &commandBuffer; 77 | 78 | submitInfo.waitSemaphoreCount = awaitBeforeExecutionCount; 79 | submitInfo.pWaitSemaphores = awaitBeforeExecution; 80 | submitInfo.pWaitDstStageMask = awaitBeforeExecutionStages; 81 | 82 | if (m_queues->getQueue(queue).submit(1, &submitInfo, VK_NULL_HANDLE) != vk::Result::eSuccess) { 83 | throw std::runtime_error("Failed to submit command buffer to queue!"); 84 | } 85 | m_queues->getQueue(queue).waitIdle(); 86 | } 87 | 88 | [[nodiscard]] VkDebugUtils *getDebug() const { 89 | return m_debug.get(); 90 | } 91 | 92 | virtual Camera *getCamera() { 93 | return nullptr; 94 | } 95 | 96 | PFN_vkVoidFunction getDeviceFunction(const char *name) const { 97 | return m_device.getProcAddr(name); 98 | } 99 | 100 | [[nodiscard]] float getDeviceLimitsTimestampPeriod() const { 101 | return m_deviceLimitsTimestampPeriod; 102 | } 103 | 104 | virtual void resizeWindow(int width, int height) {} 105 | 106 | float incrementAndReturnDeltaTime() { 107 | const auto currentTime = std::chrono::high_resolution_clock::now(); 108 | const float time = std::chrono::duration(currentTime - m_time).count(); 109 | m_time = currentTime; 110 | return time; 111 | } 112 | 113 | protected: 114 | vk::Instance m_instance{}; 115 | vk::DebugUtilsMessengerEXT m_debugMessenger{}; 116 | 117 | std::vector m_graphicsCommandBuffers; 118 | std::vector m_computeCommandBuffers; 119 | std::vector m_transferCommandBuffers; 120 | 121 | virtual void getDeviceExtensions(std::vector &extensions) const; 122 | virtual void getInstanceExtensions(std::vector &extensions) const; 123 | 124 | void incrementActiveIndex() { 125 | m_activeIndex = (m_activeIndex + 1) % MAX_FRAMES_IN_FLIGHT; 126 | } 127 | 128 | std::chrono::time_point m_time = std::chrono::high_resolution_clock::now(); 129 | 130 | private: 131 | #ifdef NDEBUG 132 | const bool enableValidationLayers = true; 133 | #else 134 | const bool enableValidationLayers = true; 135 | #endif 136 | const std::vector validationLayers = { 137 | "VK_LAYER_KHRONOS_validation"}; 138 | 139 | void initVulkan(); 140 | void releaseVulkan(); 141 | 142 | void createInstance(); 143 | bool checkValidationLayerSupport(); 144 | static void populateDebugMessengerCreateInfo(vk::DebugUtilsMessengerCreateInfoEXT &createInfo); 145 | static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, void *pUserData); 146 | void setupDebugMessenger(); 147 | static vk::Result createDebugUtilsMessengerEXT(vk::Instance instance, const vk::DebugUtilsMessengerCreateInfoEXT *pCreateInfo, const vk::AllocationCallbacks *pAllocator, vk::DebugUtilsMessengerEXT *pDebugMessenger); 148 | static void destroyDebugUtilsMessengerEXT(vk::Instance instance, vk::DebugUtilsMessengerEXT debugMessenger, const vk::AllocationCallbacks *pAllocator); 149 | void pickPhysicalDevice(); 150 | void queryPhysicalDeviceProperties(); 151 | 152 | void createLogicalDevice(); 153 | 154 | void createCommandPool(); 155 | void createCommandBuffers(); 156 | 157 | std::shared_ptr m_debug; 158 | 159 | const uint32_t MAX_FRAMES_IN_FLIGHT = 1; // TODO 160 | 161 | float m_deviceLimitsTimestampPeriod = 0.f; 162 | }; 163 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/core/HeadlessApplication.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Buffer.h" 6 | #include "GPUContext.h" 7 | #include "Renderer.h" 8 | #include "Texture.h" 9 | #include "raven/util/Camera.h" 10 | 11 | namespace raven { 12 | class HeadlessApplication : public GPUContext { 13 | public: 14 | struct ApplicationSettings { 15 | vk::SampleCountFlagBits m_msaaSamples = vk::SampleCountFlagBits::e1; 16 | 17 | /* 18 | * RayTracing 19 | * VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME, VK_KHR_DEFERRED_HOST_OPERATIONS_EXTENSION_NAME, VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME 20 | */ 21 | std::vector m_deviceExtensions = {}; 22 | 23 | int32_t m_width = 1920; 24 | int32_t m_height = 1080; 25 | 26 | uint32_t m_rendererExecutions = 1; 27 | 28 | std::string m_directory; 29 | std::string m_name; 30 | 31 | std::function m_executeAfterInit = [](GPUContext *) {}; 32 | 33 | bool m_png; 34 | }; 35 | 36 | HeadlessApplication(std::string &appName, ApplicationSettings appSettings, std::shared_ptr renderer, uint32_t requiredQueueFamilies); 37 | 38 | virtual void run(); 39 | 40 | Camera *getCamera() override { 41 | return m_camera.get(); 42 | } 43 | 44 | protected: 45 | virtual void getDeviceExtensions(std::vector &extensions) const override; 46 | 47 | std::string m_appName; 48 | ApplicationSettings m_applicationSettings; 49 | 50 | std::shared_ptr m_camera; 51 | 52 | std::shared_ptr m_renderer; 53 | 54 | Image *m_image = nullptr; 55 | 56 | void init() override; 57 | 58 | virtual void loop(); 59 | virtual void finish(); 60 | virtual void render(); 61 | 62 | void shutdown() override; 63 | 64 | void assertMSAASamplesSupported(vk::SampleCountFlagBits msaaSamples); 65 | 66 | uint32_t m_queueFamilyIndex{}; 67 | 68 | uint32_t findQueueFamilyIndex() { 69 | Queues::QueueFamilyIndices queueFamilyIndices = m_queues->findQueueFamilies(m_physicalDevice); 70 | return queueFamilyIndices.graphicsFamily.value(); 71 | } 72 | 73 | [[nodiscard]] std::string prefix() const { 74 | return "[" + m_applicationSettings.m_name + "] "; 75 | } 76 | }; 77 | } // namespace raven 78 | -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/core/Queues.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "raven/RavenInclude.h" 10 | 11 | namespace raven { 12 | class Queues { 13 | public: 14 | enum QueueFamilies { 15 | GRAPHICS_FAMILY = 0x00000001, 16 | COMPUTE_FAMILY = 0x00000002, 17 | TRANSFER_FAMILY = 0x00000004, 18 | }; 19 | 20 | enum Queue { 21 | GRAPHICS = 0, 22 | COMPUTE = 1, 23 | TRANSFER = 2, 24 | }; 25 | 26 | explicit Queues(uint32_t requiredQueueFamilies) : m_requiredQueueFamilies(requiredQueueFamilies){}; 27 | 28 | struct QueueFamilyIndices { 29 | std::optional graphicsFamily; 30 | std::optional computeFamily; 31 | std::optional transferFamily; 32 | 33 | [[nodiscard]] bool isComplete(uint32_t requiredQueueFamilies) const { 34 | uint32_t graphics = GRAPHICS_FAMILY & requiredQueueFamilies; 35 | uint32_t compute = COMPUTE_FAMILY & requiredQueueFamilies; 36 | uint32_t transfer = TRANSFER_FAMILY & requiredQueueFamilies; 37 | return (!graphics || graphicsFamily.has_value()) && (!compute || computeFamily.has_value()) && (!transfer || transferFamily.has_value()); 38 | } 39 | 40 | void generateQueueCreateInfos(std::vector *queueCreateInfos, float *queuePriorities) { 41 | std::set uniqueQueueFamilies; 42 | if (graphicsFamily.has_value()) { 43 | uniqueQueueFamilies.emplace(graphicsFamily.value()); 44 | } 45 | if (computeFamily.has_value()) { 46 | uniqueQueueFamilies.emplace(computeFamily.value()); 47 | } 48 | if (transferFamily.has_value()) { 49 | uniqueQueueFamilies.emplace(transferFamily.value()); 50 | } 51 | 52 | for (uint32_t queueFamily: uniqueQueueFamilies) { // queue create infos for all required queues 53 | vk::DeviceQueueCreateInfo queueCreateInfo{}; 54 | queueCreateInfo.queueFamilyIndex = queueFamily; 55 | queueCreateInfo.queueCount = 1; 56 | queueCreateInfo.pQueuePriorities = queuePriorities; 57 | queueCreateInfos->push_back(queueCreateInfo); 58 | } 59 | } 60 | 61 | static bool requireGraphicsFamily(uint32_t requiredQueueFamilies) { 62 | return GRAPHICS_FAMILY & requiredQueueFamilies; 63 | } 64 | static bool requireComputeFamily(uint32_t requiredQueueFamilies) { 65 | return COMPUTE_FAMILY & requiredQueueFamilies; 66 | } 67 | static bool requireTransferFamily(uint32_t requiredQueueFamilies) { 68 | return TRANSFER_FAMILY & requiredQueueFamilies; 69 | } 70 | }; 71 | 72 | [[nodiscard]] QueueFamilyIndices findQueueFamilies(vk::PhysicalDevice physicalDevice) const; 73 | 74 | void generateQueueCreateInfos(vk::PhysicalDevice physicalDevice, std::vector *queueCreateInfos, float *queuePriorities) const; 75 | 76 | void createQueues(vk::Device device, vk::PhysicalDevice physicalDevice); 77 | 78 | vk::Queue getQueue(Queue queue); 79 | 80 | private: 81 | uint32_t m_requiredQueueFamilies; 82 | std::array m_queues{}; // destroyed implicitly with the device 83 | 84 | [[nodiscard]] bool isFamilyRequired(QueueFamilies queueFamily) const; 85 | 86 | static uint32_t getQueueFamilyIndex(std::vector &queueFamilyProperties, vk::QueueFlags queueFlags) { 87 | // dedicated compute queue 88 | // if (queueFlags & vk::QueueFlagBits::eCompute) { 89 | // for (uint32_t i = 0; i < queueFamilyProperties.size(); i++) { 90 | // if ((queueFamilyProperties[i].queueFlags & queueFlags) && !(queueFamilyProperties[i].queueFlags & vk::QueueFlagBits::eGraphics)) { 91 | // return i; 92 | // } 93 | // } 94 | // } 95 | // 96 | // // dedicated transfer queue 97 | // if (queueFlags & vk::QueueFlagBits::eTransfer) { 98 | // for (uint32_t i = 0; i < queueFamilyProperties.size(); i++) { 99 | // if ((queueFamilyProperties[i].queueFlags & queueFlags) && !(queueFamilyProperties[i].queueFlags & vk::QueueFlagBits::eGraphics) && !(queueFamilyProperties[i].queueFlags & vk::QueueFlagBits::eCompute)) { 100 | // return i; 101 | // } 102 | // } 103 | // } 104 | 105 | // graphics queue or fallback 106 | for (uint32_t i = 0; i < queueFamilyProperties.size(); i++) { 107 | if (queueFamilyProperties[i].queueFlags & queueFlags) { 108 | return i; 109 | } 110 | } 111 | 112 | throw std::runtime_error("Cannot find matching queue family index!"); 113 | } 114 | }; 115 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/core/RavenVkDynamicLoader.h: -------------------------------------------------------------------------------- 1 | #pragma once -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/core/Renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "GPUContext.h" 4 | #include "raven/util/Camera.h" 5 | #include "raven/core/Image.h" 6 | 7 | namespace raven { 8 | class Renderer { 9 | public: 10 | struct RendererResult { 11 | Image *m_image = nullptr; 12 | 13 | vk::Semaphore m_waitTimelineSemaphore{}; 14 | uint64_t m_waitTimelineSemaphoreValue = 0U; 15 | }; 16 | 17 | virtual ~Renderer() = default; 18 | 19 | virtual void initResources(GPUContext *gpuContext) = 0; // called only once on startup 20 | virtual void initShaderResources(GPUContext *gpuContext) = 0; // called whenever the shaders are reloaded 21 | virtual void initSwapchainResources(GPUContext *gpuContext, vk::Extent2D extent) = 0; // called whenever the swapchain size changes 22 | 23 | virtual void recordImGui(GPUContext *gpuContext, Camera *camera) = 0; 24 | 25 | virtual void update(GPUContext *gpuContext, Camera *camera, float deltaTime) = 0; 26 | virtual void render(GPUContext *gpuContext, Camera *camera, uint32_t activeIndex, RendererResult *rendererResult) = 0; 27 | 28 | virtual void releaseResources() = 0; 29 | virtual void releaseShaderResources() = 0; 30 | virtual void releaseSwapchainResources() = 0; 31 | }; 32 | } // namespace raven 33 | -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/core/TimingHeadlessApplication.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Buffer.h" 6 | #include "GPUContext.h" 7 | #include "HeadlessApplication.h" 8 | #include "Renderer.h" 9 | #include "Texture.h" 10 | #include "raven/util/Camera.h" 11 | 12 | namespace raven { 13 | class TimingHeadlessApplication : public HeadlessApplication { 14 | public: 15 | struct TimingApplicationSettings { 16 | uint32_t m_timingExecutions = 1; 17 | 18 | uint32_t m_startupExecutions = 64; 19 | 20 | std::function m_executeAfterStartupExecutions = [](GPUContext *) {}; 21 | std::function m_executeQueryTiming = [](std::ofstream &) {}; 22 | std::function m_executeEachFrame = [](uint32_t) {}; 23 | }; 24 | 25 | TimingHeadlessApplication(std::string &appName, ApplicationSettings appSettings, TimingApplicationSettings timingAppSettings, std::shared_ptr renderer, uint32_t requiredQueueFamilies); 26 | 27 | void run() override; 28 | 29 | protected: 30 | TimingApplicationSettings m_timingApplicationSettings; 31 | 32 | void loop() override; 33 | void finish() override; 34 | void render() override; 35 | 36 | private: 37 | uint32_t m_timingExecution = 0; 38 | }; 39 | } // namespace raven 40 | -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/core/Uniform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Buffer.h" 4 | #include "GPUContext.h" 5 | #include "SPIRV-Reflect/spirv_reflect.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace raven { 12 | class Uniform { 13 | public: 14 | explicit Uniform(GPUContext *gpuContext) : m_gpuContext(gpuContext) { 15 | } 16 | 17 | static std::shared_ptr reflect(GPUContext *gpuContext, const SpvReflectDescriptorBinding &binding) { 18 | assert(static_cast(binding.descriptor_type) == vk::DescriptorType::eUniformBuffer); 19 | 20 | auto uniform = std::make_shared(gpuContext); 21 | 22 | uniform->m_name = binding.type_description->type_name; 23 | uniform->m_set = binding.set; 24 | uniform->m_binding = binding.binding; 25 | 26 | uniform->m_variables.resize(binding.type_description->member_count); 27 | 28 | for (uint32_t i = 0; i < binding.type_description->member_count; i++) { 29 | // const auto &member = binding.type_description->members[i]; 30 | const auto &memberBlock = binding.block.members[i]; 31 | 32 | auto &variable = uniform->m_variables[i]; 33 | 34 | variable.name = memberBlock.name; 35 | // variable.type = member.type_flags; 36 | variable.bytes = memberBlock.size; 37 | variable.bytesPadded = memberBlock.padded_size; 38 | 39 | variable.data.resize(variable.bytes); 40 | 41 | // uint32_t bytes; 42 | // switch (member.type_flags) { 43 | // case SPV_REFLECT_TYPE_FLAG_INT: 44 | // case SPV_REFLECT_TYPE_FLAG_FLOAT: 45 | // bytes = member.traits.numeric.scalar.width / 8; 46 | // break; 47 | // case SPV_REFLECT_TYPE_FLAG_VECTOR | SPV_REFLECT_TYPE_FLAG_INT: 48 | // case SPV_REFLECT_TYPE_FLAG_VECTOR | SPV_REFLECT_TYPE_FLAG_FLOAT: 49 | // bytes = member.traits.numeric.vector.component_count * member.traits.numeric.scalar.width / 8; 50 | // break; 51 | // case SPV_REFLECT_TYPE_FLAG_MATRIX | SPV_REFLECT_TYPE_FLAG_VECTOR | SPV_REFLECT_TYPE_FLAG_INT: 52 | // case SPV_REFLECT_TYPE_FLAG_MATRIX | SPV_REFLECT_TYPE_FLAG_VECTOR | SPV_REFLECT_TYPE_FLAG_FLOAT: 53 | // bytes = member.traits.numeric.matrix.column_count * member.traits.numeric.matrix.row_count * member.traits.numeric.scalar.width / 8; 54 | // break; 55 | // default: 56 | // throw std::runtime_error("Unsupported uniform type!"); 57 | // } 58 | // variable.bytes = bytes; 59 | 60 | // std::cout << variable.name << std::endl; 61 | // std::cout << bytes << " " << memberBlock.size << " " << memberBlock.padded_size << std::endl; 62 | // assert(bytes == memberBlock.size); 63 | } 64 | 65 | return uniform; 66 | } 67 | 68 | void create() { 69 | m_buffers.resize(m_gpuContext->getMultiBufferedCount()); 70 | for (size_t i = 0; i < m_gpuContext->getMultiBufferedCount(); i++) { 71 | std::stringstream ss; 72 | ss << "[Uniform]_" << m_name << "[" << i << "]"; 73 | auto settings = Buffer::BufferSettings{.m_sizeBytes = getBytes(), .m_bufferUsages = vk::BufferUsageFlagBits::eUniformBuffer, .m_memoryProperties = vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent, .m_name=ss.str()}; 74 | m_buffers[i] = std::make_shared(m_gpuContext, settings); 75 | } 76 | } 77 | 78 | void release() { 79 | for (size_t i = 0; i < m_gpuContext->getMultiBufferedCount(); i++) { 80 | m_buffers[i]->release(); 81 | } 82 | } 83 | 84 | [[nodiscard]] uint32_t getSet() const { 85 | return m_set; 86 | } 87 | 88 | [[nodiscard]] uint32_t getBinding() const { 89 | return m_binding; 90 | } 91 | 92 | [[nodiscard]] uint32_t getBytes() const { 93 | uint32_t bytes = 0; 94 | for (const auto &variable: m_variables) { 95 | bytes += variable.bytesPadded; 96 | } 97 | return bytes; 98 | } 99 | 100 | void generateBufferInfo(vk::DescriptorBufferInfo *bufferInfo, uint32_t index) { 101 | bufferInfo->buffer = m_buffers[index]->getBuffer(); 102 | bufferInfo->offset = 0; 103 | bufferInfo->range = m_buffers[index]->getSizeBytes(); 104 | } 105 | 106 | void upload(uint32_t index) { 107 | uint32_t bytes = getBytes(); 108 | std::vector data(bytes, 0); 109 | 110 | uint32_t pointer = 0; 111 | for (uint32_t i = 0; i < m_variables.size(); i++) { 112 | const auto &variable = m_variables[i]; 113 | data.insert(data.begin() + pointer, variable.data.begin(), variable.data.end()); 114 | pointer += variable.bytesPadded; 115 | } 116 | 117 | m_buffers[index]->updateHostMemory(bytes, data.data()); 118 | } 119 | 120 | template 121 | void setVariable(const std::string &name, T value) { 122 | UniformVariable *variable = getVariable(name); 123 | uint32_t bytes = sizeof(T); 124 | assert(bytes == variable->bytes); 125 | char *bytePointer = (char *)(&value); 126 | for (uint32_t i = 0; i < bytes; i++) { 127 | variable->data[i] = bytePointer[i]; 128 | } 129 | } 130 | 131 | 132 | private: 133 | struct UniformVariable { 134 | std::string name; 135 | // SpvReflectTypeFlags type; 136 | uint32_t bytes{}; 137 | uint32_t bytesPadded{}; 138 | 139 | std::vector data; // TODO(Mirco): use one long data vector for all variables in the uniform 140 | }; 141 | 142 | uint32_t m_set{}; 143 | uint32_t m_binding{}; 144 | 145 | std::string m_name; 146 | 147 | std::vector m_variables; 148 | 149 | GPUContext *m_gpuContext; 150 | 151 | std::vector> m_buffers; 152 | 153 | UniformVariable *getVariable(const std::string &name) { 154 | for (uint32_t i = 0; i < m_variables.size(); i++) { 155 | if (strcmp(m_variables[i].name.c_str(), name.c_str()) == 0) { 156 | return &m_variables[i]; 157 | } 158 | } 159 | throw std::runtime_error("Unknown uniform variable " + name + "."); 160 | } 161 | }; 162 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/core/VideoHeadlessApplication.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Buffer.h" 6 | #include "GPUContext.h" 7 | #include "HeadlessApplication.h" 8 | #include "Renderer.h" 9 | #include "Texture.h" 10 | #include "raven/util/Camera.h" 11 | 12 | namespace raven { 13 | class VideoHeadlessApplication : public HeadlessApplication { 14 | public: 15 | struct VideoApplicationSettings { 16 | std::function m_executeAfterStartupExecutions = [](GPUContext *) {}; 17 | std::function m_executeEachFrame = [](uint32_t) {}; 18 | 19 | uint32_t m_framePerExecution = 1; 20 | }; 21 | 22 | VideoHeadlessApplication(std::string &appName, ApplicationSettings appSettings, VideoApplicationSettings videoAppSettings, std::shared_ptr renderer, uint32_t requiredQueueFamilies); 23 | 24 | void run() override; 25 | 26 | protected: 27 | VideoApplicationSettings m_videoApplicationSettings; 28 | 29 | void loop() override; 30 | void finish() override; 31 | void render() override; 32 | 33 | private: 34 | void storeImage(uint32_t execution); 35 | }; 36 | } // namespace raven 37 | -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/core/VkDebugUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "raven/RavenInclude.h" 6 | 7 | namespace raven { 8 | class VkDebugUtils { 9 | public: 10 | VkDebugUtils(vk::Device device, bool enabled) : m_device(device), m_enabled(enabled) { 11 | } 12 | 13 | static std::string getExtensionName() { 14 | return VK_EXT_DEBUG_UTILS_EXTENSION_NAME; 15 | } 16 | 17 | void setObjectName(vk::ObjectType objectType, uint64_t objectHandle, const char *name) { 18 | if (!m_enabled) { 19 | return; 20 | } 21 | vk::DebugUtilsObjectNameInfoEXT nameInfo; 22 | nameInfo.objectType = objectType; 23 | nameInfo.objectHandle = objectHandle; 24 | nameInfo.pObjectName = name; 25 | if (m_device.setDebugUtilsObjectNameEXT(&nameInfo) != vk::Result::eSuccess) { 26 | throw std::runtime_error("Failed to set debug object name!"); 27 | } 28 | } 29 | 30 | void setName(vk::ShaderModule object, const std::string &name) { 31 | setObjectName(vk::ObjectType::eShaderModule, (uint64_t) static_cast(object), ("[ShaderModule]_" + name).c_str()); 32 | } 33 | 34 | void setName(vk::DeviceMemory object, const std::string &name) { 35 | setObjectName(vk::ObjectType::eDeviceMemory, (uint64_t) static_cast(object), ("[DeviceMemory]_" + name).c_str()); 36 | } 37 | 38 | void setName(vk::Image object, const std::string &name) { 39 | setObjectName(vk::ObjectType::eImage, (uint64_t) static_cast(object), ("[Image]_" + name).c_str()); 40 | } 41 | void setName(vk::ImageView object, const std::string &name) { 42 | setObjectName(vk::ObjectType::eImageView, (uint64_t) static_cast(object), ("[ImageView]_" + name).c_str()); 43 | } 44 | void setName(vk::Sampler object, const std::string &name) { 45 | setObjectName(vk::ObjectType::eSampler, (uint64_t) static_cast(object), ("[Sampler]_" + name).c_str()); 46 | } 47 | void setName(vk::Buffer object, const std::string &name) { 48 | setObjectName(vk::ObjectType::eBuffer, (uint64_t) static_cast(object), ("[Buffer]_" + name).c_str()); 49 | } 50 | 51 | private: 52 | vk::Device m_device; 53 | 54 | bool m_enabled = false; 55 | }; 56 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/passes/Pass.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "PassShader.h" 3 | 4 | #include 5 | 6 | namespace raven { 7 | #define RAVEN_PASS_RELEASE(pass) \ 8 | if (pass) \ 9 | pass->release() 10 | 11 | class Pass { 12 | public: 13 | struct PassSettings { 14 | std::string m_name = "undefined"; 15 | 16 | bool m_semaphoreExportFlag = false; 17 | }; 18 | 19 | Pass(GPUContext *gpuContext, PassSettings settings) : m_gpuContext(gpuContext), m_passSettings(std::move(settings)) {} 20 | 21 | virtual ~Pass() = default; 22 | 23 | virtual void create() { 24 | findQueueFamily(); 25 | createCommandPool(); 26 | createCommandBuffers(); 27 | createSyncObjects(); 28 | } 29 | 30 | virtual void release() { 31 | releaseSyncObjects(); 32 | vkDestroyCommandPool(m_gpuContext->m_device, m_commandPool, nullptr); 33 | } 34 | 35 | void recreateSyncObjects() { 36 | releaseSyncObjects(); 37 | createSyncObjects(); 38 | } 39 | 40 | virtual void execute(const std::function &updateStorageBuffers, 41 | const std::function &updateUniforms, 42 | const std::function &recordCommandBuffer, 43 | const uint32_t waitTimelineSemaphoreCount, const vk::Semaphore *waitTimelineSemaphore, const uint64_t *waitTimelineSemaphoreValue, vk::PipelineStageFlags *waitDstStageMask) { 44 | { 45 | // wait for the previous frame to finish 46 | vk::SemaphoreWaitInfo waitInfo{}; 47 | waitInfo.semaphoreCount = 1; 48 | waitInfo.pSemaphores = &m_timelineSemaphore; 49 | waitInfo.pValues = &m_timelineSemaphoreValue; 50 | if (m_gpuContext->m_device.waitSemaphores(&waitInfo, UINT64_MAX) != vk::Result::eSuccess) { 51 | throw std::runtime_error("Failed to wait for timeline semaphore!"); 52 | } 53 | } 54 | 55 | updateStorageBuffers(); 56 | updateUniforms(); 57 | 58 | auto &commandBuffer = m_commandBuffer; 59 | commandBuffer.reset(); 60 | constexpr vk::CommandBufferBeginInfo beginInfo{}; 61 | if (commandBuffer.begin(&beginInfo) != vk::Result::eSuccess) { 62 | throw std::runtime_error("Failed to begin recording command buffer!"); 63 | } 64 | recordCommandBuffer(commandBuffer); 65 | commandBuffer.end(); 66 | 67 | m_timelineSemaphoreValue++; 68 | vk::TimelineSemaphoreSubmitInfo timelineSubmitInfo{}; 69 | timelineSubmitInfo.waitSemaphoreValueCount = waitTimelineSemaphoreCount; 70 | timelineSubmitInfo.pWaitSemaphoreValues = waitTimelineSemaphoreValue; 71 | timelineSubmitInfo.signalSemaphoreValueCount = 1; 72 | timelineSubmitInfo.pSignalSemaphoreValues = &m_timelineSemaphoreValue; 73 | 74 | vk::SubmitInfo submitInfo{}; 75 | submitInfo.pNext = &timelineSubmitInfo; 76 | submitInfo.waitSemaphoreCount = waitTimelineSemaphoreCount; 77 | submitInfo.pWaitSemaphores = waitTimelineSemaphore; 78 | submitInfo.pWaitDstStageMask = waitDstStageMask; 79 | submitInfo.signalSemaphoreCount = 1; 80 | submitInfo.pSignalSemaphores = &m_timelineSemaphore; 81 | submitInfo.commandBufferCount = 1; 82 | submitInfo.pCommandBuffers = &m_commandBuffer; 83 | 84 | if (m_gpuContext->m_queues->getQueue(m_queueType).submit(1, &submitInfo, VK_NULL_HANDLE) != vk::Result::eSuccess) { 85 | throw std::runtime_error("Failed to submit command buffer!"); 86 | } 87 | }; 88 | 89 | std::string getName() const { return m_passSettings.m_name; } 90 | 91 | [[nodiscard]] vk::Semaphore getTimelineSemaphore() const { return m_timelineSemaphore; } 92 | [[nodiscard]] uint64_t getTimelineSemaphoreValue() const { return m_timelineSemaphoreValue; } 93 | 94 | protected: 95 | GPUContext *m_gpuContext; 96 | 97 | PassSettings m_passSettings; 98 | 99 | uint32_t m_queueFamilyIndex{}; 100 | Queues::Queue m_queueType = Queues::GRAPHICS; 101 | 102 | vk::CommandPool m_commandPool{}; 103 | vk::CommandBuffer m_commandBuffer; // destroyed implicitly with the command pool 104 | 105 | vk::Semaphore m_timelineSemaphore{}; 106 | uint64_t m_timelineSemaphoreValue = 0U; 107 | 108 | virtual void findQueueFamily() = 0; 109 | 110 | private: 111 | void createCommandPool() { 112 | vk::CommandPoolCreateInfo poolInfo{}; 113 | poolInfo.flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer; 114 | poolInfo.queueFamilyIndex = m_queueFamilyIndex; 115 | 116 | if (m_gpuContext->m_device.createCommandPool(&poolInfo, nullptr, &m_commandPool) != vk::Result::eSuccess) { 117 | throw std::runtime_error("Failed to create command pool!"); 118 | } 119 | } 120 | 121 | void createCommandBuffers() { 122 | vk::CommandBufferAllocateInfo allocInfo{}; 123 | allocInfo.commandPool = m_commandPool; 124 | allocInfo.level = vk::CommandBufferLevel::ePrimary; 125 | allocInfo.commandBufferCount = 1; 126 | 127 | if (m_gpuContext->m_device.allocateCommandBuffers(&allocInfo, &m_commandBuffer) != vk::Result::eSuccess) { 128 | throw std::runtime_error("Failed to allocate command buffers!"); 129 | } 130 | } 131 | 132 | void createSyncObjects() { 133 | m_timelineSemaphoreValue = 0U; 134 | 135 | vk::SemaphoreTypeCreateInfo timelineCreateInfo{}; 136 | timelineCreateInfo.semaphoreType = vk::SemaphoreType::eTimeline; 137 | timelineCreateInfo.initialValue = 0; 138 | 139 | vk::ExportSemaphoreCreateInfo esci{}; 140 | if (m_passSettings.m_semaphoreExportFlag) { 141 | #ifdef WIN32 142 | auto handleType = vk::ExternalSemaphoreHandleTypeFlagBits::eOpaqueWin32; 143 | #else 144 | auto handleType = vk::ExternalSemaphoreHandleTypeFlagBits::eOpaqueFd; 145 | #endif 146 | esci.handleTypes = handleType; 147 | timelineCreateInfo.pNext = &esci; 148 | } 149 | 150 | vk::SemaphoreCreateInfo semaphoreInfo{}; 151 | semaphoreInfo.pNext = &timelineCreateInfo; 152 | 153 | if (m_gpuContext->m_device.createSemaphore(&semaphoreInfo, nullptr, &m_timelineSemaphore) != vk::Result::eSuccess) { 154 | throw std::runtime_error("Failed to create timeline semaphore!"); 155 | } 156 | } 157 | 158 | void releaseSyncObjects() const { 159 | m_gpuContext->m_device.destroySemaphore(m_timelineSemaphore, nullptr); 160 | } 161 | }; 162 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/passes/PassCompute.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Pass.h" 4 | 5 | namespace raven { 6 | class PassCompute final : public Pass { 7 | public: 8 | PassCompute(GPUContext *gpuContext, PassSettings settings) : Pass(gpuContext, std::move(settings)) {} 9 | 10 | protected: 11 | void findQueueFamily() override { 12 | Queues::QueueFamilyIndices queueFamilyIndices = m_gpuContext->m_queues->findQueueFamilies(m_gpuContext->m_physicalDevice); 13 | m_queueFamilyIndex = queueFamilyIndices.graphicsFamily.value(); 14 | m_queueType = Queues::GRAPHICS; 15 | } 16 | 17 | private: 18 | }; 19 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/passes/PassShaderCompute.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "PassShader.h" 4 | 5 | namespace raven { 6 | class PassShaderCompute : public PassShader { 7 | public: 8 | PassShaderCompute(GPUContext *gpuContext, std::string name) : PassShader(gpuContext, std::move(name)) {} 9 | 10 | void create() override { PassShader::create(); } 11 | 12 | void release() override { PassShader::release(); } 13 | 14 | void setWorkGroupCount(const uint32_t x, const uint32_t y, const uint32_t z) { 15 | m_workGroupCount = vk::Extent3D{x, y, z}; 16 | } 17 | 18 | virtual void setGlobalInvocationSize(const uint32_t width, const uint32_t height, const uint32_t depth) { 19 | const vk::Extent3D workGroupSize = m_shaders[0]->getWorkGroupSize(); 20 | m_workGroupCount = getDispatchSize(width, height, depth, workGroupSize); 21 | } 22 | 23 | static vk::Extent3D getDispatchSize(const uint32_t width, const uint32_t height, const uint32_t depth, const vk::Extent3D workGroupSize) { 24 | const uint32_t x = (width + workGroupSize.width - 1) / workGroupSize.width; 25 | const uint32_t y = (height + workGroupSize.height - 1) / workGroupSize.height; 26 | const uint32_t z = (depth + workGroupSize.depth - 1) / workGroupSize.depth; 27 | return vk::Extent3D{x, y, z}; 28 | } 29 | 30 | void execute(const std::function &recordPushConstants, 31 | const std::function &recordPipelineBarriers, 32 | vk::CommandBuffer &commandBuffer) override { 33 | assert(m_workGroupCount.width >= 1 && m_workGroupCount.height >= 1 && m_workGroupCount.depth >= 1 && "Global invocation size must be set before executing PassShaderCompute!"); 34 | 35 | queryTimeFromGPU(); 36 | 37 | commandBuffer.resetQueryPool(m_queryPoolTimestamps, 0, static_cast(m_timestamps.size())); 38 | 39 | recordPushConstants(commandBuffer, m_pipelineLayout); 40 | 41 | commandBuffer.bindPipeline(vk::PipelineBindPoint::eCompute, m_pipeline); 42 | 43 | std::vector descriptorSets; 44 | getDescriptorSets(descriptorSets); 45 | commandBuffer.bindDescriptorSets(vk::PipelineBindPoint::eCompute, m_pipelineLayout, 0, descriptorSets.size(), descriptorSets.data(), 0, nullptr); 46 | 47 | commandBuffer.writeTimestamp(vk::PipelineStageFlagBits::eComputeShader, m_queryPoolTimestamps, 0); 48 | vk::DebugUtilsLabelEXT label{}; 49 | label.pLabelName = m_name.c_str(); 50 | commandBuffer.beginDebugUtilsLabelEXT(&label); 51 | commandBuffer.dispatch(m_workGroupCount.width, m_workGroupCount.height, m_workGroupCount.depth); 52 | commandBuffer.endDebugUtilsLabelEXT(); 53 | commandBuffer.writeTimestamp(vk::PipelineStageFlagBits::eComputeShader, m_queryPoolTimestamps, 1); 54 | 55 | recordPipelineBarriers(commandBuffer); 56 | } 57 | 58 | protected: 59 | void createPipeline() override { 60 | assert(m_shaders.size() == 1 && "Only one shader is allowed for PassShaderCompute!"); 61 | 62 | const vk::PipelineShaderStageCreateInfo shaderStage = m_shaders[0]->generateShaderStageCreateInfo(); 63 | 64 | vk::ComputePipelineCreateInfo pipelineInfo{}; 65 | pipelineInfo.layout = m_pipelineLayout; 66 | pipelineInfo.stage = shaderStage; 67 | 68 | if (m_gpuContext->m_device.createComputePipelines(m_pipelineCache, 1, &pipelineInfo, nullptr, &m_pipeline) != vk::Result::eSuccess) { 69 | throw std::runtime_error("Failed to create compute pipeline!"); 70 | } 71 | } 72 | 73 | bool getPushConstantRange(vk::PushConstantRange &pushConstantRange) override { 74 | pushConstantRange.stageFlags = getPushConstantStage(); 75 | pushConstantRange.offset = 0; 76 | pushConstantRange.size = getPushConstantRangeSize(); 77 | return pushConstantRange.size > 0; 78 | } 79 | 80 | vk::ShaderStageFlagBits getPushConstantStage() override { 81 | return vk::ShaderStageFlagBits::eCompute; 82 | } 83 | 84 | private: 85 | vk::Extent3D m_workGroupCount = {0, 0, 0}; 86 | }; 87 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/rendergraph/RenderGraphPass.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "raven/rendergraph/RenderGraphResource.h" 13 | 14 | namespace raven { 15 | enum RenderGraphPassType { 16 | GRAPHICS, 17 | COMPUTE, 18 | TRANSFER 19 | }; 20 | 21 | class RenderGraphPass { 22 | public: 23 | void execute() const { 24 | m_executeFunction(); 25 | } 26 | 27 | friend std::ostream &operator<<(std::ostream &stream, const RenderGraphPass &object) { 28 | stream << "RenderGraphPass{ name=" << object.m_name << " type=" << object.m_type << " root=" << object.m_root << "\n dependencies={ \n"; 29 | for (const auto &dependency: object.m_dependencies) { 30 | stream << " " << dependency << "\n"; 31 | } 32 | stream << " }" 33 | << "\n }"; 34 | return stream; 35 | } 36 | 37 | private: 38 | friend class RenderGraphPassBuilder; 39 | friend class RenderGraph; 40 | 41 | RenderGraphPass(std::string name, const RenderGraphPassType type, const bool root) : m_name(std::move(name)), m_type(type), m_root(root) {} 42 | 43 | std::string m_name; 44 | RenderGraphPassType m_type; 45 | bool m_root = false; 46 | 47 | bool m_visited = false; 48 | std::vector m_dependencies{}; 49 | 50 | std::function m_executeFunction = []() { throw std::runtime_error("RenderGraphPass::m_executeFunction not set."); }; 51 | 52 | [[nodiscard]] bool hasReadDependencies(const std::unordered_map &resourceVersions) const { 53 | bool hasReadDependencies = false; 54 | for (const auto &dependency: m_dependencies) { 55 | if (dependency.m_type == RenderGraphResourceDependency::READ) { 56 | const auto resourceVersion = resourceVersions.at(dependency.m_name); 57 | if (resourceVersion > dependency.m_version) { 58 | throw std::runtime_error("This render pass should have been executed already."); 59 | } 60 | if (resourceVersion < dependency.m_version) { 61 | hasReadDependencies = true; 62 | break; 63 | } 64 | } 65 | } 66 | return hasReadDependencies; 67 | } 68 | 69 | [[nodiscard]] bool isFutureExecutionPossible(const std::unordered_map &resourceVersions) const { 70 | for (const auto &dependency: m_dependencies) { 71 | if (dependency.m_type == RenderGraphResourceDependency::READ) { 72 | const auto resourceVersion = resourceVersions.at(dependency.m_name); 73 | if (resourceVersion > dependency.m_version) { 74 | return false; 75 | } 76 | } 77 | } 78 | return true; 79 | } 80 | }; 81 | 82 | class RenderGraphPassBuilder { 83 | public: 84 | RenderGraphPassBuilder(const std::string &name, const RenderGraphPassType type, bool root = false) : m_renderGraphPass{new RenderGraphPass(name, type, root)} { 85 | } 86 | 87 | [[nodiscard]] RenderGraphPass build() const { 88 | return std::move(*m_renderGraphPass); 89 | } 90 | 91 | RenderGraphPassBuilder &readResource(RenderGraphResource &renderResource) { 92 | m_renderGraphPass->m_dependencies.emplace_back(renderResource.m_name, renderResource.m_version, RenderGraphResourceDependency::READ); 93 | renderResource.m_dependencies.emplace_back(m_renderGraphPass->m_name, renderResource.m_version, RenderGraphResourceDependency::READ); 94 | return *this; 95 | } 96 | 97 | RenderGraphPassBuilder &writeResource(RenderGraphResource &renderResource) { 98 | m_renderGraphPass->m_dependencies.emplace_back(renderResource.m_name, renderResource.m_version, RenderGraphResourceDependency::WRITE); 99 | renderResource.m_dependencies.emplace_back(m_renderGraphPass->m_name, renderResource.m_version, RenderGraphResourceDependency::WRITE); 100 | renderResource.m_version++; 101 | return *this; 102 | } 103 | 104 | RenderGraphPassBuilder &execute(std::function executeFunction) { 105 | m_renderGraphPass->m_executeFunction = std::move(executeFunction); 106 | return *this; 107 | } 108 | 109 | private: 110 | std::unique_ptr m_renderGraphPass; 111 | }; 112 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/rendergraph/RenderGraphResource.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace raven { 10 | struct RenderGraphResourceDependency { 11 | enum RenderGraphResourceDependencyType { 12 | READ, 13 | WRITE 14 | }; 15 | 16 | std::string m_name; // either name of related resource or render pass 17 | uint32_t m_version; 18 | RenderGraphResourceDependencyType m_type; 19 | 20 | friend std::ostream &operator<<(std::ostream &stream, const RenderGraphResourceDependency &object) { 21 | stream << "RenderGraphResourceDependency{ name=" << object.m_name << " version=" << object.m_version << " type=" << (object.m_type == READ ? "R" : "W") << " }"; 22 | return stream; 23 | } 24 | }; 25 | 26 | class RenderGraphResource { 27 | public: 28 | explicit RenderGraphResource(std::string name) : m_name(std::move(name)) {} 29 | 30 | private: 31 | std::string m_name; 32 | uint32_t m_version = 0; 33 | 34 | std::vector m_dependencies{}; 35 | 36 | friend std::ostream &operator<<(std::ostream &stream, const RenderGraphResource &object) { 37 | stream << "RenderGraphResource{ name=" << object.m_name << " nextVersion=" << object.m_version << "\n dependencies={ \n"; 38 | for (const auto &dependency: object.m_dependencies) { 39 | stream << " " << dependency << "\n"; 40 | } 41 | stream << " }" 42 | << "\n }"; 43 | return stream; 44 | } 45 | 46 | friend class RenderGraphPass; 47 | friend class RenderGraphPassBuilder; 48 | friend class RenderGraph; 49 | }; 50 | } // namespace raven 51 | -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/scene/ISceneLoader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "RavenLight.h" 3 | #include "RavenMaterial.h" 4 | #include "RavenSceneNode.h" 5 | #include "RavenTexture.h" 6 | 7 | 8 | #include 9 | 10 | namespace raven { 11 | class ISceneLoader { 12 | protected: 13 | ~ISceneLoader() = default; 14 | 15 | public: 16 | virtual std::shared_ptr loadScene(std::function&)> registerMaterial, 17 | std::function&)> registerTexture, 18 | std::function&)> registerLight) = 0; 19 | }; 20 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/scene/RavenLight.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace raven { 4 | class RavenLight { 5 | public: 6 | #define LIGHT_TYPE_AREA 0 7 | #define LIGHT_TYPE_POINT 1 8 | struct Light { 9 | uint32_t type = LIGHT_TYPE_AREA; 10 | 11 | uint32_t objectDescriptorId = 0; 12 | uint32_t triangleId = 0; 13 | 14 | glm::vec3 position = glm::vec3(0); 15 | glm::vec3 emission = glm::vec3(1); 16 | }; 17 | 18 | std::string m_key{}; 19 | std::string m_name = "RavenLight"; 20 | Light m_light{}; 21 | }; 22 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/scene/RavenMaterial.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace raven { 7 | class RavenMaterial { 8 | public: 9 | struct Material { 10 | glm::vec3 baseColorFactor = glm::vec4(1.f); 11 | int32_t baseColorTexture = -1; 12 | float metallicFactor = 1.f; 13 | float roughnessFactor = 1.f; 14 | int32_t metallicRoughnessTexture = -1; 15 | 16 | int32_t normalTexture = -1; 17 | 18 | glm::vec3 emission = glm::vec3(0.f); 19 | 20 | float subsurface = 0.f; // [0,1], 0 no sss, 1 only sss 21 | glm::vec3 meanFreePath = glm::vec3(0.f); // l 22 | 23 | [[nodiscard]] bool isEmissive() const { 24 | return glm::any(glm::greaterThan(emission, glm::vec3(0.f))); 25 | } 26 | 27 | void mfpFromVolumetricCoefficients(glm::vec3 scatteringCoefficient, glm::vec3 absorptionCoefficient) { 28 | glm::vec3 extinctionCoefficient = scatteringCoefficient + absorptionCoefficient; 29 | meanFreePath = 1.f / extinctionCoefficient; 30 | } 31 | 32 | [[nodiscard]] glm::vec3 scatteringScaling(glm::vec3 surfaceAlbedo) const { 33 | glm::vec3 a = surfaceAlbedo - glm::vec3(0.8f); 34 | return 1.9f - surfaceAlbedo + 3.5f * a * a; 35 | } 36 | 37 | [[nodiscard]] glm::vec3 scatteringDistance(glm::vec3 surfaceAlbedo) const { 38 | return subsurface * meanFreePath / scatteringScaling(surfaceAlbedo); 39 | } 40 | }; 41 | 42 | std::string m_key{}; 43 | std::string m_name = "RavenMaterial"; 44 | Material m_material{}; 45 | glm::vec3 m_emissiveFactor = glm::vec3(0.f); 46 | float m_emissiveStrength = 0.f; 47 | 48 | void setEmission(const glm::vec3 emissiveFactor, const float emissiveStrength) { 49 | m_emissiveFactor = emissiveFactor; 50 | m_emissiveStrength = emissiveStrength; 51 | updateEmission(); 52 | } 53 | void setEmission(const glm::vec3 emissiveFactor) { 54 | m_emissiveFactor = emissiveFactor; 55 | updateEmission(); 56 | } 57 | void setEmission(const float emissiveStrength) { 58 | m_emissiveStrength = emissiveStrength; 59 | updateEmission(); 60 | } 61 | void updateEmission() { 62 | m_material.emission = m_emissiveFactor * m_emissiveStrength; 63 | } 64 | 65 | std 66 | ::string m_baseColorTexture{}; 67 | std::string m_metallicRoughnessTexture{}; 68 | std::string m_normalTexture{}; 69 | 70 | void updateTextureIds(const std::function &textureIdFromName) { 71 | m_material.baseColorTexture = textureIdFromName(m_baseColorTexture); 72 | m_material.metallicRoughnessTexture = textureIdFromName(m_metallicRoughnessTexture); 73 | m_material.normalTexture = textureIdFromName(m_normalTexture); 74 | } 75 | }; 76 | } // namespace RavenMaterial -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/scene/RavenSceneNode.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "RavenSceneObject.h" 3 | 4 | 5 | #include 6 | #include 7 | 8 | namespace raven { 9 | class RavenSceneNode { 10 | public: 11 | std::string m_name = "RavenSceneNode"; 12 | 13 | std::optional m_transformation; 14 | 15 | std::vector> m_children; 16 | std::shared_ptr m_object = nullptr; 17 | 18 | 19 | }; 20 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/scene/RavenSceneObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "raven/core/AccelerationStructure.h" 3 | #include "raven/util/AABB.h" 4 | 5 | 6 | #include 7 | 8 | namespace raven { 9 | class RavenSceneObject { 10 | public: 11 | std::string m_name = "RavenSceneObject"; 12 | 13 | struct Vertex { 14 | float position_x; 15 | float position_y; 16 | float position_z; 17 | float normal_x; 18 | float normal_y; 19 | float normal_z; 20 | float tangent_x; 21 | float tangent_y; 22 | float tangent_z; 23 | float tangent_w; // bitangent sign 24 | float texCoord_u; 25 | float texCoord_v; 26 | }; 27 | 28 | AABB m_aabb; 29 | 30 | std::vector m_vertices; 31 | std::vector m_indices; 32 | 33 | std::string m_material{}; 34 | 35 | // GPU 36 | struct GPUSceneObject { 37 | std::shared_ptr m_vertexBuffer = nullptr; 38 | std::shared_ptr m_indexBuffer = nullptr; 39 | uint32_t m_materialId = 0; 40 | 41 | uint32_t m_numPrimitives = 0; 42 | 43 | std::shared_ptr m_blas = nullptr; 44 | 45 | glm::mat4 m_modelMatrix{}; 46 | 47 | glm::mat4 m_globalTransformation{}; 48 | 49 | AABB m_abbb{}; 50 | 51 | RavenSceneObject *m_sceneObject = nullptr; 52 | }; 53 | 54 | GPUSceneObject gpu(GPUContext *gpuContext, uint32_t materialId, const glm::mat4 &transformation, const glm::mat4 &globalTransformation) { 55 | GPUSceneObject gpuSceneObject{}; 56 | 57 | // if (m_material.isEmissive()) { 58 | // for (uint32_t lId = 0; lId < getNumPrimitives(); lId++) { 59 | // info.m_lights.push_back({lId + numPrimitives}); 60 | // } 61 | // } 62 | 63 | gpuSceneObject.m_vertexBuffer = Buffer::fillDeviceWithStagingBuffer(gpuContext, 64 | {.m_sizeBytes = static_cast(m_vertices.size() * sizeof(Vertex)), .m_bufferUsages = vk::BufferUsageFlagBits::eShaderDeviceAddress | vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eVertexBuffer | vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR, .m_memoryProperties = vk::MemoryPropertyFlagBits::eDeviceLocal, .m_memoryAllocateFlagBits = vk::MemoryAllocateFlagBits::eDeviceAddress, .m_name = "vertex0"}, 65 | reinterpret_cast(m_vertices.data())); 66 | gpuSceneObject.m_indexBuffer = Buffer::fillDeviceWithStagingBuffer(gpuContext, 67 | {.m_sizeBytes = static_cast(m_indices.size() * sizeof(uint32_t)), .m_bufferUsages = vk::BufferUsageFlagBits::eShaderDeviceAddress | vk::BufferUsageFlagBits::eTransferDst | vk::BufferUsageFlagBits::eIndexBuffer | vk::BufferUsageFlagBits::eAccelerationStructureBuildInputReadOnlyKHR, .m_memoryProperties = vk::MemoryPropertyFlagBits::eDeviceLocal, .m_memoryAllocateFlagBits = vk::MemoryAllocateFlagBits::eDeviceAddress, .m_name = "index0"}, 68 | reinterpret_cast(m_indices.data())); 69 | 70 | gpuSceneObject.m_materialId = materialId; 71 | 72 | gpuSceneObject.m_numPrimitives = m_indices.size() / 3; 73 | 74 | gpuSceneObject.m_blas = std::make_shared(gpuContext, gpuSceneObject.m_vertexBuffer->getDeviceAddress(), static_cast(m_vertices.size()), sizeof(Vertex), gpuSceneObject.m_indexBuffer->getDeviceAddress(), m_indices.size() / 3); 75 | gpuSceneObject.m_blas->transform(transformation); 76 | gpuSceneObject.m_blas->build(); 77 | 78 | gpuSceneObject.m_modelMatrix = transformation; 79 | 80 | gpuSceneObject.m_globalTransformation = globalTransformation; 81 | 82 | gpuSceneObject.m_abbb.expand(m_aabb.m_min); 83 | gpuSceneObject.m_abbb.expand(m_aabb.m_max); 84 | 85 | gpuSceneObject.m_sceneObject = this; 86 | 87 | return gpuSceneObject; 88 | } 89 | }; 90 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/scene/RavenTexture.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace raven { 4 | class RavenTexture { 5 | public: 6 | std::string m_key{}; 7 | std::string m_name = "RavenTexture"; 8 | 9 | std::string m_directory; 10 | std::string m_uri; 11 | }; 12 | } -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/util/AABB.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace raven { 6 | 7 | struct AABB { 8 | glm::vec3 m_min = glm::vec3(FLT_MAX); 9 | glm::vec3 m_max = glm::vec3(-FLT_MAX); 10 | 11 | void expand(const glm::vec3 vec) { 12 | if (m_min.x > vec.x) { 13 | m_min.x = vec.x; 14 | } 15 | if (m_min.y > vec.y) { 16 | m_min.y = vec.y; 17 | } 18 | if (m_min.z > vec.z) { 19 | m_min.z = vec.z; 20 | } 21 | 22 | if (m_max.x < vec.x) { 23 | m_max.x = vec.x; 24 | } 25 | if (m_max.y < vec.y) { 26 | m_max.y = vec.y; 27 | } 28 | if (m_max.z < vec.z) { 29 | m_max.z = vec.z; 30 | } 31 | } 32 | 33 | [[nodiscard]] float calculateVolume() const { 34 | if (m_min.x >= m_max.x || m_min.y >= m_max.y || m_min.z >= m_max.z) { 35 | return 0.f; 36 | } 37 | return (m_max.x - m_min.x) * (m_max.y - m_min.y) * (m_max.z - m_min.z); 38 | } 39 | 40 | [[nodiscard]] float m_maxExtent() const { return glm::max(0.f, glm::max(m_max.x - m_min.x, glm::max(m_max.y - m_min.y, m_max.z - m_min.z))); }; 41 | 42 | [[nodiscard]] float m_maxExtentAxis() const { 43 | const float xExtent = m_max.x - m_min.x; 44 | const float yExtent = m_max.y - m_min.y; 45 | const float zExtent = m_max.z - m_min.z; 46 | if (xExtent > yExtent && xExtent > zExtent) { 47 | return 0.f; 48 | } 49 | return yExtent > zExtent ? 1 : 2; 50 | } 51 | 52 | [[nodiscard]] float maxElement() const { return glm::max(m_max.x, glm::max(m_max.y, m_max.z)); } 53 | 54 | [[nodiscard]] float minElement() const { return glm::min(m_min.x, glm::min(m_min.y, m_min.z)); } 55 | 56 | [[nodiscard]] glm::vec3 center() const { 57 | return .5f * (m_min + m_max); 58 | } 59 | 60 | [[nodiscard]] glm::vec3 halfSize() const { 61 | return .5f * (m_max - m_min); 62 | } 63 | 64 | friend std::ostream &operator<<(std::ostream &stream, const AABB &aabb) { 65 | stream << "AABB{ m_min=(" << aabb.m_min.x << "," << aabb.m_min.y << "," << aabb.m_min.z << "), m_max=(" << aabb.m_max.x << "," << aabb.m_max.y << "," << aabb.m_max.z << ") }"; 66 | return stream; 67 | } 68 | }; 69 | 70 | struct iAABB { 71 | glm::ivec3 m_min = glm::ivec3(INT32_MAX); 72 | glm::ivec3 m_max = glm::ivec3(INT32_MIN); 73 | 74 | void expand(const glm::ivec3 vec) { 75 | if (m_min.x > vec.x) { 76 | m_min.x = vec.x; 77 | } 78 | if (m_min.y > vec.y) { 79 | m_min.y = vec.y; 80 | } 81 | if (m_min.z > vec.z) { 82 | m_min.z = vec.z; 83 | } 84 | 85 | if (m_max.x < vec.x) { 86 | m_max.x = vec.x; 87 | } 88 | if (m_max.y < vec.y) { 89 | m_max.y = vec.y; 90 | } 91 | if (m_max.z < vec.z) { 92 | m_max.z = vec.z; 93 | } 94 | } 95 | 96 | [[nodiscard]] int32_t calculateVolume() const { 97 | if (m_min.x >= m_max.x || m_min.y >= m_max.y || m_min.z >= m_max.z) { 98 | return 0; 99 | } 100 | return (m_max.x - m_min.x) * (m_max.y - m_min.y) * (m_max.z - m_min.z); 101 | } 102 | 103 | [[nodiscard]] uint32_t maxExtent() const { return glm::max(0, glm::max(m_max.x - m_min.x, glm::max(m_max.y - m_min.y, m_max.z - m_min.z))); }; 104 | 105 | [[nodiscard]] int32_t maxExtentAxis() const { 106 | const int32_t xExtent = m_max.x - m_min.x; 107 | const int32_t yExtent = m_max.y - m_min.y; 108 | const int32_t zExtent = m_max.z - m_min.z; 109 | if (xExtent > yExtent && xExtent > zExtent) { 110 | return 0; 111 | } 112 | return yExtent > zExtent ? 1 : 2; 113 | } 114 | 115 | [[nodiscard]] int32_t maxElement() const { return glm::max(m_max.x, glm::max(m_max.y, m_max.z)); } 116 | 117 | [[nodiscard]] int32_t minElement() const { return glm::min(m_min.x, glm::min(m_min.y, m_min.z)); } 118 | 119 | [[nodiscard]] glm::vec3 center() const { 120 | return .5f * glm::vec3(m_min + m_max); 121 | } 122 | 123 | [[nodiscard]] glm::vec3 halfSize() const { 124 | return .5f * glm::vec3(m_max - m_min); 125 | } 126 | 127 | friend std::ostream &operator<<(std::ostream &stream, const iAABB &aabb) { 128 | stream << "iAABB{ m_min=(" << aabb.m_min.x << "," << aabb.m_min.y << "," << aabb.m_min.z << "), m_max=(" << aabb.m_max.x << "," << aabb.m_max.y << "," << aabb.m_max.z << ") }"; 129 | return stream; 130 | } 131 | }; 132 | 133 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/util/Paths.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace raven { 5 | class Paths { 6 | public: 7 | inline static std::string m_resourceDirectoryPath; 8 | 9 | private: 10 | Paths() = default; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/util/Trajectory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace raven { 5 | class Trajectory { 6 | public: 7 | Trajectory() = default; 8 | 9 | void init(glm::vec3 start, glm::vec3 end, uint32_t steps) { 10 | m_start = start; 11 | m_end = end; 12 | m_steps = steps; 13 | m_stepCount = 0; 14 | } 15 | 16 | bool step(glm::vec3 *position) { 17 | if (m_stepCount >= m_steps) { 18 | return false; 19 | } 20 | 21 | m_stepCount++; 22 | 23 | float t = static_cast(m_stepCount) / static_cast(m_steps); 24 | *position = m_start + t * (m_end - m_start); 25 | 26 | return true; 27 | } 28 | 29 | private: 30 | glm::vec3 m_start{}; 31 | glm::vec3 m_end{}; 32 | uint32_t m_steps{}; 33 | 34 | uint32_t m_stepCount = 0; 35 | }; 36 | } -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/util/animation/BSpline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace raven { 7 | class BSpline { 8 | public: 9 | [[nodiscard]] glm::vec3 evaluate(float u) const { 10 | const int interval = static_cast(glm::floor(u)); 11 | const float t = glm::fract(u); 12 | 13 | assert(interval >= 0 && interval < m_controlPoints.size() - 3); 14 | 15 | const glm::vec3 p0 = m_controlPoints[interval]; 16 | const glm::vec3 p1 = m_controlPoints[interval + 1]; 17 | const glm::vec3 p2 = m_controlPoints[interval + 2]; 18 | const glm::vec3 p3 = m_controlPoints[interval + 3]; 19 | 20 | const float t2 = t * t; 21 | const float t3 = t2 * t; 22 | 23 | return 1.f / 6.f * ((-p0 + 3.f * p1 - 3.f * p2 + p3) * t3 + (3.f * p0 - 6.f * p1 + 3.f * p2) * t2 + (-3.f * p0 + 3.f * p2) * t + (p0 + 4.f * p1 + p2)); 24 | } 25 | 26 | [[nodiscard]] float getMaxU() const { 27 | return static_cast(static_cast(m_controlPoints.size()) - 3); 28 | } 29 | 30 | std::vector m_controlPoints; 31 | }; 32 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/include/raven/util/sampling/AliasTable.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | namespace raven { 8 | class AliasTable { 9 | public: 10 | explicit AliasTable(std::vector weights) : m_bins(weights.size()) { 11 | // Normalize _weights_ to compute alias table PDF 12 | const float sum = std::accumulate(weights.begin(), weights.end(), 0.); 13 | assert(sum > 0); 14 | for (size_t i = 0; i < weights.size(); ++i) 15 | m_bins[i].p = weights[i] / sum; 16 | 17 | // Create alias table work lists 18 | struct Outcome { 19 | float pHat; 20 | size_t index; 21 | }; 22 | std::vector under, over; 23 | for (size_t i = 0; i < m_bins.size(); ++i) { 24 | // Add outcome _i_ to an alias table work list 25 | const float pHat = m_bins[i].p * m_bins.size(); 26 | if (pHat < 1) 27 | under.push_back(Outcome{pHat, i}); 28 | else 29 | over.push_back(Outcome{pHat, i}); 30 | } 31 | 32 | // Process under and over work item together 33 | while (!under.empty() && !over.empty()) { 34 | // Remove items _un_ and _ov_ from the alias table work lists 35 | const Outcome un = under.back(), ov = over.back(); 36 | under.pop_back(); 37 | over.pop_back(); 38 | 39 | // Initialize probability and alias for _un_ 40 | m_bins[un.index].q = un.pHat; 41 | m_bins[un.index].alias = ov.index; 42 | 43 | // Push excess probability on to work list 44 | const float pExcess = un.pHat + ov.pHat - 1; 45 | if (pExcess < 1) 46 | under.push_back(Outcome{pExcess, ov.index}); 47 | else 48 | over.push_back(Outcome{pExcess, ov.index}); 49 | } 50 | 51 | // Handle remaining alias table work items 52 | while (!over.empty()) { 53 | const Outcome ov = over.back(); 54 | over.pop_back(); 55 | m_bins[ov.index].q = 1; 56 | m_bins[ov.index].alias = -1; 57 | } 58 | while (!under.empty()) { 59 | const Outcome un = under.back(); 60 | under.pop_back(); 61 | m_bins[un.index].q = 1; 62 | m_bins[un.index].alias = -1; 63 | } 64 | } 65 | 66 | int32_t sample(float xi, float *pdf) const { 67 | // Compute alias table _offset_ and remapped random sample _up_ 68 | const int offset = std::min(xi * m_bins.size(), m_bins.size() - 1); 69 | const float up = std::min(xi * m_bins.size() - offset, 0x1.fffffep-1); 70 | 71 | if (up < m_bins[offset].q) { 72 | // Return sample for alias table at _offset_ 73 | assert(m_bins[offset].p > 0); 74 | if (pdf) 75 | *pdf = m_bins[offset].p; 76 | return offset; 77 | } else { 78 | // Return sample for alias table at _alias[offset]_ 79 | const int alias = m_bins[offset].alias; 80 | assert(alias >= 0); 81 | assert(m_bins[alias].p > 0); 82 | if (pdf) 83 | *pdf = m_bins[alias].p; 84 | return alias; 85 | } 86 | } 87 | 88 | // private: 89 | struct Bin { 90 | float q, p; 91 | int32_t alias; 92 | }; 93 | 94 | std::vector m_bins; 95 | }; 96 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/src/raven/core/Queues.cpp: -------------------------------------------------------------------------------- 1 | #include "raven/core/Queues.h" 2 | 3 | namespace raven { 4 | 5 | Queues::QueueFamilyIndices Queues::findQueueFamilies(vk::PhysicalDevice physicalDevice) const { 6 | QueueFamilyIndices familyIndices; 7 | 8 | uint32_t queueFamilyCount = 0; 9 | vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr); 10 | std::vector queueFamilies(queueFamilyCount); 11 | physicalDevice.getQueueFamilyProperties(&queueFamilyCount, queueFamilies.data()); 12 | 13 | // graphics queue 14 | if (raven::Queues::QueueFamilyIndices::requireGraphicsFamily(m_requiredQueueFamilies)) { 15 | familyIndices.graphicsFamily = getQueueFamilyIndex(queueFamilies, vk::QueueFlagBits::eGraphics); 16 | } 17 | 18 | // dedicated compute queue 19 | if (raven::Queues::QueueFamilyIndices::requireComputeFamily(m_requiredQueueFamilies)) { 20 | familyIndices.computeFamily = getQueueFamilyIndex(queueFamilies, vk::QueueFlagBits::eCompute); 21 | } 22 | 23 | // dedicated transfer queue 24 | if (raven::Queues::QueueFamilyIndices::requireTransferFamily(m_requiredQueueFamilies)) { 25 | familyIndices.transferFamily = getQueueFamilyIndex(queueFamilies, vk::QueueFlagBits::eTransfer); 26 | } 27 | 28 | return familyIndices; 29 | } 30 | 31 | void Queues::generateQueueCreateInfos(vk::PhysicalDevice physicalDevice, std::vector *queueCreateInfos, float *queuePriorities) const { 32 | QueueFamilyIndices familyIndices = findQueueFamilies(physicalDevice); 33 | familyIndices.generateQueueCreateInfos(queueCreateInfos, queuePriorities); 34 | } 35 | 36 | void Queues::createQueues(vk::Device device, vk::PhysicalDevice physicalDevice) { 37 | QueueFamilyIndices familyIndices = findQueueFamilies(physicalDevice); 38 | if (isFamilyRequired(GRAPHICS_FAMILY)) { 39 | device.getQueue(familyIndices.graphicsFamily.value(), 0, &m_queues[GRAPHICS]); 40 | } 41 | if (isFamilyRequired(COMPUTE_FAMILY)) { 42 | device.getQueue(familyIndices.computeFamily.value(), 0, &m_queues[COMPUTE]); 43 | } 44 | if (isFamilyRequired(TRANSFER_FAMILY)) { 45 | device.getQueue(familyIndices.transferFamily.value(), 0, &m_queues[TRANSFER]); 46 | } 47 | } 48 | 49 | vk::Queue Queues::getQueue(Queues::Queue queue) { 50 | return m_queues[queue]; 51 | } 52 | 53 | bool Queues::isFamilyRequired(Queues::QueueFamilies queueFamily) const { 54 | return m_requiredQueueFamilies & queueFamily; 55 | } 56 | } // namespace raven -------------------------------------------------------------------------------- /VkRaven/raven/src/raven/core/RavenVkDynamicLoader.cpp: -------------------------------------------------------------------------------- 1 | #include "raven/RavenInclude.h" 2 | 3 | #if (VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1) 4 | VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE 5 | #endif -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MircoWerner/ReSTIR-SSS/c209f2b72b85cc51aa2577c14534952154ae4313/screenshot.png -------------------------------------------------------------------------------- /teaser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MircoWerner/ReSTIR-SSS/c209f2b72b85cc51aa2577c14534952154ae4313/teaser.png --------------------------------------------------------------------------------