├── .editorconfig ├── .gitignore ├── .gitmodules ├── README.md ├── assets ├── defaults │ └── camera_path.cam ├── images │ ├── Barcelona_Spain_Background-1421.jpg │ ├── Chinese_HDTV_test_card.png │ ├── Forest_Sunlight_Background-954.jpg │ ├── readme.txt │ ├── thingrid_2560x1440.png │ └── thingrid_inv_2560x1440.png └── models │ ├── SoccerBall_diff.png │ ├── Soccer_Ball_README.txt │ ├── Soccer_Ball_lores.mtl │ ├── Soccer_Ball_lores.obj │ ├── goblin.dae │ ├── goblin.dds │ ├── goblin_README.txt │ └── sphere_smooth.obj ├── external └── include │ ├── mini │ └── ini.h │ ├── portable-file-dialogs.h │ └── renderdoc_app.h ├── extras ├── EmeraldSquare_Day.fscene ├── README.txt └── TestScene │ ├── TestScene.blend │ ├── TestScene.fbx │ ├── TestScene.fscene │ ├── TestScene2.blend │ ├── TestScene2.fbx │ ├── TestScene_instances.fscene │ ├── TestScene_multimodel.fscene │ └── TestScene_multimodel_instances.fscene ├── shaders ├── Fxaa3_11_mod.h ├── animatedObject.vert ├── antialias_fxaa.comp ├── antialias_fxaa_prepare.comp ├── blinnphong_and_normal_mapping.frag ├── build_scene_buffers.comp ├── calc_shadows.glsl ├── draw_frustum.frag ├── draw_frustum.vert ├── draw_shadowmap.frag ├── draw_shadowmap.vert ├── drawpath.frag ├── drawpath.vert ├── ffx_a.h ├── ffx_cas.h ├── frustum_culling.comp ├── fwd_geometry.frag ├── lighting_pass.frag ├── lighting_pass.vert ├── post_process.comp ├── rt_test.rchit ├── rt_test.rgen ├── rt_test.rmiss ├── rt_test_shadowray.rchit ├── rt_test_shadowray.rmiss ├── rt_test_shadowray_transp.rahit ├── rt_test_transp.rahit ├── shader_common_main.glsl ├── shader_cpu_common.h ├── shader_raytrace_common.glsl ├── shader_raytrace_lod_approximation.glsl ├── shadowmap.vert ├── shadowmap_animated.vert ├── shadowmap_transparent.frag ├── shadowmap_transparent.vert ├── sharpen.comp ├── sharpen_cas.comp ├── sky_gradient.frag ├── sky_gradient.vert ├── taa.comp ├── testimage.frag ├── testimage.vert └── transform_and_pass_on.vert ├── source ├── BoundingBox.cpp ├── BoundingBox.hpp ├── FrustumCulling.hpp ├── IniUtil.cpp ├── IniUtil.h ├── InterpolationCurve.cpp ├── InterpolationCurve.hpp ├── RayTraceCallback.h ├── ShadowMap.cpp ├── ShadowMap.hpp ├── cg_stdafx.cpp ├── cg_stdafx.hpp ├── cg_targetver.hpp ├── helper_functions.hpp ├── imgui_helper.hpp ├── imgui_stdlib.cpp ├── imgui_stdlib.h ├── main.cpp ├── rdoc_helper.hpp ├── splines.cpp ├── splines.hpp └── taa.hpp ├── taa.sln ├── taa.vcxproj ├── taa.vcxproj.filters └── todo.txt /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_style = tab 3 | indent_size = 4 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific files 2 | *.suo 3 | 4 | # NuGet Packages 5 | *.nupkg 6 | # The packages folder can be ignored because of Package Restore 7 | **/packages/* 8 | # except build/, which is used as an MSBuild target. 9 | !**/packages/build/ 10 | # Uncomment if necessary however generally it will be regenerated when needed 11 | #!**/packages/repositories.config 12 | # NuGet v3's project.json files produces more ignoreable files 13 | *.nuget.props 14 | *.nuget.targets 15 | 16 | # Visual Studio build results 17 | [Tt]emp/ 18 | [Bb]in/ 19 | 20 | # Visual Studio cache/options directory 21 | .vs/ 22 | 23 | # Ignore temporary MS-Office files 24 | ~$*.doc* 25 | ~$*.dot* 26 | ~$*.xls* 27 | ~$*.xlt* 28 | ~$*.ppt* 29 | ~$*.pot* 30 | 31 | # Ignore Visual Studio user-specific settings 32 | taa.vcxproj.user 33 | 34 | # Other files to ignore 35 | notes.txt 36 | extras/TestScene/*.blend1 37 | shaders/compile_manually.bat 38 | 39 | # Optional assets (cannot include those due to licensing) 40 | assets/optional 41 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "gears_vk"] 2 | path = gears_vk 3 | url = https://github.com/cg-tuwien/Gears-Vk 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TAA-STAR 2 | 3 | Implementations of several state of the art Temporal Anti-Aliasing (TAA) techniques. 4 | 5 | ## Project Description 6 | 7 | TBD. 8 | 9 | ## Setup Instructions and Submodules 10 | 11 | 1. Clone the repository with all submodules recursively: 12 | `git clone https://github.com/cg-tuwien/TAA-STAR.git . --recursive` (to check out into `.`) 13 | 2. Open `taa.sln` with Visual Studio 2019, set `taa` as the startup project, build and run 14 | 15 | You might want to have all submodules checked-out to their `master` branch. You can do so using: 16 | `git submodule foreach --recursive git checkout master`. 17 | There are two submodules: One under `gears_vk/` (referencing https://github.com/cg-tuwien/Gears-Vk) and another under `gears_vk/auto_vk/` (referencing https://github.com/cg-tuwien/Auto-Vk). 18 | 19 | To update the submodules on a daily basis, use the following command: 20 | `git submodule foreach --recursive 'git checkout master && git pull'` 21 | 22 | To contribute to either of the submodules, please do so via pull requests and follow the ["Contributing Guidelines" from Gears-Vk](https://github.com/cg-tuwien/Gears-Vk/blob/master/CONTRIBUTING.md). Every time you check something in, make sure that the correct submodule-commits (may also reference forks) are referenced so that one can always get a compiling and working version by cloning as described in step 1! 23 | 24 | ## Scene Setup 25 | 26 | 1. Download the Emerald Square scene from https://developer.nvidia.com/orca/nvidia-emerald-square 27 | 2. Extract it to a (new) folder of your choice 28 | 3. Copy the file `extras/EmeraldSquare_Day.fscene` from the repository into that folder 29 | 4. Launch the program: `taa.exe ` 30 | 31 | If no scene file is specified, the included Sponza-scene is used. 32 | There is also a very simple, fast-loading test scene included in `extras/TestScene/`. 33 | 34 | ## Documentation 35 | 36 | TBD. 37 | 38 | ## License 39 | 40 | TBD. 41 | -------------------------------------------------------------------------------- /assets/defaults/camera_path.cam: -------------------------------------------------------------------------------- 1 | [campath] 2 | type=2 3 | duration=40.000000 4 | constantspeed=1 5 | lookalong=1 6 | num_pos=16 7 | pos_0.x=0.000000 8 | pos_0.y=1.000000 9 | pos_0.z=0.000000 10 | pos_1.x=-0.298379 11 | pos_1.y=1.000000 12 | pos_1.z=-59.751087 13 | pos_2.x=0.976464 14 | pos_2.y=1.000000 15 | pos_2.z=-80.715034 16 | pos_3.x=71.798103 17 | pos_3.y=1.000000 18 | pos_3.z=-78.929810 19 | pos_4.x=80.719917 20 | pos_4.y=1.000000 21 | pos_4.z=-70.170128 22 | pos_5.x=76.965752 23 | pos_5.y=1.000000 24 | pos_5.z=62.839920 25 | pos_6.x=76.111839 26 | pos_6.y=1.000000 27 | pos_6.z=76.450470 28 | pos_7.x=52.731930 29 | pos_7.y=1.000000 30 | pos_7.z=77.099274 31 | pos_8.x=25.468878 32 | pos_8.y=14.800884 33 | pos_8.z=77.674072 34 | pos_9.x=-31.196514 35 | pos_9.y=14.610768 36 | pos_9.z=76.081375 37 | pos_10.x=-55.907600 38 | pos_10.y=1.000000 39 | pos_10.z=56.768272 40 | pos_11.x=-56.159760 41 | pos_11.y=9.217593 42 | pos_11.z=18.412666 43 | pos_12.x=-32.248280 44 | pos_12.y=5.065829 45 | pos_12.z=12.778225 46 | pos_13.x=-19.508131 47 | pos_13.y=3.385854 48 | pos_13.z=40.319248 49 | pos_14.x=1.561506 50 | pos_14.y=1.933083 51 | pos_14.z=34.666378 52 | pos_15.x=-0.243341 53 | pos_15.y=1.000000 54 | pos_15.z=-8.232195 -------------------------------------------------------------------------------- /assets/images/Barcelona_Spain_Background-1421.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg-tuwien/TAA-STAR/1ef2bd3d0aeb8a995d3c83a99b095ee1e86e6fa6/assets/images/Barcelona_Spain_Background-1421.jpg -------------------------------------------------------------------------------- /assets/images/Chinese_HDTV_test_card.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg-tuwien/TAA-STAR/1ef2bd3d0aeb8a995d3c83a99b095ee1e86e6fa6/assets/images/Chinese_HDTV_test_card.png -------------------------------------------------------------------------------- /assets/images/Forest_Sunlight_Background-954.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg-tuwien/TAA-STAR/1ef2bd3d0aeb8a995d3c83a99b095ee1e86e6fa6/assets/images/Forest_Sunlight_Background-954.jpg -------------------------------------------------------------------------------- /assets/images/readme.txt: -------------------------------------------------------------------------------- 1 | Background images from https://freeartbackgrounds.com/ 2 | 3 | Test-card from https://commons.wikimedia.org/ 4 | 5 | -------------------------------------------------------------------------------- /assets/images/thingrid_2560x1440.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg-tuwien/TAA-STAR/1ef2bd3d0aeb8a995d3c83a99b095ee1e86e6fa6/assets/images/thingrid_2560x1440.png -------------------------------------------------------------------------------- /assets/images/thingrid_inv_2560x1440.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg-tuwien/TAA-STAR/1ef2bd3d0aeb8a995d3c83a99b095ee1e86e6fa6/assets/images/thingrid_inv_2560x1440.png -------------------------------------------------------------------------------- /assets/models/SoccerBall_diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg-tuwien/TAA-STAR/1ef2bd3d0aeb8a995d3c83a99b095ee1e86e6fa6/assets/models/SoccerBall_diff.png -------------------------------------------------------------------------------- /assets/models/Soccer_Ball_README.txt: -------------------------------------------------------------------------------- 1 | Original file from Turbosquid: 2 | https://www.turbosquid.com/3d-models/free-max-mode-soccer-ball/573210 3 | 4 | Centered, scaled & poly count reduced drastically. 5 | Material changed and texture converted to png. 6 | 7 | -------------------------------------------------------------------------------- /assets/models/Soccer_Ball_lores.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'None' 2 | # Material Count: 1 3 | 4 | newmtl SoccerBall_mat 5 | Ns 10.000002 6 | Ka 0.100000 0.100000 0.100000 7 | Kd 1.000000 1.000000 1.000000 8 | Ks 0.000000 0.000000 0.000000 9 | Ke 0.0 0.0 0.0 10 | Ni 1.500000 11 | d 1.000000 12 | illum 1 13 | map_Kd SoccerBall_diff.png 14 | -------------------------------------------------------------------------------- /assets/models/goblin.dds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg-tuwien/TAA-STAR/1ef2bd3d0aeb8a995d3c83a99b095ee1e86e6fa6/assets/models/goblin.dds -------------------------------------------------------------------------------- /assets/models/goblin_README.txt: -------------------------------------------------------------------------------- 1 | Goblin model from Sascha Willems' Vulkan Examples: 2 | https://www.saschawillems.de/creations/vulkan-examples/ 3 | -------------------------------------------------------------------------------- /extras/EmeraldSquare_Day.fscene: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "camera_speed": 1.0, 4 | "lighting_scale": 1.0, 5 | "active_camera": "Camera0", 6 | "models": [ 7 | { 8 | "file": "EmeraldSquare_Day.fbx", 9 | "name": "EmeraldSquare_Day", 10 | "instances": [ 11 | { 12 | "name": "EmeraldSquare_Day0", 13 | "translation": [ 14 | 0.0, 15 | 0.0, 16 | 0.0 17 | ], 18 | "scaling": [ 19 | 1.0, 20 | 1.0, 21 | 1.0 22 | ], 23 | "rotation": [ 24 | 0.0, 25 | 0.0, 26 | 0.0 27 | ] 28 | } 29 | ] 30 | } 31 | ], 32 | "lights": [ 33 | { 34 | "name": "SunLight", 35 | "type": "dir_light", 36 | "intensity": [ 37 | 1.0, 38 | 1.0, 39 | 1.0 40 | ], 41 | "direction": [ 42 | -0.33333333333333333, 43 | -0.66666666666666666, 44 | -0.33333333333333333 45 | ] 46 | } 47 | ], 48 | "cameras": [ 49 | { 50 | "name": "Camera0", 51 | "pos": [ 52 | 0.01715730130672455, 53 | 3.184415578842163, 54 | 71.125 55 | ], 56 | "target": [ 57 | 0.008677838370203972, 58 | 3.20275616645813, 59 | 70.12520599365235 60 | ], 61 | "up": [ 62 | 0.002032371936365962, 63 | 0.999836266040802, 64 | 0.01836729794740677 65 | ], 66 | "focal_length": 21.0, 67 | "depth_range": [ 68 | 0.10000000149011612, 69 | 10000.0 70 | ], 71 | "aspect_ratio": 1.0 72 | } 73 | ] 74 | } -------------------------------------------------------------------------------- /extras/README.txt: -------------------------------------------------------------------------------- 1 | Download the Emerald-Square scene from: 2 | https://developer.nvidia.com/orca/nvidia-emerald-square 3 | 4 | Extract it to a folder of your choice, and copy the file 5 | "EmeraldSquare_Day.fscene" 6 | into the same folder. 7 | -------------------------------------------------------------------------------- /extras/TestScene/TestScene.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg-tuwien/TAA-STAR/1ef2bd3d0aeb8a995d3c83a99b095ee1e86e6fa6/extras/TestScene/TestScene.blend -------------------------------------------------------------------------------- /extras/TestScene/TestScene.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg-tuwien/TAA-STAR/1ef2bd3d0aeb8a995d3c83a99b095ee1e86e6fa6/extras/TestScene/TestScene.fbx -------------------------------------------------------------------------------- /extras/TestScene/TestScene.fscene: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "camera_speed": 1.0, 4 | "lighting_scale": 1.0, 5 | "active_camera": "Camera0", 6 | "models": [ 7 | { 8 | "file": "TestScene.fbx", 9 | "name": "TestScene", 10 | "instances": [ 11 | { 12 | "name": "TestScene0", 13 | "translation": [ 14 | 0.0, 15 | 0.0, 16 | 0.0 17 | ], 18 | "scaling": [ 19 | 1.0, 20 | 1.0, 21 | 1.0 22 | ], 23 | "rotation": [ 24 | 0.0, 25 | 0.0, 26 | 0.0 27 | ] 28 | } 29 | ] 30 | } 31 | ], 32 | "lights": [ 33 | { 34 | "name": "SunLight", 35 | "type": "dir_light", 36 | "intensity": [ 37 | 1.0, 38 | 1.0, 39 | 1.0 40 | ], 41 | "direction": [ 42 | -0.33333333333333333, 43 | -0.66666666666666666, 44 | -0.33333333333333333 45 | ] 46 | } 47 | ], 48 | "cameras": [ 49 | { 50 | "name": "Camera0", 51 | "pos": [ 52 | 0.01715730130672455, 53 | 3.184415578842163, 54 | 71.125 55 | ], 56 | "target": [ 57 | 0.008677838370203972, 58 | 3.20275616645813, 59 | 70.12520599365235 60 | ], 61 | "up": [ 62 | 0.002032371936365962, 63 | 0.999836266040802, 64 | 0.01836729794740677 65 | ], 66 | "focal_length": 21.0, 67 | "depth_range": [ 68 | 0.10000000149011612, 69 | 10000.0 70 | ], 71 | "aspect_ratio": 1.0 72 | } 73 | ] 74 | } -------------------------------------------------------------------------------- /extras/TestScene/TestScene2.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg-tuwien/TAA-STAR/1ef2bd3d0aeb8a995d3c83a99b095ee1e86e6fa6/extras/TestScene/TestScene2.blend -------------------------------------------------------------------------------- /extras/TestScene/TestScene2.fbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cg-tuwien/TAA-STAR/1ef2bd3d0aeb8a995d3c83a99b095ee1e86e6fa6/extras/TestScene/TestScene2.fbx -------------------------------------------------------------------------------- /extras/TestScene/TestScene_instances.fscene: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "camera_speed": 1.0, 4 | "lighting_scale": 1.0, 5 | "active_camera": "Camera0", 6 | "models": [ 7 | { 8 | "file": "TestScene.fbx", 9 | "name": "TestScene", 10 | "instances": [ 11 | { 12 | "name": "TestScene_inst0", 13 | "translation": [ 14 | 0.0, 15 | 0.0, 16 | 0.0 17 | ], 18 | "scaling": [ 19 | 1.0, 20 | 1.0, 21 | 1.0 22 | ], 23 | "rotation": [ 24 | 0.0, 25 | 0.0, 26 | 0.0 27 | ] 28 | }, 29 | { 30 | "name": "TestScene_inst1", 31 | "translation": [ 32 | 1.0, 33 | 1.0, 34 | 0.0 35 | ], 36 | "scaling": [ 37 | 1.0, 38 | 1.0, 39 | 1.0 40 | ], 41 | "rotation": [ 42 | 0.0, 43 | 0.0, 44 | 0.0 45 | ] 46 | } 47 | ] 48 | } 49 | ], 50 | "lights": [ 51 | { 52 | "name": "SunLight", 53 | "type": "dir_light", 54 | "intensity": [ 55 | 1.0, 56 | 1.0, 57 | 1.0 58 | ], 59 | "direction": [ 60 | -0.33333333333333333, 61 | -0.66666666666666666, 62 | -0.33333333333333333 63 | ] 64 | } 65 | ], 66 | "cameras": [ 67 | { 68 | "name": "Camera0", 69 | "pos": [ 70 | 0.01715730130672455, 71 | 3.184415578842163, 72 | 71.125 73 | ], 74 | "target": [ 75 | 0.008677838370203972, 76 | 3.20275616645813, 77 | 70.12520599365235 78 | ], 79 | "up": [ 80 | 0.002032371936365962, 81 | 0.999836266040802, 82 | 0.01836729794740677 83 | ], 84 | "focal_length": 21.0, 85 | "depth_range": [ 86 | 0.10000000149011612, 87 | 10000.0 88 | ], 89 | "aspect_ratio": 1.0 90 | } 91 | ] 92 | } -------------------------------------------------------------------------------- /extras/TestScene/TestScene_multimodel.fscene: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "camera_speed": 1.0, 4 | "lighting_scale": 1.0, 5 | "active_camera": "Camera0", 6 | "models": [ 7 | { 8 | "file": "TestScene.fbx", 9 | "name": "TestScene", 10 | "instances": [ 11 | { 12 | "name": "TestScene_inst0", 13 | "translation": [ 14 | 0.0, 15 | 0.0, 16 | 0.0 17 | ], 18 | "scaling": [ 19 | 1.0, 20 | 1.0, 21 | 1.0 22 | ], 23 | "rotation": [ 24 | 0.0, 25 | 0.0, 26 | 0.0 27 | ] 28 | } 29 | ] 30 | }, 31 | { 32 | "file": "TestScene2.fbx", 33 | "name": "TestScene2", 34 | "instances": [ 35 | { 36 | "name": "TestScene2_inst0", 37 | "translation": [ 38 | 0.0, 39 | 0.0, 40 | 0.0 41 | ], 42 | "scaling": [ 43 | 1.0, 44 | 1.0, 45 | 1.0 46 | ], 47 | "rotation": [ 48 | 0.0, 49 | 0.0, 50 | 0.0 51 | ] 52 | } 53 | ] 54 | } 55 | ], 56 | "lights": [ 57 | { 58 | "name": "SunLight", 59 | "type": "dir_light", 60 | "intensity": [ 61 | 1.0, 62 | 1.0, 63 | 1.0 64 | ], 65 | "direction": [ 66 | -0.33333333333333333, 67 | -0.66666666666666666, 68 | -0.33333333333333333 69 | ] 70 | } 71 | ], 72 | "cameras": [ 73 | { 74 | "name": "Camera0", 75 | "pos": [ 76 | 0.01715730130672455, 77 | 3.184415578842163, 78 | 71.125 79 | ], 80 | "target": [ 81 | 0.008677838370203972, 82 | 3.20275616645813, 83 | 70.12520599365235 84 | ], 85 | "up": [ 86 | 0.002032371936365962, 87 | 0.999836266040802, 88 | 0.01836729794740677 89 | ], 90 | "focal_length": 21.0, 91 | "depth_range": [ 92 | 0.10000000149011612, 93 | 10000.0 94 | ], 95 | "aspect_ratio": 1.0 96 | } 97 | ] 98 | } -------------------------------------------------------------------------------- /extras/TestScene/TestScene_multimodel_instances.fscene: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "camera_speed": 1.0, 4 | "lighting_scale": 1.0, 5 | "active_camera": "Camera0", 6 | "models": [ 7 | { 8 | "file": "TestScene.fbx", 9 | "name": "TestScene", 10 | "instances": [ 11 | { 12 | "name": "TestScene_inst0", 13 | "translation": [ 14 | 0.0, 15 | 0.0, 16 | 0.0 17 | ], 18 | "scaling": [ 19 | 1.0, 20 | 1.0, 21 | 1.0 22 | ], 23 | "rotation": [ 24 | 0.0, 25 | 0.0, 26 | 0.0 27 | ] 28 | }, 29 | { 30 | "name": "TestScene_inst1", 31 | "translation": [ 32 | 1.0, 33 | 1.0, 34 | 0.0 35 | ], 36 | "scaling": [ 37 | 1.0, 38 | 1.0, 39 | 1.0 40 | ], 41 | "rotation": [ 42 | 0.0, 43 | 0.0, 44 | 0.0 45 | ] 46 | } 47 | ] 48 | }, 49 | { 50 | "file": "TestScene2.fbx", 51 | "name": "TestScene2", 52 | "instances": [ 53 | { 54 | "name": "TestScene2_inst0", 55 | "translation": [ 56 | 0.0, 57 | 0.0, 58 | 0.0 59 | ], 60 | "scaling": [ 61 | 1.0, 62 | 1.0, 63 | 1.0 64 | ], 65 | "rotation": [ 66 | 0.0, 67 | 0.0, 68 | 0.0 69 | ] 70 | }, 71 | { 72 | "name": "TestScene2_inst1", 73 | "translation": [ 74 | 0.0, 75 | 2.0, 76 | 0.0 77 | ], 78 | "scaling": [ 79 | 1.0, 80 | 1.0, 81 | 1.0 82 | ], 83 | "rotation": [ 84 | 0.0, 85 | 0.0, 86 | 0.0 87 | ] 88 | }, 89 | { 90 | "name": "TestScene2_inst2", 91 | "translation": [ 92 | 0.0, 93 | 4.0, 94 | 0.0 95 | ], 96 | "scaling": [ 97 | 1.0, 98 | 1.0, 99 | 1.0 100 | ], 101 | "rotation": [ 102 | 0.0, 103 | 0.0, 104 | 0.0 105 | ] 106 | } 107 | ] 108 | } 109 | ], 110 | "lights": [ 111 | { 112 | "name": "SunLight", 113 | "type": "dir_light", 114 | "intensity": [ 115 | 1.0, 116 | 1.0, 117 | 1.0 118 | ], 119 | "direction": [ 120 | -0.33333333333333333, 121 | -0.66666666666666666, 122 | -0.33333333333333333 123 | ] 124 | } 125 | ], 126 | "cameras": [ 127 | { 128 | "name": "Camera0", 129 | "pos": [ 130 | 0.01715730130672455, 131 | 3.184415578842163, 132 | 71.125 133 | ], 134 | "target": [ 135 | 0.008677838370203972, 136 | 3.20275616645813, 137 | 70.12520599365235 138 | ], 139 | "up": [ 140 | 0.002032371936365962, 141 | 0.999836266040802, 142 | 0.01836729794740677 143 | ], 144 | "focal_length": 21.0, 145 | "depth_range": [ 146 | 0.10000000149011612, 147 | 10000.0 148 | ], 149 | "aspect_ratio": 1.0 150 | } 151 | ] 152 | } -------------------------------------------------------------------------------- /shaders/animatedObject.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | // ------------------------------------------------------- 4 | 5 | #include "shader_common_main.glsl" 6 | #include "shader_cpu_common.h" 7 | 8 | // TODO: fix tangents, bitangents 9 | 10 | 11 | // ###### VERTEX SHADER/PIPELINE INPUT DATA ############## 12 | // Several vertex attributes (These are the buffers passed 13 | // to command_buffer_t::draw_indexed in the same order): 14 | layout (location = 0) in vec3 aPosition; 15 | layout (location = 1) in vec2 aTexCoords; 16 | layout (location = 2) in vec3 aNormal; 17 | layout (location = 3) in vec3 aTangent; 18 | layout (location = 4) in vec3 aBitangent; 19 | layout (location = 5) in vec4 aBoneWeights; 20 | layout (location = 6) in uvec4 aBoneIndices; 21 | 22 | // push constants 23 | layout(push_constant) PUSHCONSTANTSDEF_DII; 24 | 25 | 26 | // "mMatrices" uniform buffer containing camera matrices: 27 | // It is updated every frame. 28 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 29 | 30 | layout(set = 3, binding = 0, std430) readonly buffer BoneMatricesBuffer { mat4 mat[]; } boneMatrices; 31 | layout(set = 3, binding = 1, std430) readonly buffer BoneMatricesPrevBuffer { mat4 mat[]; } boneMatricesPrev; 32 | 33 | // ------------------------------------------------------- 34 | 35 | // ###### DATA PASSED ON ALONG THE PIPELINE ############## 36 | // Data from vert -> tesc or frag: 37 | layout (location = 0) out VertexData { 38 | vec4 positionWS; 39 | vec3 positionVS; 40 | vec2 texCoords; 41 | vec3 normalOS; 42 | vec3 tangentOS; 43 | vec3 bitangentOS; 44 | vec4 positionCS; // TODO: don't really need this! 45 | vec4 positionCS_prev; // position in previous frame 46 | 47 | flat uint materialIndex; 48 | flat mat4 modelMatrix; 49 | flat int movingObjectId; 50 | } v_out; 51 | // ------------------------------------------------------- 52 | 53 | // ###### VERTEX SHADER MAIN ############################# 54 | void main() 55 | { 56 | // moving object 57 | v_out.materialIndex = mMover_materialIndex; 58 | v_out.modelMatrix = uboMatUsr.mMover_additionalModelMatrix * mMover_baseModelMatrix; 59 | mat4 prev_modelMatrix = uboMatUsr.mMover_additionalModelMatrix_prev * mMover_baseModelMatrix; 60 | v_out.movingObjectId = -mDrawType; 61 | 62 | vec4 boneWeights = aBoneWeights; 63 | // boneWeights.w = 1.0 - boneWeights.x - boneWeights.y - boneWeights.z; // no longer necessary to "normalize", this is now done at model loading 64 | 65 | uint bonesBaseIndex = mMover_meshIndex * MAX_BONES; 66 | 67 | // weighted sum of the four bone matrices 68 | mat4 boneMat = boneMatrices.mat [bonesBaseIndex + aBoneIndices[0]] * boneWeights[0] 69 | + boneMatrices.mat [bonesBaseIndex + aBoneIndices[1]] * boneWeights[1] 70 | + boneMatrices.mat [bonesBaseIndex + aBoneIndices[2]] * boneWeights[2] 71 | + boneMatrices.mat [bonesBaseIndex + aBoneIndices[3]] * boneWeights[3]; 72 | 73 | mat4 prev_boneMat = boneMatricesPrev.mat[bonesBaseIndex + aBoneIndices[0]] * boneWeights[0] 74 | + boneMatricesPrev.mat[bonesBaseIndex + aBoneIndices[1]] * boneWeights[1] 75 | + boneMatricesPrev.mat[bonesBaseIndex + aBoneIndices[2]] * boneWeights[2] 76 | + boneMatricesPrev.mat[bonesBaseIndex + aBoneIndices[3]] * boneWeights[3]; 77 | 78 | mat4 mMatrix = v_out.modelMatrix; 79 | mat4 vMatrix = uboMatUsr.mViewMatrix; 80 | mat4 pMatrix = uboMatUsr.mProjMatrix; 81 | mat4 vmMatrix = vMatrix * mMatrix; 82 | mat4 pvmMatrix = pMatrix * vmMatrix; 83 | 84 | vec4 positionOS = boneMat * vec4(aPosition, 1.0); 85 | vec4 positionVS = vmMatrix * positionOS; 86 | vec4 positionCS = pMatrix * positionVS; 87 | 88 | mat3 normalMatrix = mat3(inverse(transpose(boneMat))); // TODO: can we do inverse(transpose(mat3(M))) instead? could be faster 89 | vec3 normalOS = normalize(normalMatrix * normalize(aNormal)); // TODO: (1) first normalize() necessary? (2) aNormal should be normalized already... (really?) 90 | vec3 tangentOS = normalize(normalMatrix * normalize(aTangent)); 91 | vec3 bitangentOS = normalize(normalMatrix * normalize(aBitangent)); 92 | 93 | v_out.positionWS = mMatrix * positionOS; 94 | v_out.positionVS = positionVS.xyz; 95 | v_out.texCoords = aTexCoords; 96 | v_out.normalOS = normalOS; 97 | v_out.tangentOS = tangentOS; 98 | v_out.bitangentOS = bitangentOS; 99 | v_out.positionCS = positionCS; // TODO: recheck - is it ok to interpolate clip space vars? 100 | v_out.positionCS_prev = uboMatUsr.mPrevFrameProjViewMatrix * prev_modelMatrix * prev_boneMat * vec4(aPosition, 1.0); 101 | 102 | gl_Position = positionCS; 103 | } 104 | // ------------------------------------------------------- 105 | 106 | -------------------------------------------------------------------------------- /shaders/antialias_fxaa.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_samplerless_texture_functions : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_cpu_common.h" 6 | 7 | // ###### SRC/DST IMAGES ################################# 8 | layout(set = 0, binding = 1) uniform sampler2D texInput; 9 | layout(set = 0, binding = 2, TAA_SHADER_OUTPUT_FORMAT) writeonly uniform restrict image2D uOutput; 10 | layout(set = 0, binding = 3, TAA_SHADER_FORMAT_SEGMASK) uniform uimage2D taaSegMask; 11 | // ------------------------------------------------------- 12 | 13 | layout(push_constant) uniform PushConstants { 14 | vec2 fxaaQualityRcpFrame; 15 | float fxaaQualitySubpix; 16 | float fxaaQualityEdgeThreshold; 17 | float fxaaQualityEdgeThresholdMin; 18 | float pad1, pad2, pad3; 19 | } pushConstants; 20 | 21 | // set main configuration for FXAA QUALITY PC and include FXAA code 22 | #define FXAA_PC 1 23 | #define FXAA_GLSL_130 1 24 | #define FXAA_QUALITY_PRESET 12 25 | //#define FXAA_QUALITY_PRESET 25 26 | #include "Fxaa3_11_mod.h" // mod just renamed double-underscore-defines to single-underscore-defines 27 | 28 | // ################## COMPUTE SHADER MAIN ################### 29 | 30 | layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; 31 | void main() 32 | { 33 | ivec2 iuv = ivec2(gl_GlobalInvocationID.xy); 34 | if (any(greaterThanEqual(iuv, textureSize(texInput, 0)))) return; 35 | 36 | vec4 color; 37 | 38 | // check if this pixel is marked for FXAA - if it is, do it, else just keep its current color 39 | uint segMask = imageLoad(taaSegMask, iuv).r & 3; 40 | if (segMask == 1) { 41 | color = FxaaPixelShader( 42 | (vec2(iuv) + 0.5) * pushConstants.fxaaQualityRcpFrame, // pos - center of pixel (uv coordinates) 43 | vec4(0), // fxaaConsolePosPos - unused 44 | texInput, // tex 45 | texInput, // fxaaConsole360TexExpBiasNegOne 46 | texInput, // fxaaConsole360TexExpBiasNegTwo 47 | pushConstants.fxaaQualityRcpFrame, // fxaaQualityRcpFrame 48 | vec4(0), // fxaaConsoleRcpFrameOpt - unused 49 | vec4(0), // fxaaConsoleRcpFrameOpt2 - unused 50 | vec4(0), // fxaaConsole360RcpFrameOpt2 - unused 51 | pushConstants.fxaaQualitySubpix, // fxaaQualitySubpix 52 | pushConstants.fxaaQualityEdgeThreshold, // fxaaQualityEdgeThreshold 53 | pushConstants.fxaaQualityEdgeThresholdMin, // fxaaQualityEdgeThresholdMin 54 | 0.0, // fxaaConsoleEdgeSharpness - unused 55 | 0.0, // fxaaConsoleEdgeThreshold - unused 56 | 0.0, // fxaaConsoleEdgeThresholdMin - unused 57 | vec4(0) // fxaaConsole360ConstDir - unused 58 | ); 59 | } else { 60 | color = texelFetch(texInput, iuv, 0); 61 | } 62 | 63 | imageStore(uOutput, iuv, color); 64 | } 65 | 66 | -------------------------------------------------------------------------------- /shaders/antialias_fxaa_prepare.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_samplerless_texture_functions : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_cpu_common.h" 6 | 7 | // ###### SRC/DST IMAGES ################################# 8 | layout(set = 0, binding = 1) uniform texture2D uInput; 9 | layout(set = 0, binding = 2, TAA_SHADER_OUTPUT_FORMAT) writeonly uniform restrict image2D uOutput; 10 | // ------------------------------------------------------- 11 | 12 | // ################## COMPUTE SHADER MAIN ################### 13 | 14 | layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; 15 | void main() 16 | { 17 | ivec2 iuv = ivec2(gl_GlobalInvocationID.xy); 18 | if (any(greaterThanEqual(iuv, textureSize(uInput, 0)))) return; 19 | 20 | // FXAA needs luma in alpha channel - compute it (see fxaa3_11.h) 21 | 22 | vec4 color; 23 | color.rgb = texelFetch(uInput, iuv, 0).rgb; 24 | color.a = dot(color.rgb, vec3(0.299, 0.587, 0.114)); // compute luma 25 | imageStore(uOutput, iuv, color); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /shaders/blinnphong_and_normal_mapping.frag: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_nonuniform_qualifier : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | #extension GL_EXT_post_depth_coverage : enable 5 | // ------------------------------------------------------- 6 | 7 | #include "shader_common_main.glsl" 8 | #include "shader_cpu_common.h" 9 | 10 | // ac: disable this, otherwise discarded fragments write to depth buffer! 11 | //layout(early_fragment_tests) in; 12 | //layout(post_depth_coverage) in; 13 | 14 | // ###### MATERIAL DATA ################################## 15 | 16 | // The actual material buffer (of type MaterialGpuData): 17 | // It is bound to descriptor set at index 0 and 18 | // within the descriptor set, to binding location 0 19 | layout(set = 0, binding = 0) BUFFERDEF_Material materialsBuffer; 20 | 21 | 22 | // Array of samplers containing all the material's images: 23 | // These samplers are referenced from materials by 24 | // index, namely by all those m*TexIndex members. 25 | layout(set = 0, binding = 1) uniform sampler2D textures[]; 26 | 27 | // set 0, binding 2-4 used in vertex shader 28 | 29 | // ------------------------------------------------------- 30 | 31 | // ###### PIPELINE INPUT DATA ############################ 32 | 33 | // Uniform buffer containing camera matrices and user input: 34 | // It is updated every frame. 35 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 36 | 37 | // "mLightsources" uniform buffer containing all the light source data: 38 | layout(set = 1, binding = 1) UNIFORMDEF_LightsourceData uboLights; 39 | 40 | // ------------------------------------------------------- 41 | 42 | // ###### FRAG INPUT ##################################### 43 | layout (location = 0) in VertexData 44 | { 45 | vec4 positionWS; // not used in this shader 46 | vec3 positionVS; // interpolated vertex position in view-space 47 | vec2 texCoords; // texture coordinates 48 | vec3 normalOS; // interpolated vertex normal in object-space 49 | vec3 tangentOS; // interpolated vertex tangent in object-space 50 | vec3 bitangentOS; // interpolated vertex bitangent in object-space 51 | vec4 positionCS; // TODO: don't really need this! can calc from gl_FragCoord 52 | vec4 positionCS_prev; // position in previous frame 53 | 54 | flat uint materialIndex; 55 | flat mat4 modelMatrix; 56 | flat int movingObjectId; 57 | } fs_in; 58 | // ------------------------------------------------------- 59 | 60 | // ###### FRAG OUTPUT #################################### 61 | layout (location = 0) out vec4 oFragUvNrm; 62 | layout (location = 1) out uint oFragMatId; 63 | layout (location = 2) out vec4 oFragVelocity; 64 | // ------------------------------------------------------- 65 | 66 | // ###### HELPER FUNCTIONS ############################### 67 | 68 | vec4 sample_from_normals_texture() 69 | { 70 | uint matIndex = fs_in.materialIndex; 71 | int texIndex = materialsBuffer.materials[matIndex].mNormalsTexIndex; 72 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mNormalsTexOffsetTiling; 73 | vec2 texCoords = fs_in.texCoords * offsetTiling.zw + offsetTiling.xy; 74 | vec4 normalSample = SAMPLE_TEXTURE(textures[texIndex], texCoords); 75 | FIX_NORMALMAPPING(normalSample); 76 | return normalSample; 77 | } 78 | 79 | vec4 sample_from_diffuse_texture() 80 | { 81 | uint matIndex = fs_in.materialIndex; 82 | int texIndex = materialsBuffer.materials[matIndex].mDiffuseTexIndex; 83 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mDiffuseTexOffsetTiling; 84 | vec2 texCoords = fs_in.texCoords * offsetTiling.zw + offsetTiling.xy; 85 | return SAMPLE_TEXTURE(textures[texIndex], texCoords); 86 | } 87 | 88 | 89 | // Re-orthogonalizes the first vector w.r.t. the second vector (Gram-Schmidt process) 90 | vec3 re_orthogonalize(vec3 first, vec3 second) 91 | { 92 | return normalize(first - dot(first, second) * second); 93 | } 94 | 95 | // Calculates the normalized normal in view space by sampling the 96 | // normal from the normal map and transforming it with the TBN-matrix. 97 | vec3 calc_normalized_normalVS(vec3 sampledNormal) 98 | { 99 | mat4 vmMatrix = uboMatUsr.mViewMatrix * fs_in.modelMatrix; 100 | mat3 vmNormalMatrix = mat3(inverse(transpose(vmMatrix))); 101 | 102 | // build the TBN matrix from the varyings 103 | vec3 normalOS = normalize(fs_in.normalOS); 104 | vec3 tangentOS = re_orthogonalize(fs_in.tangentOS, normalOS); 105 | vec3 bitangentOS = re_orthogonalize(fs_in.bitangentOS, normalOS); 106 | 107 | mat3 matrixTStoOS = inverse(transpose(mat3(tangentOS, bitangentOS, normalOS))); 108 | 109 | // sample the normal from the normal map and bring it into view space 110 | vec3 normalSample = normalize(sampledNormal * 2.0 - 1.0); 111 | 112 | uint matIndex = fs_in.materialIndex; 113 | float normalMappingStrengthFactor = 1.0f - materialsBuffer.materials[matIndex].mCustomData[2]; 114 | 115 | float userDefinedDisplacementStrength = uboMatUsr.mUserInput[1]; 116 | normalSample.xy *= userDefinedDisplacementStrength * normalMappingStrengthFactor; 117 | 118 | vec3 normalVS = vmNormalMatrix * matrixTStoOS * normalSample; 119 | 120 | return normalize(normalVS); 121 | } 122 | 123 | // ------------------------------------------------------- 124 | 125 | // ###### FRAGMENT SHADER MAIN ############################# 126 | void main() 127 | { 128 | // simple alpha-testing (no blending) in the deferred shader only 129 | float alpha = sample_from_diffuse_texture().a; 130 | if (alpha < uboMatUsr.mUserInput.w) { discard; return; } 131 | 132 | vec3 normalVS = calc_normalized_normalVS(sample_from_normals_texture().rgb); 133 | float l = length(normalVS.xy); 134 | vec2 sphericalVS = vec2((l == 0) ? 0 : acos(clamp(normalVS.x / l, -1, 1)), asin(normalVS.z)); 135 | if (normalVS.y < 0) sphericalVS.x = TAU - sphericalVS.x; 136 | oFragUvNrm = vec4(fs_in.texCoords, sphericalVS); 137 | oFragMatId = (fs_in.materialIndex + 1) | (fs_in.movingObjectId != 0 ? 0x80000000 : 0); 138 | 139 | // calculate and write velocity 140 | vec3 positionNDC = fs_in.positionCS.xyz / fs_in.positionCS.w; 141 | vec3 positionNDC_prev = fs_in.positionCS_prev.xyz / fs_in.positionCS_prev.w; 142 | // adjust for jitter! 143 | positionNDC.xy -= uboMatUsr.mJitterCurrentPrev.xy; 144 | positionNDC_prev.xy -= uboMatUsr.mJitterCurrentPrev.zw; 145 | vec3 motionVector = (positionNDC - positionNDC_prev) * vec3(0.5, 0.5, 1.0); // TODO: check if z scale is ok 146 | oFragVelocity = vec4(motionVector, fs_in.movingObjectId); 147 | } 148 | // ------------------------------------------------------- 149 | 150 | -------------------------------------------------------------------------------- /shaders/build_scene_buffers.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | 4 | #include "shader_cpu_common.h" 5 | 6 | // --- input 7 | layout(push_constant) uniform BuildSceneBuffersPushConstants { 8 | uint frustum; // 0 = main camera, 1 - 5 = shadow cascades 9 | } pushc; 10 | 11 | layout(set = 0, binding = 0) uniform CullingUniforms { 12 | uint numMeshgroups; 13 | uint numInstances; 14 | uint numFrusta; 15 | uint drawcmdbuf_FirstTransparentIndex; // index (not offset!) where transparent draw commands start in the DrawCommandsBuffer 16 | vec4 frustumPlanes[5*6]; // frustum planes, 6 per frustum (frustum #0 = main camera, #1 - #5 = shadow cascades) 17 | } ubo; 18 | 19 | struct MeshgroupBasicInfoGpu { 20 | uint materialIndex; 21 | uint numInstances; 22 | uint numIndices; 23 | uint baseIndex; 24 | bool transparent; 25 | // pad? 26 | }; 27 | 28 | layout (std430, set = 0, binding = 1) readonly buffer CullingVisibilityBuffer { uint visible[]; }; // for total # instances; bits 0..5 correspond to different frusta 29 | layout (std430, set = 0, binding = 2) readonly buffer MeshgroupInfoBuffer { MeshgroupBasicInfoGpu mg_info[]; }; // for total # meshgroups (opaque + transparent) 30 | 31 | // --- output 32 | struct VkDrawIndexedIndirectCommand { 33 | uint indexCount; 34 | uint instanceCount; 35 | uint firstIndex; 36 | int vertexOffset; 37 | uint firstInstance; 38 | }; 39 | 40 | struct DrawnMeshgroupData { 41 | uint materialIndex; // material index 42 | uint meshIndexBase; // index of first mesh of the group in MeshAttribOffsetBuffer 43 | }; 44 | 45 | layout (std430, set = 0, binding = 3) writeonly buffer DrawnMeshgroupBuffer { DrawnMeshgroupData drawn_meshgroup_data[]; }; // per drawn meshgroup, indexed via glDrawId (dynamic) 46 | layout (std430, set = 0, binding = 4) writeonly buffer DrawnMeshAttribIndexBuffer { uint attrib_index[]; }; // per drawn mesh: index for AttributesBuffer (dynamic) 47 | layout (std430, set = 0, binding = 5) writeonly buffer MeshgroupsLayoutInfoBuffer { uint transparentMeshgroupsOffset; }; // first transparent meshgroup index (dynamic) 48 | layout (std430, set = 0, binding = 6) writeonly buffer DrawCommandsBuffer { VkDrawIndexedIndirectCommand cmd[]; } drawcmd; 49 | layout (std430, set = 0, binding = 7) writeonly buffer DrawCountBuffer { uint cnt[2]; } drawcount; 50 | 51 | // ################## COMPUTE SHADER MAIN ################### 52 | layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in; 53 | void main() { 54 | uint visMask = 1 << pushc.frustum; 55 | uint globMeshCount = 0; 56 | uint attribIndexCnt = 0; 57 | uint cmdCnt = 0, cmdCntOpaque = 0, cmdCntTransp = 0; 58 | for (uint iMg = 0; iMg < ubo.numMeshgroups; ++iMg) { 59 | MeshgroupBasicInfoGpu mg = mg_info[iMg]; 60 | 61 | uint globMeshFirstId = globMeshCount; 62 | globMeshCount += mg.numInstances; 63 | 64 | DrawnMeshgroupData drawnMgData; 65 | drawnMgData.materialIndex = mg.materialIndex; 66 | drawnMgData.meshIndexBase = attribIndexCnt; 67 | 68 | uint numVisInstances = 0; 69 | for (uint iLocalInst = 0; iLocalInst < mg.numInstances; ++iLocalInst) { 70 | uint currentInstanceGlobalId = globMeshFirstId + iLocalInst; 71 | if ((visible[currentInstanceGlobalId] & visMask) != 0) { 72 | // instance is visible 73 | numVisInstances++; 74 | attrib_index[attribIndexCnt] = currentInstanceGlobalId; 75 | attribIndexCnt++; 76 | } 77 | } 78 | 79 | if (numVisInstances > 0) { 80 | drawn_meshgroup_data[cmdCnt] = drawnMgData; 81 | 82 | VkDrawIndexedIndirectCommand cmd; 83 | cmd.indexCount = mg.numIndices; 84 | cmd.instanceCount = numVisInstances; 85 | cmd.firstIndex = mg.baseIndex; 86 | cmd.vertexOffset = 0; // already taken care of 87 | cmd.firstInstance = 0; 88 | 89 | if (mg.transparent) { 90 | drawcmd.cmd[ubo.drawcmdbuf_FirstTransparentIndex + cmdCntTransp] = cmd; 91 | cmdCntTransp++; 92 | } else { 93 | drawcmd.cmd[cmdCntOpaque] = cmd; 94 | cmdCntOpaque++; 95 | } 96 | 97 | cmdCnt++; 98 | } 99 | } 100 | 101 | drawcount.cnt[0] = cmdCntOpaque; 102 | drawcount.cnt[1] = cmdCntTransp; 103 | 104 | transparentMeshgroupsOffset = cmdCntOpaque; // offset in DrawnMeshgroupBuffer (not in DrawCommandsBuffer(!), offset is fixed there) 105 | } 106 | 107 | 108 | -------------------------------------------------------------------------------- /shaders/calc_shadows.glsl: -------------------------------------------------------------------------------- 1 | //? #version 460 2 | //? #extension GL_EXT_nonuniform_qualifier : require 3 | // all the // ? lines are just for the VS GLSL language integration plugin 4 | 5 | #ifndef CALC_SHADOWS_INCLUDED 6 | #define CALC_SHADOWS_INCLUDED 1 7 | 8 | #include "shader_common_main.glsl" 9 | #include "shader_cpu_common.h" 10 | 11 | //? layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 12 | #if ENABLE_SHADOWMAP 13 | //? layout(set = SHADOWMAP_BINDING_SET, binding = SHADOWMAP_BINDING_SLOT) uniform sampler2DShadow shadowMap[]; 14 | #endif 15 | 16 | int gDebugShadowCascade = -1; 17 | float calc_shadow_factor(in vec4 positionWS) { 18 | #if ENABLE_SHADOWMAP 19 | if (!uboMatUsr.mUseShadowMap) return 1.0; 20 | 21 | // find cascade to use // TODO - optimize 22 | int cascade = uboMatUsr.mShadowNumCascades-1; 23 | for (int i = 0; i < uboMatUsr.mShadowNumCascades-1; ++i) { 24 | if (gl_FragCoord.z < uboMatUsr.mShadowMapMaxDepth[i]) { 25 | cascade = i; 26 | break; 27 | } 28 | } 29 | gDebugShadowCascade = cascade; 30 | 31 | 32 | float light = 1.0; 33 | 34 | vec4 p = uboMatUsr.mShadowmapProjViewMatrix[cascade] * positionWS; 35 | p /= p.w; // no w-division should be needed if light proj is ortho... but .w could be off due to bone transforms (?), so do it anyway 36 | p.xy = p.xy * .5 + .5; 37 | if (all(greaterThanEqual(p.xyz, vec3(0))) && all(lessThan(p.xyz, vec3(1)))) { 38 | p.z -= uboMatUsr.mShadowBias; // FIXME - using manual bias for now 39 | light = texture(shadowMap[cascade], p.xyz); 40 | light = 1.0 - (1.0 - light) * SHADOW_OPACITY; 41 | } 42 | 43 | return light; 44 | #else 45 | return 1.0; 46 | #endif 47 | } 48 | 49 | vec4 debug_shadow_cascade_color() { 50 | vec3 cascCol; 51 | if (gDebugShadowCascade < 0) cascCol = vec3(1); 52 | else if (gDebugShadowCascade == 0) cascCol = vec3(0, 1, 0); 53 | else if (gDebugShadowCascade == 1) cascCol = vec3(1, 1, 0); 54 | else if (gDebugShadowCascade == 2) cascCol = vec3(0.6, 0.6, 1); 55 | else cascCol = vec3(1, 0.6, 1); 56 | return vec4(cascCol,1); 57 | } 58 | 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /shaders/draw_frustum.frag: -------------------------------------------------------------------------------- 1 | #version 460 2 | 3 | layout (location = 0) in vec3 in_color; 4 | layout (location = 0) out vec4 oFragColor; 5 | 6 | void main() { 7 | oFragColor = vec4(in_color, 1); 8 | } 9 | -------------------------------------------------------------------------------- /shaders/draw_frustum.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | // ------------------------------------------------------- 4 | 5 | #include "shader_common_main.glsl" 6 | #include "shader_cpu_common.h" 7 | 8 | // no vertex input 9 | // shader is called with vertex count 12 * 2 * 5; to be rendered as line list (4 light cameras + debug camera) 10 | 11 | 12 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 13 | 14 | layout (location = 0) out vec3 out_color; 15 | 16 | void main() { 17 | const float zmin = 0; 18 | const float zmax = 1; 19 | vec3 coord[8] = { 20 | {-1,-1,zmin}, {-1,1,zmin}, {1,1,zmin}, {1,-1,zmin}, 21 | {-1,-1,zmax}, {-1,1,zmax}, {1,1,zmax}, {1,-1,zmax} 22 | }; 23 | ivec2 lines[12] = { 24 | {0,1}, {1,2}, {2,3}, {3,0}, // near plane 25 | {4,5}, {5,6}, {6,7}, {7,4}, // far plane 26 | {0,4}, {1,5}, {2,6}, {3,7} // sides 27 | }; 28 | vec3 cascCol[5] = { 29 | {0, 1, 0}, 30 | {1, 1, 0}, 31 | {0.6, 0.6, 1}, 32 | {1, 0.6, 1}, 33 | {1, 0, 1} 34 | }; 35 | 36 | int vertId = gl_VertexIndex; 37 | int cascade = vertId / 24; 38 | vertId %= 24; 39 | 40 | if (cascade < 4 && cascade >= uboMatUsr.mShadowNumCascades) { 41 | out_color = vec3(0); 42 | gl_Position = vec4(2,2,2,1); 43 | return; 44 | } 45 | 46 | mat4 invPV; 47 | if (cascade < 4) { 48 | invPV = inverse(uboMatUsr.mShadowmapProjViewMatrix[cascade]); 49 | } else { 50 | invPV = inverse(uboMatUsr.mDebugCamProjViewMatrix); 51 | } 52 | 53 | 54 | int lineId = vertId / 2; 55 | int pointId = vertId % 2; 56 | vec3 ndc = coord[lines[lineId][pointId]]; 57 | 58 | vec4 world = invPV * vec4(ndc, 1.); 59 | gl_Position = uboMatUsr.mProjMatrix * uboMatUsr.mViewMatrix * world; 60 | out_color = cascCol[cascade]; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /shaders/draw_shadowmap.frag: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_nonuniform_qualifier : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | // ------------------------------------------------------- 5 | 6 | #include "shader_common_main.glsl" 7 | #include "shader_cpu_common.h" 8 | 9 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 10 | layout(set = SHADOWMAP_BINDING_SET, binding = SHADOWMAP_BINDING_SLOT) uniform texture2D texShadowMap[]; 11 | layout(set = 5, binding = 0) uniform sampler uSampler; 12 | 13 | layout (location = 0) out vec4 oFragColor; 14 | 15 | layout (location = 0) in VertexData { 16 | vec2 texCoords; 17 | } f_in; 18 | 19 | void main() { 20 | //oFragColor = vec4(vec3(texture(sampler2D(texShadowMap[0], uSampler), f_in.texCoords).r), 1.0); 21 | vec2 uv; 22 | int cascade; 23 | if (f_in.texCoords.x < 0.5 && f_in.texCoords.y < 0.5) { 24 | cascade = 0; 25 | uv = f_in.texCoords * 2.0; 26 | } else if (f_in.texCoords.x >= 0.5 && f_in.texCoords.y < 0.5) { 27 | cascade = 1; 28 | uv = (f_in.texCoords - vec2(0.5, 0.0)) * 2.0; 29 | } else if (f_in.texCoords.x < 0.5 && f_in.texCoords.y >= 0.5) { 30 | cascade = 2; 31 | uv = (f_in.texCoords - vec2(0.0, 0.5)) * 2.0; 32 | } else { 33 | cascade = 3; 34 | uv = (f_in.texCoords - vec2(0.5, 0.5)) * 2.0; 35 | } 36 | if (cascade < uboMatUsr.mShadowNumCascades) { 37 | oFragColor = vec4(vec3(texture(sampler2D(texShadowMap[cascade], uSampler), vec2(uv.x, 1-uv.y)).r), 1.0); // flip y (if shadow cam is oriented upside down) 38 | //oFragColor = vec4(vec3(texture(sampler2D(texShadowMap[cascade], uSampler), uv).r), 1.0); 39 | } else { 40 | oFragColor = vec4(0,0,0,1); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /shaders/draw_shadowmap.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | // ------------------------------------------------------- 4 | 5 | // ###### VERTEX SHADER/PIPELINE INPUT DATA ############## 6 | // Several vertex attributes (These are the buffers passed 7 | // to command_buffer_t::draw_indexed in the same order): 8 | layout (location = 0) in vec3 aPosition; 9 | layout (location = 1) in vec2 aTexCoords; 10 | 11 | // ###### DATA PASSED ON ALONG THE PIPELINE ############## 12 | // Data from vert -> tesc or frag: 13 | layout (location = 0) out VertexData { 14 | vec2 texCoords; 15 | } v_out; 16 | // ------------------------------------------------------- 17 | 18 | // ###### VERTEX SHADER MAIN ############################# 19 | void main() 20 | { 21 | v_out.texCoords = aTexCoords; 22 | gl_Position = vec4(aPosition, 1.0); 23 | } 24 | // ------------------------------------------------------- 25 | 26 | -------------------------------------------------------------------------------- /shaders/drawpath.frag: -------------------------------------------------------------------------------- 1 | #version 460 2 | 3 | layout (location = 0) in flat float controlPointId; 4 | 5 | layout (location = 0) out vec4 oFragColor; 6 | 7 | void main() { 8 | if (controlPointId > 0) { 9 | oFragColor = vec4(0,1,0,1); 10 | } else { 11 | oFragColor = vec4(1,0,0,1); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /shaders/drawpath.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | // ------------------------------------------------------- 4 | 5 | #include "shader_common_main.glsl" 6 | 7 | layout (location = 0) in vec4 aPositionAndId; 8 | 9 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 10 | 11 | layout (location = 0) out flat float controlPointId; 12 | 13 | void main() { 14 | gl_Position = uboMatUsr.mProjMatrix * uboMatUsr.mViewMatrix * vec4(aPositionAndId.xyz, 1.0); 15 | controlPointId = aPositionAndId.w; 16 | gl_PointSize = (controlPointId > 0) ? 10.0 : 5.0; 17 | } 18 | -------------------------------------------------------------------------------- /shaders/frustum_culling.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | 4 | #include "shader_cpu_common.h" 5 | 6 | // ------------------------------------------------------- 7 | 8 | struct CullingBoundingBox { vec4 minPos, maxPos; }; // only .xyz used 9 | 10 | layout(set = 0, binding = 0) uniform CullingUniforms { 11 | uint numMeshgroups; 12 | uint numInstances; 13 | uint numFrusta; 14 | uint drawcmdbuf_FirstTransparentIndex; // index (not offset!) where transparent draw commands start in the DrawCommandsBuffer 15 | vec4 frustumPlanes[5*6]; // frustum planes, 6 per frustum (frustum #0 = main camera, #1 - #5 = shadow cascades) 16 | } ubo; 17 | 18 | layout (std430, set = 0, binding = 1) writeonly buffer CullingVisibilityBuffer { uint visible[]; } result; // for total # instances; bits 0..5 correspond to different frusta 19 | layout (std430, set = 0, binding = 2) readonly buffer CullingBoundingBoxBuffer{ CullingBoundingBox boundingBox[]; }; // for total # instances 20 | 21 | 22 | // ###### HELPER FUNCTIONS ############################### 23 | 24 | // FrustumAABBIntersect code adapted from https://gist.github.com/Kinwailo 25 | // Returns: INTERSECT : 0 26 | // INSIDE : 1 27 | // OUTSIDE : 2 28 | int FrustumAABBIntersect(vec3 mins, vec3 maxs, uint planeBase) { 29 | int ret = 1; // INSIDE 30 | vec3 vmin, vmax; 31 | 32 | for(uint i = planeBase; i < planeBase + 6; ++i) { 33 | if(ubo.frustumPlanes[i].x > 0) { vmin.x = mins.x; vmax.x = maxs.x; } else { vmin.x = maxs.x; vmax.x = mins.x; } // X axis 34 | if(ubo.frustumPlanes[i].y > 0) { vmin.y = mins.y; vmax.y = maxs.y; } else { vmin.y = maxs.y; vmax.y = mins.y; } // Y axis 35 | if(ubo.frustumPlanes[i].z > 0) { vmin.z = mins.z; vmax.z = maxs.z; } else { vmin.z = maxs.z; vmax.z = mins.z; } // Z axis 36 | if(dot(ubo.frustumPlanes[i].xyz, vmin) + ubo.frustumPlanes[i].w > 0) return 2; // OUTSIDE 37 | if(dot(ubo.frustumPlanes[i].xyz, vmax) + ubo.frustumPlanes[i].w >= 0) ret = 0; // INTERSECT 38 | } 39 | return ret; 40 | } 41 | 42 | // ################## COMPUTE SHADER MAIN ################### 43 | layout(local_size_x = GPU_FRUSTUM_CULLING_WORKGROUP_SIZE, local_size_y = 1, local_size_z = 1) in; 44 | void main() { 45 | uint instance = gl_GlobalInvocationID.x; 46 | if (instance >= ubo.numInstances) return; 47 | 48 | if (ubo.numFrusta == 0) { 49 | // just for debugging: disable culling, set everything visible 50 | result.visible[instance] = 0x1f; 51 | return; 52 | } 53 | 54 | uint allVisible = 0; 55 | uint planeBase = 0; 56 | for (int frustum = 0; frustum < ubo.numFrusta; ++frustum, planeBase += 6) { 57 | CullingBoundingBox bb = boundingBox[instance]; 58 | bool isVisible = (2 != FrustumAABBIntersect(bb.minPos.xyz, bb.maxPos.xyz, planeBase)); 59 | 60 | if (isVisible) allVisible |= (1 << frustum); 61 | } 62 | 63 | result.visible[instance] = allVisible; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /shaders/lighting_pass.frag: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_nonuniform_qualifier : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | // ------------------------------------------------------- 5 | 6 | #include "shader_common_main.glsl" 7 | #include "shader_cpu_common.h" 8 | 9 | // ###### MATERIAL DATA ################################## 10 | // The actual material buffer (of type MaterialGpuData): 11 | // It is bound to descriptor set at index 0 and 12 | // within the descriptor set, to binding location 0 13 | layout(set = 0, binding = 0) BUFFERDEF_Material materialsBuffer; 14 | 15 | // Array of samplers containing all the material's images: 16 | // These samplers are referenced from materials by 17 | // index, namely by all those m*TexIndex members. 18 | layout(set = 0, binding = 1) uniform sampler2D textures[]; 19 | // ------------------------------------------------------- 20 | 21 | // ###### PIPELINE INPUT DATA ############################ 22 | 23 | // "mMatrices" uniform buffer containing camera matrices: 24 | // It is updated every frame. 25 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 26 | 27 | // "mLightsources" uniform buffer containing all the light source data: 28 | layout(set = 1, binding = 1) UNIFORMDEF_LightsourceData uboLights; 29 | 30 | #if ENABLE_SHADOWMAP 31 | layout(set = SHADOWMAP_BINDING_SET, binding = SHADOWMAP_BINDING_SLOT) uniform sampler2DShadow shadowMap[]; 32 | #endif 33 | 34 | // ------------------------------------------------------- 35 | 36 | // include shadow calculation after uniforms are defined 37 | #include "calc_shadows.glsl" 38 | 39 | // ------------------------------------------------------- 40 | 41 | // ###### FRAG INPUT ##################################### 42 | layout (location = 0) in VertexData 43 | { 44 | vec2 texCoords; // texture coordinates 45 | } fs_in; 46 | layout (input_attachment_index = 0, set = 2, binding = 0) uniform subpassInput iDepth; 47 | layout (input_attachment_index = 1, set = 2, binding = 1) uniform subpassInput iUvNrm; 48 | layout (input_attachment_index = 2, set = 2, binding = 2) uniform usubpassInput iMatId; 49 | // ------------------------------------------------------- 50 | 51 | // ###### FRAG OUTPUT #################################### 52 | layout (location = 0) out vec4 oFragColor; 53 | // ------------------------------------------------------- 54 | 55 | // ###### HELPER FUNCTIONS ############################### 56 | vec4 sample_from_diffuse_texture(int matIndex, vec2 uv) 57 | { 58 | int texIndex = materialsBuffer.materials[matIndex].mDiffuseTexIndex; 59 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mDiffuseTexOffsetTiling; 60 | vec2 texCoords = uv * offsetTiling.zw + offsetTiling.xy; 61 | return SAMPLE_TEXTURE(textures[texIndex], texCoords); 62 | } 63 | 64 | vec4 sample_from_specular_texture(int matIndex, vec2 uv) 65 | { 66 | int texIndex = materialsBuffer.materials[matIndex].mSpecularTexIndex; 67 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mSpecularTexOffsetTiling; 68 | vec2 texCoords = uv * offsetTiling.zw + offsetTiling.xy; 69 | return SAMPLE_TEXTURE(textures[texIndex], texCoords); 70 | } 71 | 72 | vec4 sample_from_emissive_texture(int matIndex, vec2 uv) // ac 73 | { 74 | int texIndex = materialsBuffer.materials[matIndex].mEmissiveTexIndex; 75 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mEmissiveTexOffsetTiling; 76 | vec2 texCoords = uv * offsetTiling.zw + offsetTiling.xy; 77 | return SAMPLE_TEXTURE(textures[texIndex], texCoords); 78 | } 79 | 80 | // Calculates the light attenuation dividend for the given attenuation vector. 81 | // @param atten attenuation data 82 | // @param dist distance 83 | // @param dist2 squared distance 84 | float calc_attenuation(vec4 atten, float dist, float dist2) 85 | { 86 | return atten[0] + atten[1] * dist + atten[2] * dist2; 87 | } 88 | 89 | // Calculates the diffuse and specular illumination contribution for the given 90 | // parameters according to the Blinn-Phong lighting model. 91 | // All parameters must be normalized. 92 | vec3 calc_blinn_phong_contribution(vec3 toLight, vec3 toEye, vec3 normal, vec3 diffFactor, vec3 specFactor, float specShininess) 93 | { 94 | float nDotL = max(0.0, dot(normal, toLight)); // lambertian coefficient 95 | vec3 h = normalize(toLight + toEye); 96 | float nDotH = max(0.0, dot(normal, h)); 97 | float specPower = (nDotH == 0 && specShininess == 0) ? 1 : pow(nDotH, specShininess); 98 | 99 | vec3 diffuse = diffFactor * nDotL; // component-wise product 100 | vec3 specular = specFactor * specPower; 101 | 102 | return diffuse + specular; 103 | } 104 | 105 | // Calculates the diffuse and specular illumination contribution for all the light sources. 106 | // All calculations are performed in view space 107 | vec3 calc_illumination_in_vs(vec3 posVS, vec3 normalVS, vec3 diff, vec3 spec, float shini) 108 | { 109 | vec3 diffAndSpec = vec3(0.0, 0.0, 0.0); 110 | 111 | // Calculate shading in view space since all light parameters are passed to the shader in view space 112 | vec3 eyePosVS = vec3(0.0, 0.0, 0.0); 113 | vec3 toEyeNrmVS = normalize(eyePosVS - posVS); 114 | 115 | // directional lights 116 | for (uint i = uboLights.mRangesAmbientDirectional[2]; i < uboLights.mRangesAmbientDirectional[3]; ++i) { 117 | vec3 toLightDirVS = normalize(-uboLights.mLightData[i].mDirection.xyz); 118 | vec3 dirLightIntensity = uboLights.mLightData[i].mColor.rgb; 119 | diffAndSpec += dirLightIntensity * calc_blinn_phong_contribution(toLightDirVS, toEyeNrmVS, normalVS, diff, spec, shini); 120 | } 121 | 122 | // point lights 123 | for (uint i = uboLights.mRangesPointSpot[0]; i < uboLights.mRangesPointSpot[1]; ++i) 124 | { 125 | vec3 lightPosVS = uboLights.mLightData[i].mPosition.xyz; 126 | vec3 toLight = lightPosVS - posVS; 127 | float distSq = dot(toLight, toLight); 128 | float dist = sqrt(distSq); 129 | vec3 toLightNrm = toLight / dist; 130 | 131 | float atten = calc_attenuation(uboLights.mLightData[i].mAttenuation, dist, distSq); 132 | vec3 intensity = uboLights.mLightData[i].mColor.rgb / atten; 133 | 134 | diffAndSpec += intensity * calc_blinn_phong_contribution(toLightNrm, toEyeNrmVS, normalVS, diff, spec, shini); 135 | } 136 | 137 | // spot lights 138 | for (uint i = uboLights.mRangesPointSpot[2]; i < uboLights.mRangesPointSpot[3]; ++i) 139 | { 140 | vec3 lightPosVS = uboLights.mLightData[i].mPosition.xyz; 141 | vec3 toLight = lightPosVS - posVS; 142 | float distSq = dot(toLight, toLight); 143 | float dist = sqrt(distSq); 144 | vec3 toLightNrm = toLight / dist; 145 | 146 | float atten = calc_attenuation(uboLights.mLightData[i].mAttenuation, dist, distSq); 147 | vec3 intensity = uboLights.mLightData[i].mColor.rgb / atten; 148 | 149 | vec3 dirVS = uboLights.mLightData[i].mDirection.xyz; 150 | float cosOfHalfOuter = uboLights.mLightData[i].mAnglesFalloff[0]; 151 | float cosOfHalfInner = uboLights.mLightData[i].mAnglesFalloff[1]; 152 | float falloff = uboLights.mLightData[i].mAnglesFalloff[2]; 153 | float cosAlpha = dot(-toLightNrm, dirVS); 154 | float da = cosAlpha - cosOfHalfOuter; 155 | float fade = cosOfHalfInner - cosOfHalfOuter; 156 | intensity *= da <= 0.0 ? 0.0 : pow(min(1.0, da / max(0.0001, fade)), falloff); 157 | 158 | diffAndSpec += intensity * calc_blinn_phong_contribution(toLightNrm, toEyeNrmVS, normalVS, diff, spec, shini); 159 | } 160 | 161 | return diffAndSpec; 162 | } 163 | // ------------------------------------------------------- 164 | 165 | // ###### VERTEX SHADER MAIN ############################# 166 | void main() 167 | { 168 | float depth = subpassLoad(iDepth).r; 169 | vec4 uvNormal = subpassLoad(iUvNrm).rgba; 170 | int matIndex = int(subpassLoad(iMatId).r); 171 | 172 | if (depth == 1) discard; 173 | 174 | // unpack uv and normal 175 | vec2 uv = uvNormal.rg; 176 | vec3 normalVS = vec3(cos(uvNormal.z) * cos(uvNormal.w), sin(uvNormal.z) * cos(uvNormal.w), sin(uvNormal.w)); 177 | 178 | // reconstruct position from depth buffer 179 | vec4 clipSpace = vec4(fs_in.texCoords * 2 - 1, depth, 1); 180 | vec4 viewSpace = inverse(uboMatUsr.mProjMatrix) * clipSpace; 181 | vec3 positionVS = viewSpace.xyz / viewSpace.w; 182 | 183 | #if ENABLE_SHADOWMAP 184 | vec4 worldSpace = inverse(uboMatUsr.mViewMatrix) * viewSpace; 185 | worldSpace /= worldSpace.w; 186 | float shadowFactor = calc_shadow_factor(worldSpace); 187 | #else 188 | float shadowFactor = 1.0; 189 | #endif 190 | 191 | vec3 diffTexColor = sample_from_diffuse_texture(matIndex, uv).rgb; 192 | float specTexValue = sample_from_specular_texture(matIndex, uv).r; 193 | vec3 emissiveTexColor = sample_from_emissive_texture(matIndex, uv).rgb; // ac 194 | 195 | // ac: hack, because emissiveTexColor is white now, if there is no texture assigned 196 | //if (emissiveTexColor == vec3(1)) emissiveTexColor = vec3(0); 197 | 198 | // Initialize all the colors: 199 | vec3 ambient = materialsBuffer.materials[matIndex].mAmbientReflectivity.rgb * diffTexColor; 200 | //vec3 emissive = materialsBuffer.materials[matIndex].mEmissiveColor.rgb; 201 | vec3 emissive = materialsBuffer.materials[matIndex].mEmissiveColor.rgb * emissiveTexColor; // ac 202 | //vec3 emissive = emissiveTexColor; // ac 203 | vec3 diff = materialsBuffer.materials[matIndex].mDiffuseReflectivity.rgb * diffTexColor; 204 | vec3 spec = materialsBuffer.materials[matIndex].mSpecularReflectivity.rgb * specTexValue; 205 | float shininess = materialsBuffer.materials[matIndex].mShininess; 206 | 207 | // Calculate ambient illumination: 208 | vec3 ambientIllumination = vec3(0.0, 0.0, 0.0); 209 | for (uint i = uboLights.mRangesAmbientDirectional[0]; i < uboLights.mRangesAmbientDirectional[1]; ++i) { 210 | ambientIllumination += uboLights.mLightData[i].mColor.rgb * ambient; 211 | } 212 | 213 | // Calculate diffuse and specular illumination from all light sources: 214 | vec3 diffAndSpecIllumination = calc_illumination_in_vs(positionVS, normalVS, diff, spec, shininess); 215 | 216 | // Add all together: 217 | //vec4 blinnPhongColor = vec4(shadowFactor * vec3(ambientIllumination + emissive + diffAndSpecIllumination), 1.0); 218 | vec4 blinnPhongColor = vec4(vec3(ambientIllumination + emissive + shadowFactor * diffAndSpecIllumination), 1.0); 219 | 220 | 221 | if (uboMatUsr.mUserInput.z < 1.f) { 222 | oFragColor = blinnPhongColor; 223 | } else if (uboMatUsr.mUserInput.z < 2.f) { 224 | // don't use lights 225 | oFragColor = vec4(diff, 1.0); 226 | } else if (uboMatUsr.mUserInput.z < 3.f) { 227 | // Debug: SM cascade 228 | oFragColor = debug_shadow_cascade_color() * blinnPhongColor; 229 | } else { 230 | // other debug modes not used here 231 | oFragColor = vec4(1,0,1,1); 232 | } 233 | } 234 | // ------------------------------------------------------- 235 | 236 | -------------------------------------------------------------------------------- /shaders/lighting_pass.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | // ------------------------------------------------------- 4 | 5 | // ###### VERTEX SHADER/PIPELINE INPUT DATA ############## 6 | // Several vertex attributes (These are the buffers passed 7 | // to command_buffer_t::draw_indexed in the same order): 8 | layout (location = 0) in vec3 aPosition; 9 | layout (location = 1) in vec2 aTexCoords; 10 | 11 | // ###### DATA PASSED ON ALONG THE PIPELINE ############## 12 | // Data from vert -> tesc or frag: 13 | layout (location = 0) out VertexData { 14 | vec2 texCoords; 15 | } v_out; 16 | // ------------------------------------------------------- 17 | 18 | // ###### VERTEX SHADER MAIN ############################# 19 | void main() 20 | { 21 | v_out.texCoords = aTexCoords; 22 | gl_Position = vec4(aPosition, 1.0); 23 | } 24 | // ------------------------------------------------------- 25 | 26 | -------------------------------------------------------------------------------- /shaders/post_process.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_samplerless_texture_functions : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_cpu_common.h" 6 | 7 | // ###### SRC/DST IMAGES ################################# 8 | layout(set = 0, binding = 1) uniform texture2D uInputFrame; 9 | layout(set = 0, binding = 2) uniform texture2D uDebugFrame; 10 | layout(set = 0, binding = 3, TAA_SHADER_FORMAT_POSTPROCESS) writeonly uniform restrict image2D uOutput; 11 | // ------------------------------------------------------- 12 | 13 | // ###### PUSH CONSTANTS AND UBOs ######################## 14 | layout(push_constant) uniform PushConstants { 15 | ivec4 zoomSrcLTWH; 16 | ivec4 zoomDstLTWH; 17 | vec4 debugL_mask; 18 | vec4 debugR_mask; 19 | bool zoom; 20 | bool showZoomBox; 21 | int splitX; 22 | bool debugL_show; 23 | bool debugR_show; 24 | } pushConstants; 25 | 26 | // ------------------------------------------------------- 27 | 28 | // ################## COMPUTE SHADER MAIN ################### 29 | layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; 30 | void main() 31 | { 32 | ivec2 iuv = ivec2(gl_GlobalInvocationID.xy); 33 | if (any(greaterThanEqual(iuv, textureSize(uInputFrame, 0)))) return; 34 | 35 | vec2 uv = (vec2(iuv) + 0.5) / textureSize(uInputFrame, 0); 36 | 37 | ivec2 iuvFetchFrom = iuv; 38 | 39 | // splitscreen-splitter 40 | if (iuv.x == pushConstants.splitX) { 41 | imageStore(uOutput, iuv, vec4(0,0,0,0)); 42 | return; 43 | } 44 | 45 | // zoom source border box 46 | if (pushConstants.zoom && pushConstants.showZoomBox) { 47 | if ( ((iuv.x == pushConstants.zoomSrcLTWH.x - 1) || (iuv.x == pushConstants.zoomSrcLTWH.x + pushConstants.zoomSrcLTWH.z)) && (iuv.y >= pushConstants.zoomSrcLTWH.y - 1) && (iuv.y <= pushConstants.zoomSrcLTWH.y + pushConstants.zoomSrcLTWH.w) 48 | || ((iuv.y == pushConstants.zoomSrcLTWH.y - 1) || (iuv.y == pushConstants.zoomSrcLTWH.y + pushConstants.zoomSrcLTWH.w)) && (iuv.x >= pushConstants.zoomSrcLTWH.x - 1) && (iuv.x <= pushConstants.zoomSrcLTWH.x + pushConstants.zoomSrcLTWH.z) ) { 49 | imageStore(uOutput, iuv, vec4(1,0,0,0)); 50 | return; 51 | } 52 | } 53 | 54 | // zoom target 55 | if (pushConstants.zoom && all(greaterThanEqual(iuv, pushConstants.zoomDstLTWH.xy)) && all(lessThan(iuv, pushConstants.zoomDstLTWH.xy + pushConstants.zoomDstLTWH.zw))) { 56 | // target border 57 | if ( ((iuv.x == pushConstants.zoomDstLTWH.x) || (iuv.x == pushConstants.zoomDstLTWH.x + pushConstants.zoomDstLTWH.z - 1)) && (iuv.y >= pushConstants.zoomDstLTWH.y) && (iuv.y <= pushConstants.zoomDstLTWH.y + pushConstants.zoomDstLTWH.w - 1) 58 | || ((iuv.y == pushConstants.zoomDstLTWH.y) || (iuv.y == pushConstants.zoomDstLTWH.y + pushConstants.zoomDstLTWH.w - 1)) && (iuv.x >= pushConstants.zoomDstLTWH.x) && (iuv.x <= pushConstants.zoomDstLTWH.x + pushConstants.zoomDstLTWH.z - 1) ) { 59 | imageStore(uOutput, iuv, vec4(1,1,1,0)); 60 | return; 61 | } 62 | 63 | // scale range zoomDst to zoomSrc 64 | vec2 zoomUv = (iuv - pushConstants.zoomDstLTWH.xy + 0.5) / vec2(pushConstants.zoomDstLTWH.zw); 65 | iuvFetchFrom = ivec2(pushConstants.zoomSrcLTWH.xy + zoomUv * pushConstants.zoomSrcLTWH.zw); 66 | } 67 | 68 | // show data from input image or debug image 69 | bool leftside = (pushConstants.splitX < 0) || (iuv.x < pushConstants.splitX); 70 | bool showdebug; 71 | vec4 debugMask; 72 | if (leftside) { 73 | showdebug = pushConstants.debugL_show; 74 | debugMask = pushConstants.debugL_mask; 75 | } else { 76 | showdebug = pushConstants.debugR_show; 77 | debugMask = pushConstants.debugR_mask; 78 | } 79 | vec4 val; 80 | if (showdebug) { 81 | vec4 dbg = texelFetch(uDebugFrame, iuvFetchFrom, 0); 82 | val = vec4(dbg.rgb, 1); 83 | if (debugMask.a > 0) val.rb += dbg.a; // make alpha channel visible 84 | } else { 85 | val = texelFetch(uInputFrame, iuvFetchFrom, 0); 86 | } 87 | imageStore(uOutput, iuv, val); 88 | } 89 | 90 | -------------------------------------------------------------------------------- /shaders/rt_test.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_EXT_nonuniform_qualifier : require 4 | #extension GL_GOOGLE_include_directive : enable 5 | 6 | #include "shader_cpu_common.h" 7 | #include "shader_common_main.glsl" 8 | #include "shader_raytrace_common.glsl" 9 | 10 | layout(push_constant) PUSHCONSTANTSDEF_RAYTRACING pushConstants; 11 | 12 | layout(location = 0) rayPayloadInEXT MainRayPayload hitValue; 13 | layout(location = 1) rayPayloadEXT float shadowHitValue; 14 | 15 | layout(set = 0, binding = 0) BUFFERDEF_Material materialsBuffer; 16 | layout(set = 0, binding = 1) uniform sampler2D textures[]; 17 | layout(set = 0, binding = 2) uniform usamplerBuffer indexBuffers[]; // one index buffer per [meshgroupId]; contents of each buffer are in uvec3s 18 | layout(set = 0, binding = 3) uniform samplerBuffer texCoordsBuffers[]; // ditto, entries are vec2 19 | layout (std430, set = 0, binding = 4) readonly buffer MaterialIndexBuffer { uint materialIndices[]; }; 20 | layout(set = 0, binding = 5) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 21 | layout(set = 1, binding = 0, SHADER_FORMAT_RAYTRACE) uniform image2D image; 22 | layout(set = 2, binding = 0) uniform accelerationStructureEXT topLevelAS; 23 | layout(set = 0, binding = 6) uniform samplerBuffer normalsBuffers[]; // entries are vec3 24 | layout(set = 0, binding = 10) uniform samplerBuffer tangentsBuffers[]; // entries are vec3 25 | layout(set = 0, binding = 11) uniform samplerBuffer bitangentsBuffers[]; // entries are vec3 26 | layout(set = 0, binding = 14) uniform samplerBuffer positionsBuffers[]; // entries are vec3, positions in OS 27 | //layout (std430, set = 0, binding = 8) readonly buffer AnimObjNormalsBuffer { vec3 animObjNormals[]; }; // contains normals of all meshes of current anim object 28 | layout(set = 0, binding = 8) uniform samplerBuffer animObjNormals; // contains normals of all meshes of current anim object 29 | layout(set = 0, binding = 12) uniform samplerBuffer animObjTangents; 30 | layout(set = 0, binding = 13) uniform samplerBuffer animObjBitangents; 31 | layout(set = 0, binding = 15) uniform samplerBuffer animObjPositions; 32 | layout(std430, set = 0, binding = 9) readonly buffer AnimObjNTBOffsetBuffer { uint animObjNTBOff[]; }; // .[meshIndex] = start index in animObjNormals[] for mesh meshIndex of current anim object 33 | 34 | hitAttributeEXT vec2 bary2; 35 | 36 | mat3 matrixNormalsOStoWS; // matrix to bring normals from object to world space 37 | 38 | 39 | // ###### LOD APPROXIMATION ######################## 40 | #include "shader_raytrace_lod_approximation.glsl" 41 | // ------------------------------------------------------- 42 | 43 | 44 | vec4 sample_from_normals_texture(uint matIndex, vec2 uv) 45 | { 46 | int texIndex = materialsBuffer.materials[matIndex].mNormalsTexIndex; 47 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mNormalsTexOffsetTiling; 48 | vec2 texCoords = uv * offsetTiling.zw + offsetTiling.xy; 49 | vec4 normalSample = sampleTextureWithLodApprox(textures[texIndex], texCoords, pushConstants.mApproximateLodMaxAnisotropy); 50 | FIX_NORMALMAPPING(normalSample); 51 | return normalSample; 52 | } 53 | 54 | vec4 sample_from_diffuse_texture(uint matIndex, vec2 uv) 55 | { 56 | int texIndex = materialsBuffer.materials[matIndex].mDiffuseTexIndex; 57 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mDiffuseTexOffsetTiling; 58 | vec2 texCoords = uv * offsetTiling.zw + offsetTiling.xy; 59 | return sampleTextureWithLodApprox(textures[texIndex], texCoords, pushConstants.mApproximateLodMaxAnisotropy); 60 | } 61 | 62 | vec4 sample_from_specular_texture(uint matIndex, vec2 uv) 63 | { 64 | int texIndex = materialsBuffer.materials[matIndex].mSpecularTexIndex; 65 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mSpecularTexOffsetTiling; 66 | vec2 texCoords = uv * offsetTiling.zw + offsetTiling.xy; 67 | return sampleTextureWithLodApprox(textures[texIndex], texCoords, pushConstants.mApproximateLodMaxAnisotropy); 68 | } 69 | 70 | vec4 sample_from_emissive_texture(uint matIndex, vec2 uv) 71 | { 72 | int texIndex = materialsBuffer.materials[matIndex].mEmissiveTexIndex; 73 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mEmissiveTexOffsetTiling; 74 | vec2 texCoords = uv * offsetTiling.zw + offsetTiling.xy; 75 | return sampleTextureWithLodApprox(textures[texIndex], texCoords, pushConstants.mApproximateLodMaxAnisotropy); 76 | } 77 | 78 | 79 | // Calculates the diffuse and specular illumination contribution for the given 80 | // parameters according to the Blinn-Phong lighting model. 81 | // All parameters must be normalized. 82 | vec3 calc_blinn_phong_contribution(vec3 toLight, vec3 toEye, vec3 normal, vec3 diffFactor, vec3 specFactor, float specShininess, bool twoSided) 83 | { 84 | if (twoSided) { 85 | if (dot(normal, toEye) < 0) normal = -normal; // flip normal if it points away from us 86 | } 87 | 88 | float nDotL = max(0.0, dot(normal, toLight)); // lambertian coefficient 89 | vec3 h = normalize(toLight + toEye); 90 | float nDotH = max(0.0, dot(normal, h)); 91 | 92 | float specPower = (nDotH == 0 && specShininess == 0) ? 1 : pow(nDotH, specShininess); 93 | 94 | vec3 diffuse = diffFactor * nDotL; // component-wise product 95 | vec3 specular = specFactor * specPower; 96 | 97 | return diffuse + specular; 98 | } 99 | 100 | // Re-orthogonalizes the first vector w.r.t. the second vector (Gram-Schmidt process) 101 | vec3 re_orthogonalize(vec3 first, vec3 second) 102 | { 103 | return normalize(first - dot(first, second) * second); 104 | } 105 | 106 | // Calculates the normalized normal in world space by sampling the 107 | // normal from the normal map and transforming it with the TBN-matrix. 108 | // input vectors need to be normalized already 109 | vec3 calc_normalized_normalWS(vec3 sampledNormal, in vec3 normalOS, in vec3 tangentOS, in vec3 bitangentOS, uint matIndex) 110 | { 111 | // mat4 vmMatrix = uboMatUsr.mViewMatrix * fs_in.modelMatrix; 112 | // mat3 vmNormalMatrix = mat3(inverse(transpose(vmMatrix))); 113 | 114 | // build the TBN matrix from the varyings 115 | tangentOS = re_orthogonalize(tangentOS, normalOS); 116 | bitangentOS = re_orthogonalize(bitangentOS, normalOS); 117 | 118 | mat3 matrixTStoOS = inverse(transpose(mat3(tangentOS, bitangentOS, normalOS))); 119 | 120 | // sample the normal from the normal map and bring it into view space 121 | vec3 normalSample = normalize(sampledNormal * 2.0 - 1.0); 122 | 123 | float normalMappingStrengthFactor = 1.0f - materialsBuffer.materials[matIndex].mCustomData[2]; 124 | 125 | float userDefinedDisplacementStrength = pushConstants.mNormalMappingStrength; 126 | normalSample.xy *= userDefinedDisplacementStrength * normalMappingStrengthFactor; 127 | 128 | vec3 normalWS = matrixNormalsOStoWS * matrixTStoOS * normalSample; 129 | 130 | return normalize(normalWS); 131 | } 132 | 133 | #define INTERPOL_BARY(a_,b_,c_) ((a_) * barycentrics.x + (b_) * barycentrics.y + (c_) * barycentrics.z) 134 | #define INTERPOL_BARY_TEXELFETCH(tex_,indices_,swz_) INTERPOL_BARY(texelFetch((tex_), (indices_).x).swz_, texelFetch((tex_), (indices_).y).swz_, texelFetch((tex_), (indices_).z).swz_) 135 | 136 | void main() 137 | { 138 | matrixNormalsOStoWS = inverse(transpose(mat3(gl_ObjectToWorldEXT))); 139 | 140 | // which index buffer to use? -> meshgroupId (stored in geometry custom index) 141 | int meshgroupId = gl_InstanceCustomIndexEXT; 142 | 143 | // calc texture coordinates by interpolating barycentric coordinates 144 | const vec3 barycentrics = vec3(1.0 - bary2.x - bary2.y, bary2); 145 | ivec3 indices = ivec3(texelFetch(indexBuffers[meshgroupId], gl_PrimitiveID).xyz); // get the indices of the 3 triangle corners 146 | //vec2 uv = INTERPOL_BARY_TEXELFETCH(texCoordsBuffers[meshgroupId], indices, xy); // and interpolate 147 | // we need the 3 corner values later 148 | vec2 uv0 = texelFetch(texCoordsBuffers[meshgroupId], indices.x).xy; 149 | vec2 uv1 = texelFetch(texCoordsBuffers[meshgroupId], indices.y).xy; 150 | vec2 uv2 = texelFetch(texCoordsBuffers[meshgroupId], indices.z).xy; 151 | vec2 uv = INTERPOL_BARY(uv0, uv1, uv2); 152 | 153 | uint matIndex = materialIndices[meshgroupId]; 154 | 155 | // animated objects have their own buffers, so indices into those need to be adjusted 156 | bool isAnimObject = meshgroupId >= pushConstants.mAnimObjFirstMeshId && meshgroupId < (pushConstants.mAnimObjFirstMeshId + pushConstants.mAnimObjNumMeshes); 157 | ivec3 animObjIndices; 158 | if (isAnimObject) { 159 | int meshIndex = meshgroupId - pushConstants.mAnimObjFirstMeshId; 160 | animObjIndices = indices + int(animObjNTBOff[meshIndex]); 161 | } 162 | 163 | #if RAYTRACING_APPROXIMATE_LOD 164 | if (pushConstants.mApproximateLod) { 165 | // set up lod calculation 166 | vec3 P0_OS, P1_OS, P2_OS; 167 | if (isAnimObject) { 168 | P0_OS = texelFetch(animObjPositions, animObjIndices.x).xyz; 169 | P1_OS = texelFetch(animObjPositions, animObjIndices.y).xyz; 170 | P2_OS = texelFetch(animObjPositions, animObjIndices.z).xyz; 171 | } else { 172 | P0_OS = texelFetch(positionsBuffers[meshgroupId], indices.x).xyz; 173 | P1_OS = texelFetch(positionsBuffers[meshgroupId], indices.y).xyz; 174 | P2_OS = texelFetch(positionsBuffers[meshgroupId], indices.z).xyz; 175 | } 176 | approximate_lod_homebrewed_setup(P0_OS, P1_OS, P2_OS, uv0, uv1, uv2, matIndex, uv); 177 | 178 | //float lod = approximate_lod_homebrewed_final( vec2(textureSize(textures[materialsBuffer.materials[matIndex].mDiffuseTexIndex], 0)) ); 179 | //hitValue.color.rgb = vec3(lod/10.0); return; 180 | } 181 | #endif 182 | 183 | // get normal, tangent, bitangent - this works different for animated objects 184 | vec3 normalWS, normalOS, tangentOS, bitangentOS; 185 | if (isAnimObject) { 186 | normalOS = normalize(INTERPOL_BARY_TEXELFETCH(animObjNormals, animObjIndices, xyz)); 187 | tangentOS = normalize(INTERPOL_BARY_TEXELFETCH(animObjTangents, animObjIndices, xyz)); 188 | bitangentOS = normalize(INTERPOL_BARY_TEXELFETCH(animObjBitangents, animObjIndices, xyz)); 189 | } else { 190 | normalOS = normalize(INTERPOL_BARY_TEXELFETCH(normalsBuffers [meshgroupId], indices, xyz)); 191 | tangentOS = normalize(INTERPOL_BARY_TEXELFETCH(tangentsBuffers [meshgroupId], indices, xyz)); 192 | bitangentOS = normalize(INTERPOL_BARY_TEXELFETCH(bitangentsBuffers[meshgroupId], indices, xyz)); 193 | } 194 | //normalWS = normalize(matrixNormalsOStoWS * normalOS); 195 | normalWS = calc_normalized_normalWS(sample_from_normals_texture(matIndex, uv).rgb, normalOS, tangentOS, bitangentOS, matIndex); 196 | 197 | // cast a shadow ray 198 | float shadowFactor; 199 | if ((pushConstants.mDoShadows & 0x01) != 0) { 200 | vec3 origin = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT; 201 | //origin += normalWS * 0.1; // just testing - this helps a bit against the self-shadows on goblin; however 0.1 seems a bit much for a general offset 202 | vec3 direction = normalize(-pushConstants.mLightDir.xyz); // mLightDir is the direction FROM the light source 203 | //uint rayFlags = gl_RayFlagsOpaqueEXT | gl_RayFlagsTerminateOnFirstHitEXT; 204 | uint rayFlags = gl_RayFlagsCullBackFacingTrianglesEXT | gl_RayFlagsTerminateOnFirstHitEXT; 205 | uint cullMask = (pushConstants.mDoShadows & 0x02) != 0 ? RAYTRACING_CULLMASK_OPAQUE | RAYTRACING_CULLMASK_TRANSPARENT : RAYTRACING_CULLMASK_OPAQUE; 206 | float tmin = 0.001; 207 | float tmax = pushConstants.mMaxRayLength; //100.0; 208 | traceRayEXT(topLevelAS, rayFlags, cullMask, 1 /*sbtRecordOffset*/, 0 /*sbtRecordStride*/, 1 /*missIndex*/, origin, tmin, direction, tmax, 1 /*payload*/); 209 | shadowFactor = 1.0 - SHADOW_OPACITY * shadowHitValue; 210 | } else { 211 | shadowFactor = 1.0; 212 | } 213 | 214 | // simple light calculation 215 | // we only support one directional light here (+ ambient) 216 | 217 | vec4 diffTexColorRGBA = sample_from_diffuse_texture (matIndex, uv); 218 | float specTexValue = sample_from_specular_texture(matIndex, uv).r; 219 | vec3 emissiveTexColor = sample_from_emissive_texture(matIndex, uv).rgb; 220 | 221 | vec3 ambient = materialsBuffer.materials[matIndex].mAmbientReflectivity.rgb * diffTexColorRGBA.rgb; 222 | vec3 emissive = materialsBuffer.materials[matIndex].mEmissiveColor.rgb * emissiveTexColor; // TODO: check if we really want to multiply with emissive color (is typically vec3(0.5) for emerald square) 223 | vec3 diff = materialsBuffer.materials[matIndex].mDiffuseReflectivity.rgb * diffTexColorRGBA.rgb; 224 | vec3 spec = materialsBuffer.materials[matIndex].mSpecularReflectivity.rgb * specTexValue; 225 | float shininess = materialsBuffer.materials[matIndex].mShininess; 226 | bool twoSided = materialsBuffer.materials[matIndex].mCustomData[3] > 0.5; 227 | 228 | vec3 ambientIllumination = pushConstants.mAmbientLightIntensity.rgb * ambient; 229 | vec3 dirLightIntensity = pushConstants.mDirLightIntensity.rgb; 230 | vec3 toLightWS = normalize(-pushConstants.mLightDir.xyz); 231 | vec3 toEyeWS = -gl_WorldRayDirectionEXT; 232 | vec3 diffAndSpec = dirLightIntensity * calc_blinn_phong_contribution(toLightWS, toEyeWS, normalWS, diff, spec, shininess, twoSided); 233 | vec4 blinnPhongColor = vec4(vec3(ambientIllumination + emissive + shadowFactor * diffAndSpec), 1.0); 234 | 235 | hitValue.color.rgb = blinnPhongColor.rgb; 236 | 237 | // use the same debug settings as in the raster version 238 | if (uboMatUsr.mUserInput.z < 1.f) { 239 | hitValue.color.rgb = blinnPhongColor.rgb; 240 | } else if (uboMatUsr.mUserInput.z < 2.f) { 241 | // don't use lights 242 | hitValue.color.rgb = diff; 243 | } else if (uboMatUsr.mUserInput.z < 3.f) { 244 | // Debug: SM cascade 245 | hitValue.color.rgb = vec3(0); // NA here 246 | } else if (uboMatUsr.mUserInput.z < 4.f) { 247 | // Debug: show normals 248 | hitValue.color.rgb = normalWS; 249 | } else if (uboMatUsr.mUserInput.z < 5.f) { 250 | // Debug2: show geometry normals (not affected by normal mapping) 251 | vec3 normalWS = matrixNormalsOStoWS * normalOS; 252 | hitValue.color.rgb = normalWS.xyz; 253 | } else { 254 | // show LOD level of diffuse texture 255 | float lod = approximate_lod_homebrewed_final(vec2(textureSize(textures[materialsBuffer.materials[matIndex].mDiffuseTexIndex], 0)), pushConstants.mApproximateLodMaxAnisotropy); 256 | hitValue.color.rgb = vec3(lod / 10.0, 0, 0); 257 | } 258 | 259 | 260 | 261 | 262 | // gl_PrimitiveID = triangle id. ; if multiple meshgroup-instances -> multiple triangles with same gl_PrimitiveID 263 | // gl_InstanceCustomIndexEXT = whatever is set in the GeometryInstance in user code 264 | } -------------------------------------------------------------------------------- /shaders/rt_test.rgen: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_cpu_common.h" 6 | #include "shader_common_main.glsl" 7 | #include "shader_raytrace_common.glsl" 8 | 9 | layout(push_constant) PUSHCONSTANTSDEF_RAYTRACING pushConstants; 10 | 11 | layout (std430, set = 0, binding = 7) readonly buffer PixelOffsetBuffer { vec2 pixel_offset[]; }; 12 | layout(set = 2, binding = 0) uniform accelerationStructureEXT topLevelAS; 13 | layout(set = 1, binding = 0, SHADER_FORMAT_RAYTRACE) uniform image2D image; 14 | layout(set = 3, binding = 0, TAA_SHADER_OUTPUT_FORMAT) uniform image2D taaInput; 15 | layout(set = 3, binding = 1, TAA_SHADER_FORMAT_SEGMASK) uniform uimage2D taaSegMask; 16 | 17 | //layout(location = 0) rayPayloadEXT vec3 hitValue; // payload to traceRayEXT 18 | layout(location = 0) rayPayloadEXT MainRayPayload hitValue; // payload to traceRayEXT 19 | 20 | float rand(vec2 n) { 21 | return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453); 22 | } 23 | 24 | vec2 pixelOffset(int currentSample, int numSamples) { 25 | //return vec2(rand(gl_LaunchIDEXT.xy), rand(gl_LaunchIDEXT.xy * 2)); 26 | 27 | //vec2 offsets[] = { {0.5, 0.5}, {0.25, 0.25}, {0.75, 0.25}, {0.75, 0.75}, {0.25, 0.75} }; 28 | //return offsets[currentSample % 5]; 29 | 30 | if (numSamples == 1) { 31 | return vec2(0.5); 32 | } else { 33 | return vec2(0.5) + pixel_offset[currentSample]; 34 | } 35 | } 36 | 37 | void main() 38 | { 39 | // clear target pixel 40 | //imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(0.0, 0.0, 0.0, 0.0)); 41 | 42 | if (pushConstants.mAugmentTAA) { 43 | //imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(1,0,1,1)); 44 | uint segMask = imageLoad(taaSegMask, ivec2(gl_LaunchIDEXT.xy)).r & 3; 45 | if (segMask != 2) { 46 | imageStore(image, ivec2(gl_LaunchIDEXT.xy), imageLoad(taaInput, ivec2(gl_LaunchIDEXT.xy))); 47 | return; 48 | } 49 | if (pushConstants.mAugmentTAADebug) { 50 | imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(1,1,0,1)); 51 | return; 52 | } 53 | } 54 | 55 | int numSamples = clamp(pushConstants.mNumSamples, 1, RAYTRACING_MAX_SAMPLES_PER_PIXEL); 56 | vec3 accumulated = vec3(0); 57 | 58 | float aspectRatio = float(gl_LaunchSizeEXT.x) / float(gl_LaunchSizeEXT.y); 59 | 60 | for (int iSample = 0; iSample < numSamples; ++iSample) { 61 | 62 | //const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy ) + vec2(0.5); 63 | const vec2 pixelCenter = vec2(gl_LaunchIDEXT.xy) + pixelOffset(iSample, numSamples); 64 | const vec2 inUV = pixelCenter/vec2(gl_LaunchSizeEXT.xy); 65 | 66 | vec3 origin, direction; 67 | float aspectRatio = float(gl_LaunchSizeEXT.x) / float(gl_LaunchSizeEXT.y); 68 | calc_ray(inUV, pushConstants.mCameraTransform, aspectRatio, origin, direction); 69 | 70 | uint rayFlags = gl_RayFlagsCullBackFacingTrianglesEXT; // note: two-sided materials have culling disabled in their geometry instance 71 | //uint rayFlags = gl_RayFlagsNoneEXT; 72 | uint cullMask = 0xff; 73 | float tmin = 0.001; 74 | float tmax = pushConstants.mMaxRayLength; // 100.0; 75 | hitValue.pixelCenterUV = inUV; 76 | traceRayEXT(topLevelAS, rayFlags, cullMask, 0 /*sbtRecordOffset*/, 0 /*sbtRecordStride*/, 0 /*missIndex*/, origin, tmin, direction, tmax, 0 /*payload*/); 77 | 78 | accumulated += hitValue.color.rgb; 79 | } 80 | 81 | imageStore(image, ivec2(gl_LaunchIDEXT.xy), vec4(accumulated / float(numSamples), 0.0)); 82 | } 83 | -------------------------------------------------------------------------------- /shaders/rt_test.rmiss: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_raytrace_common.glsl" 6 | 7 | layout(location = 0) rayPayloadInEXT MainRayPayload hitValue; 8 | 9 | void main() 10 | { 11 | //hitValue = vec3(1,0,1); return; 12 | 13 | // Skybox: 14 | const float pi = 3.1415926535897932384626433832795; 15 | const float half_pi = pi * 0.5; 16 | const float hdr_factor = 1.0; 17 | 18 | // Normalize direction vector towards the sky sphere: 19 | //vec3 nc = normalize(vSphereCoords); 20 | vec3 nc = gl_WorldRayDirectionEXT; 21 | 22 | // Compute the skybox color and store the result in oFragColor: 23 | float latitude = acos(nc.y); 24 | float longitude = atan(nc.z, nc.x); 25 | float s = cos(abs(longitude)) * 0.5 + 0.5; 26 | float t = mix(1.0 - nc.y, 0.5 + cos((nc.y + 0.5) * 0.5 * pi), 0.5); 27 | vec4 color = mix(vec4(0.1, 0.26, 0.4, 1.0), vec4(1.0, 0.68, 0.28, 1.0) * hdr_factor, t*t*t*t); 28 | float tf = clamp(latitude, 0.0, 1.0); 29 | color = mix(vec4(0.1, 0.26, 0.4, 1.0), color, s*s*s*s * tf); 30 | color = mix(color, vec4(0.0, 0.0, 0.5, 1.0), sin(clamp(-nc.y, 0.0, 1.0) * half_pi)); 31 | 32 | hitValue.color.rgb = color.rgb; 33 | } -------------------------------------------------------------------------------- /shaders/rt_test_shadowray.rchit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | 4 | layout(location = 0) rayPayloadInEXT float shadowHitValue; 5 | 6 | void main() 7 | { 8 | shadowHitValue = 1; 9 | } 10 | -------------------------------------------------------------------------------- /shaders/rt_test_shadowray.rmiss: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | 4 | layout(location = 0) rayPayloadInEXT float shadowHitValue; 5 | 6 | void main() 7 | { 8 | shadowHitValue = 0; 9 | } 10 | -------------------------------------------------------------------------------- /shaders/rt_test_shadowray_transp.rahit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_EXT_nonuniform_qualifier : require 4 | #extension GL_GOOGLE_include_directive : enable 5 | 6 | #include "shader_cpu_common.h" 7 | #include "shader_common_main.glsl" 8 | #include "shader_raytrace_common.glsl" 9 | 10 | // difference to rt_test_transp.rahit: This shader does not use LOD approximation, since the (shadow) ray does not origin from the camera! 11 | 12 | layout(push_constant) PUSHCONSTANTSDEF_RAYTRACING pushConstants; 13 | 14 | layout(location = 0) rayPayloadInEXT MainRayPayload hitValue; 15 | 16 | layout(set = 0, binding = 0) BUFFERDEF_Material materialsBuffer; 17 | layout(set = 0, binding = 1) uniform sampler2D textures[]; 18 | layout(set = 0, binding = 2) uniform usamplerBuffer indexBuffers[]; // one index buffer per [meshgroupId]; contents of each buffer are in uvec3s 19 | layout(set = 0, binding = 3) uniform samplerBuffer texCoordsBuffers[]; // ditto, entries are vec2 20 | layout (std430, set = 0, binding = 4) readonly buffer MaterialIndexBuffer { uint materialIndices[]; }; 21 | layout(set = 0, binding = 5) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 22 | layout(set = 0, binding = 14) uniform samplerBuffer positionsBuffers[]; // entries are vec3, positions in OS 23 | 24 | layout(set = 2, binding = 0) uniform accelerationStructureEXT topLevelAS; 25 | 26 | hitAttributeEXT vec2 bary2; 27 | 28 | // ###### LOD APPROXIMATION ######################## 29 | #include "shader_raytrace_lod_approximation.glsl" 30 | // ------------------------------------------------------- 31 | 32 | 33 | vec4 sample_from_diffuse_texture(uint matIndex, vec2 uv) 34 | { 35 | int texIndex = materialsBuffer.materials[matIndex].mDiffuseTexIndex; 36 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mDiffuseTexOffsetTiling; 37 | vec2 texCoords = uv * offsetTiling.zw + offsetTiling.xy; 38 | return texture(textures[texIndex], texCoords); 39 | } 40 | 41 | void main() 42 | { 43 | // which index buffer to use? -> meshgroupId (stored in geometry custom index) 44 | int meshgroupId = gl_InstanceCustomIndexEXT; 45 | 46 | // calc texture coordinates by interpolating barycentric coordinates 47 | const vec3 barycentrics = vec3(1.0 - bary2.x - bary2.y, bary2); 48 | ivec3 indices = ivec3(texelFetch(indexBuffers[meshgroupId], gl_PrimitiveID).xyz); // get the indices of the 3 triangle corners 49 | vec2 uv0 = texelFetch(texCoordsBuffers[meshgroupId], indices.x).xy; // and use them to look up the corresponding texture coordinates 50 | vec2 uv1 = texelFetch(texCoordsBuffers[meshgroupId], indices.y).xy; 51 | vec2 uv2 = texelFetch(texCoordsBuffers[meshgroupId], indices.z).xy; 52 | vec2 uv = uv0 * barycentrics.x + uv1 * barycentrics.y + uv2 * barycentrics.z; // and interpolate 53 | 54 | uint matIndex = materialIndices[meshgroupId]; 55 | 56 | // alpha-test 57 | float alpha = sample_from_diffuse_texture(matIndex, uv).a; 58 | if (alpha < uboMatUsr.mUserInput.w) ignoreIntersectionEXT; 59 | } -------------------------------------------------------------------------------- /shaders/rt_test_transp.rahit: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_ray_tracing : require 3 | #extension GL_EXT_nonuniform_qualifier : require 4 | #extension GL_GOOGLE_include_directive : enable 5 | 6 | #include "shader_cpu_common.h" 7 | #include "shader_common_main.glsl" 8 | #include "shader_raytrace_common.glsl" 9 | 10 | layout(push_constant) PUSHCONSTANTSDEF_RAYTRACING pushConstants; 11 | 12 | layout(location = 0) rayPayloadInEXT MainRayPayload hitValue; 13 | 14 | layout(set = 0, binding = 0) BUFFERDEF_Material materialsBuffer; 15 | layout(set = 0, binding = 1) uniform sampler2D textures[]; 16 | layout(set = 0, binding = 2) uniform usamplerBuffer indexBuffers[]; // one index buffer per [meshgroupId]; contents of each buffer are in uvec3s 17 | layout(set = 0, binding = 3) uniform samplerBuffer texCoordsBuffers[]; // ditto, entries are vec2 18 | layout (std430, set = 0, binding = 4) readonly buffer MaterialIndexBuffer { uint materialIndices[]; }; 19 | layout(set = 0, binding = 5) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 20 | layout(set = 0, binding = 14) uniform samplerBuffer positionsBuffers[]; // entries are vec3, positions in OS 21 | 22 | layout(set = 2, binding = 0) uniform accelerationStructureEXT topLevelAS; 23 | 24 | hitAttributeEXT vec2 bary2; 25 | 26 | // ###### LOD APPROXIMATION ######################## 27 | #include "shader_raytrace_lod_approximation.glsl" 28 | // ------------------------------------------------------- 29 | 30 | 31 | vec4 sample_from_diffuse_texture(uint matIndex, vec2 uv) 32 | { 33 | int texIndex = materialsBuffer.materials[matIndex].mDiffuseTexIndex; 34 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mDiffuseTexOffsetTiling; 35 | vec2 texCoords = uv * offsetTiling.zw + offsetTiling.xy; 36 | return sampleTextureWithLodApprox(textures[texIndex], texCoords, pushConstants.mApproximateLodMaxAnisotropy); 37 | } 38 | 39 | void main() 40 | { 41 | // which index buffer to use? -> meshgroupId (stored in geometry custom index) 42 | int meshgroupId = gl_InstanceCustomIndexEXT; 43 | 44 | // calc texture coordinates by interpolating barycentric coordinates 45 | const vec3 barycentrics = vec3(1.0 - bary2.x - bary2.y, bary2); 46 | ivec3 indices = ivec3(texelFetch(indexBuffers[meshgroupId], gl_PrimitiveID).xyz); // get the indices of the 3 triangle corners 47 | vec2 uv0 = texelFetch(texCoordsBuffers[meshgroupId], indices.x).xy; // and use them to look up the corresponding texture coordinates 48 | vec2 uv1 = texelFetch(texCoordsBuffers[meshgroupId], indices.y).xy; 49 | vec2 uv2 = texelFetch(texCoordsBuffers[meshgroupId], indices.z).xy; 50 | vec2 uv = uv0 * barycentrics.x + uv1 * barycentrics.y + uv2 * barycentrics.z; // and interpolate 51 | 52 | uint matIndex = materialIndices[meshgroupId]; 53 | 54 | // we also need to approximate the LOD for sampling alpha... 55 | #if 1 56 | #if RAYTRACING_APPROXIMATE_LOD 57 | if (pushConstants.mApproximateLod && !uboMatUsr.mAlphaUseLod0) { 58 | // set up lod calculation - this is never an animated object, always static scenery, so this is simpler than in the closest-hit-shader 59 | vec3 P0_OS, P1_OS, P2_OS; 60 | P0_OS = texelFetch(positionsBuffers[meshgroupId], indices.x).xyz; 61 | P1_OS = texelFetch(positionsBuffers[meshgroupId], indices.y).xyz; 62 | P2_OS = texelFetch(positionsBuffers[meshgroupId], indices.z).xyz; 63 | approximate_lod_homebrewed_setup(P0_OS, P1_OS, P2_OS, uv0, uv1, uv2, matIndex, uv); 64 | } 65 | #endif 66 | #endif 67 | 68 | // alpha-test 69 | float alpha = sample_from_diffuse_texture(matIndex, uv).a; 70 | if (alpha < uboMatUsr.mUserInput.w) ignoreIntersectionEXT; 71 | } -------------------------------------------------------------------------------- /shaders/shader_common_main.glsl: -------------------------------------------------------------------------------- 1 | //? #version 460 2 | // above line is just for the VS GLSL language integration plugin 3 | 4 | #ifndef SHADER_COMMON_MAIN_INCLUDED 5 | #define SHADER_COMMON_MAIN_INCLUDED 1 6 | 7 | #define TAU 6.28318530718 // TAU = 2 * PI 8 | 9 | // ----- helper functions 10 | 11 | // Sample textures with LOD-bias (prerequiste: uboMatUsr.mLodBias must exist) 12 | 13 | // ideally we'd set a the lod bias when creating the sampler 14 | // this is not suitable here though, because we want to experiment with dynamic values 15 | 16 | #define SAMPLE_TEXTURE(t,u) textureLod((t),(u),uboMatUsr.mAlwaysUseLod0 ? 0 : (textureQueryLod((t), (u)).y + uboMatUsr.mLodBias)) 17 | //#define SAMPLE_TEXTURE(t,u) textureLod((t),(u),(textureQueryLod((t), (u)).y + uboMatUsr.mLodBias)) 18 | //#define SAMPLE_TEXTURE(t,u) texture((t),(u)) 19 | 20 | 21 | 22 | // Fix normal mapping for 2-component normal maps 23 | #define NORMALMAP_FIX_MISSING_Z 1 // substitute missing z in normal map by +1.0 ? 24 | #define NORMALMAP_FIX_SIMPLE 0 // use simple method (set z=1)? (if not: project .xy to +z hemisphere to obtain normal) 25 | 26 | #if NORMALMAP_FIX_MISSING_Z 27 | // always double-check if z is zero, so this should still work with full .rgb textures, where .z IS set 28 | #if NORMALMAP_FIX_SIMPLE 29 | #define FIX_NORMALMAPPING(n) { if ((n).z == 0.0) (n).z = 1.0; } 30 | #else 31 | #define FIX_NORMALMAPPING(n) \ 32 | if ((n).z == 0.0) { \ 33 | /* project to +z hemisphere */ \ 34 | vec3 v = vec3((n).xy * 2.0 - 1.0, 0.0); \ 35 | v.z = sqrt(1.0 - v.x * v.x + v.y * v.y); \ 36 | (n).xyz = normalize(v) * 0.5 + 0.5; /* probably don't need normalize()... */ \ 37 | } 38 | #endif 39 | #else 40 | #define FIX_NORMALMAPPING(n) 41 | #endif 42 | 43 | // ----- uniform declarations 44 | 45 | // Push constants for draw-indexed-indirect draw calls (and also for dynamic object draw-indexed calls) 46 | #define PUSHCONSTANTSDEF_DII uniform PushConstantsDII { \ 47 | /* dynamic objects current mesh properties */ \ 48 | mat4 mMover_baseModelMatrix; \ 49 | int mMover_materialIndex; \ 50 | int mMover_meshIndex; \ 51 | \ 52 | int mDrawType; /* 0:scene opaque, 1:scene transparent, negative numbers: moving object id */ \ 53 | int mShadowMapCascadeToBuild; \ 54 | } 55 | 56 | // Push constants for ray tracing moved to shader_raytrace_common.glsl 57 | 58 | // Uniform buffer containing camera matrices and user input: 59 | // It is updated every frame. 60 | #define UNIFORMDEF_MatricesAndUserInput uniform MatricesAndUserInput { \ 61 | /* view matrix as returned from quake_camera */ \ 62 | mat4 mViewMatrix; \ 63 | /* projection matrix as returned from quake_camera */ \ 64 | mat4 mProjMatrix; \ 65 | /* transformation matrix which tranforms to camera's position */ \ 66 | mat4 mCamPos; \ 67 | /* x = tessellation factor, y = displacement strength, z = use lighting/show normals, w = alpha threshold */ \ 68 | vec4 mUserInput; \ 69 | \ 70 | mat4 mPrevFrameProjViewMatrix; \ 71 | vec4 mJitterCurrentPrev; \ 72 | \ 73 | mat4 mMover_additionalModelMatrix; \ 74 | mat4 mMover_additionalModelMatrix_prev; \ 75 | \ 76 | mat4 mShadowmapProjViewMatrix[4]; \ 77 | mat4 mDebugCamProjViewMatrix; \ 78 | vec4 mShadowMapMaxDepth; /* for up to 4 cascades */ \ 79 | \ 80 | float mLodBias; \ 81 | bool mAlwaysUseLod0; \ 82 | bool mAlphaUseLod0; \ 83 | bool mUseShadowMap; \ 84 | float mShadowBias; \ 85 | int mShadowNumCascades; \ 86 | float pad1, pad2; \ 87 | } 88 | 89 | // "mLightsources" uniform buffer containing all the light source data: 90 | #define UNIFORMDEF_LightsourceData uniform LightsourceData { \ 91 | /* x,y ... ambient light sources start and end indices; z,w ... directional light sources start and end indices */ \ 92 | uvec4 mRangesAmbientDirectional; \ 93 | /* x,y ... point light sources start and end indices; z,w ... spot light sources start and end indices */ \ 94 | uvec4 mRangesPointSpot; \ 95 | /* Contains all the data of all the active light sources */ \ 96 | LightsourceGpuData mLightData[128]; \ 97 | } 98 | 99 | // The actual material buffer (of type MaterialGpuData): 100 | #define BUFFERDEF_Material buffer Material { \ 101 | MaterialGpuData materials[]; \ 102 | } 103 | 104 | // ----- uniform structure definitions 105 | 106 | struct LightsourceGpuData 107 | { 108 | /** Color of the light source. */ 109 | vec4 mColor; 110 | /** Direction of the light source. */ 111 | vec4 mDirection; 112 | /** Position of the light source. */ 113 | vec4 mPosition; 114 | /** Angles, where the individual elements contain the following data: [0] cosine of halve outer cone angle, [1] cosine of halve inner cone angle, [2] falloff, [3] unused */ 115 | vec4 mAnglesFalloff; 116 | /* Light source attenuation, where the individual elements contain the following data: [0] constant attenuation factor, [1] linear attenuation factor, [2] quadratic attenuation factor, [3], unused */ 117 | vec4 mAttenuation; 118 | /** General information about the light source, where the individual elements contain the following data:[0] type of the light source */ 119 | ivec4 mInfo; 120 | }; 121 | 122 | // Material data struct definition: 123 | struct MaterialGpuData { 124 | vec4 mDiffuseReflectivity; 125 | vec4 mAmbientReflectivity; 126 | vec4 mSpecularReflectivity; 127 | vec4 mEmissiveColor; 128 | vec4 mTransparentColor; 129 | vec4 mReflectiveColor; 130 | vec4 mAlbedo; 131 | 132 | float mOpacity; 133 | float mBumpScaling; 134 | float mShininess; 135 | float mShininessStrength; 136 | 137 | float mRefractionIndex; 138 | float mReflectivity; 139 | float mMetallic; 140 | float mSmoothness; 141 | 142 | float mSheen; 143 | float mThickness; 144 | float mRoughness; 145 | float mAnisotropy; 146 | 147 | vec4 mAnisotropyRotation; 148 | vec4 mCustomData; // old usage (ARTR): [0]:tessellate? [1]:displacement strength [2]:normal mapping strength [3]:two-sided (but only [3] is used in this project) 149 | // usage here: [0]:is_moving? [1]:displacement strength [2]:normal mapping strength [3]:two-sided (but only [3] is used in this project) 150 | int mDiffuseTexIndex; 151 | int mSpecularTexIndex; 152 | int mAmbientTexIndex; 153 | int mEmissiveTexIndex; 154 | int mHeightTexIndex; 155 | int mNormalsTexIndex; 156 | int mShininessTexIndex; 157 | int mOpacityTexIndex; 158 | int mDisplacementTexIndex; 159 | int mReflectionTexIndex; 160 | int mLightmapTexIndex; 161 | int mExtraTexIndex; 162 | 163 | vec4 mDiffuseTexOffsetTiling; 164 | vec4 mSpecularTexOffsetTiling; 165 | vec4 mAmbientTexOffsetTiling; 166 | vec4 mEmissiveTexOffsetTiling; 167 | vec4 mHeightTexOffsetTiling; 168 | vec4 mNormalsTexOffsetTiling; 169 | vec4 mShininessTexOffsetTiling; 170 | vec4 mOpacityTexOffsetTiling; 171 | vec4 mDisplacementTexOffsetTiling; 172 | vec4 mReflectionTexOffsetTiling; 173 | vec4 mLightmapTexOffsetTiling; 174 | vec4 mExtraTexOffsetTiling; 175 | }; 176 | 177 | #endif 178 | -------------------------------------------------------------------------------- /shaders/shader_cpu_common.h: -------------------------------------------------------------------------------- 1 | #ifndef SHADER_CPU_COMMON_INCLUDED 2 | #define SHADER_CPU_COMMON_INCLUDED 1 3 | 4 | // specialization constants 5 | #define SPECCONST_ID_TRANSPARENCY 1u 6 | #define SPECCONST_VAL_OPAQUE 0u 7 | #define SPECCONST_VAL_TRANSPARENT 1u 8 | 9 | // use a shadowmap? 10 | #define ENABLE_SHADOWMAP 1 11 | #define SHADOWMAP_SIZE 2048 12 | #define SHADOWMAP_INITIAL_CASCADES 2 13 | 14 | #define SHADOWMAP_MAX_CASCADES 4 // don't touch! Need to change uniform buffers and shaders too to increase that beyond 4 15 | 16 | #if SHADOWMAP_INITIAL_CASCADES > SHADOWMAP_MAX_CASCADES 17 | #error "SHADOWMAP_INITIAL_CASCADES > SHADOWMAP_MAX_CASCADES" 18 | #endif 19 | 20 | // Percentage of how much of a lightsource is removed when it is shadowed 21 | #define SHADOW_OPACITY 0.9f 22 | //#define SHADOW_OPACITY 1.0f 23 | 24 | // enable raytracing? 25 | #define ENABLE_RAYTRACING 1 26 | #define RAYTRACING_MAX_SAMPLES_PER_PIXEL 32 27 | #define RAYTRACING_CULLMASK_OPAQUE 0x01 28 | #define RAYTRACING_CULLMASK_TRANSPARENT 0x02 29 | #define RAYTRACING_APPROXIMATE_LOD 1 30 | 31 | #define TAA_RTFLAG_OUT 0x0001 32 | #define TAA_RTFLAG_DIS 0x0002 33 | #define TAA_RTFLAG_NRM 0x0004 34 | #define TAA_RTFLAG_DPT 0x0008 35 | #define TAA_RTFLAG_MID 0x0010 36 | #define TAA_RTFLAG_LUM 0x0020 37 | #define TAA_RTFLAG_CNT 0x0040 38 | #define TAA_RTFLAG_ALL 0x0080 39 | #define TAA_RTFLAG_FXD 0x0100 40 | #define TAA_RTFLAG_FXA 0x0200 41 | 42 | // max. bones for animations 43 | #define MAX_BONES 114 44 | 45 | // GPU frustum culling 46 | #define ENABLE_GPU_FRUSTUM_CULLING 1 47 | #define GPU_FRUSTUM_CULLING_WORKGROUP_SIZE 32 // TODO: Test! 48 | 49 | // don't have transparent movers (yet) 50 | 51 | // 8-bit unorm - ugly! (interestingly: way worse than with explicit sRGB output) 52 | //#define TAA_IMAGE_FORMAT_RGB vk::Format::eR8G8B8A8Unorm 53 | //#define TAA_SHADER_OUTPUT_FORMAT rgba16f 54 | 55 | // 32-bit float works *much* better 56 | //#define TAA_IMAGE_FORMAT_RGB vk::Format::eR32G32B32A32Sfloat 57 | //#define TAA_SHADER_OUTPUT_FORMAT rgba32f 58 | 59 | // 16-bit float is fine too 60 | #define TAA_IMAGE_FORMAT_RGB vk::Format::eR16G16B16A16Sfloat 61 | #define TAA_SHADER_OUTPUT_FORMAT rgba16f 62 | 63 | #define TAA_IMAGE_FORMAT_SRGB vk::Format::eUndefined // unused 64 | 65 | 66 | #define TAA_IMAGE_FORMAT_POSTPROCESS vk::Format::eR16G16B16A16Sfloat 67 | #define TAA_SHADER_FORMAT_POSTPROCESS rgba16f 68 | 69 | #define TAA_IMAGE_FORMAT_SEGMASK vk::Format::eR32Uint 70 | #define TAA_SHADER_FORMAT_SEGMASK r32ui 71 | 72 | 73 | #define IMAGE_FORMAT_COLOR vk::Format::eR16G16B16A16Sfloat 74 | #define IMAGE_FORMAT_DEPTH vk::Format::eD32Sfloat 75 | #define IMAGE_FORMAT_NORMAL vk::Format::eR32G32B32A32Sfloat 76 | #define IMAGE_FORMAT_MATERIAL vk::Format::eR32Uint 77 | #define IMAGE_FORMAT_VELOCITY vk::Format::eR16G16B16A16Sfloat 78 | 79 | #define IMAGE_FORMAT_SHADOWMAP vk::Format::eD32Sfloat 80 | #define SHADOWMAP_BINDING_SET 0 81 | #define SHADOWMAP_BINDING_SLOT 6 82 | 83 | #define IMAGE_FORMAT_RAYTRACE vk::Format::eR16G16B16A16Sfloat 84 | #define SHADER_FORMAT_RAYTRACE rgba16f 85 | 86 | // for debugging 87 | #define USE_DEBUG_POSBUFFERS 1 88 | #define IMAGE_FORMAT_POSITION vk::Format::eR16G16B16A16Sfloat 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /shaders/shader_raytrace_common.glsl: -------------------------------------------------------------------------------- 1 | //? #version 460 2 | // above line is just for the VS GLSL language integration plugin 3 | 4 | #ifndef SHADER_RAYTRACE_COMMON_INCLUDED 5 | #define SHADER_RAYTRACE_COMMON_INCLUDED 1 6 | 7 | void calc_ray(in vec2 pixelUV, in mat4 camTransform, float aspectRatio, out vec3 origin, out vec3 direction) { 8 | // pixelUV: target location in uv screen space (range [0,1]) 9 | // aspectRatio = float(gl_LaunchSizeEXT.x) / float(gl_LaunchSizeEXT.y); 10 | 11 | vec2 d = pixelUV * 2.0 - 1.0; 12 | origin = vec3(0.0, 0.0, 0.0); 13 | // Up == +Y in World, but UV-coordinates have +Y pointing down 14 | // | Forward == -Z n World Space 15 | // | | 16 | // v v 17 | direction = normalize(vec3(d.x * aspectRatio, -d.y, -sqrt(3))); // 1 => sqrt(3) is the scaling factor from a fov of 90 to 60 18 | vec4 p1 = vec4(origin, 1.0); 19 | vec4 p2 = vec4(origin + direction, 1.0); 20 | vec4 vp1 = camTransform * p1; 21 | vec4 vp2 = camTransform * p2; 22 | origin = vec3(vp1); 23 | direction = vec3(normalize(vp2 - vp1)); 24 | } 25 | 26 | // ----- uniform declarations 27 | 28 | // Push constants for ray tracing 29 | #define PUSHCONSTANTSDEF_RAYTRACING uniform PushConstantsRayTracing { \ 30 | mat4 mCameraTransform; \ 31 | mat4 mCameraViewProjMatrix; \ 32 | vec4 mLightDir; \ 33 | vec4 mDirLightIntensity; \ 34 | vec4 mAmbientLightIntensity; \ 35 | float mNormalMappingStrength; \ 36 | float mMaxRayLength; \ 37 | int mNumSamples; \ 38 | int mAnimObjFirstMeshId; \ 39 | int mAnimObjNumMeshes; \ 40 | uint mDoShadows; /* bit 0: general shadows, bit 1: shadows of transp. objs */ \ 41 | bool mAugmentTAA; \ 42 | bool mAugmentTAADebug; \ 43 | bool mApproximateLod; \ 44 | int mApproximateLodMaxAnisotropy; \ 45 | float pad1, pad2; \ 46 | } 47 | 48 | // ----- uniform structure definitions 49 | 50 | struct MainRayPayload { 51 | vec4 color; // only rgb used 52 | vec2 pixelCenterUV; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /shaders/shader_raytrace_lod_approximation.glsl: -------------------------------------------------------------------------------- 1 | //? #version 460 2 | // above line is just for the VS GLSL language integration plugin 3 | #extension GL_EXT_ray_tracing : require 4 | #extension GL_EXT_nonuniform_qualifier : require 5 | #extension GL_GOOGLE_include_directive : enable 6 | 7 | #include "shader_cpu_common.h" 8 | #include "shader_common_main.glsl" 9 | #include "shader_raytrace_common.glsl" 10 | 11 | // ###### LOD APPROXIMATION ######################## 12 | 13 | // interim results for lod calculation 14 | bool gLodApprox_valid = false; 15 | vec2 gLodApprox_dx_vuv = vec2(0); 16 | vec2 gLodApprox_dy_vuv = vec2(0); 17 | 18 | //float approximate_lod_from_triangle_area(vec3 P0_OS, vec3 P1_OS, vec3 P2_OS, vec2 uv0, vec2 uv1, vec2 uv2, uint matIndex) { 19 | // // screen-space (pixels) triangle area 20 | // vec4 P0_CS = pushConstants.mCameraViewProjMatrix * vec4(gl_ObjectToWorldEXT * vec4(P0_OS,1), 1); 21 | // vec4 P1_CS = pushConstants.mCameraViewProjMatrix * vec4(gl_ObjectToWorldEXT * vec4(P1_OS,1), 1); 22 | // vec4 P2_CS = pushConstants.mCameraViewProjMatrix * vec4(gl_ObjectToWorldEXT * vec4(P2_OS,1), 1); 23 | // vec2 imSize = vec2(imageSize(image)); 24 | // vec2 P0_SS = 0.5 * P0_CS.xy / P0_CS.w + 0.5; 25 | // vec2 P1_SS = 0.5 * P1_CS.xy / P1_CS.w + 0.5; 26 | // vec2 P2_SS = 0.5 * P2_CS.xy / P2_CS.w + 0.5; 27 | // //float doubleArea = length(cross((P1_SS - P0_SS), (P2_SS - P0_SS))); 28 | // vec2 v01 = P1_SS - P0_SS; 29 | // vec2 v02 = P2_SS - P0_SS; 30 | // float doubleAreaPixels = imSize.x * imSize.y * abs(v01.x * v02.y - v01.y * v02.x); 31 | // 32 | // // texels triangle area 33 | // int texIndex = materialsBuffer.materials[matIndex].mDiffuseTexIndex; 34 | // vec2 texSize = textureSize(textures[texIndex], 0); 35 | // vec2 t01 = uv1 - uv0; 36 | // vec2 t02 = uv2 - uv0; 37 | // float doubleAreaTexels = texSize.x * texSize.y * abs(t01.x * t02.y - t01.y * t02.x); 38 | // 39 | // return 0.5 * log2(doubleAreaTexels / doubleAreaPixels); 40 | //} 41 | 42 | // intersect_triangle adapted from https://stackoverflow.com/questions/42740765/intersection-between-line-and-triangle-in-3d/42752998#42752998 43 | // When the function returns true, the intersection point is given by Ray_Origin + t * Ray_Dir. The barycentric coordinates of the intersection in the triangle are u, v, 1-u-v 44 | bool intersect_triangle(in vec3 Ray_Origin, in vec3 Ray_Dir, in vec3 A, in vec3 B, in vec3 C, out float t, out float u, out float v, out vec3 N) { 45 | vec3 E1 = B-A; 46 | vec3 E2 = C-A; 47 | N = cross(E1,E2); 48 | float det = -dot(Ray_Dir, N); 49 | float invdet = 1.0/det; 50 | vec3 AO = Ray_Origin - A; 51 | vec3 DAO = cross(AO, Ray_Dir); 52 | u = dot(E2,DAO) * invdet; 53 | v = -dot(E1,DAO) * invdet; 54 | t = dot(AO,N) * invdet; 55 | return (det >= 1e-6 && t >= 0.0 && u >= 0.0 && v >= 0.0 && (u+v) <= 1.0); 56 | } 57 | 58 | // this is just to avoid errors in the VS GLSL plugin: 59 | //!mat4x3 dummyObjToWorldMat; 60 | //!ivec2 dummyLaunchSize; 61 | //!vec2 dummyPixelCenterUV; 62 | //!mat4 dummyCameraTransform; 63 | //!#define RAYTRACE_LOD_APPROXIMATION_OBJECT_TO_WORLD_MATRIX dummyObjToWorldMat 64 | //!#define RAYTRACE_LOD_APPROXIMATION_LAUNCHSIZE dummyLaunchSize 65 | //!#define RAYTRACE_LOD_APPROXIMATION_PIXELCENTERUV dummyPixelCenterUV 66 | //!#define RAYTRACE_LOD_APPROXIMATION_CAMERATRANSFORM dummyCameraTransform 67 | 68 | #ifndef RAYTRACE_LOD_APPROXIMATION_OBJECT_TO_WORLD_MATRIX 69 | #define RAYTRACE_LOD_APPROXIMATION_OBJECT_TO_WORLD_MATRIX gl_ObjectToWorldEXT 70 | #endif 71 | #ifndef RAYTRACE_LOD_APPROXIMATION_LAUNCHSIZE 72 | #define RAYTRACE_LOD_APPROXIMATION_LAUNCHSIZE gl_LaunchSizeEXT 73 | #endif 74 | #ifndef RAYTRACE_LOD_APPROXIMATION_PIXELCENTERUV 75 | #define RAYTRACE_LOD_APPROXIMATION_PIXELCENTERUV hitValue.pixelCenterUV 76 | #endif 77 | #ifndef RAYTRACE_LOD_APPROXIMATION_CAMERATRANSFORM 78 | #define RAYTRACE_LOD_APPROXIMATION_CAMERATRANSFORM pushConstants.mCameraTransform 79 | #endif 80 | 81 | 82 | void approximate_lod_homebrewed_setup(vec3 P0_OS, vec3 P1_OS, vec3 P2_OS, vec2 uv0, vec2 uv1, vec2 uv2, uint matIndex, vec2 uv_here) { 83 | // idea: calc triangle intersection of rays through (px+1,py) and through (px, py+1), 84 | // fina uv coords, calc au/ax, av/ax, au/ay, av/ay 85 | 86 | vec3 P0_WS = RAYTRACE_LOD_APPROXIMATION_OBJECT_TO_WORLD_MATRIX * vec4(P0_OS,1); 87 | vec3 P1_WS = RAYTRACE_LOD_APPROXIMATION_OBJECT_TO_WORLD_MATRIX * vec4(P1_OS,1); 88 | vec3 P2_WS = RAYTRACE_LOD_APPROXIMATION_OBJECT_TO_WORLD_MATRIX * vec4(P2_OS,1); 89 | 90 | // calc ray origins and directions 91 | vec2 onePixel = vec2(1.0) / vec2(RAYTRACE_LOD_APPROXIMATION_LAUNCHSIZE); 92 | float aspectRatio = float(RAYTRACE_LOD_APPROXIMATION_LAUNCHSIZE.x) / float(RAYTRACE_LOD_APPROXIMATION_LAUNCHSIZE.y); 93 | vec3 origin_dx, origin_dy, direction_dx, direction_dy; 94 | calc_ray(RAYTRACE_LOD_APPROXIMATION_PIXELCENTERUV + vec2(onePixel.x, 0), RAYTRACE_LOD_APPROXIMATION_CAMERATRANSFORM, aspectRatio, origin_dx, direction_dx); 95 | calc_ray(RAYTRACE_LOD_APPROXIMATION_PIXELCENTERUV + vec2(0, onePixel.y), RAYTRACE_LOD_APPROXIMATION_CAMERATRANSFORM, aspectRatio, origin_dy, direction_dy); 96 | 97 | // find hit points (don't care if they actually fall into the triangle) 98 | vec2 bar_dx, bar_dy; 99 | float t; 100 | vec3 N; 101 | intersect_triangle(origin_dx, direction_dx, P0_WS, P1_WS, P2_WS, t, bar_dx.x, bar_dx.y, N); 102 | intersect_triangle(origin_dy, direction_dy, P0_WS, P1_WS, P2_WS, t, bar_dy.x, bar_dy.y, N); 103 | 104 | // get texture coordinates at hit points (attn: bary coord interpolation order) 105 | vec2 uv_dx = uv0 * (1.0 - bar_dx.x - bar_dx.y) + uv1 * bar_dx.x + uv2 * bar_dx.y; 106 | vec2 uv_dy = uv0 * (1.0 - bar_dy.x - bar_dy.y) + uv1 * bar_dy.x + uv2 * bar_dy.y; 107 | 108 | // result of this function: partial derivatives in uv space 109 | gLodApprox_dx_vuv = (uv_dx - uv_here); 110 | gLodApprox_dy_vuv = (uv_dy - uv_here); 111 | gLodApprox_valid = true; 112 | } 113 | 114 | float approximate_lod_homebrewed_final(in vec2 texSize, int maxAnisotropy) { 115 | // finalize lod calculation for a particular texture 116 | 117 | // approximate_lod_homebrewed_setup() must have been called before, so that gLod_dx_vuv and gLod_dy_vuv are valid! 118 | // otherwise return level 0 119 | if (!gLodApprox_valid) return 0.0; 120 | 121 | // calc lod 122 | vec2 dx_vtc = texSize * gLodApprox_dx_vuv; 123 | vec2 dy_vtc = texSize * gLodApprox_dy_vuv; 124 | 125 | if (maxAnisotropy <= 0) { 126 | float delta_max_sqr = max(dot(dx_vtc, dx_vtc), dot(dy_vtc, dy_vtc)); 127 | return max(0, 0.5 * log2(delta_max_sqr)); 128 | } else { 129 | // aniso variant 130 | float px = dot(dx_vtc, dx_vtc); 131 | float py = dot(dy_vtc, dy_vtc); 132 | float maxLod = 0.5 * log2(max(px,py)); 133 | float minLod = 0.5 * log2(min(px,py)); 134 | return maxLod - min(maxLod - minLod, log2(float(maxAnisotropy))); 135 | } 136 | } 137 | 138 | vec4 sampleTextureWithLodApprox(in sampler2D tex, vec2 uv, int maxAnisotropy) { 139 | float lod = approximate_lod_homebrewed_final(vec2(textureSize(tex, 0)), maxAnisotropy); 140 | return textureLod(tex, uv, lod); 141 | } 142 | 143 | // new version, using textureGrad - let the driver deal with anisotropy as configured for the sampler 144 | // !! does not seem to work correctly yet, esp. on grass 145 | //vec4 sampleTextureWithLodApprox(in sampler2D tex, vec2 uv, int maxAnisotropy) { 146 | // return textureGrad(tex, uv, gLodApprox_dx_vuv, gLodApprox_dy_vuv); 147 | //} 148 | 149 | // ------------------------------------------------------- 150 | -------------------------------------------------------------------------------- /shaders/shadowmap.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | // ------------------------------------------------------- 4 | 5 | #include "shader_common_main.glsl" 6 | #include "shader_cpu_common.h" 7 | 8 | // Note: this is the only shader in shadowmap generation for non-transparent objects (no frag shader) 9 | 10 | // ###### VERTEX SHADER/PIPELINE INPUT DATA ############## 11 | layout (location = 0) in vec3 aPosition; 12 | 13 | struct PerInstanceAttribute { mat4 modelMatrix; }; 14 | struct DrawnMeshgroupData { 15 | uint materialIndex; // material index 16 | uint meshIndexBase; // index of first mesh of the group in MeshAttribOffsetBuffer 17 | }; 18 | layout (std430, set = 0, binding = 2) readonly buffer AttributesBuffer { PerInstanceAttribute attrib[]; }; // per global mesh, persistent 19 | layout (std430, set = 0, binding = 3) readonly buffer DrawnMeshgroupBuffer { DrawnMeshgroupData meshgroup_data[]; }; // per drawn meshgroup, indexed via glDrawId (dynamic) 20 | layout (std430, set = 0, binding = 4) readonly buffer MeshAttribIndexBuffer { uint attrib_index[]; }; // per drawn mesh: index for AttributesBuffer (dynamic) 21 | layout (std430, set = 0, binding = 5) readonly buffer MeshgroupsLayoutInfoBuffer { uint transparentMeshgroupsOffset; }; // first transparent meshgroup index (dynamic) 22 | 23 | // push constants 24 | layout(push_constant) PUSHCONSTANTSDEF_DII; 25 | 26 | // matrices 27 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 28 | 29 | // ------------------------------------------------------- 30 | 31 | // ###### VERTEX SHADER MAIN ############################# 32 | void main() 33 | { 34 | mat4 modelMatrix; 35 | if (mDrawType >= 0) { 36 | // static scenery 37 | DrawnMeshgroupData mgInfo = meshgroup_data[gl_DrawID + mDrawType * transparentMeshgroupsOffset]; 38 | uint attribIndex = attrib_index[mgInfo.meshIndexBase + gl_InstanceIndex]; 39 | modelMatrix = attrib[attribIndex].modelMatrix; 40 | } else { 41 | // moving object 42 | modelMatrix = uboMatUsr.mMover_additionalModelMatrix * mMover_baseModelMatrix; 43 | } 44 | 45 | gl_Position = uboMatUsr.mShadowmapProjViewMatrix[mShadowMapCascadeToBuild] * modelMatrix * vec4(aPosition, 1.0); 46 | } 47 | // ------------------------------------------------------- 48 | 49 | -------------------------------------------------------------------------------- /shaders/shadowmap_animated.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | // ------------------------------------------------------- 4 | 5 | #include "shader_common_main.glsl" 6 | #include "shader_cpu_common.h" 7 | 8 | // ###### VERTEX SHADER/PIPELINE INPUT DATA ############## 9 | layout (location = 0) in vec3 aPosition; 10 | layout (location = 1) in vec4 aBoneWeights; 11 | layout (location = 2) in uvec4 aBoneIndices; 12 | 13 | layout(push_constant) PUSHCONSTANTSDEF_DII; 14 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 15 | 16 | layout(set = 3, binding = 0, std430) readonly buffer BoneMatricesBuffer { mat4 mat[]; } boneMatrices; 17 | 18 | // ###### VERTEX SHADER MAIN ############################# 19 | void main() 20 | { 21 | mat4 modelMatrix = uboMatUsr.mMover_additionalModelMatrix * mMover_baseModelMatrix; 22 | 23 | vec4 boneWeights = aBoneWeights; 24 | //boneWeights.w = 1.0 - boneWeights.x - boneWeights.y - boneWeights.z; // no longer necessary to "normalize", this is now done at model loading 25 | 26 | uint bonesBaseIndex = mMover_meshIndex * MAX_BONES; 27 | 28 | // weighted sum of the four bone matrices 29 | mat4 boneMat = boneMatrices.mat [bonesBaseIndex + aBoneIndices[0]] * boneWeights[0] 30 | + boneMatrices.mat [bonesBaseIndex + aBoneIndices[1]] * boneWeights[1] 31 | + boneMatrices.mat [bonesBaseIndex + aBoneIndices[2]] * boneWeights[2] 32 | + boneMatrices.mat [bonesBaseIndex + aBoneIndices[3]] * boneWeights[3]; 33 | 34 | gl_Position = uboMatUsr.mShadowmapProjViewMatrix[mShadowMapCascadeToBuild] * modelMatrix * boneMat * vec4(aPosition, 1.0); 35 | } 36 | // ------------------------------------------------------- 37 | 38 | -------------------------------------------------------------------------------- /shaders/shadowmap_transparent.frag: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_nonuniform_qualifier : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | // ------------------------------------------------------- 5 | 6 | #include "shader_common_main.glsl" 7 | #include "shader_cpu_common.h" 8 | 9 | layout(set = 0, binding = 0) BUFFERDEF_Material materialsBuffer; 10 | layout(set = 0, binding = 1) uniform sampler2D textures[]; 11 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 12 | 13 | layout (location = 0) in VertexData 14 | { 15 | vec2 texCoords; // texture coordinates 16 | flat uint materialIndex; 17 | } fs_in; 18 | // ------------------------------------------------------- 19 | 20 | vec4 sample_from_diffuse_texture() 21 | { 22 | uint matIndex = fs_in.materialIndex; 23 | int texIndex = materialsBuffer.materials[matIndex].mDiffuseTexIndex; 24 | vec4 offsetTiling = materialsBuffer.materials[matIndex].mDiffuseTexOffsetTiling; 25 | vec2 texCoords = fs_in.texCoords * offsetTiling.zw + offsetTiling.xy; 26 | return SAMPLE_TEXTURE(textures[texIndex], texCoords); 27 | } 28 | 29 | void main() 30 | { 31 | float alpha = sample_from_diffuse_texture().a; 32 | if (alpha < uboMatUsr.mUserInput.w) discard; 33 | } 34 | 35 | -------------------------------------------------------------------------------- /shaders/shadowmap_transparent.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | // ------------------------------------------------------- 4 | 5 | #include "shader_common_main.glsl" 6 | #include "shader_cpu_common.h" 7 | 8 | // Note: this is the only shader in shadowmap generation for non-transparent objects (no frag shader) 9 | 10 | // ###### VERTEX SHADER/PIPELINE INPUT DATA ############## 11 | layout (location = 0) in vec3 aPosition; 12 | layout (location = 1) in vec2 aTexCoords; 13 | 14 | struct PerInstanceAttribute { mat4 modelMatrix; }; 15 | struct DrawnMeshgroupData { 16 | uint materialIndex; // material index 17 | uint meshIndexBase; // index of first mesh of the group in MeshAttribOffsetBuffer 18 | }; 19 | layout (std430, set = 0, binding = 2) readonly buffer AttributesBuffer { PerInstanceAttribute attrib[]; }; // per global mesh, persistent 20 | layout (std430, set = 0, binding = 3) readonly buffer DrawnMeshgroupBuffer { DrawnMeshgroupData meshgroup_data[]; }; // per drawn meshgroup, indexed via glDrawId (dynamic) 21 | layout (std430, set = 0, binding = 4) readonly buffer MeshAttribIndexBuffer { uint attrib_index[]; }; // per drawn mesh: index for AttributesBuffer (dynamic) 22 | layout (std430, set = 0, binding = 5) readonly buffer MeshgroupsLayoutInfoBuffer { uint transparentMeshgroupsOffset; }; // first transparent meshgroup index (dynamic) 23 | 24 | // push constants 25 | layout(push_constant) PUSHCONSTANTSDEF_DII; 26 | 27 | // matrices 28 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 29 | 30 | // ###### DATA PASSED ON ALONG THE PIPELINE ############## 31 | layout (location = 0) out VertexData { 32 | vec2 texCoords; 33 | flat uint materialIndex; 34 | } v_out; 35 | 36 | // ------------------------------------------------------- 37 | 38 | // ###### VERTEX SHADER MAIN ############################# 39 | void main() 40 | { 41 | mat4 modelMatrix; 42 | if (mDrawType >= 0) { 43 | // static scenery 44 | DrawnMeshgroupData mgInfo = meshgroup_data[gl_DrawID + mDrawType * transparentMeshgroupsOffset]; 45 | uint attribIndex = attrib_index[mgInfo.meshIndexBase + gl_InstanceIndex]; 46 | v_out.materialIndex = mgInfo.materialIndex; 47 | modelMatrix = attrib[attribIndex].modelMatrix; 48 | } else { 49 | // moving object 50 | v_out.materialIndex = mMover_materialIndex; 51 | modelMatrix = uboMatUsr.mMover_additionalModelMatrix * mMover_baseModelMatrix; 52 | } 53 | 54 | gl_Position = uboMatUsr.mShadowmapProjViewMatrix[mShadowMapCascadeToBuild] * modelMatrix * vec4(aPosition, 1.0); 55 | v_out.texCoords = aTexCoords; 56 | } 57 | // ------------------------------------------------------- 58 | 59 | -------------------------------------------------------------------------------- /shaders/sharpen.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_samplerless_texture_functions : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_cpu_common.h" 6 | 7 | // ###### SRC/DST IMAGES ################################# 8 | layout(set = 0, binding = 1) uniform texture2D uInputFrame; 9 | layout(set = 0, binding = 2, TAA_SHADER_OUTPUT_FORMAT) writeonly uniform restrict image2D uOutput; 10 | // ------------------------------------------------------- 11 | 12 | // ###### PUSH CONSTANTS AND UBOs ######################## 13 | layout(push_constant) uniform PushConstants { 14 | float sharpeningFactor; 15 | } pushConstants; 16 | 17 | // ------------------------------------------------------- 18 | 19 | // ################## COMPUTE SHADER MAIN ################### 20 | 21 | #define CLAMP_TO_TEX(v) clamp((v), ivec2(0), textureSize(uInputFrame,0)) 22 | 23 | layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in; 24 | void main() 25 | { 26 | ivec2 iuv = ivec2(gl_GlobalInvocationID.xy); 27 | if (any(greaterThanEqual(iuv, textureSize(uInputFrame, 0)))) return; 28 | 29 | vec3 L = texelFetch(uInputFrame, CLAMP_TO_TEX(iuv + ivec2(-1, 0)), 0).rgb; 30 | vec3 R = texelFetch(uInputFrame, CLAMP_TO_TEX(iuv + ivec2( 1, 0)), 0).rgb; 31 | vec3 T = texelFetch(uInputFrame, CLAMP_TO_TEX(iuv + ivec2( 0,-1)), 0).rgb; 32 | vec3 B = texelFetch(uInputFrame, CLAMP_TO_TEX(iuv + ivec2( 0, 1)), 0).rgb; 33 | vec3 C = texelFetch(uInputFrame, iuv, 0).rgb; 34 | 35 | vec3 val = C + (4.0 * C - L - R - T - B) * pushConstants.sharpeningFactor; 36 | val = clamp(val, vec3(0), vec3(1)); // TODO: clamp or not clamp? 37 | imageStore(uOutput, iuv, vec4(val,1)); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /shaders/sharpen_cas.comp: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_samplerless_texture_functions : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | 5 | #include "shader_cpu_common.h" 6 | 7 | // ###### SRC/DST IMAGES ################################# 8 | layout(set = 0, binding = 1, TAA_SHADER_OUTPUT_FORMAT) readonly uniform restrict image2D imgSrc; 9 | layout(set = 0, binding = 2, TAA_SHADER_OUTPUT_FORMAT) writeonly uniform restrict image2D imgDst; 10 | // ------------------------------------------------------- 11 | 12 | // ###### PUSH CONSTANTS AND UBOs ######################## 13 | layout(push_constant) uniform PushConstants { 14 | uvec4 const0; 15 | uvec4 const1; 16 | }; 17 | 18 | // ------------------------------------------------------- 19 | 20 | #define A_GPU 1 21 | #define A_GLSL 1 22 | #include "ffx_a.h" 23 | AF3 CasLoad(ASU2 p) { return imageLoad(imgSrc, p).rgb; } 24 | void CasInput(inout AF1 r, inout AF1 g, inout AF1 b) {} 25 | #include "ffx_cas.h" 26 | 27 | 28 | // ################## COMPUTE SHADER MAIN ################### 29 | 30 | layout(local_size_x = 64) in; 31 | void main() 32 | { 33 | const bool sharpenOnly = true; 34 | 35 | // Do remapping of local xy in workgroup for a more PS-like swizzle pattern. 36 | AU2 gxy = ARmp8x8(gl_LocalInvocationID.x)+AU2(gl_WorkGroupID.x<<4u,gl_WorkGroupID.y<<4u); 37 | 38 | AF4 c; 39 | CasFilter(c.r, c.g, c.b, gxy, const0, const1, sharpenOnly); 40 | imageStore(imgDst, ASU2(gxy), c); 41 | gxy.x += 8u; 42 | 43 | CasFilter(c.r, c.g, c.b, gxy, const0, const1, sharpenOnly); 44 | imageStore(imgDst, ASU2(gxy), c); 45 | gxy.y += 8u; 46 | 47 | CasFilter(c.r, c.g, c.b, gxy, const0, const1, sharpenOnly); 48 | imageStore(imgDst, ASU2(gxy), c); 49 | gxy.x -= 8u; 50 | 51 | CasFilter(c.r, c.g, c.b, gxy, const0, const1, sharpenOnly); 52 | imageStore(imgDst, ASU2(gxy), c); 53 | } 54 | 55 | -------------------------------------------------------------------------------- /shaders/sky_gradient.frag: -------------------------------------------------------------------------------- 1 | #version 460 2 | 3 | // vSphereCoords represents the direction vector towards the sky sphere: 4 | layout (location = 0) in vec3 vSphereCoords; 5 | 6 | layout (location = 0) out vec4 oFragColor; 7 | 8 | void main() 9 | { 10 | const float pi = 3.1415926535897932384626433832795; 11 | const float half_pi = pi * 0.5; 12 | const float hdr_factor = 1.0; 13 | 14 | // Normalize direction vector towards the sky sphere: 15 | vec3 nc = normalize(vSphereCoords); 16 | 17 | // Compute the skybox color and store the result in oFragColor: 18 | float latitude = acos(nc.y); 19 | float longitude = atan(nc.z, nc.x); 20 | float s = cos(abs(longitude)) * 0.5 + 0.5; 21 | float t = mix(1.0 - nc.y, 0.5 + cos((nc.y + 0.5) * 0.5 * pi), 0.5); 22 | oFragColor = mix(vec4(0.1, 0.26, 0.4, 1.0), vec4(1.0, 0.68, 0.28, 1.0) * hdr_factor, t*t*t*t); 23 | float tf = clamp(latitude, 0.0, 1.0); 24 | oFragColor = mix(vec4(0.1, 0.26, 0.4, 1.0), oFragColor, s*s*s*s * tf); 25 | oFragColor = mix(oFragColor, vec4(0.0, 0.0, 0.5, 1.0), sin(clamp(-nc.y, 0.0, 1.0) * half_pi)); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /shaders/sky_gradient.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | // ------------------------------------------------------- 4 | 5 | #include "shader_common_main.glsl" 6 | 7 | layout (location = 0) in vec3 aVertexPosition; 8 | 9 | layout (location = 0) out vec3 vSphereCoords; 10 | 11 | layout(set = 0, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 12 | 13 | 14 | void main() 15 | { 16 | vSphereCoords = aVertexPosition.xyz; 17 | vec4 position_cs = uboMatUsr.mProjMatrix * uboMatUsr.mViewMatrix * uboMatUsr.mCamPos * vec4(aVertexPosition, 1.0); 18 | gl_Position = position_cs; 19 | } 20 | 21 | -------------------------------------------------------------------------------- /shaders/testimage.frag: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_EXT_nonuniform_qualifier : require 3 | #extension GL_GOOGLE_include_directive : enable 4 | // ------------------------------------------------------- 5 | 6 | #include "shader_common_main.glsl" 7 | 8 | layout (location = 0) in VertexData { 9 | vec2 texCoords; 10 | } fs_in; 11 | 12 | layout(set = 0, binding = 0) uniform sampler uSampler; 13 | layout(set = 0, binding = 1) uniform texture2D uInput; 14 | 15 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 16 | 17 | layout (location = 0) out vec4 oFragColor; 18 | 19 | void main() { 20 | #define JITTER_UV (params.mJitterNdcAndAlpha.xy * 0.5 * params.mUnjitterFactor) 21 | vec2 jitterUv = uboMatUsr.mJitterCurrentPrev.xy * 0.5 * -1.0; // jitter is in NDC units! 22 | vec2 uv = fs_in.texCoords + jitterUv; 23 | oFragColor = textureLod(sampler2D(uInput, uSampler), uv, 0); 24 | } 25 | 26 | -------------------------------------------------------------------------------- /shaders/testimage.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | // ------------------------------------------------------- 4 | 5 | // ###### VERTEX SHADER/PIPELINE INPUT DATA ############## 6 | // Several vertex attributes (These are the buffers passed 7 | // to command_buffer_t::draw_indexed in the same order): 8 | layout (location = 0) in vec3 aPosition; 9 | layout (location = 1) in vec2 aTexCoords; 10 | 11 | // ###### DATA PASSED ON ALONG THE PIPELINE ############## 12 | // Data from vert -> tesc or frag: 13 | layout (location = 0) out VertexData { 14 | vec2 texCoords; 15 | } v_out; 16 | // ------------------------------------------------------- 17 | 18 | // ###### VERTEX SHADER MAIN ############################# 19 | void main() 20 | { 21 | v_out.texCoords = aTexCoords; 22 | gl_Position = vec4(aPosition, 1.0); 23 | } 24 | // ------------------------------------------------------- 25 | 26 | -------------------------------------------------------------------------------- /shaders/transform_and_pass_on.vert: -------------------------------------------------------------------------------- 1 | #version 460 2 | #extension GL_GOOGLE_include_directive : enable 3 | // ------------------------------------------------------- 4 | 5 | #include "shader_common_main.glsl" 6 | #include "shader_cpu_common.h" 7 | 8 | // specialization constant to differentiate between static and dynamic objects 9 | //layout(constant_id = SPECCONST_ID_MOVINGOBJECT) const uint movingObject = SPECCONST_VAL_STATIC; 10 | 11 | // ###### VERTEX SHADER/PIPELINE INPUT DATA ############## 12 | // Several vertex attributes (These are the buffers passed 13 | // to command_buffer_t::draw_indexed in the same order): 14 | layout (location = 0) in vec3 aPosition; 15 | layout (location = 1) in vec2 aTexCoords; 16 | layout (location = 2) in vec3 aNormal; 17 | layout (location = 3) in vec3 aTangent; 18 | layout (location = 4) in vec3 aBitangent; 19 | 20 | struct PerInstanceAttribute { mat4 modelMatrix; }; 21 | struct DrawnMeshgroupData { 22 | uint materialIndex; // material index 23 | uint meshIndexBase; // index of first mesh of the group in MeshAttribOffsetBuffer 24 | }; 25 | layout (std430, set = 0, binding = 2) readonly buffer AttributesBuffer { PerInstanceAttribute attrib[]; }; // per global mesh, persistent 26 | layout (std430, set = 0, binding = 3) readonly buffer DrawnMeshgroupBuffer { DrawnMeshgroupData meshgroup_data[]; }; // per drawn meshgroup, indexed via glDrawId (dynamic) 27 | layout (std430, set = 0, binding = 4) readonly buffer MeshAttribIndexBuffer { uint attrib_index[]; }; // per drawn mesh: index for AttributesBuffer (dynamic) 28 | layout (std430, set = 0, binding = 5) readonly buffer MeshgroupsLayoutInfoBuffer { uint transparentMeshgroupsOffset; }; // first transparent meshgroup index (dynamic) 29 | 30 | // push constants 31 | layout(push_constant) PUSHCONSTANTSDEF_DII; 32 | 33 | 34 | // "mMatrices" uniform buffer containing camera matrices: 35 | // It is updated every frame. 36 | layout(set = 1, binding = 0) UNIFORMDEF_MatricesAndUserInput uboMatUsr; 37 | 38 | // ------------------------------------------------------- 39 | 40 | // ###### DATA PASSED ON ALONG THE PIPELINE ############## 41 | // Data from vert -> tesc or frag: 42 | layout (location = 0) out VertexData { 43 | vec4 positionWS; 44 | vec3 positionVS; 45 | vec2 texCoords; 46 | vec3 normalOS; 47 | vec3 tangentOS; 48 | vec3 bitangentOS; 49 | vec4 positionCS; // TODO: don't really need this! 50 | vec4 positionCS_prev; // position in previous frame 51 | 52 | flat uint materialIndex; 53 | flat mat4 modelMatrix; 54 | flat int movingObjectId; 55 | } v_out; 56 | // ------------------------------------------------------- 57 | 58 | // ###### VERTEX SHADER MAIN ############################# 59 | void main() 60 | { 61 | mat4 prev_modelMatrix; 62 | if (mDrawType >= 0) { 63 | // static scenery 64 | DrawnMeshgroupData mgInfo = meshgroup_data[gl_DrawID + mDrawType * transparentMeshgroupsOffset]; 65 | uint attribIndex = attrib_index[mgInfo.meshIndexBase + gl_InstanceIndex]; 66 | v_out.materialIndex = mgInfo.materialIndex; 67 | v_out.modelMatrix = attrib[attribIndex].modelMatrix; 68 | prev_modelMatrix = v_out.modelMatrix; 69 | v_out.movingObjectId = 0; 70 | } else { 71 | // moving object 72 | v_out.materialIndex = mMover_materialIndex; 73 | v_out.modelMatrix = uboMatUsr.mMover_additionalModelMatrix * mMover_baseModelMatrix; 74 | prev_modelMatrix = uboMatUsr.mMover_additionalModelMatrix_prev * mMover_baseModelMatrix; 75 | v_out.movingObjectId = -mDrawType; 76 | } 77 | 78 | 79 | mat4 mMatrix = v_out.modelMatrix; 80 | mat4 vMatrix = uboMatUsr.mViewMatrix; 81 | mat4 pMatrix = uboMatUsr.mProjMatrix; 82 | mat4 vmMatrix = vMatrix * mMatrix; 83 | mat4 pvmMatrix = pMatrix * vmMatrix; 84 | 85 | vec4 positionOS = vec4(aPosition, 1.0); 86 | vec4 positionVS = vmMatrix * positionOS; 87 | vec4 positionCS = pMatrix * positionVS; 88 | vec3 normalOS = normalize(aNormal); 89 | vec3 tangentOS = normalize(aTangent); 90 | vec3 bitangentOS = normalize(aBitangent); 91 | 92 | v_out.positionWS = mMatrix * positionOS; 93 | v_out.positionVS = positionVS.xyz; 94 | v_out.texCoords = aTexCoords; 95 | v_out.normalOS = normalOS; 96 | v_out.tangentOS = tangentOS; 97 | v_out.bitangentOS = bitangentOS; 98 | v_out.positionCS = positionCS; // TODO: recheck - is it ok to interpolate clip space vars? 99 | v_out.positionCS_prev = uboMatUsr.mPrevFrameProjViewMatrix * prev_modelMatrix * positionOS; 100 | 101 | gl_Position = positionCS; 102 | } 103 | // ------------------------------------------------------- 104 | 105 | -------------------------------------------------------------------------------- /source/BoundingBox.cpp: -------------------------------------------------------------------------------- 1 | #include "BoundingBox.hpp" 2 | 3 | void BoundingBox::combineWith(const BoundingBox &other) { 4 | combineWith(other.min); 5 | combineWith(other.max); 6 | } 7 | 8 | void BoundingBox::combineWith(const glm::vec3 &point) { 9 | min = glm::min(min, point); 10 | max = glm::max(max, point); 11 | } 12 | 13 | float BoundingBox::getAbsMaxValue() { 14 | glm::vec3 v = glm::max(glm::abs(min), glm::abs(max)); 15 | return glm::max(v.x, glm::max(v.y, v.z)); 16 | } 17 | 18 | float BoundingBox::getLongestSide() { 19 | glm::vec3 v = max - min; 20 | return glm::max(v.x, glm::max(v.y, v.z)); 21 | } 22 | 23 | void BoundingBox::calcFromPoints(size_t numPts, glm::vec3 * pPts) { 24 | if (numPts < 1) return; 25 | min = max = pPts[0]; 26 | for (auto i = 1; i < numPts; i++) combineWith(pPts[i]); 27 | } 28 | 29 | void BoundingBox::calcFromPoints(size_t numPts, glm::vec4 * pPts) { 30 | if (numPts < 1) return; 31 | min = max = glm::vec3(pPts[0]); 32 | for (auto i = 1; i < numPts; i++) combineWith(glm::vec3(pPts[i])); 33 | } 34 | 35 | void BoundingBox::intersectWith(const BoundingBox &other) { 36 | min = glm::max(min, other.min); 37 | max = glm::min(max, other.max); 38 | } 39 | 40 | void BoundingBox::getPointsV4(glm::vec4 * p) { 41 | p[0] = glm::vec4(min.x, min.y, min.z, 1.0f); 42 | p[1] = glm::vec4(max.x, min.y, min.z, 1.0f); 43 | p[2] = glm::vec4(min.x, max.y, min.z, 1.0f); 44 | p[3] = glm::vec4(max.x, max.y, min.z, 1.0f); 45 | p[4] = glm::vec4(min.x, min.y, max.z, 1.0f); 46 | p[5] = glm::vec4(max.x, min.y, max.z, 1.0f); 47 | p[6] = glm::vec4(min.x, max.y, max.z, 1.0f); 48 | p[7] = glm::vec4(max.x, max.y, max.z, 1.0f); 49 | } 50 | 51 | void BoundingBox::getTransformedPointsV4(const glm::mat4 & transform, glm::vec4 * p) { 52 | p[0] = transform * glm::vec4(min.x, min.y, min.z, 1.0f); 53 | p[1] = transform * glm::vec4(max.x, min.y, min.z, 1.0f); 54 | p[2] = transform * glm::vec4(min.x, max.y, min.z, 1.0f); 55 | p[3] = transform * glm::vec4(max.x, max.y, min.z, 1.0f); 56 | p[4] = transform * glm::vec4(min.x, min.y, max.z, 1.0f); 57 | p[5] = transform * glm::vec4(max.x, min.y, max.z, 1.0f); 58 | p[6] = transform * glm::vec4(min.x, max.y, max.z, 1.0f); 59 | p[7] = transform * glm::vec4(max.x, max.y, max.z, 1.0f); 60 | } 61 | -------------------------------------------------------------------------------- /source/BoundingBox.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | struct BoundingBox { 6 | glm::vec3 min, max; 7 | 8 | void combineWith(const BoundingBox &other); 9 | void combineWith(const glm::vec3 &point); 10 | float getAbsMaxValue(); 11 | float getLongestSide(); 12 | void calcFromPoints(size_t numPts, glm::vec3 *pPts); 13 | void calcFromPoints(size_t numPts, glm::vec4 *pPts); // w-components are ignored 14 | void intersectWith(const BoundingBox &other); 15 | void getPointsV4(glm::vec4 *p); 16 | void getTransformedPointsV4(const glm::mat4 &transform, glm::vec4 *p); 17 | }; 18 | -------------------------------------------------------------------------------- /source/FrustumCulling.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | // TODO: check https://gist.github.com/Kinwailo for a possibly faster method to extract the planes 7 | 8 | class FrustumCulling { 9 | private: 10 | glm::vec4 mPlanes[6]; // .xyz = normal, .w = distance 11 | 12 | const static bool normalize_planes = false; // not needed 13 | public: 14 | enum class TestResult { inside, outside, intersect }; 15 | 16 | FrustumCulling(const glm::mat4 &projViewMatrix) { 17 | using namespace glm; 18 | // see Real-Time Rendering 4th ed., pp. 984 for derivation of frustrum planes from the projViewMatrix m 19 | // left -(m3, + m0,) 20 | // right -(m3, - m0,) 21 | // bottom -(m3, + m1,) 22 | // top -(m3, - m1,) 23 | // near -(m3, + m2,) 24 | // far -(m3, - m2,) 25 | 26 | // calculate normal vectors and offset for frustum planes (note mi, denotes i'th ROW above - that is m[.][i] in a glm::mat4) 27 | vec4 m0 = glm::row(projViewMatrix, 0); 28 | vec4 m1 = glm::row(projViewMatrix, 1); 29 | vec4 m2 = glm::row(projViewMatrix, 2); 30 | vec4 m3 = glm::row(projViewMatrix, 3); 31 | 32 | mPlanes[0] = -(m3 + m0); 33 | mPlanes[1] = -(m3 - m0); 34 | mPlanes[2] = -(m3 + m1); 35 | mPlanes[3] = -(m3 - m1); 36 | mPlanes[4] = -(m3 + m2); 37 | mPlanes[5] = -(m3 - m2); 38 | 39 | if (normalize_planes) { 40 | for (int i = 0; i < 6; i++) { 41 | float len = length(vec3(mPlanes[i])); 42 | mPlanes[i] /= len; 43 | } 44 | } 45 | 46 | } 47 | 48 | // FrustumAABBIntersect code adapted from https://gist.github.com/Kinwailo 49 | // Returns: INTERSECT : 0 50 | // INSIDE : 1 51 | // OUTSIDE : 2 52 | TestResult FrustumAABBIntersect(const glm::vec3 &mins, const glm::vec3 &maxs) const { 53 | TestResult ret = TestResult::inside; 54 | glm::vec3 vmin, vmax; 55 | 56 | for(int i = 0; i < 6; ++i) { 57 | // X axis 58 | if(mPlanes[i].x > 0) { 59 | vmin.x = mins.x; 60 | vmax.x = maxs.x; 61 | } else { 62 | vmin.x = maxs.x; 63 | vmax.x = mins.x; 64 | } 65 | // Y axis 66 | if(mPlanes[i].y > 0) { 67 | vmin.y = mins.y; 68 | vmax.y = maxs.y; 69 | } else { 70 | vmin.y = maxs.y; 71 | vmax.y = mins.y; 72 | } 73 | // Z axis 74 | if(mPlanes[i].z > 0) { 75 | vmin.z = mins.z; 76 | vmax.z = maxs.z; 77 | } else { 78 | vmin.z = maxs.z; 79 | vmax.z = mins.z; 80 | } 81 | if(glm::dot(glm::vec3(mPlanes[i]), vmin) + mPlanes[i].w > 0.f) return TestResult::outside; 82 | if(glm::dot(glm::vec3(mPlanes[i]), vmax) + mPlanes[i].w >= 0.f) ret = TestResult::intersect; 83 | } 84 | return ret; 85 | } 86 | 87 | bool CanCull(const BoundingBox &bb) const { 88 | return TestResult::outside == FrustumAABBIntersect(bb.min, bb.max); 89 | } 90 | 91 | glm::vec4 Plane(int index) { return mPlanes[index]; } 92 | }; 93 | -------------------------------------------------------------------------------- /source/IniUtil.cpp: -------------------------------------------------------------------------------- 1 | #include "IniUtil.h" 2 | 3 | 4 | static bool valid_char[256]; 5 | static bool valid_char_inited = false; 6 | 7 | static const int textLineLength = 200; 8 | 9 | static void initValidChars() { 10 | if (valid_char_inited) return; 11 | const char *keep = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 +-/\"'#.,_!*"; 12 | for (int i = 0; i < 256; ++i) valid_char[i] = false; 13 | for (const char *p = keep; *p; ++p) valid_char[*p] = true; 14 | valid_char_inited = true; 15 | } 16 | 17 | static std::string encodeText(std::string s) { 18 | initValidChars(); 19 | std::string res = ""; 20 | for (const char c : s) { 21 | if (valid_char[c]) { 22 | res += c; 23 | } else { 24 | char buf[10]; 25 | snprintf(buf, 10, "\\%.2x", c); 26 | res += buf; 27 | } 28 | } 29 | return res; 30 | } 31 | 32 | static std::string decodeText(std::string s) { 33 | std::string res = ""; 34 | bool fail = false; 35 | for (size_t i = 0; i < s.length(); ++i) { 36 | if (s[i] != '\\') { 37 | res += s[i]; 38 | } else { 39 | char c1, c2; 40 | if (++i < s.length()) { c1 = s[i]; } else { fail = true; break; } 41 | if (++i < s.length()) { c2 = s[i]; } else { fail = true; break; } 42 | if (c1 >= 'a' && c1 <= 'f') { c1 = c1 - 'a' + 10; } else if (c1 >= '0' && c1 <= '9') { c1 -= '0'; } else { fail = true; break; } 43 | if (c2 >= 'a' && c2 <= 'f') { c2 = c2 - 'a' + 10; } else if (c2 >= '0' && c2 <= '9') { c2 -= '0'; } else { fail = true; break; } 44 | res += c1 * 16 + c2; 45 | } 46 | } 47 | return res; 48 | } 49 | 50 | // TODO: check if floats always use "." as comma when using to_string 51 | void iniWriteString(mINI::INIStructure &ini, const std::string §ion, const std::string &name, const std::string &val) { ini[section][name] = val; } 52 | void iniWriteBool (mINI::INIStructure &ini, const std::string §ion, const std::string &name, const bool &val) { ini[section][name] = val ? "1" : "0"; } 53 | void iniWriteBool32(mINI::INIStructure &ini, const std::string §ion, const std::string &name, const uint32_t &val) { ini[section][name] = std::to_string(val); } 54 | void iniWriteInt (mINI::INIStructure &ini, const std::string §ion, const std::string &name, const int &val) { ini[section][name] = std::to_string(val); } 55 | void iniWriteFloat (mINI::INIStructure &ini, const std::string §ion, const std::string &name, const float &val) { ini[section][name] = std::to_string(val); } 56 | void iniWriteVec2 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, const glm::vec2 &val) { 57 | iniWriteFloat(ini, section, name + ".x", val.x); 58 | iniWriteFloat(ini, section, name + ".y", val.y); 59 | } 60 | void iniWriteIVec2 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, const glm::ivec2 &val) { 61 | iniWriteInt(ini, section, name + ".x", val.x); 62 | iniWriteInt(ini, section, name + ".y", val.y); 63 | } 64 | void iniWriteVec3 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, const glm::vec3 &val) { 65 | iniWriteFloat(ini, section, name + ".x", val.x); 66 | iniWriteFloat(ini, section, name + ".y", val.y); 67 | iniWriteFloat(ini, section, name + ".z", val.z); 68 | } 69 | void iniWriteIVec3 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, const glm::ivec3 &val) { 70 | iniWriteInt(ini, section, name + ".x", val.x); 71 | iniWriteInt(ini, section, name + ".y", val.y); 72 | iniWriteInt(ini, section, name + ".z", val.z); 73 | } 74 | void iniWriteVec4 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, const glm::vec4 &val) { 75 | iniWriteFloat(ini, section, name + ".x", val.x); 76 | iniWriteFloat(ini, section, name + ".y", val.y); 77 | iniWriteFloat(ini, section, name + ".z", val.z); 78 | iniWriteFloat(ini, section, name + ".w", val.w); 79 | } 80 | void iniWriteIVec4 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, const glm::ivec4 &val) { 81 | iniWriteInt(ini, section, name + ".x", val.x); 82 | iniWriteInt(ini, section, name + ".y", val.y); 83 | iniWriteInt(ini, section, name + ".z", val.z); 84 | iniWriteInt(ini, section, name + ".w", val.w); 85 | } 86 | void iniWriteQuat (mINI::INIStructure &ini, const std::string §ion, const std::string &name, const glm::quat &val) { 87 | iniWriteFloat(ini, section, name + ".x", val.x); 88 | iniWriteFloat(ini, section, name + ".y", val.y); 89 | iniWriteFloat(ini, section, name + ".z", val.z); 90 | iniWriteFloat(ini, section, name + ".w", val.w); 91 | } 92 | void iniWriteText(mINI::INIStructure &ini, const std::string §ion, const std::string &name, const std::string &val) { 93 | std::string s = encodeText(val); 94 | int numLines = static_cast((s.length() + textLineLength - 1) / textLineLength); 95 | iniWriteInt(ini, section, name + ".n", numLines); 96 | for (int i = 0; i < numLines; ++i) { 97 | iniWriteString(ini, section, name + ".s" + std::to_string(i), s.substr(i * textLineLength, textLineLength)); 98 | } 99 | } 100 | 101 | 102 | 103 | void iniReadString(mINI::INIStructure &ini, const std::string §ion, const std::string &name, std::string &val) { if (ini[section][name] != "") val = ini[section][name]; } 104 | void iniReadBool (mINI::INIStructure &ini, const std::string §ion, const std::string &name, bool &val) { if (ini[section][name] != "") val = (ini[section][name] == "1") || (ini[section][name] == "true"); } 105 | void iniReadBool32(mINI::INIStructure &ini, const std::string §ion, const std::string &name, uint32_t &val) { if (ini[section][name] != "") val = std::stoul(ini[section][name]); } 106 | void iniReadInt (mINI::INIStructure &ini, const std::string §ion, const std::string &name, int &val) { if (ini[section][name] != "") val = std::stol(ini[section][name]); } 107 | void iniReadInt (mINI::INIStructure &ini, const std::string §ion, const std::string &name, uint32_t &val) { if (ini[section][name] != "") val = std::stoul(ini[section][name]); } 108 | void iniReadFloat (mINI::INIStructure &ini, const std::string §ion, const std::string &name, float &val) { if (ini[section][name] != "") val = std::stof(ini[section][name]); } 109 | void iniReadVec2 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, glm::vec2 &val) { 110 | iniReadFloat(ini, section, name + ".x", val.x); 111 | iniReadFloat(ini, section, name + ".y", val.y); 112 | } 113 | void iniReadIVec2 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, glm::ivec2 &val) { 114 | iniReadInt(ini, section, name + ".x", val.x); 115 | iniReadInt(ini, section, name + ".y", val.y); 116 | } 117 | void iniReadVec3 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, glm::vec3 &val) { 118 | iniReadFloat(ini, section, name + ".x", val.x); 119 | iniReadFloat(ini, section, name + ".y", val.y); 120 | iniReadFloat(ini, section, name + ".z", val.z); 121 | } 122 | void iniReadIVec3 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, glm::ivec3 &val) { 123 | iniReadInt(ini, section, name + ".x", val.x); 124 | iniReadInt(ini, section, name + ".y", val.y); 125 | iniReadInt(ini, section, name + ".z", val.z); 126 | } 127 | void iniReadVec4 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, glm::vec4 &val) { 128 | iniReadFloat(ini, section, name + ".x", val.x); 129 | iniReadFloat(ini, section, name + ".y", val.y); 130 | iniReadFloat(ini, section, name + ".z", val.z); 131 | iniReadFloat(ini, section, name + ".w", val.w); 132 | } 133 | void iniReadIVec4 (mINI::INIStructure &ini, const std::string §ion, const std::string &name, glm::ivec4 &val) { 134 | iniReadInt(ini, section, name + ".x", val.x); 135 | iniReadInt(ini, section, name + ".y", val.y); 136 | iniReadInt(ini, section, name + ".z", val.z); 137 | iniReadInt(ini, section, name + ".w", val.w); 138 | } 139 | void iniReadQuat (mINI::INIStructure &ini, const std::string §ion, const std::string &name, glm::quat &val) { 140 | iniReadFloat(ini, section, name + ".x", val.x); 141 | iniReadFloat(ini, section, name + ".y", val.y); 142 | iniReadFloat(ini, section, name + ".z", val.z); 143 | iniReadFloat(ini, section, name + ".w", val.w); 144 | } 145 | void iniReadText (mINI::INIStructure &ini, const std::string §ion, const std::string &name, std::string &val) { 146 | int numLines = -1; 147 | iniReadInt(ini, section, name + ".n", numLines); 148 | if (numLines < 0) return; 149 | 150 | std::string s = ""; 151 | for (int i = 0; i < numLines; ++i) { 152 | std::string tmp = ""; 153 | iniReadString(ini, section, name + ".s" + std::to_string(i), tmp); 154 | s += tmp; 155 | } 156 | 157 | val = decodeText(s); 158 | } 159 | 160 | 161 | //#define DEF_INI_DO(NAME,TYPE) \ 162 | //void iniDo ## NAME (bool write, mINI::INIStructure & ini, const std::string & section, const std::string &name, TYPE &val) { \ 163 | // if (write) \ 164 | // iniWrite ## NAME(ini, section, name, val); \ 165 | // else \ 166 | // iniRead ## NAME(ini, section, name, val); \ 167 | //} 168 | // 169 | // 170 | //DEF_INI_DO(String, std::string) 171 | 172 | -------------------------------------------------------------------------------- /source/IniUtil.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | // Warn: iniWriteString/iniReadString assumes there are no special characters like newlines in the string. And probably the length is limited too. 7 | // use iniWriteText/iniReadText for general purpose strings (can be multiline) 8 | 9 | void iniWriteString(mINI::INIStructure & ini, const std::string & section, const std::string & name, const std::string & val); 10 | void iniWriteBool (mINI::INIStructure & ini, const std::string & section, const std::string & name, const bool & val); 11 | void iniWriteBool32(mINI::INIStructure & ini, const std::string & section, const std::string & name, const uint32_t & val); 12 | void iniWriteInt (mINI::INIStructure & ini, const std::string & section, const std::string & name, const int & val); 13 | void iniWriteFloat (mINI::INIStructure & ini, const std::string & section, const std::string & name, const float & val); 14 | void iniWriteVec2 (mINI::INIStructure & ini, const std::string & section, const std::string & name, const glm::vec2 & val); 15 | void iniWriteIVec2 (mINI::INIStructure & ini, const std::string & section, const std::string & name, const glm::ivec2 & val); 16 | void iniWriteVec3 (mINI::INIStructure & ini, const std::string & section, const std::string & name, const glm::vec3 & val); 17 | void iniWriteIVec3 (mINI::INIStructure & ini, const std::string & section, const std::string & name, const glm::ivec3 & val); 18 | void iniWriteVec4 (mINI::INIStructure & ini, const std::string & section, const std::string & name, const glm::vec4 & val); 19 | void iniWriteIVec4 (mINI::INIStructure & ini, const std::string & section, const std::string & name, const glm::ivec4 & val); 20 | void iniWriteQuat (mINI::INIStructure & ini, const std::string & section, const std::string & name, const glm::quat & val); 21 | void iniWriteText (mINI::INIStructure & ini, const std::string & section, const std::string & name, const std::string & val); 22 | 23 | void iniReadString (mINI::INIStructure & ini, const std::string & section, const std::string & name, std::string & val); 24 | void iniReadBool (mINI::INIStructure & ini, const std::string & section, const std::string & name, bool & val); 25 | void iniReadBool32 (mINI::INIStructure & ini, const std::string & section, const std::string & name, uint32_t & val); 26 | void iniReadInt (mINI::INIStructure & ini, const std::string & section, const std::string & name, int & val); 27 | void iniReadInt (mINI::INIStructure & ini, const std::string & section, const std::string & name, uint32_t & val); 28 | void iniReadFloat (mINI::INIStructure & ini, const std::string & section, const std::string & name, float & val); 29 | void iniReadVec2 (mINI::INIStructure & ini, const std::string & section, const std::string & name, glm::vec2 & val); 30 | void iniReadIVec2 (mINI::INIStructure & ini, const std::string & section, const std::string & name, glm::ivec2 & val); 31 | void iniReadVec3 (mINI::INIStructure & ini, const std::string & section, const std::string & name, glm::vec3 & val); 32 | void iniReadIVec3 (mINI::INIStructure & ini, const std::string & section, const std::string & name, glm::ivec3 & val); 33 | void iniReadVec4 (mINI::INIStructure & ini, const std::string & section, const std::string & name, glm::vec4 & val); 34 | void iniReadIVec4 (mINI::INIStructure & ini, const std::string & section, const std::string & name, glm::ivec4 & val); 35 | void iniReadQuat (mINI::INIStructure & ini, const std::string & section, const std::string & name, glm::quat & val); 36 | void iniReadText (mINI::INIStructure & ini, const std::string & section, const std::string & name, std::string & val); 37 | 38 | //void iniDoString (bool write, mINI::INIStructure & ini, const std::string & section, const std::string & name, std::string & val); 39 | 40 | -------------------------------------------------------------------------------- /source/InterpolationCurve.cpp: -------------------------------------------------------------------------------- 1 | #include "InterpolationCurve.hpp" 2 | 3 | void InterpolationCurve::setType(InterpolationCurveType aType) { 4 | if (aType == mType) return; 5 | 6 | // save control points 7 | std::vector oldPts = interpolator().control_points(); 8 | mType = aType; 9 | interpolator().set_control_points(oldPts); 10 | 11 | invalidateArcLenTable(); 12 | } 13 | 14 | gvk::cp_interpolation & InterpolationCurve::interpolator() 15 | { 16 | switch (mType) { 17 | case InterpolationCurveType::bezier_curve: return mInterpolatorBezier; 18 | case InterpolationCurveType::quadratic_uniform_b_spline: return mInterpolatorQuadB; 19 | case InterpolationCurveType::cubic_uniform_b_spline: return mInterpolatorCubeB; 20 | case InterpolationCurveType::catmull_rom_spline: return mInterpolatorCatmull; 21 | } 22 | throw avk::runtime_error("Invalid interpolation curve type"); 23 | } 24 | 25 | void InterpolationCurve::set_control_points(std::vector pControlPoints) { interpolator().set_control_points(pControlPoints); invalidateArcLenTable(); } 26 | const std::vector& InterpolationCurve::control_points() { return interpolator().control_points(); } 27 | const glm::vec3& InterpolationCurve::control_point_at(size_t index) { return interpolator().control_point_at(index); } 28 | size_t InterpolationCurve::num_control_points() { return interpolator().control_points().size(); } 29 | glm::vec3 InterpolationCurve::value_at(float t) { return valid() ? interpolator().value_at(t) : glm::vec3(0); } 30 | glm::vec3 InterpolationCurve::slope_at(float t) { return valid() ? interpolator().slope_at(t) : glm::vec3(0); } 31 | 32 | bool InterpolationCurve::valid() 33 | { 34 | if (mType == InterpolationCurveType::catmull_rom_spline) { 35 | return interpolator().num_control_points() >= 4; 36 | } else { 37 | return interpolator().num_control_points() >= 2; 38 | } 39 | } 40 | 41 | void InterpolationCurve::buildArcLenTable() 42 | { 43 | int nSegs = static_cast((mType == InterpolationCurveType::catmull_rom_spline) ? num_control_points() - 3 : num_control_points() - 1); 44 | int nSamples = mArcLenSamplesPerSegment * nSegs; 45 | 46 | if (!valid() || nSamples < 2) return; 47 | 48 | mArcLenTable.resize(nSamples); 49 | float distance = 0.f; 50 | auto prev = value_at(0.f); 51 | mArcLenTable[0] = distance; 52 | for (int i = 1; i < nSamples; ++i) { 53 | float t = static_cast(i) / static_cast(nSamples - 1); 54 | auto next = value_at(t); 55 | distance += glm::length(next - prev); 56 | mArcLenTable[i] = distance; 57 | prev = next; 58 | } 59 | if (distance > 0.f) { 60 | for (int i = 0; i < nSamples; ++i) mArcLenTable[i] /= distance; 61 | } 62 | } 63 | 64 | void InterpolationCurve::invalidateArcLenTable() 65 | { 66 | mArcLenTable.clear(); 67 | } 68 | 69 | 70 | float InterpolationCurve::mapConstantSpeedTime(float t) 71 | { 72 | if (mArcLenTable.empty()) buildArcLenTable(); 73 | if (mArcLenTable.empty()) return t; 74 | 75 | int nSamples = static_cast(mArcLenTable.size()); 76 | 77 | if (t < mArcLenTable[0]) return 0.f; 78 | if (t > mArcLenTable[nSamples-1]) return 1.f; 79 | 80 | // binary search in normalized arc len table; find first entry with value > t 81 | int lo = 0; 82 | int hi = nSamples - 1; 83 | while (lo + 1 < hi) { 84 | int mid = (lo + hi) / 2; 85 | if (mArcLenTable[mid] < t) { 86 | lo = mid; 87 | } else { 88 | hi = mid; 89 | } 90 | } 91 | assert(lo + 1 == hi); 92 | assert(mArcLenTable[lo] <= t); 93 | assert(mArcLenTable[hi] >= t); 94 | 95 | float f = (mArcLenTable[lo] == mArcLenTable[hi]) ? 0.f : (t - mArcLenTable[lo]) / (mArcLenTable[hi] - mArcLenTable[lo]); 96 | float t1 = static_cast(lo) / static_cast(nSamples - 1); 97 | float t2 = static_cast(hi) / static_cast(nSamples - 1); 98 | return t1 * (1.f - f) + t2 * f; 99 | } 100 | 101 | -------------------------------------------------------------------------------- /source/InterpolationCurve.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | enum class InterpolationCurveType {bezier_curve, quadratic_uniform_b_spline, cubic_uniform_b_spline, catmull_rom_spline}; 5 | 6 | class InterpolationCurve { 7 | public: 8 | InterpolationCurve() : mType(InterpolationCurveType::bezier_curve) {} 9 | InterpolationCurve(InterpolationCurveType aType, std::vector pControlPoints) : mType(aType) { interpolator().set_control_points(pControlPoints); } 10 | 11 | void setType(InterpolationCurveType aType); 12 | InterpolationCurveType type() { return mType; } 13 | 14 | void set_control_points(std::vector pControlPoints); 15 | const std::vector& control_points(); 16 | const glm::vec3& control_point_at(size_t index); 17 | size_t num_control_points(); 18 | glm::vec3 value_at(float t); 19 | glm::vec3 slope_at(float t); 20 | 21 | float mapConstantSpeedTime(float t); 22 | 23 | int arcLenSamplesPerSegment() { return mArcLenSamplesPerSegment; } 24 | void setArcLenSamplesPerSegment(int numSamples) { mArcLenSamplesPerSegment = numSamples; invalidateArcLenTable(); } 25 | 26 | bool valid(); 27 | private: 28 | InterpolationCurveType mType; 29 | 30 | gvk::bezier_curve mInterpolatorBezier; 31 | gvk::quadratic_uniform_b_spline mInterpolatorQuadB; 32 | gvk::cubic_uniform_b_spline mInterpolatorCubeB; 33 | gvk::catmull_rom_spline mInterpolatorCatmull; 34 | 35 | int mArcLenSamplesPerSegment = 20; 36 | 37 | std::vector mArcLenTable; 38 | 39 | gvk::cp_interpolation & interpolator(); 40 | void buildArcLenTable(); 41 | void invalidateArcLenTable(); 42 | }; 43 | 44 | -------------------------------------------------------------------------------- /source/RayTraceCallback.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // https://stackoverflow.com/questions/400257/how-can-i-pass-a-class-member-function-as-a-callback 4 | 5 | class RayTraceCallback { 6 | public: 7 | virtual void ray_trace_callback(avk::command_buffer &cmd) = 0; 8 | virtual int getNumRayTraceSamples() = 0; 9 | virtual void setNumRayTraceSamples(int aNumSamples) = 0; 10 | virtual bool getRayTraceAugmentTaaDebug() = 0; 11 | virtual void setRayTraceAugmentTaaDebug(bool aDebug) = 0; 12 | }; -------------------------------------------------------------------------------- /source/ShadowMap.cpp: -------------------------------------------------------------------------------- 1 | #include "ShadowMap.hpp" 2 | 3 | void ShadowMap::init(const BoundingBox & aSceneBoundingBox, float camNear, float camFar, int aShadowMapTextureSize, int numCascades, bool autoCalcCascades) 4 | { 5 | assert(numCascades > 0 && numCascades <= MAX_CASCADES); 6 | 7 | mSceneBoundingBox = aSceneBoundingBox; 8 | mCamNear = camNear; 9 | mCamFar = camFar; 10 | mNumCascades = numCascades; 11 | mTextureSize = aShadowMapTextureSize; 12 | 13 | for (int i = 0; i < MAX_CASCADES; i++) { 14 | mCascadeProjMatrix[i] = mCascadeVPMatrix[i] = glm::mat4(1); 15 | } 16 | 17 | if (autoCalcCascades) calc_cascade_ends(); 18 | } 19 | 20 | void ShadowMap::calc_cascade_ends() { 21 | // see article "Cascaded Shadow Maps" by Rouslan Dimitrov for NVIDIA OpenGL SDK sample about CSM 22 | float lambda = .75f; 23 | float ratio = mCamFar / mCamNear; 24 | for (int i = 1; i < mNumCascades; i++) { 25 | float z = lambda * mCamNear * powf(mCamFar / mCamNear, (float)i / mNumCascades) + (1.0f - lambda)*(mCamNear + ((float)i / mNumCascades)*(mCamFar - mCamNear)); 26 | cascadeEnd[i - 1] = (z - mCamNear) / (mCamFar - mCamNear); 27 | //PRINTOUT("z(" << i << ")=" << z << ", cascadeEnd[" << i-1 << "]=" << cascadeEnd[i-1]); 28 | } 29 | cascadeEnd[mNumCascades - 1] = 1.0f; 30 | } 31 | 32 | void ShadowMap::calc(const glm::vec3 & aLightDirection, const glm::mat4 & aCamViewMatrix, const glm::mat4 & aCamProjMatrix, std::optional aIncludeThisPoint) 33 | { 34 | mCamViewMatrix = aCamViewMatrix; 35 | mCamProjMatrix = aCamProjMatrix; 36 | mCamVPMatrix = mCamProjMatrix * mCamViewMatrix; 37 | mLightDirection = glm::normalize(aLightDirection); 38 | mAdjustForAdditionalPoint = aIncludeThisPoint; 39 | calcLightView(); 40 | } 41 | 42 | void ShadowMap::calcLightView() 43 | { 44 | // create light view matrix, centered at origin 45 | glm::vec3 lookFrom = glm::vec3(0); 46 | glm::vec3 lookAt = mLightDirection; 47 | 48 | glm::vec3 up = glm::vec3(0,1,0); 49 | if (abs(glm::dot(up, mLightDirection)) > 0.999f) up = glm::vec3(0,0,-1); 50 | glm::vec3 right = glm::cross(mLightDirection, up); 51 | up = glm::cross(right, mLightDirection); 52 | mViewMatrix = glm::lookAt(lookFrom, lookAt, up); 53 | 54 | // convert scene bounds to light space 55 | BoundingBox bbScene = mSceneBoundingBox; 56 | if (mAdjustForAdditionalPoint.has_value()) bbScene.combineWith(glm::vec4(mAdjustForAdditionalPoint.value(), 1.0f)); 57 | glm::vec4 scenePtLS[8]; 58 | bbScene.getTransformedPointsV4(mViewMatrix, scenePtLS); 59 | 60 | // calculate light projection 61 | for (int iCasc = 0; iCasc < mNumCascades; iCasc++) { 62 | // get the camera view frustum for the current cascade (in world space) 63 | glm::vec4 camFrustPtWS[8]; 64 | float cascBegin; 65 | if (cascadeFitMode == CascadeFitMode::fitCascade) { 66 | cascBegin = (iCasc == 0) ? 0.0f : cascadeEnd[iCasc - 1]; // new cascade begins where previous cascade ended 67 | } else { 68 | cascBegin = 0.0f; // all cascades start at zero 69 | } 70 | calcPartialCamFrustum(cascBegin, cascadeEnd[iCasc], camFrustPtWS); 71 | 72 | // convert cam frustum points from world space to light space 73 | glm::vec4 camFrustPtLS[8]; 74 | for (int i = 0; i < 8; i++) 75 | camFrustPtLS[i] = mViewMatrix * camFrustPtWS[i]; 76 | 77 | 78 | // TODO.... 79 | 80 | BoundingBox bb; 81 | bb.calcFromPoints(8, camFrustPtLS); 82 | 83 | if (restrictLightViewToScene) { // TODO: better way than intersecting with the bb(!) of the frustum? 84 | BoundingBox bb2; 85 | bb2.calcFromPoints(8, scenePtLS); 86 | bb.intersectWith(bb2); 87 | } 88 | 89 | // TODO.... 90 | 91 | if (cascadeFitMode == CascadeFitMode::fitCascade) { 92 | if (texelSnapping) { 93 | glm::vec2 bb_min_xy = glm::vec2(bb.min); 94 | glm::vec2 bb_max_xy = glm::vec2(bb.max); 95 | glm::vec2 unitsPerTexel = (bb_max_xy - bb_min_xy) / (float)mTextureSize; 96 | bb_min_xy = glm::floor(bb_min_xy / unitsPerTexel) * unitsPerTexel; 97 | bb_max_xy = glm::floor(bb_max_xy / unitsPerTexel) * unitsPerTexel; 98 | bb.min.x = bb_min_xy.x; bb.min.y = bb_min_xy.y; 99 | bb.max.x = bb_max_xy.x; bb.max.y = bb_max_xy.y; 100 | } 101 | } // TODO: snapping for other modes 102 | 103 | // --- light ortho sides are fixed now (bb x and y values) 104 | 105 | 106 | // --- now fit the near and far plane 107 | 108 | float nearPlane, farPlane; 109 | if (nearfarFitMode == NearFarFitMode::nffFrustumOnly) { 110 | nearPlane = -bb.max.z; 111 | farPlane = -bb.min.z; 112 | } else { 113 | // intersect scene box with light frustum -> gets tighter fit 114 | calcNearFar(glm::vec2(bb.min), glm::vec2(bb.max), /* out */ nearPlane, /* out */ farPlane, scenePtLS); 115 | // TODO... implement pancaking? 116 | } 117 | 118 | // create light projection matrix 119 | mCascadeProjMatrix[iCasc] = glm::ortho(bb.min.x, bb.max.x, bb.min.y, bb.max.y, nearPlane, farPlane); 120 | mCascadeVPMatrix[iCasc] = mCascadeProjMatrix[iCasc] * mViewMatrix; 121 | 122 | // calc cascade depth bounds - TODO: move this out further (init?); when does cam proj change? on screen resize for instance.. 123 | // TODO: improve performance! 124 | // ATTN: after projection z (when inside near/far) is also in NDC (-1..1), NOT in (0..1) ! // TODO - recheck for Vulkan! 125 | //glm::vec4 p = mCamProjMatrix * glm::vec4(0.0f, 0.0f, -mCamNear - cascadeEnd[iCasc] * (mCamFar - mCamNear), 1.0f); 126 | //mCascadeDepthBounds[iCasc] = (p.z / p.w) * .5f + .5f; 127 | 128 | // Vulkan: 129 | glm::vec4 p = mCamProjMatrix * glm::vec4(0.0f, 0.0f, mCamNear + cascadeEnd[iCasc] * (mCamFar - mCamNear), 1.0f); 130 | mCascadeDepthBounds[iCasc] = (p.z / p.w); 131 | } 132 | 133 | 134 | } 135 | 136 | void ShadowMap::calcNearFar(glm::vec2 lightMin, glm::vec2 lightMax, float &out_near, float &out_far, glm::vec4 *scenePtsLS) { 137 | // based on: https://github.com/walbourn/directx-sdk-samples/blob/master/CascadedShadowMaps11/CascadedShadowsManager.cpp 138 | // see also: https://docs.microsoft.com/en-us/windows/win32/dxtecharts/common-techniques-to-improve-shadow-depth-maps 139 | 140 | // scenePts (0-3 near, 4-7 far): 141 | // 6-------------7 y 142 | // |\ /| ^ 143 | // | \ / | | 144 | // | 2-------3 | +---> x 145 | // | | | | 146 | // | | | | (sketch is in world space with perspective, but passed points are in light space) 147 | // | 0-------1 | (NOTE: point order is different than in linked resources!) 148 | // | / \ | 149 | // |/ \| 150 | // 4-------------5 151 | 152 | struct Triangle { 153 | glm::vec3 pt[3]; 154 | bool culled; 155 | }; 156 | 157 | // tessellation of the frustum: 158 | const static int sceneTriIdx[3 * 12] = { // (winding order is irrelevant) 159 | 0,1,2, 1,3,2, // front 160 | 5,4,7, 4,6,7, // back 161 | 2,3,6, 3,7,6, // top 162 | 0,1,4, 1,5,4, // bottom 163 | 0,4,2, 4,6,2, // left 164 | 5,1,7, 1,3,7 // right 165 | }; 166 | 167 | out_near = FLT_MAX; 168 | out_far = -FLT_MAX; 169 | 170 | // iterate over all 12 triangles of the frustum 171 | for (int iFrustumTri = 0; iFrustumTri < 12; iFrustumTri++) { 172 | const int TRIANGLE_LIST_SIZE = 16; 173 | Triangle triangleList[TRIANGLE_LIST_SIZE]; 174 | int triangleCount = 1; 175 | 176 | triangleList[0].pt[0] = scenePtsLS[sceneTriIdx[iFrustumTri * 3 + 0]]; 177 | triangleList[0].pt[1] = scenePtsLS[sceneTriIdx[iFrustumTri * 3 + 1]]; 178 | triangleList[0].pt[2] = scenePtsLS[sceneTriIdx[iFrustumTri * 3 + 2]]; 179 | triangleList[0].culled = false; 180 | 181 | // clip triangle with the 4 (side) planes of the light frustum (simple comparison in light space), create new tris when needed 182 | for (int iPlane = 0; iPlane < 4; iPlane++) { // 0=left,1=right,2=bottom,3=top 183 | float edge; 184 | int component; 185 | switch (iPlane) { 186 | case 0: edge = lightMin.x; component = 0; break; 187 | case 1: edge = lightMax.x; component = 0; break; 188 | case 2: edge = lightMin.y; component = 1; break; 189 | case 3: edge = lightMax.y; component = 1; break; 190 | } 191 | 192 | // process triangle list 193 | for (int iTri = 0; iTri < triangleCount; iTri++) { 194 | if (triangleList[iTri].culled) continue; 195 | 196 | // check all 3 points of the triangle against the current plane 197 | int numPtsInside = 0; 198 | bool pointIsInside[3]; 199 | for (int iTriPt = 0; iTriPt < 3; iTriPt++) { 200 | switch (iPlane) { 201 | case 0: pointIsInside[iTriPt] = triangleList[iTri].pt[iTriPt].x > lightMin.x; break; 202 | case 1: pointIsInside[iTriPt] = triangleList[iTri].pt[iTriPt].x < lightMax.x; break; 203 | case 2: pointIsInside[iTriPt] = triangleList[iTri].pt[iTriPt].y > lightMin.y; break; 204 | case 3: pointIsInside[iTriPt] = triangleList[iTri].pt[iTriPt].y < lightMax.y; break; 205 | } 206 | if (pointIsInside[iTriPt]) numPtsInside++; 207 | } 208 | 209 | // move inside points to the start of the array 210 | if (pointIsInside[1] && !pointIsInside[0]) { glm::vec3 t = triangleList[iTri].pt[0]; triangleList[iTri].pt[0] = triangleList[iTri].pt[1]; triangleList[iTri].pt[1] = t; pointIsInside[0] = true; pointIsInside[1] = false; } 211 | if (pointIsInside[2] && !pointIsInside[1]) { glm::vec3 t = triangleList[iTri].pt[1]; triangleList[iTri].pt[1] = triangleList[iTri].pt[2]; triangleList[iTri].pt[2] = t; pointIsInside[1] = true; pointIsInside[2] = false; } 212 | if (pointIsInside[1] && !pointIsInside[0]) { glm::vec3 t = triangleList[iTri].pt[0]; triangleList[iTri].pt[0] = triangleList[iTri].pt[1]; triangleList[iTri].pt[1] = t; pointIsInside[0] = true; pointIsInside[1] = false; } 213 | 214 | if (numPtsInside == 0) { 215 | // all points outside -> cull triangle 216 | triangleList[iTri].culled = true; 217 | } else if (numPtsInside == 1) { 218 | // one point inside (0) -> clip triangle 219 | glm::vec3 v01 = triangleList[iTri].pt[1] - triangleList[iTri].pt[0]; 220 | glm::vec3 v02 = triangleList[iTri].pt[2] - triangleList[iTri].pt[0]; 221 | float d = edge - triangleList[iTri].pt[0][component]; // distance from inside point to edge (sign is ok, cancels out in the next two lines) 222 | triangleList[iTri].pt[1] = triangleList[iTri].pt[0] + v01 * d / v01[component]; 223 | triangleList[iTri].pt[2] = triangleList[iTri].pt[0] + v02 * d / v02[component]; 224 | triangleList[iTri].culled = false; 225 | } else if (numPtsInside == 2) { 226 | // two points inside (0,1) -> cut into two triangles 227 | // move next tri out of the way (to end of list) to make space for the new tri 228 | assert(triangleCount < TRIANGLE_LIST_SIZE); 229 | triangleList[triangleCount] = triangleList[iTri + 1]; 230 | 231 | glm::vec3 v20 = triangleList[iTri].pt[0] - triangleList[iTri].pt[2]; 232 | glm::vec3 v21 = triangleList[iTri].pt[1] - triangleList[iTri].pt[2]; 233 | float d = edge - triangleList[iTri].pt[2][component]; // distance from outside point to edge (sign is ok, cancels out in the next lines) 234 | 235 | // new triangle (0, 1, point on 2-0-edge; inserted to list) 236 | triangleList[iTri + 1].pt[0] = triangleList[iTri].pt[0]; 237 | triangleList[iTri + 1].pt[1] = triangleList[iTri].pt[1]; 238 | triangleList[iTri + 1].pt[2] = triangleList[iTri].pt[2] + v20 * d / v20[component]; 239 | triangleList[iTri + 1].culled = false; 240 | 241 | // new triangle (1, point on 2-0-edge, point on 2-1-edge; overwrites old tri in list) 242 | triangleList[iTri].pt[0] = triangleList[iTri + 1].pt[1]; 243 | triangleList[iTri].pt[1] = triangleList[iTri + 1].pt[2]; 244 | triangleList[iTri].pt[2] = triangleList[iTri].pt[2] + v21 * d / v21[component]; 245 | triangleList[iTri].culled = false; 246 | 247 | triangleCount++; // one more triangle 248 | iTri++; // but skip it now 249 | } else { 250 | // all points inside 251 | triangleList[iTri].culled = false; 252 | } 253 | } 254 | 255 | } 256 | 257 | // update near/far plane from the triangles resulting from this frustum triangle 258 | for (int iTri = 0; iTri < triangleCount; iTri++) { 259 | if (triangleList[iTri].culled) continue; 260 | for (int iTriPt = 0; iTriPt < 3; iTriPt++) { 261 | float z = -triangleList[iTri].pt[iTriPt].z; 262 | if (out_near > z) out_near = z; 263 | if (out_far < z) out_far = z; 264 | } 265 | } 266 | 267 | } 268 | 269 | } 270 | 271 | 272 | // calc camera view frustum corner points in world space 273 | void ShadowMap::getCamFrustum(glm::vec4 * out_frustumPoints) { 274 | // order: near bottom left, near bottom right, near top left, near top right, 275 | // far bottom left, far bottom right, far top left, far top right 276 | glm::mat4 invCamVP = glm::inverse(mCamVPMatrix); 277 | int i = 0; 278 | for (int z = 0; z < 2; z++) { 279 | for (int y = 0; y < 2; y++) { 280 | for (int x = 0; x < 2; x++) { 281 | //glm::vec4 p(x * 2.0f - 1.0f, y * 2.0f - 1.0f, z * 2.0f - 1.0f, 1.0f); 282 | glm::vec4 p(x * 2.0f - 1.0f, y * 2.0f - 1.0f, z, 1.0f); 283 | p = invCamVP * p; 284 | out_frustumPoints[i++] = p / p.w; 285 | } 286 | } 287 | } 288 | } 289 | 290 | // calculate corner points of a sub-frustum of the current camera view frustum 291 | void ShadowMap::calcPartialCamFrustum(float beginFactor, float endFactor, glm::vec4 * out_frustumPoints) { 292 | glm::vec4 pts[8]; 293 | getCamFrustum(pts); 294 | for (int i = 0; i < 4; i++) { 295 | glm::vec4 v = pts[i + 4] - pts[i]; 296 | out_frustumPoints[i] = pts[i] + v * beginFactor; 297 | out_frustumPoints[i+4] = pts[i] + v * endFactor; 298 | } 299 | } 300 | -------------------------------------------------------------------------------- /source/ShadowMap.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "BoundingBox.hpp" 4 | 5 | class ShadowMap { 6 | public: 7 | static const int MAX_CASCADES = 4; 8 | private: 9 | glm::mat4 mViewMatrix; 10 | int mNumCascades; 11 | float mCamNear, mCamFar; 12 | int mTextureSize; 13 | 14 | glm::mat4 mCascadeProjMatrix[MAX_CASCADES]; 15 | glm::mat4 mCascadeVPMatrix[MAX_CASCADES]; 16 | float mCascadeDepthBounds[MAX_CASCADES]; 17 | 18 | BoundingBox mSceneBoundingBox; 19 | 20 | std::optional mAdjustForAdditionalPoint; 21 | 22 | glm::mat4 mCamViewMatrix, mCamProjMatrix, mCamVPMatrix; 23 | glm::vec3 mLightDirection; 24 | 25 | void calcLightView(); 26 | void calcNearFar(glm::vec2 lightMin, glm::vec2 lightMax, float &out_near, float &out_far, glm::vec4 *scenePtsLS); 27 | void getCamFrustum(glm::vec4 *out_frustumPoints); 28 | void calcPartialCamFrustum(float beginFactor, float endFactor, glm::vec4 *out_frustumPoints); 29 | 30 | public: 31 | enum class CascadeFitMode {fitCascade, fitScene}; 32 | enum class NearFarFitMode {nffFrustumOnly, nffIntersect, /* nffIntersectAndPancake */}; 33 | 34 | // params 35 | float cascadeEnd[MAX_CASCADES] = {0.005f, 0.02f, 0.10f, 1.0f}; // only used if autoCalcCascades is false in init() 36 | CascadeFitMode cascadeFitMode = CascadeFitMode::fitCascade; 37 | bool restrictLightViewToScene = false; // clip frustum to scene? tighter bound, but other problems... not generally recommended by resources 38 | NearFarFitMode nearfarFitMode = NearFarFitMode::nffIntersect; 39 | bool texelSnapping = true; 40 | 41 | void init(const BoundingBox &aSceneBoundingBox, float camNear, float camFar, int aShadowMapTextureSize, int numCascades, bool autoCalcCascades); 42 | void calc(const glm::vec3 &aLightDirection, const glm::mat4 &aCamViewMatrix, const glm::mat4 &aCamProjMatrix, std::optional aIncludeThisPoint = std::nullopt); 43 | void calc_cascade_ends(); 44 | glm::mat4 view_matrix() { return mViewMatrix; } 45 | glm::mat4 projection_matrix(int cascade = 0) { return mCascadeProjMatrix[cascade]; } 46 | float max_depth(int cascade) { return mCascadeDepthBounds[cascade]; } 47 | }; 48 | -------------------------------------------------------------------------------- /source/cg_stdafx.cpp: -------------------------------------------------------------------------------- 1 | // cg_stdafx.cpp : source file that includes just the standard includes 2 | // cg_stdafx.pch will be the pre-compiled header 3 | // cg_stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "cg_stdafx.hpp" 6 | 7 | // TODO: reference any additional headers you need in cg_stdafx.hpp 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /source/cg_stdafx.hpp: -------------------------------------------------------------------------------- 1 | // cg_stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | #pragma once 6 | 7 | #include "cg_targetver.hpp" 8 | 9 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 10 | 11 | #define PURIFIER_CPU_ONLY 12 | 13 | #include "gvk.hpp" -------------------------------------------------------------------------------- /source/cg_targetver.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /source/imgui_helper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace imgui_helper { 6 | bool globalEnable = true; 7 | 8 | static void HelpMarker(const char* desc, bool sameLine = true) { 9 | if (sameLine) ImGui::SameLine(); 10 | 11 | ImGui::TextDisabled("(?)"); 12 | if (ImGui::IsItemHovered()) 13 | { 14 | ImGui::BeginTooltip(); 15 | ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); 16 | ImGui::TextUnformatted(desc); 17 | ImGui::PopTextWrapPos(); 18 | ImGui::EndTooltip(); 19 | } 20 | } 21 | 22 | // checkbox for VkBool32 23 | static bool CheckboxB32(const char* label, uint32_t* v) { 24 | bool b = (0u != *v); 25 | bool ret = ImGui::Checkbox(label, &b); 26 | *v = b ? 1u : 0u; 27 | return ret; 28 | } 29 | 30 | // misc ImGui functions with additional item width parameter; extend when required 31 | 32 | #define _Args(...) __VA_ARGS__ 33 | #define STRIP_PARENS(X) X 34 | #define PASS_PARAMETERS(X) STRIP_PARENS( _Args X ) 35 | #define DEF_WITH_ITEMWIDTH(func_,declparams_,callparams_) \ 36 | bool func_ ## W(const float itemwidth, ## declparams_) { \ 37 | ImGui::PushItemWidth(itemwidth); \ 38 | bool ret = ImGui:: ## func_ ## callparams_; \ 39 | ImGui::PopItemWidth(); \ 40 | return ret; \ 41 | } 42 | 43 | DEF_WITH_ITEMWIDTH(Combo, PASS_PARAMETERS((const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1)), (label, current_item, items, items_count, popup_max_height_in_items)) 44 | DEF_WITH_ITEMWIDTH(Combo, PASS_PARAMETERS((const char* label, int* current_item, const char* items_separated_by_zeros, int popup_max_height_in_items = -1)), (label, current_item, items_separated_by_zeros, popup_max_height_in_items)) 45 | DEF_WITH_ITEMWIDTH(Combo, PASS_PARAMETERS((const char* label, int* current_item, bool(*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int popup_max_height_in_items = -1)), (label, current_item, items_getter, data, items_count, popup_max_height_in_items)) 46 | 47 | DEF_WITH_ITEMWIDTH(InputFloat, PASS_PARAMETERS((const char* label, float* v, float step = 0.0f, float step_fast = 0.0f, const char* format = "%.3f", ImGuiInputTextFlags flags = 0)), (label, v, step, step_fast, format, flags)) 48 | DEF_WITH_ITEMWIDTH(InputFloat2, PASS_PARAMETERS((const char* label, float v[2], const char* format = "%.3f", ImGuiInputTextFlags flags = 0)), (label, v, format, flags)) 49 | DEF_WITH_ITEMWIDTH(InputFloat3, PASS_PARAMETERS((const char* label, float v[3], const char* format = "%.3f", ImGuiInputTextFlags flags = 0)), (label, v, format, flags)) 50 | DEF_WITH_ITEMWIDTH(InputFloat4, PASS_PARAMETERS((const char* label, float v[4], const char* format = "%.3f", ImGuiInputTextFlags flags = 0)), (label, v, format, flags)) 51 | 52 | DEF_WITH_ITEMWIDTH(InputInt, PASS_PARAMETERS((const char* label, int* v, int step = 1, int step_fast = 100, ImGuiInputTextFlags flags = 0)), (label, v, step, step_fast, flags)) 53 | DEF_WITH_ITEMWIDTH(InputInt2, PASS_PARAMETERS((const char* label, int v[2], ImGuiInputTextFlags flags = 0)), (label, v, flags)) 54 | DEF_WITH_ITEMWIDTH(InputInt3, PASS_PARAMETERS((const char* label, int v[3], ImGuiInputTextFlags flags = 0)), (label, v, flags)) 55 | DEF_WITH_ITEMWIDTH(InputInt4, PASS_PARAMETERS((const char* label, int v[4], ImGuiInputTextFlags flags = 0)), (label, v, flags)) 56 | 57 | DEF_WITH_ITEMWIDTH(InputText, PASS_PARAMETERS((const char* label, char* buf, size_t buf_size, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL)), (label, buf, buf_size, flags, callback, user_data)) 58 | //DEF_WITH_ITEMWIDTH(SliderFloat, PASS_PARAMETERS((const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f)), (label, v, v_min, v_max, format, power)) 59 | DEF_WITH_ITEMWIDTH(SliderFloat, PASS_PARAMETERS((const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0)), (label, v, v_min, v_max, format, flags)) 60 | DEF_WITH_ITEMWIDTH(SliderInt, PASS_PARAMETERS((const char* label, int* v, int v_min, int v_max, const char* format = "%d")), (label, v, v_min, v_max, format)) 61 | 62 | #undef DEF_WITH_ITEMWIDTH 63 | #undef PASS_PARAMETERS 64 | #undef STRIP_PARENS 65 | #undef _Args 66 | 67 | } 68 | -------------------------------------------------------------------------------- /source/imgui_stdlib.cpp: -------------------------------------------------------------------------------- 1 | // dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.) 2 | // This is also an example of how you may wrap your own similar types. 3 | 4 | // Compatibility: 5 | // - std::string support is only guaranteed to work from C++11. 6 | // If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture) 7 | 8 | // Changelog: 9 | // - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string 10 | 11 | #include "imgui.h" 12 | #include "imgui_stdlib.h" 13 | 14 | struct InputTextCallback_UserData 15 | { 16 | std::string* Str; 17 | ImGuiInputTextCallback ChainCallback; 18 | void* ChainCallbackUserData; 19 | }; 20 | 21 | static int InputTextCallback(ImGuiInputTextCallbackData* data) 22 | { 23 | InputTextCallback_UserData* user_data = (InputTextCallback_UserData*)data->UserData; 24 | if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) 25 | { 26 | // Resize string callback 27 | // If for some reason we refuse the new length (BufTextLen) and/or capacity (BufSize) we need to set them back to what we want. 28 | std::string* str = user_data->Str; 29 | IM_ASSERT(data->Buf == str->c_str()); 30 | str->resize(data->BufTextLen); 31 | data->Buf = (char*)str->c_str(); 32 | } 33 | else if (user_data->ChainCallback) 34 | { 35 | // Forward to user callback, if any 36 | data->UserData = user_data->ChainCallbackUserData; 37 | return user_data->ChainCallback(data); 38 | } 39 | return 0; 40 | } 41 | 42 | bool ImGui::InputText(const char* label, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) 43 | { 44 | IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 45 | flags |= ImGuiInputTextFlags_CallbackResize; 46 | 47 | InputTextCallback_UserData cb_user_data; 48 | cb_user_data.Str = str; 49 | cb_user_data.ChainCallback = callback; 50 | cb_user_data.ChainCallbackUserData = user_data; 51 | return InputText(label, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); 52 | } 53 | 54 | bool ImGui::InputTextMultiline(const char* label, std::string* str, const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) 55 | { 56 | IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 57 | flags |= ImGuiInputTextFlags_CallbackResize; 58 | 59 | InputTextCallback_UserData cb_user_data; 60 | cb_user_data.Str = str; 61 | cb_user_data.ChainCallback = callback; 62 | cb_user_data.ChainCallbackUserData = user_data; 63 | return InputTextMultiline(label, (char*)str->c_str(), str->capacity() + 1, size, flags, InputTextCallback, &cb_user_data); 64 | } 65 | 66 | bool ImGui::InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) 67 | { 68 | IM_ASSERT((flags & ImGuiInputTextFlags_CallbackResize) == 0); 69 | flags |= ImGuiInputTextFlags_CallbackResize; 70 | 71 | InputTextCallback_UserData cb_user_data; 72 | cb_user_data.Str = str; 73 | cb_user_data.ChainCallback = callback; 74 | cb_user_data.ChainCallbackUserData = user_data; 75 | return InputTextWithHint(label, hint, (char*)str->c_str(), str->capacity() + 1, flags, InputTextCallback, &cb_user_data); 76 | } 77 | -------------------------------------------------------------------------------- /source/imgui_stdlib.h: -------------------------------------------------------------------------------- 1 | // dear imgui: wrappers for C++ standard library (STL) types (std::string, etc.) 2 | // This is also an example of how you may wrap your own similar types. 3 | 4 | // Compatibility: 5 | // - std::string support is only guaranteed to work from C++11. 6 | // If you try to use it pre-C++11, please share your findings (w/ info about compiler/architecture) 7 | 8 | // Changelog: 9 | // - v0.10: Initial version. Added InputText() / InputTextMultiline() calls with std::string 10 | 11 | #pragma once 12 | 13 | #include 14 | 15 | namespace ImGui 16 | { 17 | // ImGui::InputText() with std::string 18 | // Because text input needs dynamic resizing, we need to setup a callback to grow the capacity 19 | IMGUI_API bool InputText(const char* label, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 20 | IMGUI_API bool InputTextMultiline(const char* label, std::string* str, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 21 | IMGUI_API bool InputTextWithHint(const char* label, const char* hint, std::string* str, ImGuiInputTextFlags flags = 0, ImGuiInputTextCallback callback = NULL, void* user_data = NULL); 22 | } 23 | -------------------------------------------------------------------------------- /source/rdoc_helper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // provide access to Renderdoc API for capturing, object labeling, etc. 4 | 5 | #define USE_RENDERDOC_API 1 6 | 7 | 8 | 9 | 10 | 11 | // Note: for now this module is agnostic of gears-vk, auto-vk and therefore uses simple printf for debug output 12 | 13 | //#include 14 | #include 15 | 16 | #if USE_RENDERDOC_API 17 | 18 | // only include if we really want to use Renderdoc, so compilation is possible without having renderdoc_app.h 19 | #include "renderdoc_app.h" 20 | 21 | namespace rdoc { 22 | 23 | RENDERDOC_API_1_1_2* rdoc_api = nullptr; 24 | PFN_vkDebugMarkerSetObjectNameEXT pfnDebugMarkerSetObjectNameEXT = VK_NULL_HANDLE; 25 | PFN_vkCmdDebugMarkerBeginEXT pfnCmdDebugMarkerBeginEXT = VK_NULL_HANDLE; 26 | PFN_vkCmdDebugMarkerEndEXT pfnCmdDebugMarkerEndEXT = VK_NULL_HANDLE; 27 | VkDevice currentDevice = VK_NULL_HANDLE; 28 | bool capturingActive = false; 29 | 30 | void init() { 31 | if (HMODULE mod = GetModuleHandleA("renderdoc.dll")) { 32 | pRENDERDOC_GetAPI RENDERDOC_GetAPI = (pRENDERDOC_GetAPI)GetProcAddress(mod, "RENDERDOC_GetAPI"); 33 | int ret = RENDERDOC_GetAPI(eRENDERDOC_API_Version_1_1_2, (void **)&rdoc_api); 34 | assert(ret == 1); 35 | printf("RenderDoc found, API enabled\n"); 36 | } 37 | } 38 | 39 | void init_debugmarkers(VkDevice device) { 40 | if (!rdoc_api) return; 41 | if (pfnDebugMarkerSetObjectNameEXT) return; 42 | 43 | currentDevice = device; // store, so we don't need to pass it in every time 44 | 45 | pfnDebugMarkerSetObjectNameEXT = reinterpret_cast (vkGetDeviceProcAddr(device, "vkDebugMarkerSetObjectNameEXT")); 46 | pfnCmdDebugMarkerBeginEXT = reinterpret_cast (vkGetDeviceProcAddr(device, "vkCmdDebugMarkerBeginEXT")); 47 | pfnCmdDebugMarkerEndEXT = reinterpret_cast (vkGetDeviceProcAddr(device, "vkCmdDebugMarkerEndEXT")); 48 | if (!pfnDebugMarkerSetObjectNameEXT || !pfnCmdDebugMarkerBeginEXT || !pfnCmdDebugMarkerEndEXT) 49 | printf("WARN: Failed to init debugmarkers; did you request device extension \"VK_EXT_debug_marker\" ?\n"); 50 | } 51 | 52 | bool active() { return rdoc_api; } 53 | void start_capture() { if (rdoc_api && !capturingActive) { rdoc_api->StartFrameCapture(NULL, NULL); capturingActive = true; } } 54 | void end_capture() { if (rdoc_api && capturingActive) { rdoc_api->EndFrameCapture (NULL, NULL); capturingActive = false; } } 55 | 56 | void labelObject(uint64_t object, VkDebugReportObjectTypeEXT objectType, const char *objectName, int64_t optionalIndex = -1) { 57 | if (!pfnDebugMarkerSetObjectNameEXT) return; 58 | VkDebugMarkerObjectNameInfoEXT nameInfo = { VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT }; 59 | nameInfo.objectType = objectType; 60 | nameInfo.object = object; 61 | if (optionalIndex < 0) { 62 | nameInfo.pObjectName = objectName; 63 | pfnDebugMarkerSetObjectNameEXT(currentDevice, &nameInfo); 64 | } else { 65 | std::string s = std::string(objectName) + "[" + std::to_string(optionalIndex) + "]"; 66 | nameInfo.pObjectName = s.c_str(); 67 | pfnDebugMarkerSetObjectNameEXT(currentDevice, &nameInfo); // call this while s is still alive 68 | } 69 | } 70 | 71 | void labelImage (VkImage image, const char *name, int64_t optionalIndex = -1) { labelObject(uint64_t(image), VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, name, optionalIndex); } 72 | void labelBuffer(VkBuffer buffer, const char *name, int64_t optionalIndex = -1) { labelObject(uint64_t(buffer), VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, name, optionalIndex); } 73 | void beginSection(VkCommandBuffer cmd, const char *name, int64_t optionalIndex = -1) { 74 | if (!pfnCmdDebugMarkerBeginEXT || !pfnCmdDebugMarkerEndEXT) return; 75 | VkDebugMarkerMarkerInfoEXT markerInfo = { VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT }; 76 | if (optionalIndex < 0) { 77 | markerInfo.pMarkerName = name; 78 | pfnCmdDebugMarkerBeginEXT(cmd, &markerInfo); 79 | } else { 80 | std::string s = std::string(name) + "[" + std::to_string(optionalIndex) + "]"; 81 | markerInfo.pMarkerName = s.c_str(); 82 | pfnCmdDebugMarkerBeginEXT(cmd, &markerInfo); // call this while s is still alive 83 | } 84 | } 85 | void endSection(VkCommandBuffer cmd) { 86 | if (!pfnCmdDebugMarkerBeginEXT || !pfnCmdDebugMarkerEndEXT) return; 87 | pfnCmdDebugMarkerEndEXT(cmd); 88 | } 89 | 90 | std::vector required_device_extensions() { if (rdoc_api) return { "VK_EXT_debug_marker" }; else return {}; } 91 | } 92 | 93 | #else 94 | 95 | namespace rdoc { 96 | void init() {} 97 | void init_debugmarkers(VkDevice device) {} 98 | bool active() { return false; } 99 | void start_capture() {} 100 | void end_capture() {} 101 | void labelObject(uint64_t object, VkDebugReportObjectTypeEXT objectType, const char *objectName, int64_t optionalIndex = -1) {} 102 | void labelImage(VkImage image, const char *name, int64_t optionalIndex = -1) {} 103 | void labelBuffer(VkBuffer buffer, const char *name, int64_t optionalIndex = -1) {} 104 | void beginSection(VkCommandBuffer cmd, const char *name, int64_t optionalIndex = -1) {} 105 | void endSection(VkCommandBuffer cmd) {} 106 | std::vector required_device_extensions() { return {}; } 107 | } 108 | 109 | #endif 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /source/splines.cpp: -------------------------------------------------------------------------------- 1 | #include "splines.hpp" 2 | 3 | #include 4 | 5 | // ---- Catmull Rom splines ( info source: https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline ) 6 | template 7 | float CatmullRom::catmullRom_getTime(float t, T &p0, T &p1) { 8 | // calc time for next control point 9 | return t + std::pow(glm::length(p1 - p0), mAlpha); 10 | } 11 | 12 | template 13 | T CatmullRom::catmullRom_segment(T &p0, T &p1, T &p2, T &p3, float t) { 14 | // t is the local time in the segment: 0 = p1, 1 = p2 15 | 16 | float t0 = 0.f; 17 | float t1 = catmullRom_getTime(t0, p0, p1); 18 | float t2 = catmullRom_getTime(t1, p1, p2); 19 | float t3 = catmullRom_getTime(t2, p2, p3); 20 | 21 | t = t1 + t * (t2 - t1); 22 | 23 | //T A1 = ((t1 - t) / (t1 - t0)) * p0 + ((t - t0) / (t1 - t0)) * p1; 24 | //T A2 = ((t2 - t) / (t2 - t1)) * p1 + ((t - t1) / (t2 - t1)) * p2; 25 | //T A3 = ((t3 - t) / (t3 - t2)) * p2 + ((t - t2) / (t3 - t2)) * p3; 26 | //T B1 = ((t2 - t) / (t2 - t0)) * A1 + ((t - t0) / (t2 - t0)) * A2; 27 | //T B2 = ((t3 - t) / (t3 - t1)) * A2 + ((t - t1) / (t3 - t1)) * A3; 28 | //T C = ((t2 - t) / (t2 - t1)) * B1 + ((t - t1) / (t2 - t1)) * B2; 29 | 30 | // FIXME!! 31 | float f0 = t1 - t0; 32 | float f1 = t2 - t1; 33 | float f2 = t3 - t2; 34 | float f3 = t2 - t0; 35 | float f4 = t3 - t1; 36 | float f5 = t2 - t1; 37 | const float eps = (float)1e-6; 38 | if (f0 < eps || f1 < eps || f2 < eps || f3 < eps || f4 < eps || f5 < eps) return p1; 39 | T A1 = ((t1 - t) / f0) * p0 + ((t - t0) / f0) * p1; 40 | T A2 = ((t2 - t) / f1) * p1 + ((t - t1) / f1) * p2; 41 | T A3 = ((t3 - t) / f2) * p2 + ((t - t2) / f2) * p3; 42 | T B1 = ((t2 - t) / f3) * A1 + ((t - t0) / f3) * A2; 43 | T B2 = ((t3 - t) / f4) * A2 + ((t - t1) / f4) * A3; 44 | T C = ((t2 - t) / f5) * B1 + ((t - t1) / f5) * B2; 45 | 46 | 47 | //printf("C = [%.2f %.2f %.2f]\n", C.x, C.y, C.z); 48 | return C; 49 | } 50 | 51 | template 52 | int CatmullRom::catmullRom_getCurrentSegment(std::vector &P, float t) { 53 | // which segment are we in? 54 | int numSeg = (int)P.size() - 3; 55 | assert(numSeg > 0); 56 | int curSeg = (int)floor(t * numSeg); 57 | if (curSeg >= numSeg) curSeg = numSeg-1; 58 | return curSeg; 59 | } 60 | 61 | template 62 | T CatmullRom::catmullRom_chain(std::vector &P, float t, int *out_seg, float *out_tseg) { 63 | // t is the local time in the chain: 0 = P[1], 1 = P[-2] 64 | 65 | // which segment are we in? 66 | int curSeg = catmullRom_getCurrentSegment(P, t); 67 | 68 | int numSeg = (int)P.size() - 3; 69 | assert(numSeg > 0); 70 | 71 | float t_per_seg = 1.f / numSeg; // time per segment 72 | float t_seg = (t - curSeg * t_per_seg) / t_per_seg; // local time in segment 73 | assert(t_seg >= 0.f && t_seg <= 1.f); 74 | 75 | if (out_seg) *out_seg = curSeg + 1; 76 | if (out_tseg) *out_tseg = t_seg; 77 | 78 | return catmullRom_segment(P[curSeg], P[curSeg + 1], P[curSeg + 2], P[curSeg + 3], t_seg); 79 | } 80 | 81 | template 82 | float CatmullRom::catmullRom_segmentLen(std::vector &P, int idxPseg, int numSamples) { 83 | float dt = 1.f / (float)numSamples; 84 | float sum = 0.f; 85 | for (int i = 0; i < numSamples; i++) { 86 | T a = catmullRom_segment(P[idxPseg - 1], P[idxPseg], P[idxPseg + 1], P[idxPseg + 2], dt * i); 87 | T b = catmullRom_segment(P[idxPseg - 1], P[idxPseg], P[idxPseg + 1], P[idxPseg + 2], dt * (i+1)); 88 | sum += glm::length(b - a); 89 | } 90 | return sum; 91 | } 92 | 93 | template 94 | float CatmullRom::catmullRom_chainLen(std::vector &P, int numSamplesPerSeg) { 95 | float sum = 0.f; 96 | for (int i = 0; i < P.size() - 3; i++) { 97 | sum += catmullRom_segmentLen(P, i + 1, numSamplesPerSeg); 98 | } 99 | return sum; 100 | } 101 | 102 | template 103 | std::vector CatmullRom::catmullRom_allSegmentLens(std::vector &P, float &out_totalLen, int numSamplesPerSeg) { 104 | std::vector lens; 105 | out_totalLen = 0.f; 106 | for (int i = 0; i < P.size() - 3; i++) { 107 | float len = catmullRom_segmentLen(P, i + 1, numSamplesPerSeg); 108 | out_totalLen += len; 109 | lens.push_back(len); 110 | } 111 | return lens; 112 | } 113 | 114 | 115 | 116 | 117 | 118 | float Spline::map_arclen_t(float arc_t) { 119 | if (!calced_arclen) { 120 | int numSamples = 200; 121 | float totalLen; 122 | mSegLenNormalized = cmr_pos.catmullRom_allSegmentLens(camP, totalLen, numSamples); 123 | if (totalLen > 0.f) for (auto &len : mSegLenNormalized) len /= totalLen; 124 | calced_arclen = true; 125 | } 126 | 127 | int numSeg = (int)camP.size() - 3; 128 | float t_per_seg = 1.f / numSeg; // time per segment 129 | 130 | float s = 0.f; 131 | for (int i = 0; i < int(mSegLenNormalized.size()); ++i) { 132 | float sNext = s + mSegLenNormalized[i]; 133 | if (sNext > arc_t) { 134 | // found active segment 135 | float f = (sNext > s) ? (arc_t - s) / (sNext - s) : 0.5f; 136 | return (float(i) + f) * t_per_seg; 137 | } 138 | s = sNext; 139 | } 140 | 141 | return 1.f; 142 | } 143 | 144 | void Spline::interpolate(float t, glm::vec3 &pos, glm::quat &rot) { 145 | glm::vec3 posOld = pos; 146 | 147 | t = glm::clamp(t, 0.f, 1.f); 148 | if (use_arclen) t = map_arclen_t(t); 149 | int seg; 150 | float tseg; 151 | pos = cmr_pos.catmullRom_chain(camP, t, &seg, &tseg); 152 | 153 | if (rotation_mode == 1) { 154 | // just lerp rot 155 | rot = glm::mix(camR[seg], camR[seg + 1], tseg); 156 | } else if (rotation_mode == 2) { 157 | glm::vec3 v = pos - posOld; 158 | if (glm::length2(v) > 0.f) rot = glm::quatLookAt(glm::normalize(v), glm::vec3(0, 1, 0)); 159 | 160 | //const float dt = 0.00001f; 161 | //float t2 = glm::clamp(t + dt, 0.f, 1.f); 162 | //if (t2 > t) { 163 | // glm::vec3 v = cmr_pos.catmullRom_chain(camP, t2) - pos; 164 | // if (glm::length2(v) > 0.f) { 165 | // rot = glm::quatLookAt(glm::normalize(v), glm::vec3(0, 1, 0)); 166 | // //v = glm::normalize(v); 167 | // //printf("t=%.3f v=%.2f %.2f %.2f p=%.2f %.2f %.2f q=%.2f %.2f %.2f %.2f\n", t, v.x, v.y, v.z, pos.x, pos.y, pos.z, rot.x, rot.y, rot.z, rot.w); 168 | // } 169 | //} 170 | } 171 | } 172 | 173 | -------------------------------------------------------------------------------- /source/splines.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // ---- Catmull Rom splines ( info source: https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline ) 6 | template 7 | class CatmullRom { 8 | public: 9 | float catmullRom_getTime(float t, T & p0, T & p1); 10 | T catmullRom_segment(T & p0, T & p1, T & p2, T & p3, float t); 11 | int catmullRom_getCurrentSegment(std::vector& P, float t); 12 | T catmullRom_chain(std::vector& P, float t, int *out_seg = nullptr, float *out_tseg = nullptr); 13 | float catmullRom_segmentLen(std::vector& P, int idxPseg, int numSamples); 14 | float catmullRom_chainLen(std::vector& P, int numSamplesPerSeg); 15 | std::vector catmullRom_allSegmentLens(std::vector& P, float & out_totalLen, int numSamplesPerSeg); 16 | 17 | float mAlpha = 0.5f; // 0.5 = centripetal catmull rom (0 = uniform, 1 = chordal) 18 | }; 19 | 20 | struct Spline { 21 | float cam_t_max; 22 | std::vector camP; 23 | std::vector camR; 24 | 25 | bool use_arclen; 26 | int rotation_mode = 1; // 0 = ignore; 1 = lerp keyframe rot; 2 = from positions 27 | 28 | Spline(float cam_t_max, std::vector path) : cam_t_max(cam_t_max), camP(path) { camR.resize(camP.size(), glm::quat(1.f,0.f,0.f,0.f)); } 29 | void modified() { calced_arclen = false; } 30 | 31 | void interpolate(float t, glm::vec3 &pos, glm::quat &rot); 32 | float get_catmullrom_alpha() { return cmr_pos.mAlpha; } 33 | void set_catmullrom_alpha(float alpha) { cmr_pos.mAlpha = alpha; } 34 | private: 35 | float map_arclen_t(float spline_t); 36 | 37 | bool calced_arclen; 38 | std::vector mSegLenNormalized; 39 | CatmullRom cmr_pos; 40 | }; 41 | 42 | -------------------------------------------------------------------------------- /taa.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | # Visual Studio Version 16 3 | VisualStudioVersion = 16.0.28531.58 4 | MinimumVisualStudioVersion = 10.0.40219.1 5 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gears-vk", "gears_vk\visual_studio\gears_vk\gears-vk.vcxproj", "{602F842F-50C1-466D-8696-1707937D8AB9}" 6 | EndProject 7 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "taa", "taa.vcxproj", "{85DA2900-B09A-4479-9BBB-58DA19716B43}" 8 | EndProject 9 | Global 10 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 11 | Debug_Vulkan|x64 = Debug_Vulkan|x64 12 | Publish_Vulkan|x64 = Publish_Vulkan|x64 13 | Release_Vulkan|x64 = Release_Vulkan|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {602F842F-50C1-466D-8696-1707937D8AB9}.Debug_Vulkan|x64.ActiveCfg = Debug_Vulkan|x64 17 | {602F842F-50C1-466D-8696-1707937D8AB9}.Debug_Vulkan|x64.Build.0 = Debug_Vulkan|x64 18 | {602F842F-50C1-466D-8696-1707937D8AB9}.Publish_Vulkan|x64.ActiveCfg = Publish_Vulkan|x64 19 | {602F842F-50C1-466D-8696-1707937D8AB9}.Publish_Vulkan|x64.Build.0 = Publish_Vulkan|x64 20 | {602F842F-50C1-466D-8696-1707937D8AB9}.Release_Vulkan|x64.ActiveCfg = Release_Vulkan|x64 21 | {602F842F-50C1-466D-8696-1707937D8AB9}.Release_Vulkan|x64.Build.0 = Release_Vulkan|x64 22 | {85DA2900-B09A-4479-9BBB-58DA19716B43}.Debug_Vulkan|x64.ActiveCfg = Debug_Vulkan|x64 23 | {85DA2900-B09A-4479-9BBB-58DA19716B43}.Debug_Vulkan|x64.Build.0 = Debug_Vulkan|x64 24 | {85DA2900-B09A-4479-9BBB-58DA19716B43}.Publish_Vulkan|x64.ActiveCfg = Publish_Vulkan|x64 25 | {85DA2900-B09A-4479-9BBB-58DA19716B43}.Publish_Vulkan|x64.Build.0 = Publish_Vulkan|x64 26 | {85DA2900-B09A-4479-9BBB-58DA19716B43}.Release_Vulkan|x64.ActiveCfg = Release_Vulkan|x64 27 | {85DA2900-B09A-4479-9BBB-58DA19716B43}.Release_Vulkan|x64.Build.0 = Release_Vulkan|x64 28 | EndGlobalSection 29 | GlobalSection(SolutionProperties) = preSolution 30 | HideSolutionNode = FALSE 31 | EndGlobalSection 32 | GlobalSection(ExtensibilityGlobals) = postSolution 33 | SolutionGuid = {A8961D43-F08D-46E3-B3BB-29BA8AA39C3E} 34 | EndGlobalSection 35 | EndGlobal 36 | -------------------------------------------------------------------------------- /taa.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {24240a51-8fdb-478f-8c1c-27cbca7adc3f} 6 | False 7 | 8 | 9 | {1d345cf5-0451-42e0-83a8-6a3f5a7203ca} 10 | 11 | 12 | {a498e4bc-580a-49d7-9a8e-ec57803fdcd4} 13 | 14 | 15 | {f36a9860-d83a-4a9f-a747-a02ecec28e0e} 16 | 17 | 18 | {6cf208bf-8e3c-4cb9-a6fc-05b01d638acd} 19 | 20 | 21 | {fb621773-172d-4a26-bff4-bf00185b2be7} 22 | 23 | 24 | 25 | 26 | precompiled_headers 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | precompiled_headers 39 | 40 | 41 | precompiled_headers 42 | 43 | 44 | 45 | 46 | 47 | shaders 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | shaders 66 | 67 | 68 | shaders 69 | 70 | 71 | shaders 72 | 73 | 74 | shaders 75 | 76 | 77 | assets 78 | 79 | 80 | shaders 81 | 82 | 83 | shaders 84 | 85 | 86 | shaders 87 | 88 | 89 | assets 90 | 91 | 92 | shaders 93 | 94 | 95 | shaders 96 | 97 | 98 | assets 99 | 100 | 101 | assets 102 | 103 | 104 | shaders 105 | 106 | 107 | shaders 108 | 109 | 110 | assets\defaults 111 | 112 | 113 | shaders 114 | 115 | 116 | shaders 117 | 118 | 119 | shaders 120 | 121 | 122 | shaders 123 | 124 | 125 | assets 126 | 127 | 128 | shaders 129 | 130 | 131 | shaders 132 | 133 | 134 | shaders 135 | 136 | 137 | shaders 138 | 139 | 140 | shaders 141 | 142 | 143 | shaders 144 | 145 | 146 | shaders 147 | 148 | 149 | shaders 150 | 151 | 152 | shaders 153 | 154 | 155 | 156 | shaders 157 | 158 | 159 | shaders 160 | 161 | 162 | shaders 163 | 164 | 165 | shaders 166 | 167 | 168 | shaders 169 | 170 | 171 | shaders 172 | 173 | 174 | shaders 175 | 176 | 177 | shaders 178 | 179 | 180 | shaders 181 | 182 | 183 | shaders 184 | 185 | 186 | 187 | 188 | shaders 189 | 190 | 191 | 192 | 193 | assets\images 194 | 195 | 196 | assets\images 197 | 198 | 199 | assets\images 200 | 201 | 202 | assets 203 | 204 | 205 | assets\images 206 | 207 | 208 | assets\images 209 | 210 | 211 | assets\terrain 212 | 213 | 214 | assets\terrain 215 | 216 | 217 | assets\terrain 218 | 219 | 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /todo.txt: -------------------------------------------------------------------------------- 1 | TODOs: 2 | 3 | raytracing: 4 | using separate, duplicated index/vertex buffers (and others) for now... need to extend some avk functions, esp. for AS building 5 | add subpixel jittering so taa can work on raytraced image? do we need that actually? 6 | do proper alpha-blending for transparents (accumulate hit counts + alpha-scaled colors) - need to traverse in ray sequence? 7 | ok - do normal mapping 8 | recheck - (after having fixed normals) - dark spots in anim-models are self-shadows.. need very high tmin 9 | refactor tlas/blas rebuilding 10 | ok (ish) - determine mip level for texture sampling? -> see papers "Improved Shader and Texture Level of Detail Using Ray Cones" and "Texture Level of Detail Strategies for Real-Time Ray Tracing" 11 | ok - is it really necessary to update TLAS after updating BLAS? -> yes, it is according to JU 12 | most anim objects (and other dyn objects) don't use normal mapping -> don't need full NTB calc, just set a flag in ray tracer to ignore nrm.mapping 13 | ok - use same render debug displays as in raster version 14 | ok - FXAA for off-screen disocclusions 15 | set FXAA params 16 | normals derivative for segmask? really necessary/useful? 17 | try to achieve SAME image when using RT ALL in taa - see eg. gob.ghosting scene for diff (use rt hist) 18 | should we merge ray traced (and FXAA'ed) pixels back into TAA history buffer? 19 | use same jitter pattern as TAA for ray tracing sample distribution? optional! 20 | test augmented taa with thin structures (wires, branches...) 21 | FIXME! vulkan sdk bug?: vali error on anim obj. rebuild barrier -> known issue: https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2645 22 | -> temporarily commenting out barrier for now 23 | recheck - really? goblin looks blurred in TAA when RTX-assist is on, even if segmask is all zero and fxaa disabled. wtf? 24 | !Bistro scene: wires great for RTX-TAA demonstration 25 | Bistro scene: transparents not ok in rasterer? (eg. curtains at main balcony - but curtain above is ok; backface culling?) 26 | Still some subtle color/shading differences on leaves between rasterer and ray tracer 27 | load approx with textureGrad? not quite working 28 | 29 | !!! fix validation error on compute pipeline @ startup !!! 30 | 31 | sample transparents shadows in rasterer also with lod 0 32 | 33 | didn't test or work with deferred renderer for a while. check that it is still ok or drop it. 34 | 35 | auto-detect transparent materials by looking for alpha < 1 in diffuse texture? 36 | 37 | shadowmap cascades are truncated in emerald square 38 | 39 | !add new settings to save/load funcs - main and taa 40 | 41 | test scene: normal mapping wrong? (models have no proper tangents/bitangents?) 42 | 43 | still problems with slow-mo when capturing frames - use /frame instead of /sec when capturing for now! 44 | 45 | ok - move any buffer updates from update() to render()! Update can be called for fif, if previous (same) fif is still executing! 46 | 47 | - frustum culling notes: startup view/view at park (Emerald Square, no shadows, taa on) 48 | - before separate scene data: 29/42 ms 49 | per-fif buffers: same 50 | host_coherent instead of device: 31/45 51 | - with first version cpu culling: 10.5/35 (dev buffers) 52 | 10.8/37 (host-coherent buffers) 53 | - second version: ~same results 54 | - first version GPU culling: 11/36 (but now ~same with CPU - due to new/changed buffer setup?) 55 | 56 | 57 | ok - avoid necessity of re-recording command buffers with culling (use vkCmdDrawIndexedIndirectCount) 58 | 59 | - shadows: need backface culling disabled - why? something to do with upside-down shadow camera? 60 | 61 | - Performance! Esp. w/ shadows! 62 | Note: shadows of transparent obj. consumes much time, but NOT due to sampling diff. texture (diff=only ~2ms at ES park) ! It's just the amount of additional objects 63 | 64 | ok Shadows: remove manual bias, add polygon offsets 65 | 66 | - cleanup TODO list ;-) remove obsolete stuff, add notes from scratchpads 67 | 68 | ok - do on-GPU visibility culling? 69 | 70 | - make mDynObjectInstances (so we can have more than one instance of a model - need to move prevTransform etc. there) 71 | 72 | - TAAU: WHY subtract jitter instead of add 73 | - TAAU: with 4x upsampling and 4 samples -> why are there no "holes" in history? (because hist is cleared to full image?) 74 | - TAAU: still some bugs? examine sponza lionhead border with 4xup 75 | 76 | - soccerball model is badly reduced, has some holes 77 | 78 | - moving objs with more than one mesh/material 79 | 80 | - when using deferred shading - any point in using a compute shader for the lighting pass ? 81 | 82 | - motion vectors problems, like: object coming into view from behind an obstacle. tags? 83 | 84 | - is there any point to keep using 2 render-subpasses in forward rendering? 85 | 86 | - recheck lighting, esp. w.r.t. twosided materials 87 | 88 | - fix changed lighting flags in deferred shader 89 | 90 | - shadows? 91 | 92 | - need different alpha thresholds for blending/not blending 93 | 94 | NOTES: 95 | - transparency pass without blending isn't bad either - needs larger alpha threshold ~0.5 96 | 97 | --------------------------------------------------------------------------------