Repository: TeamWisp/WispRenderer
Branch: master
Commit: 1f1493f9c903
Files: 279
Total size: 3.9 MB
Directory structure:
gitextract_vk1cvjis/
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── bug_report.md
│ │ ├── design-change.md
│ │ ├── feature_request.md
│ │ └── re-factor-request.md
│ └── PULL_REQUEST_TEMPLATE/
│ └── pull_request_template.md
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── CODE_OF_CONDUCT.md
├── Jenkinsfile
├── LICENSE
├── README.md
├── imgui.ini
├── resources/
│ ├── alien_lights.json
│ ├── shaders/
│ │ ├── deferred_composition_pass.hlsl
│ │ ├── deferred_geometry_pass.hlsl
│ │ ├── denoising_SVGF.hlsl
│ │ ├── denoising_reflections.hlsl
│ │ ├── denoising_spatial_reconstruction.hlsl
│ │ ├── dxr_ambient_occlusion.hlsl
│ │ ├── dxr_functions.hlsl
│ │ ├── dxr_global.hlsl
│ │ ├── dxr_pathtracer_accumulation.hlsl
│ │ ├── dxr_pathtracer_entries.hlsl
│ │ ├── dxr_pathtracer_functions.hlsl
│ │ ├── dxr_pathtracer_main.hlsl
│ │ ├── dxr_raytracing.hlsl
│ │ ├── dxr_reflection_entries.hlsl
│ │ ├── dxr_reflection_functions.hlsl
│ │ ├── dxr_reflection_main.hlsl
│ │ ├── dxr_shadow_entries.hlsl
│ │ ├── dxr_shadow_functions.hlsl
│ │ ├── dxr_shadow_main.hlsl
│ │ ├── dxr_structs.hlsl
│ │ ├── dxr_texture_lod.hlsl
│ │ ├── fullscreen_quad.hlsl
│ │ ├── generate_mips_cs.hlsl
│ │ ├── lighting.hlsl
│ │ ├── material_util.hlsl
│ │ ├── math.hlsl
│ │ ├── pbr_brdf_lut.hlsl
│ │ ├── pbr_cubemap_conversion.hlsl
│ │ ├── pbr_cubemap_convolution.hlsl
│ │ ├── pbr_prefilter_env_map.hlsl
│ │ ├── pbr_util.hlsl
│ │ ├── pp_bloom_blur.hlsl
│ │ ├── pp_bloom_blur_horizontal.hlsl
│ │ ├── pp_bloom_blur_vertical.hlsl
│ │ ├── pp_bloom_composition.hlsl
│ │ ├── pp_bloom_extract_bright.hlsl
│ │ ├── pp_bloom_util.hlsl
│ │ ├── pp_dof_bokeh.hlsl
│ │ ├── pp_dof_bokeh_post_filter.hlsl
│ │ ├── pp_dof_coc.hlsl
│ │ ├── pp_dof_composition.hlsl
│ │ ├── pp_dof_compute_near_mask.hlsl
│ │ ├── pp_dof_dilate.hlsl
│ │ ├── pp_dof_downscale.hlsl
│ │ ├── pp_dof_properties.hlsl
│ │ ├── pp_dof_util.hlsl
│ │ ├── pp_fxaa.hlsl
│ │ ├── pp_hdr_util.hlsl
│ │ ├── pp_tonemapping.hlsl
│ │ ├── pp_util.hlsl
│ │ └── rand_util.hlsl
│ ├── sponza_lights.json
│ └── viknell_lights.json
├── scripts/
│ └── JenkinsWebhook.bat
├── src/
│ ├── constant_buffer_pool.cpp
│ ├── constant_buffer_pool.hpp
│ ├── d3d12/
│ │ ├── d3d12_acceleration_structure..cpp
│ │ ├── d3d12_command_list.cpp
│ │ ├── d3d12_command_queue.cpp
│ │ ├── d3d12_constant_buffer_pool.cpp
│ │ ├── d3d12_constant_buffer_pool.hpp
│ │ ├── d3d12_defines.hpp
│ │ ├── d3d12_descriptor_heap.cpp
│ │ ├── d3d12_descriptors_allocations.cpp
│ │ ├── d3d12_descriptors_allocations.hpp
│ │ ├── d3d12_device.cpp
│ │ ├── d3d12_dynamic_descriptor_heap.cpp
│ │ ├── d3d12_dynamic_descriptor_heap.hpp
│ │ ├── d3d12_enums.hpp
│ │ ├── d3d12_fence.cpp
│ │ ├── d3d12_functions.hpp
│ │ ├── d3d12_heap.cpp
│ │ ├── d3d12_indirect_command_buffer.cpp
│ │ ├── d3d12_material_pool.cpp
│ │ ├── d3d12_material_pool.hpp
│ │ ├── d3d12_model_pool.cpp
│ │ ├── d3d12_model_pool.hpp
│ │ ├── d3d12_pipeline_state.cpp
│ │ ├── d3d12_readback_buffer.cpp
│ │ ├── d3d12_render_target.cpp
│ │ ├── d3d12_render_window.cpp
│ │ ├── d3d12_renderer.cpp
│ │ ├── d3d12_renderer.hpp
│ │ ├── d3d12_resource_pool_texture.cpp
│ │ ├── d3d12_resource_pool_texture.hpp
│ │ ├── d3d12_root_signature.cpp
│ │ ├── d3d12_rt_descriptor_heap.cpp
│ │ ├── d3d12_rt_descriptor_heap.hpp
│ │ ├── d3d12_settings.hpp
│ │ ├── d3d12_shader.cpp
│ │ ├── d3d12_shader_table.cpp
│ │ ├── d3d12_staging_buffer.cpp
│ │ ├── d3d12_state_object.cpp
│ │ ├── d3d12_structs.hpp
│ │ ├── d3d12_structured_buffer.cpp
│ │ ├── d3d12_structured_buffer_pool.cpp
│ │ ├── d3d12_structured_buffer_pool.hpp
│ │ ├── d3d12_texture_resources.hpp
│ │ ├── d3d12_textures.cpp
│ │ ├── d3d12_viewport.cpp
│ │ └── d3dx12.hpp
│ ├── engine_registry.cpp
│ ├── engine_registry.hpp
│ ├── entry.hpp
│ ├── frame_graph/
│ │ └── frame_graph.hpp
│ ├── id_factory.cpp
│ ├── id_factory.hpp
│ ├── imgui/
│ │ ├── ImGuizmo.cpp
│ │ ├── ImGuizmo.h
│ │ ├── imconfig.hpp
│ │ ├── imgui.cpp
│ │ ├── imgui.hpp
│ │ ├── imgui_draw.cpp
│ │ ├── imgui_impl_dx12.cpp
│ │ ├── imgui_impl_dx12.hpp
│ │ ├── imgui_impl_win32.cpp
│ │ ├── imgui_impl_win32.hpp
│ │ ├── imgui_internal.hpp
│ │ ├── imgui_widgets.cpp
│ │ ├── imstb_rectpack.hpp
│ │ ├── imstb_textedit.hpp
│ │ └── imstb_truetype.hpp
│ ├── imgui_graphics_settings.hpp
│ ├── imgui_tools.cpp
│ ├── imgui_tools.hpp
│ ├── material_pool.cpp
│ ├── material_pool.hpp
│ ├── model_loader.cpp
│ ├── model_loader.hpp
│ ├── model_loader_assimp.cpp
│ ├── model_loader_assimp.hpp
│ ├── model_loader_tinygltf.cpp
│ ├── model_loader_tinygltf.hpp
│ ├── model_pool.cpp
│ ├── model_pool.hpp
│ ├── pipeline_registry.cpp
│ ├── pipeline_registry.hpp
│ ├── platform_independend_structs.hpp
│ ├── registry.hpp
│ ├── render_tasks/
│ │ ├── d3d12_accumulation.hpp
│ │ ├── d3d12_ansel.hpp
│ │ ├── d3d12_bloom_composition.hpp
│ │ ├── d3d12_bloom_extract_bright.hpp
│ │ ├── d3d12_bloom_horizontal_blur.hpp
│ │ ├── d3d12_bloom_vertical_blur.hpp
│ │ ├── d3d12_brdf_lut_precalculation.hpp
│ │ ├── d3d12_build_acceleration_structures.hpp
│ │ ├── d3d12_cubemap_convolution.hpp
│ │ ├── d3d12_deferred_composition.cpp
│ │ ├── d3d12_deferred_composition.hpp
│ │ ├── d3d12_deferred_main.hpp
│ │ ├── d3d12_deferred_render_target_copy.hpp
│ │ ├── d3d12_dof_bokeh.hpp
│ │ ├── d3d12_dof_bokeh_postfilter.hpp
│ │ ├── d3d12_dof_coc.hpp
│ │ ├── d3d12_dof_composition.hpp
│ │ ├── d3d12_dof_compute_near_mask.hpp
│ │ ├── d3d12_dof_dilate_flatten.hpp
│ │ ├── d3d12_dof_dilate_flatten_second_pass.hpp
│ │ ├── d3d12_dof_dilate_near.hpp
│ │ ├── d3d12_down_scale.hpp
│ │ ├── d3d12_equirect_to_cubemap.hpp
│ │ ├── d3d12_hbao.hpp
│ │ ├── d3d12_imgui_render_task.hpp
│ │ ├── d3d12_path_tracer.hpp
│ │ ├── d3d12_post_processing.hpp
│ │ ├── d3d12_raytracing_task.hpp
│ │ ├── d3d12_reflection_denoiser.hpp
│ │ ├── d3d12_rt_hybrid_helpers.hpp
│ │ ├── d3d12_rt_reflection_task.hpp
│ │ ├── d3d12_rt_shadow_task.hpp
│ │ ├── d3d12_rtao_task.hpp
│ │ ├── d3d12_shadow_denoiser_task.hpp
│ │ └── d3d12_spatial_reconstruction.hpp
│ ├── renderer.cpp
│ ├── renderer.hpp
│ ├── resource_pool_texture.cpp
│ ├── resource_pool_texture.hpp
│ ├── root_signature_registry.cpp
│ ├── root_signature_registry.hpp
│ ├── rt_pipeline_registry.cpp
│ ├── rt_pipeline_registry.hpp
│ ├── scene_graph/
│ │ ├── camera_node.cpp
│ │ ├── camera_node.hpp
│ │ ├── light_node.cpp
│ │ ├── light_node.hpp
│ │ ├── mesh_node.cpp
│ │ ├── mesh_node.hpp
│ │ ├── node.cpp
│ │ ├── node.hpp
│ │ ├── scene_graph.cpp
│ │ ├── scene_graph.hpp
│ │ ├── skybox_node.cpp
│ │ └── skybox_node.hpp
│ ├── settings.hpp
│ ├── shader_registry.cpp
│ ├── shader_registry.hpp
│ ├── structs.hpp
│ ├── structured_buffer_pool.cpp
│ ├── structured_buffer_pool.hpp
│ ├── util/
│ │ ├── aabb.cpp
│ │ ├── aabb.hpp
│ │ ├── bitmap_allocator.hpp
│ │ ├── defines.hpp
│ │ ├── delegate.hpp
│ │ ├── file_watcher.cpp
│ │ ├── file_watcher.hpp
│ │ ├── log.cpp
│ │ ├── log.hpp
│ │ ├── logfile_handler.cpp
│ │ ├── logfile_handler.hpp
│ │ ├── named_type.hpp
│ │ ├── pair_hash.hpp
│ │ ├── strings.hpp
│ │ ├── thread_pool.hpp
│ │ └── user_literals.hpp
│ ├── version.hpp
│ ├── vertex.hpp
│ ├── window.cpp
│ ├── window.hpp
│ ├── wisp.hpp
│ └── wisprenderer_export.hpp
├── tests/
│ ├── CMakeLists.txt
│ ├── common/
│ │ ├── scene.cpp
│ │ └── scene.hpp
│ ├── demo/
│ │ ├── debug_camera.hpp
│ │ ├── demo.cpp
│ │ ├── demo_frame_graphs.hpp
│ │ ├── engine_interface.hpp
│ │ ├── physics_engine.cpp
│ │ ├── physics_engine.hpp
│ │ ├── physics_node.cpp
│ │ ├── physics_node.hpp
│ │ ├── scene_alien.cpp
│ │ ├── scene_alien.hpp
│ │ ├── scene_emibl.cpp
│ │ ├── scene_emibl.hpp
│ │ ├── scene_sponza.cpp
│ │ ├── scene_sponza.hpp
│ │ ├── scene_viknell.cpp
│ │ ├── scene_viknell.hpp
│ │ ├── spline_library/
│ │ │ ├── LICENSE
│ │ │ ├── spline.h
│ │ │ ├── splines/
│ │ │ │ ├── cubic_hermite_spline.h
│ │ │ │ ├── generic_b_spline.h
│ │ │ │ ├── natural_spline.h
│ │ │ │ ├── quintic_hermite_spline.h
│ │ │ │ ├── uniform_cr_spline.h
│ │ │ │ └── uniform_cubic_bspline.h
│ │ │ ├── utils/
│ │ │ │ ├── arclength.h
│ │ │ │ ├── calculus.h
│ │ │ │ ├── linearalgebra.h
│ │ │ │ ├── nanoflann.hpp
│ │ │ │ ├── spline_common.h
│ │ │ │ ├── splineinverter.h
│ │ │ │ └── splinesample_adaptor.h
│ │ │ └── vector.h
│ │ ├── spline_node.cpp
│ │ └── spline_node.hpp
│ └── graphics_benchmark/
│ ├── frame_graphs.cpp
│ ├── frame_graphs.hpp
│ ├── graphics_benchmark.cpp
│ ├── spheres_scene.cpp
│ └── spheres_scene.hpp
└── wisp.version
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/ISSUE_TEMPLATE/bug_report.md
================================================
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: bug
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behaviour:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behaviour**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Version [e.g. 22]
- Hardware [e.g. CPU:6700k, GPU:RTX 2080ti, RAM:1GB]
**Additional context**
Add any other context about the problem here.
================================================
FILE: .github/ISSUE_TEMPLATE/design-change.md
================================================
---
name: Design change
about: Suggest a design change for the project
title: ''
labels: design change
assignees: ''
---
**Is your design request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or designs you've considered.
**Additional context**
Add any other context or screenshots about the request here.
================================================
FILE: .github/ISSUE_TEMPLATE/feature_request.md
================================================
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.
================================================
FILE: .github/ISSUE_TEMPLATE/re-factor-request.md
================================================
---
name: Re-factor request
about: Suggest a re-factor of code for the project
title: ''
labels: code change
assignees: ''
---
**Is your request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions you've considered.
**Additional context**
Add any other context or screenshots about the request here.
================================================
FILE: .github/PULL_REQUEST_TEMPLATE/pull_request_template.md
================================================
**Description**
Give a clear description of the changes
**Issues**
reference related issues if any
**Possible conflicts**
list any possible conflicts
================================================
FILE: .gitignore
================================================
/build/
/build_vs2017_arm/
/build_vs2017_win64/
/build_vs2019_win64/
/build_vs2019_win32/
/build_vs2017_win32/
*.swp
*.swo
/cmake-build-debug/
/.idea/
perf_framerate.txt
*.dll
*.lib
/resources/models
/resources/materials
/deps/ansel/
/deps/hbao+/
/benchmark_images/
/CrashPadDB/
/logs/
================================================
FILE: .gitmodules
================================================
[submodule "deps/fmt"]
path = deps/fmt
url = https://github.com/fmtlib/fmt.git
[submodule "deps/DirectXTex"]
path = deps/DirectXTex
url = https://github.com/TeamWisp/DirectXTex.git
branch = master
[submodule "deps/assimp"]
path = deps/assimp
url = https://github.com/assimp/assimp
[submodule "deps/fallback"]
path = deps/fallback
url = https://github.com/TeamWisp/DXR-Fallback-Layer.git
[submodule "deps/Wisp-LFS"]
path = deps/Wisp-LFS
url = https://github.com/TeamWisp/Wisp-LFS.git
[submodule "deps/crashpad"]
path = deps/crashpad
url = https://github.com/TeamWisp/Crashpad.git
[submodule "deps/tinygltf"]
path = deps/tinygltf
url = https://github.com/syoyo/tinygltf
[submodule "deps/bullet3"]
path = deps/bullet3
url = https://github.com/TeamWisp/bullet3
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.13)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
add_compile_definitions(_ENABLE_EXTENDED_ALIGNED_STORAGE )
project(Wisp)
option(WISP_BUILD_TESTS "Enable Wisp Tests" ON)
option(WISP_LOG_TO_STDOUT "Allow printing to stdout" ON)
option(WISP_BUILD_SHARED "Build Wisp as a shared library" OFF)
if (WISP_BUILD_SHARED)
set(BUILD_SHARED_LIBS ON)
message(STATUS "Building wisp as a SHARED library")
else()
add_definitions(-DWISPRENDERER_STATIC_DEFINE)
message(STATUS "Building wisp as a STATIC library")
set(BUILD_SHARED_LIBS OFF)
endif()
if (WISP_LOG_TO_STDOUT)
message(STATUS "Wisp Renderer is allowed to print to stdout")
add_definitions(-DWISPRENDERER_LOG_TO_STDOUT)
endif()
#Detect whether we have HBAO+ SDK available.
if(EXISTS ${CMAKE_SOURCE_DIR}/deps/hbao+)
message(STATUS "Found NVIDIA Gameworks HBAO+")
set(NVIDIA_GAMEWORKS_HBAO_LIB ${CMAKE_SOURCE_DIR}/GFSDK_SSAO_D3D12.win64.lib)
add_definitions(-DNVIDIA_GAMEWORKS_HBAO)
configure_file(${CMAKE_SOURCE_DIR}/deps/hbao+/lib/GFSDK_SSAO_D3D12.win64.dll ${CMAKE_SOURCE_DIR} COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/deps/hbao+/lib/GFSDK_SSAO_D3D12.win64.lib ${CMAKE_SOURCE_DIR} COPYONLY)
else()
message(STATUS "Failed to find NVIDIA Gameworks HBAO+")
endif()
#Detect whether we have the AnselSDK available.
if(EXISTS ${CMAKE_SOURCE_DIR}/deps/ansel)
message(STATUS "Found NVIDIA Gameworks Ansel")
set(NVIDIA_GAMEWORKS_ANSEL_LIB ${CMAKE_SOURCE_DIR}/AnselSDK64.lib)
add_definitions(-DNVIDIA_GAMEWORKS_ANSEL)
configure_file(${CMAKE_SOURCE_DIR}/deps/ansel/lib/AnselSDK64.lib ${CMAKE_SOURCE_DIR} COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/deps/ansel/redist/AnselSDK64.dll ${CMAKE_SOURCE_DIR} COPYONLY)
else()
message(STATUS "Failed to find NVIDIA Gameworks Ansel")
endif()
##### OUTPUT DIRECTORIES #####
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
configure_file(${CMAKE_SOURCE_DIR}/deps/fallback/Bin/dxrfallbackcompiler.dll ${CMAKE_SOURCE_DIR} COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/deps/fallback/Bin/dxil.dll ${CMAKE_SOURCE_DIR} COPYONLY)
configure_file(${CMAKE_SOURCE_DIR}/deps/fallback/Bin/dxcompiler.dll ${CMAKE_SOURCE_DIR} COPYONLY)
##### SOURCES #####
file(GLOB HEADERS CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/*.hpp")
file(GLOB SOURCES CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
file(GLOB FG_HEADERS CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/frame_graph/*.hpp")
file(GLOB FG_SOURCES CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/frame_graph/*.cpp")
file(GLOB SG_HEADERS CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/scene_graph/*.hpp")
file(GLOB SG_SOURCES CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/scene_graph/*.cpp")
file(GLOB RT_HEADERS CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/render_tasks/*.hpp")
file(GLOB RT_SOURCES CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/render_tasks/*.cpp")
file(GLOB D3D12_HEADERS CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/d3d12/*.hpp")
file(GLOB D3D12_SOURCES CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/d3d12/*.cpp")
file(GLOB UTIL_HEADERS CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/util/*.hpp")
file(GLOB UTIL_SOURCES CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/util/*.cpp")
file(GLOB IMGUI_HEADERS CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/imgui/*.hpp")
file(GLOB IMGUI_SOURCES CONFIGURE_DEPENDS] "${CMAKE_CURRENT_SOURCE_DIR}/src/imgui/*.cpp")
source_group("High Level API" FILES ${SOURCES} ${HEADERS})
source_group("Frame Graph" FILES ${FG_SOURCES} ${FG_HEADERS})
source_group("Scene Graph" FILES ${SG_SOURCES} ${SG_HEADERS})
source_group("Render Tasks" FILES ${RT_SOURCES} ${RT_HEADERS})
source_group("D3D12" FILES ${D3D12_SOURCES} ${D3D12_HEADERS})
source_group("Utility" FILES ${UTIL_SOURCES} ${UTIL_HEADERS})
source_group("ImGui" FILES ${IMGUI_SOURCES} ${IMGUI_HEADERS})
set (CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT")
set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
set (CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /MT")
# Bullet Options
set(BUILD_CPU_DEMOSON OFF CACHE BOOL "" FORCE)
set(USE_GRAPHICAL_BENCHMARKON OFF CACHE BOOL "" FORCE)
set(BUILD_ENETON OFF CACHE BOOL "" FORCE)
set(BUILD_CLSOCKETON OFF CACHE BOOL "" FORCE)
set(BUILD_BULLET2_DEMOSON OFF CACHE BOOL "" FORCE)
set(BUILD_EXTRASON OFF CACHE BOOL "" FORCE)
set(BUILD_UNIT_TESTSON OFF CACHE BOOL "" FORCE)
set(USE_GRAPHICAL_BENCHMARKON OFF CACHE BOOL "" FORCE)
set(BUILD_STATIC_LIBON ON CACHE BOOL "" FORCE)
set(NO_EXPORTON ON CACHE BOOL "" FORCE)
## dependencies ##
add_subdirectory(${CMAKE_SOURCE_DIR}/deps/fmt ${CMAKE_BINARY_DIR}/fmt)
add_subdirectory(${CMAKE_SOURCE_DIR}/deps/DirectXTex ${CMAKE_BINARY_DIR}/DirectXTex)
add_subdirectory(${CMAKE_SOURCE_DIR}/deps/fallback ${CMAKE_BINARY_DIR}/fallback)
add_subdirectory(${CMAKE_SOURCE_DIR}/deps/bullet3 ${CMAKE_BINARY_DIR}/bullet3)
set(ASSIMP_BUILD_SHARED_LIBS OFF)
set(ASSIMP_NO_EXPORT ON CACHE BOOL "" FORCE)
set(ASSIMP_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT OFF)
set(ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT OFF)
#IMPORTERS
set( ASSIMP_BUILD_AMF_IMPORTER OFF )
set( ASSIMP_BUILD_3DS_IMPORTER OFF )
set( ASSIMP_BUILD_AC_IMPORTER OFF )
set( ASSIMP_BUILD_ASE_IMPORTER OFF )
set( ASSIMP_BUILD_ASSBIN_IMPORTER OFF )
set( ASSIMP_BUILD_ASSXML_IMPORTER OFF )
set( ASSIMP_BUILD_B3D_IMPORTER OFF )
set( ASSIMP_BUILD_BVH_IMPORTER OFF )
set( ASSIMP_BUILD_COLLADA_IMPORTER OFF )
set( ASSIMP_BUILD_DXF_IMPORTER OFF )
set( ASSIMP_BUILD_CSM_IMPORTER OFF )
set( ASSIMP_BUILD_HMP_IMPORTER OFF )
set( ASSIMP_BUILD_IRRMESH_IMPORTER OFF )
set( ASSIMP_BUILD_IRR_IMPORTER OFF )
set( ASSIMP_BUILD_LWO_IMPORTER OFF )
set( ASSIMP_BUILD_LWS_IMPORTER OFF )
set( ASSIMP_BUILD_MD2_IMPORTER OFF )
set( ASSIMP_BUILD_MD3_IMPORTER OFF )
set( ASSIMP_BUILD_MD5_IMPORTER OFF )
set( ASSIMP_BUILD_MDC_IMPORTER OFF )
set( ASSIMP_BUILD_MDL_IMPORTER OFF )
set( ASSIMP_BUILD_NFF_IMPORTER OFF )
set( ASSIMP_BUILD_NDO_IMPORTER OFF )
set( ASSIMP_BUILD_OFF_IMPORTER OFF )
set( ASSIMMP_BUILD_OBJ_IMPORTER ON ) #ON
set( ASSIMP_BUILD_OGRE_IMPORTER OFF )
set( ASSIMP_BUILD_OPENGEX_IMPORTER OFF )
set( ASSIMP_BUILD_PLY_IMPORTER OFF )
set( ASSIMP_BUILD_MS3D_IMPORTER OFF )
set( ASSIMP_BUILD_COB_IMPORTER OFF )
set( ASSIMP_BUILD_BLEND_IMPORTER OFF )
set( ASSIMP_BUILD_IFC_IMPORTER OFF )
set( ASSIMP_BUILD_XGL_IMPORTER OFF )
set( ASSIMMP_BUILD_FBX_IMPORTER ON ) #ON
set( ASSIMP_BUILD_Q3D_IMPORTER OFF )
set( ASSIMP_BUILD_Q3BSP_IMPORTER OFF )
set( ASSIMP_BUILD_RAW_IMPORTER ON ) #ON
set( ASSIMP_BUILD_SIB_IMPORTER ON ) #ON
set( ASSIMP_BUILD_SMD_IMPORTER ON ) #ON
set( ASSIMP_BUILD_STL_IMPORTER OFF )
set( ASSIMP_BUILD_TERRAGEN_IMPORTER OFF )
set( ASSIMP_BUILD_3D_IMPORTER OFF )
set( ASSIMP_BUILD_X_IMPORTER OFF )
set( ASSIMP_BUILD_X3D_IMPORTER OFF )
set( ASSIMP_BUILD_GLTF_IMPORTER ON ) #ON
set( ASSIMP_BUILD_3MF_IMPORTER OFF )
set( ASSIMP_BUILD_MMD_IMPORTER OFF )
# END IMPORTERS
#set(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT CACHE INTERNAL FALSE)
#set(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT OFF)
add_subdirectory(${CMAKE_SOURCE_DIR}/deps/assimp ${CMAKE_BINARY_DIR}/assimp)
## dependencies options ##
set(FMT_TEST OFF)
set(FMT_DOC OFF)
set(FMT_PEDANTIC OFF)
set(FMT_WERROR OFF)
## dependencies sorting ##
set_target_properties (fmt PROPERTIES FOLDER ThirdParty)
set_target_properties (DirectXTex PROPERTIES FOLDER ThirdParty)
if (MSVC)
target_compile_options(fmt PRIVATE /W0)
target_compile_options(DirectXTex PRIVATE /W0)
endif()
set_target_properties(Bullet3Common PROPERTIES FOLDER "ThirdParty/Bullet")
set_target_properties(BulletCollision PROPERTIES FOLDER "ThirdParty/Bullet")
set_target_properties(BulletDynamics PROPERTIES FOLDER "ThirdParty/Bullet")
set_target_properties(BulletInverseDynamics PROPERTIES FOLDER "ThirdParty/Bullet")
set_target_properties(BulletSoftBody PROPERTIES FOLDER "ThirdParty/Bullet")
set_target_properties(LinearMath PROPERTIES FOLDER "ThirdParty/Bullet")
set_target_properties(assimp PROPERTIES FOLDER ThirdParty)
set_target_properties(assimp_cmd PROPERTIES FOLDER ThirdParty)
set_target_properties(IrrXML PROPERTIES FOLDER ThirdParty)
set_target_properties(UpdateAssimpLibsDebugSymbolsAndDLLs PROPERTIES FOLDER ThirdParty)
set_target_properties(zlib PROPERTIES FOLDER ThirdParty)
set_target_properties(zlibstatic PROPERTIES FOLDER ThirdParty)
#set_target_properties(unit PROPERTIES FOLDER ThirdParty)
set_target_properties(uninstall PROPERTIES FOLDER ThirdParty)
if(WISP_BUILD_SHARED)
set(WISP_LIB_TYPE SHARED)
else()
set(WISP_LIB_TYPE STATIC)
endif()
add_library(WispRenderer ${WISP_LIB_TYPE} ${HEADERS} ${SOURCES} ${IMGUI_HEADERS} ${IMGUI_SOURCES} ${UTIL_HEADERS} ${UTIL_SOURCES} ${RT_HEADERS} ${RT_SOURCES} ${FG_HEADERS} ${FG_SOURCES} ${SG_HEADERS} ${SG_SOURCES} ${D3D12_SOURCES} ${D3D12_HEADERS})
set_target_properties(WispRenderer PROPERTIES CXX_STANDARD 20)
set_target_properties(WispRenderer PROPERTIES CXX_EXTENSIONS OFF)
set_target_properties(WispRenderer PROPERTIES CMAKE_CXX_STANDARD_REQUIRED ON)
if (MSVC)
target_compile_options(WispRenderer PRIVATE /W4 /permissive- /MP /Gm-)
endif()
target_include_directories(WispRenderer PUBLIC ${CMAKE_SOURCE_DIR}/deps/DirectXTex/DirectXTex/)
target_include_directories(WispRenderer PUBLIC ${CMAKE_SOURCE_DIR}/deps/fmt/include)
target_include_directories(WispRenderer PUBLIC ${CMAKE_SOURCE_DIR}/deps/tinygltf)
target_include_directories(WispRenderer PUBLIC ${CMAKE_SOURCE_DIR}/deps/assimp/include)
target_include_directories(WispRenderer PUBLIC ${CMAKE_SOURCE_DIR}/deps/fallback/Include)
target_include_directories(WispRenderer PUBLIC ${CMAKE_SOURCE_DIR}/deps/hbao+/include)
target_include_directories(WispRenderer PUBLIC ${CMAKE_SOURCE_DIR}/deps/ansel/include)
target_include_directories(WispRenderer PUBLIC ${CMAKE_SOURCE_DIR}/deps/crashpad)
target_include_directories(WispRenderer PUBLIC ${CMAKE_SOURCE_DIR}/deps/crashpad/third_party/mini_chromium/mini_chromium)
target_include_directories(WispRenderer PUBLIC ${CMAKE_SOURCE_DIR}/deps/bullet3/src)
link_directories(${CMAKE_SOURCE_DIR}/deps/crashpad/out/$(ConfigurationName)/obj/ ${CMAKE_SOURCE_DIR}/deps/crashpad/out/$(ConfigurationName)/obj/client/ ${CMAKE_SOURCE_DIR}/deps/crashpad/out/$(ConfigurationName)/obj/util/ ${CMAKE_SOURCE_DIR}/deps/crashpad/out/$(ConfigurationName)/obj/third_party/mini_chromium/mini_chromium/base/)
target_link_libraries(WispRenderer DXRFallback dxguid.lib d3d12.lib dxgi.lib d3dcompiler.lib dxcompiler DirectXTex fmt assimp ${NVIDIA_GAMEWORKS_HBAO_LIB} ${NVIDIA_GAMEWORKS_ANSEL_LIB} crashpad_client crashpad_util base)
set_target_properties(WispRenderer PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/../")
if (WISP_BUILD_TESTS)
add_subdirectory(tests ${CMAKE_BINARY_DIR}/tests)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Demo)
endif()
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at viktorzoutman@vzout.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq
================================================
FILE: Jenkinsfile
================================================
pipeline {
agent any
stages {
stage('Install'){
steps{
echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
bat '''cd "%WORKSPACE%\\Scripts"
call JenkinsWebhook.bat ":bulb: Building: %JOB_NAME%. Jenkins build nr: %BUILD_NUMBER%"
cd "%WORKSPACE%
install -remote "%WORKSPACE%"
if errorlevel 1 (
cd "%WORKSPACE%\\Scripts"
JenkinsWebhook ":x: %JOB_NAME% Build Failed!! Jenskins build nr: %BUILD_NUMBER% - install failed"
EXIT 1
)'''
}
}
stage('Build') {
steps {
/*bat '''
cd "%WORKSPACE%"
cmake --build ./build_vs2017_win32
if errorlevel 1 (
cd "%WORKSPACE%\\Scripts"
JenkinsWebhook ":x: %JOB_NAME% Build Failed!! Jenskins build nr: %BUILD_NUMBER% - 32bit build failed"
EXIT 1
)
'''*/
bat'''
cd "%WORKSPACE%"
cmake --build ./build_vs2017_win64
if errorlevel 1 (
cd "%WORKSPACE%\\Scripts"
JenkinsWebhook ":x: %JOB_NAME% Build Failed!! Jenskins build nr: %BUILD_NUMBER% - 64bit-debug build failed"
EXIT 1
)
'''
bat'''
cd "%WORKSPACE%"
cmake --build ./build_vs2017_win64 --config Release
if errorlevel 1 (
cd "%WORKSPACE%\\Scripts"
JenkinsWebhook ":x: %JOB_NAME% Build Failed!! Jenskins build nr: %BUILD_NUMBER% - 64bit-release build failed"
EXIT 1
)
'''
}
}
stage('test'){
steps{
script{
def has_failed = false
try{
bat'''
cd "%WORKSPACE%"
cd build_vs2017_win64/bin/debug
WispTest.exe
if errorlevel 1 (
EXIT 1
)
'''
}
catch( exc ){
has_failed = true
bat'''
cd "%WORKSPACE%\\Scripts"
JenkinsWebhook ":x: %JOB_NAME% Build Failed!! Jenskins build nr: %BUILD_NUMBER% - 64bit-debug Tests failed"
'''
}
try{
bat'''
cd "%WORKSPACE%"
cd build_vs2017_win64/bin/release
WispTest.exe
if errorlevel 1 (
EXIT 1
)
'''
}
catch( exc ){
has_failed = true
bat'''
cd "%WORKSPACE%\\Scripts"
JenkinsWebhook ":x: %JOB_NAME% Build Failed!! Jenskins build nr: %BUILD_NUMBER% - 64bit-release Tests failed"
'''
}
if(has_failed){
EXIT 1
}
}
}
}
stage('finalize'){
steps{
bat '''
rem mkdir builds
rem move ./RayTracingLib/Debug "./builds/build_%BUILD_NUMBER%"
cd "%WORKSPACE%\\scripts
call "JenkinsWebhook.bat" ":white_check_mark: %JOB_NAME% Build Succesfull!! Jenkins build nr: %BUILD_NUMBER%"
'''
}
}
}
}
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: README.md
================================================
# [
WispRenderer](https://teamwisp.github.io) - Real-Time Raytracing Renderer
[](https://github.com/TeamWisp/WispRenderer/releases)
[](https://github.com/TeamWisp/WispRenderer/issues)
[](https://opensource.org/licenses/EPL-2.0)
[](https://discord.gg/Q3vDfqR)
[](https://twitter.com/wisprenderer)

## [What is it?](https://teamwisp.github.io/product/)
Wisp is a general purpose high level rendering library. Specially made for real time raytracing with NVIDIA RTX graphics cards. Made by a group of students from [Breda University of Applied Sciences](https://www.buas.nl/) specializing in graphics programming.
**Features**
* Physically Based Rendering
* Ray Traced Global Illumination
* Path Traced Global Illumination
* Ray Traced Ambient Occlusion
* Ray Traced Reflections
* Ray Traced Shadows
* Translucency & Transparency.
* NVIDIA's HBAO+
* NVIDIA's AnselSDK
**Supported Rendering Backends**
* DirectX 12
**Supported Platforms**
* Windows 10 (Version 1903)
**Supported Compilers**
* Visual Studio 2017
* Visual Studio 2019
## [Installation](https://teamwisp.github.io/workspace_setup/)
### Installer
```
git clone https://github.com/TeamWisp/WispRenderer.git
```
Then run `installer.exe` located in the new `WispRenderer` folder and follow the on-screen prompts. When finished you can find the `.sln` file in the `build_vs2019_win64` folder.
### Manual
```
git clone https://github.com/TeamWisp/WispRenderer.git
cd WispRenderer
mkdir build
cd build
cmake -G "Visual Studio 16 2019" ..
```
Now you can run the `.sln` file inside the `build` folder. Want to use NVIDIA Gameworks? See the [advanced documation](https://teamwisp.github.io/workspace_setup/).
# [Documentation](https://teamwisp.github.io/)
# [Example](https://github.com/TeamWisp/WispRenderer/tree/master/demo)
# [Getting Involved](https://teamwisp.github.io/)
Want to help us out? That's definatly possible! Check out our [contribution page](https://teamwisp.github.io/) on how.
# [Development Blog](https://teamwisp.github.io/WispBlog/)
# [Discord](https://discord.gg/Q3vDfqR)
Need help, want to get updates as soon as they happen or just want a chat? Join our [Discord Server](https://discord.gg/Q3vDfqR)!
## Trailer
## Media
## [License (Eclipse Public License version 2.0)](https://opensource.org/licenses/EPL-2.0)
```
Copyright 2018-2019 Breda University of Applied Sciences
If a Contributor Distributes the Program in any form, then:
a) the Program must also be made available as Source Code, in accordance with section 3.2, and the Contributor must accompany the Program with a statement that the Source Code for the Program is available under this Agreement, and informs Recipients how to obtain it in a reasonable manner on or through a medium customarily used for software exchange; and
b) the Contributor may Distribute the Program under a license different than this Agreement, provided that such license:
i) effectively disclaims on behalf of all other Contributors all warranties and conditions, express and implied, including warranties or conditions of title and non-infringement, and implied warranties or conditions of merchantability and fitness for a particular purpose;
ii) effectively excludes on behalf of all other Contributors all liability for damages, including direct, indirect, special, incidental and consequential damages, such as lost profits;
iii) does not attempt to limit or alter the recipients' rights in the Source Code under section 3.2; and
iv) requires any subsequent distribution of the Program by any party to be under a license that satisfies the requirements of this section 3.
When the Program is Distributed as Source Code:
a) it must be made available under this Agreement, or if the Program (i) is combined with other material in a separate file or files made available under a Secondary License, and (ii) the initial Contributor attached to the Source Code the notice described in Exhibit A of this Agreement, then the Program may be made available under the terms of such Secondary Licenses, and
b) a copy of this Agreement must be included with each copy of the Program.
Contributors may not remove or alter any copyright, patent, trademark, attribution notices, disclaimers of warranty, or limitations of liability (‘notices’) contained within the Program from any copy of the Program which they Distribute, provided that Contributors may add their own appropriate notices.
```
================================================
FILE: imgui.ini
================================================
[Window][DockspaceViewport_11111111]
Pos=0,21
Size=1280,699
Collapsed=0
[Window][Debug##Default]
Pos=1022,401
Size=228,150
Collapsed=1
[Window][Theme]
Pos=1032,376
Size=248,201
Collapsed=0
DockId=0x00000009,0
[Window][ImGui Details]
Pos=1032,607
Size=248,113
Collapsed=0
[Window][Camera Settings]
Pos=0,342
Size=270,378
Collapsed=0
DockId=0x00000008,0
[Window][Light Editor]
Pos=0,21
Size=32,32
Collapsed=0
[Window][Shader Registry]
Pos=340,105
Size=590,455
Collapsed=0
[Window][Pipeline Registry]
Pos=317,134
Size=312,443
Collapsed=0
[Window][Root Signature Registry]
Pos=748,338
Size=169,259
Collapsed=0
[Window][DirectX 12 Settings]
Pos=1032,376
Size=248,201
Collapsed=0
DockId=0x00000009,2
[Window][Hardware Info]
Pos=1032,376
Size=248,201
Collapsed=0
DockId=0x00000009,1
[Window][Model Editor]
Pos=0,31
Size=32,32
Collapsed=0
[Window][Light Details]
Pos=0,403
Size=220,129
Collapsed=0
[Window][Inspect]
Pos=26,21
Size=32,32
Collapsed=0
[Window][Viewport]
Pos=272,21
Size=758,699
Collapsed=0
DockId=0x00000002,0
[Window][Scene Graph Editor]
Pos=0,21
Size=270,319
Collapsed=0
DockId=0x00000007,1
[Window][Inspector]
Pos=1032,21
Size=248,353
Collapsed=0
DockId=0x00000006,0
[Window][DockSpaceViewport_11111111]
Pos=0,21
Size=1280,699
Collapsed=0
[Window][Stats]
Pos=280,121
Size=205,85
Collapsed=0
[Window][Test popup]
ViewportPos=1503,395
ViewportId=0xB4FE7E97
Size=151,177
Collapsed=0
[Window][Emissive Multiplier]
Pos=944,589
Size=303,134
Collapsed=0
[Window][RTAO Settings]
Pos=1032,579
Size=248,141
Collapsed=0
DockId=0x0000000A,0
[Window][HBAO+ Settings]
Pos=1032,579
Size=248,141
Collapsed=0
DockId=0x0000000A,0
[Window][NVIDIA Ansel Settings]
Pos=1032,376
Size=248,201
Collapsed=0
DockId=0x00000009,3
[Window][Acceleration Structure Settings]
Pos=1032,579
Size=248,141
Collapsed=0
DockId=0x0000000A,1
[Window][Shadow Settings]
Pos=1032,579
Size=248,141
Collapsed=0
DockId=0x0000000A,2
[Window][Demo Scene]
Pos=0,21
Size=270,319
Collapsed=0
DockId=0x00000007,0
[Docking][Data]
DockSpace ID=0x8B93E3BD Pos=0,21 Size=1280,699 Split=X
DockNode ID=0x00000003 Parent=0x8B93E3BD SizeRef=1030,699 Split=X
DockNode ID=0x00000001 Parent=0x00000003 SizeRef=270,699 Split=Y SelectedTab=0xF4865B00
DockNode ID=0x00000007 Parent=0x00000001 SizeRef=219,319 SelectedTab=0xF4865B00
DockNode ID=0x00000008 Parent=0x00000001 SizeRef=219,378 SelectedTab=0x8722C6A1
DockNode ID=0x00000002 Parent=0x00000003 SizeRef=758,699 CentralNode=1 SelectedTab=0x995B0CF8
DockNode ID=0x00000004 Parent=0x8B93E3BD SizeRef=248,699 Split=Y SelectedTab=0x070A839D
DockNode ID=0x00000006 Parent=0x00000004 SizeRef=248,353 SelectedTab=0xF02CD328
DockNode ID=0x00000005 Parent=0x00000004 SizeRef=248,344 Split=Y SelectedTab=0xDA48A090
DockNode ID=0x00000009 Parent=0x00000005 SizeRef=248,201 SelectedTab=0x4BB5AED3
DockNode ID=0x0000000A Parent=0x00000005 SizeRef=248,141 SelectedTab=0xDCA1C528
================================================
FILE: resources/alien_lights.json
================================================
{
"lights": [
{
"angle": 69.0,
"color": [
0.0,
7.843137264251709,
11.764705657958984
],
"pos": [
0.5994455218315125,
1.0072081089019775,
0.7158395648002625,
0.0
],
"radius": 200.0,
"rot": [
-0.1899939924478531,
0.02998405694961548,
0.0,
0.0
],
"size": 0.0872664600610733,
"type": 0
},
{
"angle": 0.6981316804885864,
"color": [
1.0,
0.9999899864196777,
0.9999899864196777
],
"pos": [
0.8884486556053162,
1.0663642883300781,
0.0,
0.0
],
"radius": 0.0,
"rot": [
0.0,
0.0,
0.0,
0.0
],
"size": 0.0,
"type": 0
}
]
}
================================================
FILE: resources/shaders/deferred_composition_pass.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DEFERRED_COMPOSITION_PASS_HLSL__
#define __DEFERRED_COMPOSITION_PASS_HLSL__
#define LIGHTS_REGISTER register(t4)
#define MAX_REFLECTION_LOD 6
#include "fullscreen_quad.hlsl"
#include "rand_util.hlsl"
#include "pbr_util.hlsl"
#include "lighting.hlsl"
Texture2D gbuffer_albedo_roughness : register(t0);
Texture2D gbuffer_normal_metallic : register(t1);
Texture2D gbuffer_emissive_ao : register(t2);
Texture2D gbuffer_depth : register(t3);
//Consider SRV for light buffer in register t4
TextureCube skybox : register(t5);
TextureCube irradiance_map : register(t6);
TextureCube pref_env_map : register(t7);
Texture2D brdf_lut : register(t8);
Texture2D buffer_reflection : register(t9); //rgb: reflection, a : 1 / pdf
Texture2D buffer_shadow : register(t10); //r: shadow factor
Texture2D screen_space_irradiance : register(t11);
Texture2D screen_space_ao : register(t12);
RWTexture2D output : register(u0);
SamplerState point_sampler : register(s0);
SamplerState linear_sampler : register(s1);
cbuffer CameraProperties : register(b0)
{
float4x4 view;
float4x4 projection;
float4x4 inv_projection;
float4x4 inv_view;
float4x4 prev_projection;
float4x4 prev_view;
uint is_hybrid;
uint is_path_tracer;
uint is_ao;
uint has_shadows;
float3 padding1;
uint has_reflections;
};
static uint min_depth = 0xFFFFFFFF;
static uint max_depth = 0x0;
float3 unpack_position(float2 uv, float depth, float4x4 proj_inv, float4x4 view_inv) {
const float4 ndc = float4(uv * 2.0f - 1.f, depth, 1.0f);
const float4 pos = mul( view_inv, mul(proj_inv, ndc));
return (pos / pos.w).xyz;
}
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
// added offset of 0.5f to select proper pixel to sample from.
// screen coords always get floored, therefore if the coords would be (1.9, 1.0),
// it would sample (1.0, 1.0) instead of the intended (2.0, 1.0). Adding the offset solves this problem.
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y) + 0.5f;
float2 uv = screen_coord / screen_size;
const float depth_f = gbuffer_depth.SampleLevel(point_sampler, uv, 0.0f).r;
// View position and camera position
float3 pos = unpack_position(float2(uv.x, 1.f - uv.y), depth_f, inv_projection, inv_view);
float3 camera_pos = float3(inv_view[0][3], inv_view[1][3], inv_view[2][3]);
float3 V = normalize(camera_pos - pos);
float3 retval;
if(depth_f != 1.0f)
{
// GBuffer contents
float4 albedo_roughness = gbuffer_albedo_roughness.SampleLevel(point_sampler, uv, 0.0f);
float3 albedo = albedo_roughness.xyz;
const float roughness = albedo_roughness.w;
float4 normal_metallic = gbuffer_normal_metallic.SampleLevel(point_sampler, uv, 0.0f);
float3 normal = normalize(normal_metallic.xyz);
const float metallic = normal_metallic.w;
float4 emissive_ao = gbuffer_emissive_ao.SampleLevel(point_sampler, uv, 0.0f);
float3 emissive = emissive_ao.xyz;
float gbuffer_ao = emissive_ao.w;
float3 flipped_N = normal;
flipped_N.y *= -1.0f;
const float2 sampled_brdf = brdf_lut.SampleLevel(point_sampler, float2(max(dot(normal, V), 0.01f), roughness), 0).rg;
float3 sampled_environment_map = pref_env_map.SampleLevel(linear_sampler, reflect(-V, normal), roughness * MAX_REFLECTION_LOD);
// Get irradiance
float3 irradiance = lerp(
irradiance_map.SampleLevel(linear_sampler, flipped_N, 0.0f).xyz,
screen_space_irradiance.SampleLevel(point_sampler, uv, 0.0f).xyz,
is_path_tracer);
// Get ao
float ao = lerp(
1,
screen_space_ao.SampleLevel(point_sampler, uv, 0.0f).xyz,
// Lerp factor (0: env map, 1: path traced)
is_ao);
//Ao is multiplied with material texture ao, if present
ao *= gbuffer_ao;
// Get shadow factor (0: fully shadowed, 1: no shadow)
float3 shadow_factor = lerp(
// Do deferred shadow (fully lit for now)
float3(1, 1, 1),
// Shadow buffer if its hybrid rendering
buffer_shadow.SampleLevel(linear_sampler, uv, 0.0f).rgb,
// Lerp factor (0: no hybrid, 1: hybrid)
has_shadows);
// Get reflection
float3 reflection = lerp(
// Sample from environment if it IS NOT hybrid rendering
sampled_environment_map,
// Reflection buffer if it IS hybrid rendering
buffer_reflection.SampleLevel(linear_sampler, uv, 0).xyz,
// Lerp factor (0: no hybrid, 1: hybrid)
has_reflections);
// Shade pixel
retval = shade_pixel(pos, V, albedo, metallic, roughness, emissive, normal, irradiance, ao, reflection, sampled_brdf, shadow_factor, has_shadows);
}
else
{
retval = skybox.SampleLevel(linear_sampler, -V, 0.0f);
}
//Temporary hackfix for NaN pixels
if (isnan(retval).x == true)
{
retval = float3(0.0f, 0.0f, 0.0f);
}
//Do shading
output[int2(dispatch_thread_id.xy)] = float4(retval, 1.f);
}
#endif //__DEFERRED_COMPOSITION_PASS_HLSL__
================================================
FILE: resources/shaders/deferred_geometry_pass.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DEFERRED_GEOMETRY_PASS_HLSL__
#define __DEFERRED_GEOMETRY_PASS_HLSL__
//48 KiB; 48 * 1024 / sizeof(MeshNode)
//48 * 1024 / (4 * 4 * 4) = 48 * 1024 / 64 = 48 * 16 = 768
#define MAX_INSTANCES 768
#include "material_util.hlsl"
struct VS_INPUT
{
float3 pos : POSITION;
float2 uv : TEXCOORD;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 bitangent : BITANGENT;
};
struct VS_OUTPUT
{
float4 pos : SV_POSITION;
#ifdef IS_HYBRID
float4 prev_pos : PREV_POSITION;
float4 curr_pos : CURR_POSITION;
float4 world_pos : WORLD_POSITION;
#endif
float2 uv : TEXCOORD;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 bitangent : BITANGENT;
#ifdef IS_HYBRID
float3 obj_normal : OBJECT_NORMAL;
float3 obj_tangent : OBJECT_TANGENT;
float3 obj_bitangent : OBJECT_BITANGENT;
#endif
};
cbuffer CameraProperties : register(b0)
{
float4x4 view;
float4x4 projection;
float4x4 inv_projection;
float4x4 inv_view;
float4x4 prev_projection;
float4x4 prev_view;
uint is_hybrid;
uint is_path_tracer;
uint is_ao;
uint has_shadows;
float3 padding1;
uint has_reflections;
};
struct ObjectData
{
float4x4 model;
float4x4 prev_model;
};
cbuffer ObjectProperties : register(b1)
{
ObjectData instances[MAX_INSTANCES];
};
VS_OUTPUT main_vs(VS_INPUT input, uint instid : SV_InstanceId)
{
VS_OUTPUT output;
float3 pos = input.pos;
ObjectData inst = instances[instid];
//TODO: Use precalculated MVP or at least VP
float4x4 vm = mul(view, inst.model);
float4x4 mvp = mul(projection, vm);
float4x4 prev_mvp = mul(prev_projection, mul(prev_view, inst.prev_model));
output.pos = mul(mvp, float4(pos, 1.0f));
#ifdef IS_HYBRID
output.curr_pos = output.pos;
output.prev_pos = mul(prev_mvp, float4(pos, 1.0f));
output.world_pos = mul(inst.model, float4(pos, 1.0f));
#endif
output.uv = float2(input.uv.x, 1.0f - input.uv.y);
output.tangent = normalize(mul(inst.model, float4(input.tangent, 0))).xyz;
output.bitangent = normalize(mul(inst.model, float4(input.bitangent, 0))).xyz;
output.normal = normalize(mul(inst.model, float4(input.normal, 0))).xyz;
#ifdef IS_HYBRID
output.obj_normal = input.normal.xyz;
output.obj_tangent = input.tangent.xyz;
output.obj_bitangent = input.bitangent.xyz;
#endif
return output;
}
struct PS_OUTPUT
{
float4 albedo_roughness : SV_TARGET0;
float4 normal_metallic : SV_TARGET1;
float4 emissive_ao : SV_TARGET2;
#ifdef IS_HYBRID
float4 velocity : SV_TARGET3;
float4 depth : SV_TARGET4;
float4 world_position : SV_TARGET5;
#endif
};
Texture2D material_albedo : register(t0);
Texture2D material_normal : register(t1);
Texture2D material_roughness : register(t2);
Texture2D material_metallic : register(t3);
Texture2D material_ao : register(t4);
Texture2D material_emissive : register(t5);
SamplerState s0 : register(s0);
cbuffer MaterialProperties : register(b2)
{
MaterialData data;
}
uint dirToOct(float3 normal)
{
float2 p = normal.xy * (1.0 / dot(abs(normal), 1.0.xxx));
float2 e = normal.z > 0.0 ? p : (1.0 - abs(p.yx)) * (step(0.0,p)*2.0-(float2)(1.0));
return (asuint(f32tof16(e.y)) << 16) + (asuint(f32tof16(e.x)));
}
PS_OUTPUT main_ps(VS_OUTPUT input) : SV_TARGET
{
PS_OUTPUT output;
float3x3 tbn = {input.tangent, input.bitangent, input.normal};
OutputMaterialData output_data = InterpretMaterialData(data,
material_albedo,
material_normal,
material_roughness,
material_metallic,
material_emissive,
material_ao,
s0,
input.uv);
if (output_data.alpha <= 0.5f)
{
discard;
}
float3 normal = normalize(mul(output_data.normal, tbn));
output.albedo_roughness = float4(output_data.albedo.xyz, output_data.roughness);
output.normal_metallic = float4(normal, output_data.metallic);
output.emissive_ao = float4(output_data.emissive, output_data.ao);
#ifdef IS_HYBRID
float3x3 obj_tbn = {input.obj_tangent, input.obj_bitangent, input.obj_normal};
float3 obj_normal = normalize(mul(output_data.normal, obj_tbn));
float2 curr_pos = float2(input.curr_pos.xy / input.curr_pos.w) * 0.5 + 0.5;
float2 prev_pos = float2(input.prev_pos.xy / input.prev_pos.w) * 0.5 + 0.5;
const float epsilon = 1e-5;
float2 motion_vec = lerp(float2(curr_pos.x - prev_pos.x, -(curr_pos.y - prev_pos.y)), float2(0.0, 0.0), input.prev_pos.w < epsilon);
output.velocity = float4(motion_vec.xy, length(fwidth(input.world_pos.xyz)), length(fwidth(normal)));
float linear_z = input.pos.z * input.pos.w;
float prev_z = input.prev_pos.z;
float max_change_z = max(abs(ddx(linear_z)), abs(ddy(linear_z)));
float compressed_obj_normal = asfloat(dirToOct(normalize(obj_normal)));
output.depth = float4(linear_z, max_change_z, prev_z, compressed_obj_normal);
output.world_position = input.world_pos;
#endif
return output;
}
#endif //__DEFERRED_GEOMETRY_PASS_HLSL__
================================================
FILE: resources/shaders/denoising_SVGF.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DENOISING_SVGF_HLSL__
#define __DENOISING_SVGF_HLSL__
Texture2D input_texture : register(t0);
Texture2D motion_texture : register(t1);
Texture2D normal_texture : register(t2);
Texture2D depth_texture : register(t3);
Texture2D in_hist_length_texture : register(t4);
Texture2D prev_input_texture : register(t5);
Texture2D prev_moments_texture : register(t6);
Texture2D prev_normal_texture : register(t7);
Texture2D prev_depth_texture : register(t8);
RWTexture2D out_color_texture : register(u0);
RWTexture2D out_moments_texture : register(u1);
RWTexture2D out_hist_length_texture : register(u2);
SamplerState point_sampler : register(s0);
SamplerState linear_sampler : register(s1);
cbuffer DenoiserSettings : register(b0)
{
float blending_alpha;
float blending_moments_alpha;
float l_phi;
float n_phi;
float z_phi;
float step_distance;
float2 padding_2;
};
const static float VARIANCE_CLIPPING_GAMMA = 8.0;
float3 OctToDir(uint octo)
{
float2 e = float2( f16tof32(octo & 0xFFFF), f16tof32((octo>>16) & 0xFFFF) );
float3 v = float3(e, 1.0 - abs(e.x) - abs(e.y));
if (v.z < 0.0)
v.xy = (1.0 - abs(v.yx)) * (step(0.0, v.xy)*2.0 - (float2)(1.0));
return normalize(v);
}
float Luminance(float3 color)
{
return (color.r + color.r + color.b + color.g + color.g + color.g) / 6.0;
}
uint DirToOct(float3 normal)
{
float2 p = normal.xy * (1.0 / dot(abs(normal), 1.0.xxx));
float2 e = normal.z > 0.0 ? p : (1.0 - abs(p.yx)) * (step(0.0, p)*2.0 - (float2)(1.0));
return (asuint(f32tof16(e.y)) << 16) + (asuint(f32tof16(e.x)));
}
void FetchNormalAndLinearZ(in int2 ipos, out float3 norm, out float2 zLinear)
{
norm = normal_texture[ipos];
zLinear = depth_texture[ipos].xy;
}
float NormalDistanceCos(float3 n1, float3 n2, float power)
{
return pow(max(0.0, dot(n1, n2)), 128.0);
//return pow( saturate(dot(n1,n2)), power);
//return 1.0f;
}
float NormalDistanceTan(float3 a, float3 b)
{
const float d = max(1e-8, dot(a, b));
return sqrt(max(0.0, 1.0 - d * d)) / d;
}
float CalcWeights(
float depth_center, float depth_p, float phi_depth,
float3 normal_center, float3 normal_p, float norm_power,
float luminance_direct_center, float luminance_direct_p, float phi_direct)
{
const float w_normal = NormalDistanceCos(normal_center, normal_p, norm_power);
const float w_z = (phi_depth == 0) ? 0.0f : abs(depth_center - depth_p) / phi_depth;
const float w_l_direct = abs(luminance_direct_center - luminance_direct_p) / phi_direct;
const float w_direct = exp(0.0 - max(w_l_direct, 0.0) - max(w_z, 0.0)) * w_normal;
return w_direct;
}
float ComputeWeightNoLuminance(float depth_center, float depth_p, float phi_depth, float3 normal_center, float3 normal_p)
{
const float w_normal = NormalDistanceCos(normal_center, normal_p, n_phi);
const float w_z = abs(depth_center - depth_p) / phi_depth;
return exp(-max(w_z, 0.0)) * w_normal;
}
bool IsReprojectionValid(int2 coord, float z, float z_prev, float fwidth_z, float3 normal, float3 normal_prev, float fwidth_normal)
{
int2 screen_size = int2(0, 0);
input_texture.GetDimensions(screen_size.x, screen_size.y);
bool ret = (coord.x > -1 && coord.x < screen_size.x && coord.y > -1 && coord.y < screen_size.y);
ret = ret && ((abs(z_prev - z) / (fwidth_z + 1e-4)) < 2.0);
ret = ret && ((distance(normal, normal_prev) / (fwidth_normal + 1e-2)) < 16.0);
return ret;
}
bool LoadPrevData(float2 screen_coord, out float4 prev_direct, out float2 prev_moments, out float history_length)
{
float2 screen_size = float2(0.f, 0.f);
input_texture.GetDimensions(screen_size.x, screen_size.y);
float2 uv = screen_coord / screen_size;
float4 motion = motion_texture.SampleLevel(point_sampler, uv, 0);
float2 q_uv = uv - motion.xy;
float2 prev_coords = q_uv * screen_size;
float4 depth = depth_texture[prev_coords];
float3 normal = OctToDir(asuint(depth.w));
prev_direct = float4(0, 0, 0, 0);
prev_moments = float2(0, 0);
bool v[4];
const float2 pos_prev = prev_coords;
int2 offset[4] = {int2(0, 0), int2(1, 0), int2(0, 1), int2(1, 1)};
bool valid = false;
[unroll]
for(int sample_idx = 0; sample_idx < 4; ++sample_idx)
{
int2 loc = int2(pos_prev) + offset[sample_idx];
float4 depth_prev = prev_depth_texture[loc];
float3 normal_prev = OctToDir(asuint(depth_prev.w));
v[sample_idx] = IsReprojectionValid(loc, depth.z, depth_prev.x, depth.y, normal, normal_prev, motion.w);
valid = valid || v[sample_idx];
}
if(valid)
{
float sum_weights = 0;
float x = frac(pos_prev.x);
float y = frac(pos_prev.y);
float weights[4] = {(1 - x) * (1 - y),
x * (1 - y),
(1 - x) * y,
x * y };
[unroll]
for(int sample_idx = 0; sample_idx < 4; ++sample_idx)
{
int2 loc = int2(pos_prev) + offset[sample_idx];
prev_direct += weights[sample_idx] * prev_input_texture[loc] * float(v[sample_idx]);
prev_moments += weights[sample_idx] * prev_moments_texture[loc] * float(v[sample_idx]);
sum_weights += weights[sample_idx] * float(v[sample_idx]);
}
valid = (sum_weights >= 0.01);
prev_direct = lerp(float4(0, 0, 0, 0), prev_direct / sum_weights, valid);
prev_moments = lerp(float2(0, 0), prev_moments / sum_weights, valid);
}
if(!valid)
{
float cnt = 0.0;
const int radius = 1;
for(int y = -radius; y <= radius; ++y)
{
for(int x = -radius; x <= radius; ++x)
{
int2 p = prev_coords + int2(x, y);
float4 depth_filter = prev_depth_texture[p];
float3 normal_filter = OctToDir(asuint(depth_filter.w));
if(IsReprojectionValid(prev_coords, depth.z, depth_filter.x, depth.y, normal, normal_filter, motion.w))
{
prev_direct += prev_input_texture[p];
prev_moments += prev_moments_texture[p];
cnt += 1.0;
}
}
}
valid = cnt > 0;
prev_direct /= lerp(1, cnt, cnt > 0);
prev_moments /= lerp(1, cnt, cnt > 0);
}
if(valid)
{
history_length = in_hist_length_texture[prev_coords].r;
}
else
{
prev_direct = float4(0, 0, 0, 0);
prev_moments = float2(0, 0);
history_length = 0;
}
return valid;
}
float ComputeVarianceCenter(int2 center)
{
float sum = 0.0;
const float kernel[2][2] = {
{1.0 / 4.0, 1.0 / 8.0},
{1.0 / 8.0, 1.0 / 16.0}
};
const int radius = 1;
[unroll]
for(int y = -radius; y <= radius; ++y)
{
[unroll]
for(int x = -radius; x <= radius; ++x)
{
int2 p = center + int2(x, y);
float k = kernel[abs(x)][abs(y)];
sum += input_texture[p].w * k;
}
}
return sum;
}
float4 LineBoxIntersection(float3 box_min, float3 box_max, float3 c_in, float3 c_hist)
{
float3 p_clip = 0.5 * (box_max + box_min);
float3 e_clip = 0.5 * (box_max - box_min);
float3 v_clip = c_hist - p_clip;
float3 v_unit = v_clip.xyz / e_clip;
float3 a_unit = abs(v_unit);
float ma_unit = max(a_unit.x, max(a_unit.y, a_unit.z));
if(ma_unit > 1.0)
{
return float4((p_clip + v_clip / ma_unit).xyz, ma_unit);
}
else
{
return float4(c_hist.xyz, ma_unit);
}
}
[numthreads(16,16,1)]
void reprojection_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
out_color_texture.GetDimensions(screen_size.x, screen_size.y);
float2 uv = float2(dispatch_thread_id.x / screen_size.x, dispatch_thread_id.y / screen_size.y);
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y);
float4 direct = input_texture[screen_coord];
float4 prev_direct = float4(0.0, 0.0, 0.0, 0.0);
float2 prev_moments = float2(0.0, 0.0);
float history_length = 0.0;
bool success = LoadPrevData(screen_coord, prev_direct, prev_moments, history_length);
if(isnan(prev_direct.x) || isnan(prev_direct.y) || isnan(prev_direct.z))
{
success = false;
prev_direct = 0.f;
prev_moments = 0.f;
history_length = 0.f;
}
float3 moment_1 = float3(0.0, 0.0, 0.0);
float3 moment_2 = float3(0.0, 0.0, 0.0);
float3 clamp_min = 1.0;
float3 clamp_max = 0.0;
[unroll]
for(int y = -2; y <= 2; ++y)
{
[unroll]
for(int x = -2; x <= 2; ++x)
{
float3 color = input_texture[screen_coord + int2(x, y)].xyz;
moment_1 += color;
moment_2 += color * color;
clamp_min = min(color, clamp_min);
clamp_max = max(color, clamp_max);
}
}
float3 mu = moment_1 / 25.0;
float3 sigma = sqrt(moment_2 / 25.0 - mu*mu);
float3 box_min = max(mu - VARIANCE_CLIPPING_GAMMA * sigma, clamp_min);
float3 box_max = min(mu + VARIANCE_CLIPPING_GAMMA * sigma, clamp_max);
float4 clipped = LineBoxIntersection(box_min, box_max, direct.xyz, prev_direct.xyz);
//success = clipped.w > 1.0;
prev_direct = float4(clipped.xyz, prev_direct.w);
history_length = min(32.0, success ? (history_length + 1.0) : 1.0);
const float alpha = lerp(1.0, max(blending_alpha, 1.0/history_length), success);
const float moments_alpha = lerp(1.0, max(blending_moments_alpha, 1.0/history_length), success);
float2 moments = float2(0, 0);
moments.r = Luminance(direct.xyz);
moments.g = moments.r * moments.r;
moments = lerp(prev_moments, moments, moments_alpha);
out_moments_texture[screen_coord] = moments;
out_hist_length_texture[screen_coord] = history_length;
float variance = max(0.f, moments.g - moments.r * moments.r);
direct = lerp(prev_direct, direct, alpha);
out_color_texture[screen_coord] = float4(direct.xyz, variance);
}
[numthreads(16,16,1)]
void filter_moments_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
out_color_texture.GetDimensions(screen_size.x, screen_size.y);
float2 uv = float2(dispatch_thread_id.x / screen_size.x, dispatch_thread_id.y / screen_size.y);
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y);
float h = in_hist_length_texture[screen_coord].r;
if(h < 4.0)
{
float sum_weights = 0.0;
float3 sum_direct = float3(0.0, 0.0, 0.0);
float2 sum_moments = float2(0.0, 0.0);
const float4 direct_center = input_texture[screen_coord];
const float luminance_direct_center = Luminance(direct_center.xyz);
float3 normal_center = float3(0.0, 0.0, 0.0);
float2 depth_center = float2(0.0, 0.0);
FetchNormalAndLinearZ(screen_coord, normal_center, depth_center);
if(depth_center.x < 0.0)
{
out_color_texture[screen_coord] = direct_center;
return;
}
const float phi_direct = l_phi;
const float phi_depth = max(depth_center.y, 1e-8) * 3.0;
const int radius = 3;
[unroll]
for(int y = -radius; y <= radius; ++y)
{
[unroll]
for(int x = -radius; x <= radius; ++x)
{
const int2 p = screen_coord + int2(x, y);
const bool inside = p.x >= 0 && p.x < screen_size.x && p.y >= 0 && p.y < screen_size.y;
const bool same_pixel = (x==0) && (y==0);
const float kernel = 1.0;
if(inside)
{
const float3 direct_p = input_texture[p].xyz;
const float2 moments_p = prev_moments_texture[p].xy;
if(isnan(direct_p.x) || isnan(direct_p.y) || isnan(direct_p.z) || isnan(moments_p.x) || isnan(moments_p.y))
{
continue;
}
const float l_direct_p = Luminance(direct_p);
float3 normal_p;
float2 z_p;
FetchNormalAndLinearZ(p, normal_p, z_p);
const float w = CalcWeights(
depth_center.x, z_p.x, phi_depth * length(float2(x, y)),
normal_center, normal_p, n_phi,
luminance_direct_center, l_direct_p, l_phi);
if(isnan(w))
{
continue;
}
sum_weights += w;
sum_direct += direct_p * w;
sum_moments += moments_p * float2(w.xx);
}
}
}
sum_weights = max(sum_weights, 1e-6f);
sum_direct /= sum_weights;
sum_moments /= float2(sum_weights.xx);
float variance = sum_moments.y - sum_moments.x * sum_moments.x;
variance *= 4.0/h;
out_color_texture[screen_coord] = float4(sum_direct.xyz, variance);
}
else
{
out_color_texture[screen_coord] = input_texture[screen_coord];
}
}
[numthreads(16,16,1)]
void wavelet_filter_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
out_color_texture.GetDimensions(screen_size.x, screen_size.y);
float2 uv = float2(dispatch_thread_id.x / screen_size.x, dispatch_thread_id.y / screen_size.y);
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y);
const float eps_variance = 1e-10;
const float kernel_weights[3] = {1.0, 2.0 / 3.0, 1.0 / 6.0};
const float4 direct_center = input_texture[screen_coord];
const float luminance_direct_center = Luminance(direct_center.xyz);
const float variance = ComputeVarianceCenter(int2(screen_coord.xy));
out_color_texture[screen_coord] = direct_center;
const float history_length = in_hist_length_texture[screen_coord].r;
float3 normal_center;
float2 depth_center;
FetchNormalAndLinearZ(screen_coord, normal_center, depth_center);
if(depth_center.x < 0)
{
out_color_texture[screen_coord] = direct_center;
return;
}
const float phi_l_direct = l_phi * sqrt(max(0.0, eps_variance + variance));
const float phi_depth = max(depth_center.y, 1e-8) * step_distance;
float sum_weights = 1.0;
float4 sum_direct = direct_center;
[unroll]
for(int y = -2; y <= 2; ++y)
{
[unroll]
for(int x = -2; x <= 2; ++x)
{
const int2 p = int2(screen_coord.xy) + int2(x, y) * step_distance;
const bool inside = p.x >= 0 && p.x < screen_size.x && p.y >= 0 && p.y < screen_size.y;
const float kernel = kernel_weights[abs(x)] * kernel_weights[abs(y)];
if(inside && (x != 0 || y != 0))
{
const float4 direct_p = input_texture[p];
if(isnan(direct_p.x) || isnan(direct_p.y) || isnan(direct_p.z) || isnan(direct_p.w))
{
continue;
}
float3 normal_p;
float2 depth_p;
FetchNormalAndLinearZ(p, normal_p, depth_p);
const float luminance_direct_p = Luminance(direct_p.xyz);
const float w = CalcWeights(
depth_center.x, depth_p.x, phi_depth*length(float2(x, y)),
normal_center, normal_p, n_phi,
luminance_direct_center, luminance_direct_p, phi_l_direct
);
if(isnan(w))
{
continue;
}
const float w_direct = w * kernel;
sum_weights += w_direct;
sum_direct += float4(w_direct.xxx, w_direct * w_direct) * direct_p;
}
}
}
sum_weights = max(sum_weights, 1e-6f);
out_color_texture[screen_coord] = float4(sum_direct / float4(sum_weights.xxx, sum_weights * sum_weights));
}
#endif //__DENOISING_SVGF_HLSL__
================================================
FILE: resources/shaders/denoising_reflections.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DENOISING_REFLECTIONS_HLSL__
#define __DENOISING_REFLECTIONS_HLSL__
#include "pbr_util.hlsl"
#include "rand_util.hlsl"
Texture2D input_texture : register(t0);
Texture2D ray_raw_texture : register(t1);
Texture2D dir_hit_t_texture : register(t2);
Texture2D albedo_roughness_texture : register(t3);
Texture2D normal_metallic_texture : register(t4);
Texture2D motion_texture : register(t5); // xy: motion, z: fwidth position, w: fwidth normal
Texture2D linear_depth_texture : register(t6);
Texture2D world_position_texture : register(t7);
Texture2D in_history_texture : register(t8);
Texture2D accum_texture : register(t9);
Texture2D prev_normal_texture : register(t10);
Texture2D prev_depth_texture : register(t11);
Texture2D in_moments_texture : register(t12);
RWTexture2D output_texture : register(u0);
RWTexture2D out_history_texture : register(u1);
RWTexture2D out_moments_texture : register(u2);
SamplerState point_sampler : register(s0);
SamplerState linear_sampler : register(s0);
cbuffer CameraProperties : register(b0)
{
float4x4 view;
float4x4 projection;
float4x4 inv_projection;
float4x4 inv_view;
float4x4 prev_projection;
float4x4 prev_view;
uint is_hybrid;
uint is_path_tracer;
uint is_ao;
uint has_shadows;
float3 padding1;
uint has_reflections;
};
cbuffer DenoiserSettings : register(b1)
{
float color_integration_alpha;
float moments_integration_alpha;
float variance_clipping_sigma;
float roughness_reprojection_threshold;
int max_history_samples;
float n_phi;
float z_phi;
float l_phi;
};
cbuffer WaveletPass : register(b2)
{
float wavelet_size;
}
float3 OctToDir(uint octo)
{
float2 e = float2( f16tof32(octo & 0xFFFF), f16tof32((octo>>16) & 0xFFFF) );
float3 v = float3(e, 1.0 - abs(e.x) - abs(e.y));
if (v.z < 0.0f)
v.xy = (1.0f - abs(v.yx)) * (step(0.0f, v.xy) * 2.0f - float2(1.0f,1.0f));
return normalize(v);
}
float Luminance(float3 color)
{
return (color.r + color.r + color.b + color.g + color.g + color.g) / 6.0f;
}
void FetchNormalAndLinearZ(in float2 ipos, out float3 norm, out float2 zLinear)
{
norm = normal_metallic_texture[ipos].xyz;
zLinear = linear_depth_texture[ipos].xy;
}
float NormalDistanceCos(float3 n1, float3 n2, float power)
{
return pow(max(0.0f, dot(n1, n2)), power);
}
float ComputeWeight(
float depth_center, float depth_p, float phi_depth,
float3 normal_center, float3 normal_p, float norm_power,
float luminance_direct_center, float luminance_direct_p, float phi_direct)
{
const float w_normal = NormalDistanceCos(normal_center, normal_p, norm_power);
const float w_z = (phi_depth == 0.f) ? 0.0f : abs(depth_center - depth_p) / phi_depth;
const float w_l_direct = abs(luminance_direct_center - luminance_direct_p) / phi_direct;
const float w_direct = exp(0.0f - max(w_l_direct, 0.0f) - max(w_z, 0.0f)) * w_normal;
return w_direct;
}
float ComputeWeightNoLuminance(float depth_center, float depth_p, float phi_depth, float3 normal_center, float3 normal_p)
{
const float w_normal = NormalDistanceCos(normal_center, normal_p, 128.f);
const float w_z = abs(depth_center - depth_p) / phi_depth;
return exp(-max(w_z, 0.0f)) * w_normal;
}
bool IsReprojectionValid(float2 coord, float z, float z_prev, float fwidth_z, float3 normal, float3 normal_prev, float fwidth_normal)
{
int2 screen_size = int2(0, 0);
output_texture.GetDimensions(screen_size.x, screen_size.y);
bool ret = (coord.x >= 0.f && coord.x < screen_size.x && coord.y >= 0.f && coord.y < screen_size.y);
ret = ret && ((distance(normal, normal_prev) / (fwidth_normal + 1e-2)) < 16.0);
return ret;
}
bool LoadPrevData(float2 screen_coord, inout float2 found_pos, out float4 prev_direct, out float2 prev_moments, out float history_length)
{
float2 screen_size = float2(0.f, 0.f);
output_texture.GetDimensions(screen_size.x, screen_size.y);
float2 uv = screen_coord / screen_size;
float4 motion = motion_texture.SampleLevel(point_sampler, uv, 0);
float2 q_uv = uv - motion.xy;
float2 prev_coords = q_uv * screen_size;
const float roughness = albedo_roughness_texture[screen_coord].w;
float4 depth = linear_depth_texture[prev_coords];
float3 normal = OctToDir(asuint(depth.w));
prev_direct = float4(0.0f, 0.0f, 0.0f, 0.0f);
prev_moments = float2(0.0f, 0.0f);
bool v[4];
const float2 pos_prev = prev_coords;
int2 offset[4] = {int2(0, 0), int2(1, 0), int2(0, 1), int2(1, 1)};
bool valid = false;
[unroll]
for(int sample_idx = 0; sample_idx < 4; ++sample_idx)
{
float2 loc = pos_prev + offset[sample_idx];
float4 depth_prev = prev_depth_texture[loc];
float3 normal_prev = OctToDir(asuint(depth_prev.w));
v[sample_idx] = IsReprojectionValid(loc, depth.z, depth_prev.x, depth.y, normal, normal_prev, motion.w);
valid = valid || v[sample_idx];
}
if(valid)
{
float sum_weights = 0.0f;
float x = frac(pos_prev.x);
float y = frac(pos_prev.y);
float weights[4] = {(1.0f - x) * (1.0f - y),
x * (1.0f - y),
(1.0f - x) * y,
x * y };
[unroll]
for(int sample_idx = 0; sample_idx < 4; ++sample_idx)
{
float2 loc = pos_prev + offset[sample_idx];
prev_direct += weights[sample_idx] * accum_texture[loc] * float(v[sample_idx]);
prev_moments += weights[sample_idx] * in_moments_texture[loc].xy * float(v[sample_idx]);
sum_weights += weights[sample_idx] * float(v[sample_idx]);
}
valid = (sum_weights >= 0.01f);
prev_direct = lerp(float4(0.0f, 0.0f, 0.0f, 0.0f), prev_direct / sum_weights, valid);
prev_moments = lerp(float2(0.0f, 0.0f), prev_moments / sum_weights, valid);
}
if(!valid)
{
float cnt = 0.0f;
const int radius = 1;
for(int y = -radius; y <= radius; ++y)
{
for(int x = -radius; x <= radius; ++x)
{
float2 p = prev_coords + float2(x, y);
float4 depth_filter = prev_depth_texture[p];
float3 normal_filter = OctToDir(asuint(depth_filter.w));
if(IsReprojectionValid(prev_coords, depth.z, depth_filter.x, depth.y, normal, normal_filter, motion.w))
{
prev_direct += accum_texture[p];
prev_moments += in_moments_texture[p].xy;
cnt += 1.0;
}
}
}
valid = cnt > 0;
prev_direct /= lerp(1, cnt, cnt > 0);
prev_moments /= lerp(1, cnt, cnt > 0);
}
if(valid)
{
history_length = in_history_texture[prev_coords].r;
}
else
{
prev_direct = float4(0.0f, 0.0f, 0.0f, 0.0f);
prev_moments = float2(0.0f, 0.0f);
history_length = 0;
}
found_pos = lerp(float2(-1.0f, -1.0f), pos_prev, valid);
return valid;
}
float ComputeVarianceCenter(int2 center)
{
float sum = 0.0f;
const float kernel[2][2] = {
{1.0f / 4.0f, 1.0f / 8.0f},
{1.0f / 8.0f, 1.0f / 16.0f}
};
const int radius = 1;
[unroll]
for(int y = -radius; y <= radius; ++y)
{
[unroll]
for(int x = -radius; x <= radius; ++x)
{
int2 p = center + int2(x, y);
float k = kernel[abs(x)][abs(y)];
sum += input_texture[p].w * k;
}
}
return sum;
}
float4 LineBoxIntersection(float3 box_min, float3 box_max, float3 c_in, float3 c_hist)
{
float3 p_clip = 0.5f * (box_max + box_min);
float3 e_clip = 0.5f * (box_max - box_min);
float3 v_clip = c_hist - p_clip;
float3 v_unit = v_clip.xyz / e_clip;
float3 a_unit = abs(v_unit);
float ma_unit = max(a_unit.x, max(a_unit.y, a_unit.z));
if(ma_unit > 1.0f)
{
return float4((p_clip + v_clip / ma_unit).xyz, ma_unit);
}
else
{
return float4(c_hist.xyz, ma_unit);
}
}
[numthreads(16, 16, 1)]
void temporal_denoiser_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_coord = float2(dispatch_thread_id.xy);
float2 screen_size = float2(0.0f, 0.0f);
output_texture.GetDimensions(screen_size.x, screen_size.y);
float2 uv = screen_coord / (screen_size - 1.0f);
float4 accum_color = float4(0.0f, 0.0f, 0.0f, 0.0f);
float2 prev_moments = float2(0.0f, 0.0f);
float history = 0;
float2 prev_pos = float2(0.0f, 0.0f);
bool valid = LoadPrevData(screen_coord, prev_pos, accum_color, prev_moments, history);
history = lerp(0, history, valid);
float4 input_color = input_texture[screen_coord];
float pdf = ray_raw_texture.SampleLevel(point_sampler, uv, 0).w;
if(pdf <= 0.0f)
{
output_texture[screen_coord] = float4(input_color.xyz, 0.f);
return;
}
float3 moment_1 = float3(0.0f, 0.0f, 0.0f);
float3 moment_2 = float3(0.0f, 0.0f, 0.0f);
float3 clamp_min = 1.0f;
float3 clamp_max = 0.0f;
[unroll]
for(int y = -3; y <= 3; ++y)
{
[unroll]
for(int x = -3; x <= 3; ++x)
{
float3 color = input_texture[screen_coord + int2(x, y)].xyz;
moment_1 += color;
moment_2 += color * color;
clamp_min = min(color, clamp_min);
clamp_max = max(color, clamp_max);
}
}
float3 mu = moment_1 / 49.0f;
float3 sigma = sqrt(moment_2 / 49.0f - mu*mu);
float3 box_min = mu - variance_clipping_sigma * sigma;
float3 box_max = mu + variance_clipping_sigma * sigma;
float4 clipped = LineBoxIntersection(box_min, box_max, input_color.xyz, accum_color.xyz);
const float roughness = albedo_roughness_texture[screen_coord].w;
//perhaps replace the 0.25 with a clamping strength variable for the settings screen
accum_color = lerp(clipped, accum_color, pow(clamp(roughness, 0.0f, 1.0f), 0.25f));
history = min(max_history_samples, history + 1);
const float alpha = lerp(1.0f, max(color_integration_alpha, 1.0f/history), valid);
const float moments_alpha = lerp(1.0f, max(moments_integration_alpha, 1.0f/history), valid);
float2 cur_moments = float2(0.0f, 0.0f);
cur_moments.x = Luminance(input_color.xyz);
cur_moments.y = cur_moments.x * cur_moments.x;
cur_moments = lerp(prev_moments, cur_moments, moments_alpha);
float variance = cur_moments.y - cur_moments.x * cur_moments.x;
float3 output = lerp(accum_color, input_color, alpha);
output_texture[floor(screen_coord)] = float4(output.xyz, variance);
out_history_texture[floor(screen_coord)] = history;
out_moments_texture[floor(screen_coord)] = cur_moments;
}
[numthreads(16, 16, 1)]
void variance_estimator_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_coord = float2(dispatch_thread_id.xy);
float2 screen_size = float2(0.f, 0.f);
output_texture.GetDimensions(screen_size.x, screen_size.y);
float2 uv = screen_coord / screen_size;
float history = in_history_texture[screen_coord].r;
[branch]
if(history < 5.f)
{
float sum_weights = 0.0f;
float3 sum_direct = float3(0.0f, 0.0f, 0.0f);
float2 sum_moments = float2(0.0f, 0.0f);
const float4 direct_center = input_texture[screen_coord];
float3 normal_center = float3(0.0f, 0.0f, 0.0f);
float2 depth_center = float2(0.0f, 0.0f);
FetchNormalAndLinearZ(screen_coord, normal_center, depth_center);
if(depth_center.x < 0.0f)
{
output_texture[screen_coord] = direct_center;
return;
}
const float phi_direct = l_phi;
const float phi_depth = max(depth_center.y, 1e-8) * 3.0f;
const int radius = 3.f;
[unroll]
for(int y = -radius; y <= radius; ++y)
{
[unroll]
for(int x = -radius; x <= radius; ++x)
{
const int2 p = screen_coord + int2(x, y);
const bool inside = p.x >= 0.f && p.x < screen_size.x && p.y >= 0.f && p.y < screen_size.y;
const bool same_pixel = (x==0.f) && (y==0.f);
const float kernel = 1.0f;
if(inside)
{
const float3 direct_p = input_texture[p].xyz;
const float2 moments_p = in_moments_texture[p].xy;
float3 normal_p;
float2 z_p;
FetchNormalAndLinearZ(p, normal_p, z_p);
const float w = ComputeWeightNoLuminance(
depth_center.x, z_p.x, phi_depth * length(float2(x, y)),
normal_center, normal_p);
if(isnan(direct_p.x) || isnan(direct_p.y) || isnan(direct_p.z) || isnan(w))
{
continue;
}
sum_weights += w;
sum_direct += direct_p * w;
sum_moments += moments_p * float2(w.xx);
}
}
}
sum_weights = max(sum_weights, 1e-6f);
sum_direct /= sum_weights;
sum_moments /= float2(sum_weights.xx);
float variance = sum_moments.y - sum_moments.x * sum_moments.x;
variance *= 5.0f/history;
output_texture[screen_coord] = float4(sum_direct.xyz, variance);
}
else
{
output_texture[screen_coord] = input_texture[screen_coord];
}
}
[numthreads(16, 16, 1)]
void spatial_denoiser_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_coord = float2(dispatch_thread_id.xy);
float2 screen_size = float2(0.0f, 0.0f);
output_texture.GetDimensions(screen_size.x, screen_size.y);
float2 uv = screen_coord / screen_size;
const float eps_variance = 1e-10;
const float kernel_weights[3] = {1.0f, 2.0f / 3.0f, 1.0f / 6.0f};
const float4 direct_center = input_texture[screen_coord];
const float luminance_direct_center = Luminance(direct_center.xyz);
const float variance = ComputeVarianceCenter(int2(screen_coord.xy));
if(isnan(variance))
{
output_texture[screen_coord] = float4(0.0f, 1.0f, 0.0f, 0.0f);
return;
}
output_texture[screen_coord] = direct_center;
const float history_length = in_history_texture[screen_coord].r;
float3 normal_center;
float2 depth_center;
FetchNormalAndLinearZ(screen_coord, normal_center, depth_center);
if(depth_center.x < 0.0f)
{
output_texture[screen_coord] = direct_center;
return;
}
const float roughness = albedo_roughness_texture[screen_coord].w;
const float phi_l_direct = l_phi * sqrt(max(0.0f, variance));
const float phi_depth = max(depth_center.y, 1e-8) * wavelet_size;
float sum_weights = 1.0f;
float4 sum_direct = direct_center;
[unroll]
for(int y = -2; y <= 2; ++y)
{
[unroll]
for(int x = -2; x <= 2; ++x)
{
const int2 p = int2(screen_coord.xy) + int2(x, y) * wavelet_size;
const bool inside = p.x >= 0 && p.x < screen_size.x && p.y >= 0 && p.y < screen_size.y;
const float kernel = kernel_weights[abs(x)] * kernel_weights[abs(y)];
if(inside && (x != 0 || y != 0))
{
const float4 direct_p = input_texture[p];
const float luminance_direct_p = Luminance(direct_p.xyz);
float3 normal_p;
float2 depth_p;
FetchNormalAndLinearZ(p, normal_p, depth_p);
const float w = ComputeWeight(
depth_center.x, depth_p.x, phi_depth*length(float2(x, y)),
normal_center, normal_p, n_phi,
luminance_direct_center, luminance_direct_p, phi_l_direct) * sqrt(max(1e-15f, roughness));
const float w_direct = w * kernel;
sum_weights += w_direct;
sum_direct += float4(w_direct.xxx, w_direct * w_direct) * direct_p;
}
}
}
output_texture[screen_coord] = sum_direct / sum_weights;
}
#endif
================================================
FILE: resources/shaders/denoising_spatial_reconstruction.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DENOISING_SPATIAL_RECONSTRUCTION_HLSL__
#define __DENOISING_SPATIAL_RECONSTRUCTION_HLSL__
#include "pbr_util.hlsl"
#include "rand_util.hlsl"
cbuffer CameraProperties : register(b0)
{
float4x4 inv_vp;
float4x4 inv_view;
float padding;
uint frame_idx;
float near_plane, far_plane;
};
RWTexture2D filtered : register(u0);
Texture2D reflection_pdf : register(t0);
Texture2D dir_hit_t : register(t1);
Texture2D albedo_roughness : register(t2);
Texture2D normal_metallic : register(t3);
Texture2D depth_buffer : register(t4);
SamplerState nearest_sampler : register(s0);
SamplerState linear_sampler : register(s1);
float linearize_depth(float D)
{
float z_n = D * 2.0f - 1.0f;
return 2.0f * near_plane * far_plane / (far_plane + near_plane - z_n * (far_plane - near_plane));
}
//Get total weight from neighbor using normal and normalized depth from both neighbor and center
float neighbor_edge_weight(float3 N, float3 N_neighbor, float D, float D_neighbor, float2 uv)
{
return float(uv.x >= 0.f && uv.y >= 0.f && uv.x <= 1.f && uv.y <= 1.f) * (D != 1.0f && D_neighbor != 1.0f);
}
//Hardcode the samples for now; settings: kernelSize=5, points=16
//https://github.com/Nielsbishere/NoisePlayground/blob/master/bluenoise_test.py
static const uint sample_count = 16;
static const float2 samples[4][16] = {
{
float2(0.f , 0.f), float2(-1.f , -1.f), float2(1.f , 0.f), float2(-2.f , -1.f),
float2(-2.f , 1.f), float2(0.f , -3.f), float2(2.f , -2.f), float2(1.f , 2.f),
float2(0.f , 3.f), float2(-4.f , -1.f), float2(0.f , -4.f), float2(-2.f , 3.f),
float2(-4.f , 1.f), float2(3.f , 1.f), float2(3.f , -3.f), float2(4.f , 0.f)
},
{
float2(0.f , 0.f), float2(1.f , -1.f), float2(0.f , -2.f), float2(-1.f , -2.f),
float2(-1.f , 2.f), float2(0.f , 2.f), float2(2.f , 0.f), float2(-3.f , 1.f),
float2(-3.f , -2.f), float2(1.f , -3.f), float2(-3.f , 2.f), float2(3.f , 0.f),
float2(-2.f , -4.f), float2(1.f , 3.f), float2(-4.f , -2.f), float2(2.f , 3.f)
},
{
float2(0.f , 0.f), float2(-1.f , 0.f), float2(0.f , 1.f), float2(-2.f , 0.f),
float2(2.f , -1.f), float2(-1.f , -3.f), float2(-3.f , -1.f), float2(2.f , 2.f),
float2(2.f , -3.f), float2(3.f , -1.f), float2(-3.f , -3.f), float2(-4.f , 0.f),
float2(-1.f , -4.f), float2(-4.f , 2.f), float2(-3.f , 3.f), float2(4.f , -1.f)
},
{
float2(0.f , 0.f), float2(0.f , -1.f), float2(-1.f , 1.f), float2(-2.f , -2.f),
float2(1.f , 1.f), float2(1.f , -2.f), float2(-3.f , 0.f), float2(2.f , 1.f),
float2(-2.f , -3.f), float2(-2.f , 2.f), float2(-1.f , 3.f), float2(1.f , -4.f),
float2(3.f , -2.f), float2(3.f , 2.f), float2(-4.f , -3.f), float2(0.f , 4.f)
}
};
//Sample a neighbor; 0,0 -> 1,1; outside of that range indicates an invalid uv
float2 sample_neighbor_uv(uint sampleId, uint2 full_res_pixel, uint2 resolution, float2 rand, float kernelSize)
{
uint pixId = full_res_pixel.x % 2 + full_res_pixel.y % 2 * 2;
float2 offset = samples[pixId][sampleId] * kernelSize;
offset = mul(float2x2(rand.x, rand.y, -rand.y, rand.x), offset);
return (float2(full_res_pixel / 2.f) + offset) / float2(resolution / 2.f - 1.f);
}
static const float3 luminance = float3(0.2126f, 0.7152f, 0.0722f);
float3 unpack_position(float2 uv, float depth)
{
// Get world space position
const float4 ndc = float4(uv * 2.0f - 1.0f, depth, 1.0f);
float4 wpos = mul(inv_vp, ndc);
return (wpos.xyz / wpos.w).xyz;
}
[numthreads(16, 16, 1)]
void main(int3 pix3 : SV_DispatchThreadID)
{
//Get dispatch dimensions
uint2 pix = uint2(pix3.xy);
uint width, height;
depth_buffer.GetDimensions(width, height);
//Get per pixel values
const float depth = depth_buffer[pix].r;
const float2 uv = float2(pix.xy) / float2(width - 1.f, height - 1.f);
const float3 pos = unpack_position(uv, depth);
const float3 camera_pos = float3(inv_view[0][3], inv_view[1][3], inv_view[2][3]);
const float3 V = normalize(camera_pos - pos);
float roughness = albedo_roughness[pix].w;
const float3 N = normalize(normal_metallic[pix].xyz);
const float pdf = reflection_pdf.SampleLevel(nearest_sampler, uv, 0).w;
float3 result3;
//pdf < 0 disables spatial reconstruction
if (pdf >= 0)
{
//Weigh the samples correctly
float3 result = float3(0.f, 0.f, 0.f);
float weight_sum = 0.0f;
uint rand_seed = initRand(pix.x + pix.y * width, frame_idx);
float distance = length(camera_pos - pos);
float sampleCountScalar = lerp(1.f, (1.f - distance / far_plane) * roughness, 1);
roughness = max(roughness, 1e-2);
float kernel_size = 8.f;
for (uint i = 0; i < max(ceil(kernel_size), 1); ++i) {
//Get sample related data
float2 random = float2(nextRand(rand_seed), nextRand(rand_seed));
const float2 neighbor_uv = sample_neighbor_uv(i, pix, uint2(width, height), random, 1);
const float depth_neighbor = depth_buffer.SampleLevel(nearest_sampler, neighbor_uv, 0).r;
const float3 pos_neighbor = unpack_position(neighbor_uv, depth_neighbor);
const float4 hit_t = dir_hit_t.SampleLevel(nearest_sampler, neighbor_uv, 0);
const float3 V_neighbor = normalize(camera_pos - pos_neighbor);
const float4 reflection_pdf_neighbor = reflection_pdf.SampleLevel(nearest_sampler, neighbor_uv, 0);
if(reflection_pdf_neighbor.w>0.0)
{
const float3 color = clamp(reflection_pdf_neighbor.xyz, 0, 1);
const float3 L = hit_t.xyz;
const float pdf_neighbor = max(reflection_pdf_neighbor.w, 1e-5);
const float3 N_neighbor = normalize(normal_metallic.SampleLevel(nearest_sampler, neighbor_uv, 0).xyz);
//Calculate weight and weight sum
const float neighbor_weight = neighbor_edge_weight(N, N_neighbor, depth, depth_neighbor, neighbor_uv);
float weight = (brdf_weight(-V, L, N, roughness) / pdf_neighbor) * neighbor_weight;
weight = isnan(weight) || isinf(weight) ? 0 : weight;
result += color * weight;
weight_sum += weight;
}
}
result3 = result / weight_sum;
if(weight_sum == 0.0f)
{
result3 = reflection_pdf.SampleLevel(nearest_sampler, uv, 0).xyz;
}
if(isnan(weight_sum) == true)
{
result3 = float3(0, 0, 1);
filtered[pix] = float4(result3, 1);
return;
}
}
else
{
result3 = reflection_pdf.SampleLevel(nearest_sampler, uv, 0).xyz;
}
filtered[pix] = float4(result3, 1);
}
#endif
================================================
FILE: resources/shaders/dxr_ambient_occlusion.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_AMBIENT_OCCLUSION_HLSL__
#define __DXR_AMBIENT_OCCLUSION_HLSL__
#include "rand_util.hlsl"
#include "dxr_global.hlsl"
RWTexture2D output : register(u0); // x: AO value
Texture2D gbuffer_normal : register(t1);
Texture2D gbuffer_depth : register(t2);
struct AOHitInfo
{
float is_hit;
float thisvariablesomehowmakeshybridrenderingwork_killme;
};
cbuffer CBData : register(b0)
{
float4x4 inv_vp;
float4x4 inv_view;
float bias;
float radius;
float power;
float max_distance;
float2 padding;
float frame_idx;
unsigned int sample_count;
};
struct Attributes { };
float3 unpack_position(float2 uv, float depth)
{
// Get world space position
const float4 ndc = float4(uv * 2.0 - 1.0, depth, 1.0);
float4 wpos = mul(inv_vp, ndc);
return (wpos.xyz / wpos.w).xyz;
}
bool TraceAORay(uint idx, float3 origin, float3 direction, float far, unsigned int depth)
{
// Define a ray, consisting of origin, direction, and the min-max distance values
RayDesc ray;
ray.Origin = origin;
ray.Direction = direction;
ray.TMin = 0.f;
ray.TMax = far;
AOHitInfo payload = { 1.0f, 0.0f };
// Trace the ray
TraceRay(
Scene,
RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_SKIP_CLOSEST_HIT_SHADER,
~0, // InstanceInclusionMask
0, // RayContributionToHitGroupIndex
0, // MultiplierForGeometryContributionToHitGroupIndex
0, // miss shader index is set to idx but can probably be anything.
ray,
payload);
return payload.is_hit;
}
[shader("raygeneration")]
void AORaygenEntry()
{
// Texture UV coordinates [0, 1]
float2 uv = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy - 1);
uint rand_seed = initRand(DispatchRaysIndex().x + DispatchRaysIndex().y * DispatchRaysDimensions().x, frame_idx);
// Screen coordinates [0, resolution] (inverted y)
int2 screen_co = DispatchRaysIndex().xy;
float3 normal = gbuffer_normal[screen_co].xyz;
float depth = gbuffer_depth[screen_co].x;
float3 wpos = unpack_position(float2(uv.x, 1.f - uv.y), depth);
float3 camera_pos = float3(inv_view[0][3], inv_view[1][3], inv_view[2][3]);
float cam_distance = length(wpos-camera_pos);
if(cam_distance < max_distance)
{
//SPP decreases the closer a pixel is to the max distance
//Total is always calculated using the full sample count to have further pixels less occluded
int spp = min(sample_count, round(sample_count * ((max_distance - cam_distance)/max_distance)));
int ao_value = sample_count;
for(uint i = 0; i< spp; i++)
{
ao_value -= TraceAORay(0, wpos + normal * bias , getCosHemisphereSample(rand_seed, normal), radius, 0);
}
output[DispatchRaysIndex().xy].x = pow(ao_value/float(sample_count), power);
}
else
{
output[DispatchRaysIndex().xy].x = 1.f;
}
}
[shader("miss")]
void MissEntry(inout AOHitInfo hit : SV_RayPayload)
{
hit.is_hit = 0.0f;
}
#endif //__DXR_AMBIENT_OCCLUSION_HLSL__
================================================
FILE: resources/shaders/dxr_functions.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_FUNCTIONS_HLSL__
#define __DXR_FUNCTIONS_HLSL__
float3 HitAttribute(float3 a, float3 b, float3 c, BuiltInTriangleIntersectionAttributes attr)
{
float3 vertexAttribute[3];
vertexAttribute[0] = a;
vertexAttribute[1] = b;
vertexAttribute[2] = c;
return vertexAttribute[0] +
attr.barycentrics.x * (vertexAttribute[1] - vertexAttribute[0]) +
attr.barycentrics.y * (vertexAttribute[2] - vertexAttribute[0]);
}
uint3 Load3x32BitIndices(ByteAddressBuffer buffer, uint offsetBytes)
{
// Load first 2 indices
return buffer.Load3(offsetBytes);
}
// Retrieve hit world position.
float3 HitWorldPosition()
{
return WorldRayOrigin() + RayTCurrent() * WorldRayDirection();
}
float3 unpack_position(float2 uv, float depth, float4x4 inv_vp)
{
// Get world space position
const float4 ndc = float4(uv * 2.0 - 1.0, depth, 1.0);
float4 wpos = mul(inv_vp, ndc);
return (wpos.xyz / wpos.w).xyz;
}
float3 CalcPeturbedNormal(float3 normal, float3 normal_map, float3 tangent, float3 bitangent, float3 V, out float3 world_normal)
{
float3x4 object_to_world = ObjectToWorld3x4();
float3 N = normalize(mul(object_to_world, float4(normal, 0)));
float3 T = normalize(mul(object_to_world, float4(tangent, 0)));
#ifndef CALC_BITANGENT
const float3 B = normalize(mul(object_to_world, float4(bitangent, 0)));
#else
T = normalize(T - dot(T, N) * N);
float3 B = cross(N, T);
#endif
const float3x3 TBN = float3x3(T, B, N);
float3 fN = normalize(mul(normal_map, TBN));
world_normal = N;
return fN;
}
float3 CalcPeturbedNormal(float3 normal, float3 normal_map, float3 tangent, float3 bitangent, float3 V)
{
float3 temp = 0;
return CalcPeturbedNormal(normal, normal_map, tangent, bitangent, V, temp);
}
#endif //__DXR_FUNCTIONS_HLSL__
================================================
FILE: resources/shaders/dxr_global.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_GLOBAL_HLSL__
#define __DXR_GLOBAL_HLSL__
#define MAX_RECURSION 2
//#define FOUR_X_A
//#define PATH_TRACING
//#define DEPTH_OF_FIELD
#define EPSILON 0.1
#define SOFT_SHADOWS
#define MAX_SHADOW_SAMPLES 1
//#define PERFECT_MIRROR_REFLECTIONS
#define GROUND_TRUTH_REFLECTIONS
#define MAX_GT_REFLECTION_SAMPLES 4
//#define DISABLE_SPATIAL_RECONSTRUCTION
#define RUSSIAN_ROULETTE
#define NO_PATH_TRACED_NORMALS
#define CALC_BITANGENT // calculate bitangent in the shader instead of using the bitangent uploaded
#ifdef FALLBACK
#undef MAX_RECURSION
#define MAX_RECURSION 1
#undef GROUND_TRUTH_REFLECTIONS
#undef MAX_GT_REFLECTION_SAMPLES
#define MAX_GT_REFLECTION_SAMPLES 2
//#define NO_SHADOWS
#endif
RaytracingAccelerationStructure Scene : register(t0, space0);
#endif //__DXR_GLOBAL_HLSL__
================================================
FILE: resources/shaders/dxr_pathtracer_accumulation.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_PATHTRACER_ACCUMULATION_HLSL__
#define __DXR_PATHTRACER_ACCUMULATION_HLSL__
#include "pp_util.hlsl"
#include "pp_hdr_util.hlsl"
Texture2D input : register(t0);
RWTexture2D output : register(u0);
SamplerState s0 : register(s0);
cbuffer Properties : register(b0)
{
float frame_idx;
};
[numthreads(16, 16, 1)]
void main(uint3 DTid : SV_DispatchThreadID)
{
float4 current = input[DTid.xy]; // Last path tracer result
float4 prev = output[DTid.xy]; // Previous path tracer output
float accum_count = frame_idx; // 0 to x, the number of times the accumulation has ran.
float4 color = (accum_count * prev + current) / (accum_count + 1); // accumulate
output[DTid.xy] = color; // update the output with the accumulated result.
}
#endif //__DXR_PATHTRACER_ACCUMULATION_HLSL__
================================================
FILE: resources/shaders/dxr_pathtracer_entries.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_PATHTRACER_ENTRIES_HLSL__
#define __DXR_PATHTRACER_ENTRIES_HLSL__
#include "dxr_shadow_entries.hlsl"
//Reflections
[shader("closesthit")]
void ReflectionHit(inout PathTracingHitInfoCone payload, in Attributes attr)
{
// Calculate the essentials
const Offset offset = g_offsets[InstanceID()];
const Material material = g_materials[offset.material_idx];
const float3 hit_pos = HitWorldPosition();
const float index_offset = offset.idx_offset;
const float vertex_offset = offset.vertex_offset;
// Find first index location
const uint index_size = 4;
const uint indices_per_triangle = 3;
const uint triangle_idx_stride = indices_per_triangle * index_size;
uint base_idx = PrimitiveIndex() * triangle_idx_stride;
base_idx += index_offset * 4; // offset the start
uint3 indices = Load3x32BitIndices(g_indices, base_idx);
indices += float3(vertex_offset, vertex_offset, vertex_offset); // offset the start
// Gather triangle vertices
const Vertex v0 = g_vertices[indices.x];
const Vertex v1 = g_vertices[indices.y];
const Vertex v2 = g_vertices[indices.z];
// Variables
const float3 V = normalize(payload.origin - hit_pos);
// Calculate actual "fragment" attributes.
const float3 frag_pos = HitAttribute(v0.pos, v1.pos, v2.pos, attr);
const float3 normal = normalize(HitAttribute(v0.normal, v1.normal, v2.normal, attr));
const float3 tangent = HitAttribute(v0.tangent, v1.tangent, v2.tangent, attr);
const float3 bitangent = HitAttribute(v0.bitangent, v1.bitangent, v2.bitangent, attr);
float2 uv = HitAttribute(float3(v0.uv, 0), float3(v1.uv, 0), float3(v2.uv, 0), attr).xy;
uv.y = 1.0f - uv.y;
float mip_level = payload.depth + 1;
OutputMaterialData output_data = InterpretMaterialDataRT(material.data,
g_textures[material.albedo_id],
g_textures[material.normal_id],
g_textures[material.roughness_id],
g_textures[material.metalicness_id],
g_textures[material.emissive_id],
g_textures[material.ao_id],
mip_level,
s0,
uv);
float3 albedo = output_data.albedo;
float roughness = output_data.roughness;
float metal = output_data.metallic;
float3 emissive = output_data.emissive;
float ao = output_data.ao;
#ifdef NO_PATH_TRACED_NORMALS
float3 N = normalize(mul(ObjectToWorld3x4(), float4(normal, 0)));
float3 fN = N;
#else
float3 N = 0;
float3 fN = CalcPeturbedNormal(normal, output_data.normal, tangent, bitangent, V, N);
#endif
// #################### GGX #####################
nextRand(payload.seed);
payload.color = ggxIndirect(hit_pos, fN, N, V, albedo, metal, roughness, ao, payload.seed, payload.depth + 1, true, payload.cone);
payload.color += ggxDirect(hit_pos, fN, N, V, albedo, metal, roughness, payload.seed, payload.depth + 1);
payload.color += emissive;
}
//Reflection skybox
[shader("miss")]
void ReflectionMiss(inout PathTracingHitInfoCone payload)
{
payload.color = skybox.SampleLevel(s0, WorldRayDirection(), 0).rgb;
}
#endif //__DXR_PATHTRACER_ENTRIES_HLSL__
================================================
FILE: resources/shaders/dxr_pathtracer_functions.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_PATHTRACER_FUNCTIONS_HLSL__
#define __DXR_PATHTRACER_FUNCTIONS_HLSL__
#include "pbr_util.hlsl"
float3 TraceColorRay(float3 origin, float3 direction, unsigned int depth, unsigned int seed)
{
if (depth >= MAX_RECURSION)
{
return float3(0, 0, 0);
}
// Define a ray, consisting of origin, direction, and the min-max distance values
RayDesc ray;
ray.Origin = origin;
ray.Direction = direction;
ray.TMin = 0;
ray.TMax = 1.0e38f;
PathTracingHitInfo payload = { float3(1, 1, 1), seed, origin, depth };
// Trace the ray
TraceRay(
Scene,
RAY_FLAG_NONE,
~0, // InstanceInclusionMask
0, // RayContributionToHitGroupIndex
0, // MultiplierForGeometryContributionToHitGroupIndex
0, // miss shader index
ray,
payload);
return payload.color;
}
float3 TraceColorRayCone(float3 origin, float3 direction, unsigned int depth, unsigned int seed, RayCone cone)
{
if (depth >= MAX_RECURSION)
{
return float3(0, 0, 0);
}
// Define a ray, consisting of origin, direction, and the min-max distance values
RayDesc ray;
ray.Origin = origin;
ray.Direction = direction;
ray.TMin = 0;
ray.TMax = 1.0e38f;
PathTracingHitInfoCone payload = { float3(1, 1, 1), seed, origin, depth, cone };
// Trace the ray
TraceRay(
Scene,
RAY_FLAG_NONE,
~0, // InstanceInclusionMask
0, // RayContributionToHitGroupIndex
0, // MultiplierForGeometryContributionToHitGroupIndex
0, // miss shader index
ray,
payload);
return payload.color;
}
// NVIDIA's luminance function
inline float luminance(float3 rgb)
{
return dot(rgb, float3(0.2126f, 0.7152f, 0.0722f));
}
// NVIDIA's probability function
float probabilityToSampleDiffuse(float3 difColor, float3 specColor)
{
float lumDiffuse = max(0.01f, luminance(difColor.rgb));
float lumSpecular = max(0.01f, luminance(specColor.rgb));
return lumDiffuse / (lumDiffuse + lumSpecular);
}
static RayCone null_cone = { 0, 0 };
float3 ggxDirect(float3 hit_pos, float3 fN, float3 N, float3 V, float3 albedo, float metal, float roughness, unsigned int seed, unsigned int depth)
{
// #################### GGX #####################
uint light_count = lights[0].tid >> 2;
if (light_count < 1) return 0;
int light_to_sample = min(int(nextRand(seed) * light_count), light_count - 1);
Light light = lights[light_to_sample];
float3 L = 0;
float max_light_dist = 0;
float3 light_intensity = 0;
{
// Calculate light properties
uint tid = light.tid & 3;
//Light direction (constant with directional, position dependent with other)
L = (lerp(light.pos - hit_pos, light.dir, tid == light_type_directional));
float light_dist = length(L);
L /= light_dist;
//Spot intensity (only used with spot; but always calculated)
float min_cos = cos(light.ang);
float max_cos = lerp(min_cos, 1, 0.5f);
float cos_angle = dot(light.dir, L);
float spot_intensity = lerp(smoothstep(min_cos, max_cos, cos_angle), 1, tid != light_type_spot);
//Attenuation & spot intensity (only used with point or spot)
float attenuation = lerp(1.0f - smoothstep(0, light.rad, light_dist), 1, tid == light_type_directional);
light_intensity = (light.col * spot_intensity) * attenuation;
max_light_dist = lerp(light_dist, 100000, tid == light_type_directional);
}
float3 H = normalize(V + L);
// Shadow
float shadow_mult = float(light_count) * GetShadowFactor(hit_pos + (L * EPSILON), L, light.light_size, max_light_dist, MAX_SHADOW_SAMPLES, depth, CALLINGPASS_PATHTRACING, seed);
// Compute some dot products needed for shading
float NdotV = saturate(dot(fN, V));
float NdotL = saturate(dot(fN, L));
float NdotH = saturate(dot(fN, H));
float LdotH = saturate(dot(L, H));
// D = Normal distribution (Distribution of the microfacets)
float D = D_GGX(NdotH, max(0.05, roughness));
// G = Geometric shadowing term (Microfacets shadowing)
float G = G_SchlicksmithGGX(NdotL, NdotV, max(0.05, roughness));
// F = Fresnel factor (Reflectance depending on angle of incidence)
float3 F = F_Schlick(LdotH, metal, albedo);
//float3 F = F_ShlickSimple(metal, LdotH);
float3 kS = F_SchlickRoughness(NdotV, metal, albedo, roughness);
float3 kD = (1.f - kS) * (1.0 - metal);
float3 spec = (D * F * G) / (4.0 * NdotV * NdotL + 0.001f);
float3 lighting = (light_intensity * (NdotL * spec + NdotL * albedo / M_PI));
return (shadow_mult * lighting) * kD;
}
float3 ggxIndirect(float3 hit_pos, float3 fN, float3 N, float3 V, float3 albedo, float metal, float roughness, float ao, unsigned int seed, unsigned int depth, bool use_raycone = false, RayCone cone = null_cone)
{
// #################### GGX #####################
float diffuse_probability = probabilityToSampleDiffuse(albedo, metal);
float choose_diffuse = (nextRand(seed) < diffuse_probability);
// Diffuse lobe
if (choose_diffuse)
{
float3 color = (albedo / diffuse_probability) * ao;
#ifdef RUSSIAN_ROULETTE
// ############## RUSSIAN ROULETTE ###############
// Russian Roulette
// Randomly terminate a path with a probability inversely equal to the throughput
float p = max(color.x, max(color.y, color.z));
// Add the energy we 'lose' by randomly terminating paths
color *= 1 / p;
if (nextRand(seed) > p) {
return 0;
}
#endif
// ##### BOUNCE #####
nextRand(seed);
const float3 rand_dir = getCosHemisphereSample(seed, N);
float3 irradiance = 0;
if (use_raycone)
{
irradiance = TraceColorRayCone(hit_pos + (EPSILON * N), rand_dir, depth, seed, cone);
}
else
{
irradiance = TraceColorRay(hit_pos + (EPSILON * N), rand_dir, depth, seed);
}
if (dot(N, rand_dir) <= 0.0f) irradiance = float3(0, 0, 0);
float3 kS = F_SchlickRoughness(max(dot(fN, V), 0.0f), metal, albedo, roughness);
float3 kD = 1.0f - kS;
kD *= 1.0f - metal;
return kD * (irradiance * color);
}
else
{
nextRand(seed);
float3 H = getGGXMicrofacet(seed, roughness, N);
// ### BRDF ###
float3 L = normalize(2.f * dot(V, H) * H - V);
// Compute some dot products needed for shading
float NdotV = saturate(dot(N, V));
float NdotL = saturate(dot(N, L));
float NdotH = saturate(dot(N, H));
float LdotH = saturate(dot(L, H));
// D = Normal distribution (Distribution of the microfacets)
float D = D_GGX(NdotH, max(0.05, roughness));
// G = Geometric shadowing term (Microfacets shadowing)
float G = G_SchlicksmithGGX(NdotL, NdotV, max(0.05, roughness));
// F = Fresnel factor (Reflectance depending on angle of incidence)
float3 F = F_Schlick(NdotH, metal, albedo);
float3 spec = (D * F * G) / ((4.0 * NdotL * NdotV + 0.001f));
float ggx_probability = D * NdotH / (4 * LdotH);
float3 color = (NdotL * spec / (ggx_probability * (1.0f - diffuse_probability)));
#ifdef RUSSIAN_ROULETTE
// ############## RUSSIAN ROULETTE ###############
// Russian Roulette
// Randomly terminate a path with a probability inversely equal to the throughput
float p = max(color.x, max(color.y, color.z));
// Add the energy we 'lose' by randomly terminating paths
color *= 1 / p;
if (nextRand(seed) > p) {
return 0;
}
#endif
// #### BOUNCE ####
float3 irradiance = 0;
if (use_raycone)
{
irradiance = TraceColorRayCone(hit_pos + (EPSILON * N), L, depth, seed, cone);
}
else
{
irradiance = TraceColorRay(hit_pos + (EPSILON * N), L, depth, seed);
}
if (dot(N, L) <= 0.0f) irradiance = float3(0, 0, 0);
return color * irradiance;
}
}
#endif //__DXR_PATHTRACER_FUNCTIONS_HLSL__
================================================
FILE: resources/shaders/dxr_pathtracer_main.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_PATHTRACER_MAIN_HLSL__
#define __DXR_PATHTRACER_MAIN_HLSL__
#define LIGHTS_REGISTER register(t2)
#include "rand_util.hlsl"
#include "pbr_util.hlsl"
#include "material_util.hlsl"
#include "lighting.hlsl"
#include "dxr_texture_lod.hlsl"
// Definitions for:
// - Vertex, Material, Offset
// - Ray, RayCone, ReflectionHitInfo, etc
#include "dxr_structs.hlsl"
// Definitions for:
// - HitWorldPosition, Load3x32BitIndices, unpack_position, HitAttribute
#include "dxr_functions.hlsl"
RWTexture2D output : register(u0); // xyz: reflection, a: shadow factor
ByteAddressBuffer g_indices : register(t1);
StructuredBuffer g_vertices : register(t3);
StructuredBuffer g_materials : register(t4);
StructuredBuffer g_offsets : register(t5);
Texture2D g_textures[1000] : register(t10);
Texture2D gbuffer_albedo : register(t1010);
Texture2D gbuffer_normal : register(t1011);
Texture2D gbuffer_emissive : register(t1012);
Texture2D gbuffer_depth : register(t1013);
TextureCube skybox : register(t6);
TextureCube irradiance_map : register(t9);
SamplerState s0 : register(s0);
typedef BuiltInTriangleIntersectionAttributes Attributes;
cbuffer CameraProperties : register(b0)
{
float4x4 inv_view;
float4x4 inv_projection;
float4x4 inv_vp;
float frame_idx;
float3 padding;
};
#include "dxr_pathtracer_functions.hlsl"
#include "dxr_pathtracer_entries.hlsl"
[shader("raygeneration")]
void RaygenEntry()
{
uint rand_seed = initRand((DispatchRaysIndex().x + DispatchRaysIndex().y * DispatchRaysDimensions().x), frame_idx);
// Texture UV coordinates [0, 1]
float2 uv = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy - 1);
// Screen coordinates [0, resolution] (inverted y)
int2 screen_co = DispatchRaysIndex().xy;
// Get g-buffer information
float4 albedo_roughness = gbuffer_albedo[screen_co];
float4 normal_metallic = gbuffer_normal[screen_co];
float4 emissive_ao = gbuffer_emissive[screen_co];
// Unpack G-Buffer
float depth = gbuffer_depth[screen_co].x;
float3 albedo = albedo_roughness.rgb;
float3 wpos = unpack_position(float2(uv.x, 1.f - uv.y), depth, inv_vp);
float3 normal = normalize(normal_metallic.xyz);
float metallic = normal_metallic.w;
float roughness = albedo_roughness.w;
float3 emissive = emissive_ao.xyz;
float ao = emissive_ao.w;
// Do lighting
float3 cpos = float3(inv_view[0][3], inv_view[1][3], inv_view[2][3]);
float3 V = normalize(cpos - wpos);
float3 result = float3(0, 0, 0);
SurfaceHit sfhit;
sfhit.pos = wpos;
sfhit.normal = normal;
sfhit.dist = length(cpos - wpos);
sfhit.surface_spread_angle = ComputeSurfaceSpreadAngle(gbuffer_depth, gbuffer_normal, inv_vp, wpos, normal);
// Compute the initial ray cone from the gbuffers.
RayCone cone = ComputeRayConeFromGBuffer(sfhit, 1.39626, DispatchRaysDimensions().y);
nextRand(rand_seed);
const float3 rand_dir = getCosHemisphereSample(rand_seed, normal);
const float cos_theta = cos(dot(rand_dir, normal));
result = TraceColorRayCone(wpos + (EPSILON * normal), rand_dir, 0, rand_seed, cone);
if (any(isnan(result)))
{
result = 0;
}
result = clamp(result, 0, 100);
output[DispatchRaysIndex().xy] = float4(result, 1);
}
#endif //__DXR_PATHTRACER_MAIN_HLSL__
================================================
FILE: resources/shaders/dxr_raytracing.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_RAYTRACING_HLSL__
#define __DXR_RAYTRACING_HLSL__
#define LIGHTS_REGISTER register(t2)
#include "rand_util.hlsl"
#include "pbr_util.hlsl"
#include "lighting.hlsl"
#include "material_util.hlsl"
// Definitions for:
// - Vertex, Material, Offset
// - Ray, RayCone, ReflectionHitInfo
#include "dxr_structs.hlsl"
// Definitions for:
// - HitWorldPosition, Load3x32BitIndices, unpack_position, HitAttribute
#include "dxr_functions.hlsl"
RWTexture2D gOutput : register(u0);
ByteAddressBuffer g_indices : register(t1);
StructuredBuffer g_vertices : register(t3);
StructuredBuffer g_materials : register(t4);
StructuredBuffer g_offsets : register(t5);
TextureCube skybox : register(t6);
Texture2D brdf_lut : register(t7);
TextureCube irradiance_map : register(t8);
Texture2D g_textures[1000] : register(t9);
SamplerState s0 : register(s0);
SamplerState point_sampler : register(s1);
typedef BuiltInTriangleIntersectionAttributes MyAttributes;
#include "dxr_pathtracer_functions.hlsl"
cbuffer CameraProperties : register(b0)
{
float4x4 view;
float4x4 inv_projection_view;
float3 camera_position;
float padding;
float focal_radius;
float focal_len;
float frame_idx;
float intensity;
};
inline Ray GenerateCameraRay(uint2 index, in float3 cameraPosition, in float4x4 projectionToWorld, in float2 offset, unsigned int seed)
{
#ifdef DEPTH_OF_FIELD
float2 pixelOff = float2(nextRand(seed), nextRand(seed)); // Random offset in pixel to reduce floating point error.
float3 cameraU = float3(1, 0, 0);
float3 cameraV = float3(0, 1, 0);
float3 cameraW = float3(0, 0, 1);
float2 xy = (index + offset + pixelOff) + 0.5f; // center in the middle of the pixel.
float2 screenPos = xy / DispatchRaysDimensions().xy;
// Invert Y for DirectX-style coordinates.
screenPos.y = -screenPos.y;
// Unproject the pixel coordinate into a world positon.
float4 world = mul(float4(screenPos, 0, 1), projectionToWorld);
world.xyz = world.x * cameraU + world.y * cameraV + cameraW;
world.xyz /= 1;
float2 pixelCenter = (index + offset) / DispatchRaysDimensions().xy; // Pixel ID -> [0..1] over screen
float2 ndc = float2(2, -2) * pixelCenter + float2(-1, 1); // Convert to [-1..1]
float3 rayDir = ndc.x * cameraU + ndc.y * cameraV + cameraW; // Ray to point on near plane
rayDir /= 1;
float focallen = focal_len;
float lensrad = focal_len / (2.0f * 16);
float3 focalPt = cameraPosition + focallen * world;
float2 rngLens = float2(6.2831853f * nextRand(seed), lensrad * nextRand(seed));
float2 lensPos = float2(cos(rngLens.x) * rngLens.y, sin(rngLens.x) * rngLens.y);
//lensPos = mul(float4(lensPos, 0, 0), projectionToWorld);
Ray ray;
ray.origin = cameraPosition + float3(lensPos, 0);
ray.direction = normalize(focalPt.xyz - ray.origin);
#else
float2 xy = (index + offset) + 0.5f; // center in the middle of the pixel.
float2 screenPos = xy / DispatchRaysDimensions().xy * 2.0 - 1.0;
// Invert Y for DirectX-style coordinates.
screenPos.y = -screenPos.y;
// Unproject the pixel coordinate into a world positon.
float4 world = mul(float4(screenPos, 0, 1), projectionToWorld);
world.xyz /= world.w;
Ray ray;
ray.origin = cameraPosition;
ray.direction = normalize(world.xyz - ray.origin);
return ray;
#endif
}
[shader("raygeneration")]
void RaygenEntry()
{
uint rand_seed = initRand(DispatchRaysIndex().x + DispatchRaysIndex().y * DispatchRaysDimensions().x, frame_idx);
#ifdef FOUR_X_AA
Ray a = GenerateCameraRay(DispatchRaysIndex().xy, camera_position, inv_projection_view, float2(0.5, 0), rand_seed);
Ray b = GenerateCameraRay(DispatchRaysIndex().xy, camera_position, inv_projection_view, float2(-0.5, 0), rand_seed);
Ray c = GenerateCameraRay(DispatchRaysIndex().xy, camera_position, inv_projection_view, float2(0.0, 0.5), rand_seed);
Ray d = GenerateCameraRay(DispatchRaysIndex().xy, camera_position, inv_projection_view, float2(0.0, -0.5), rand_seed);
float3 result_a = TraceColorRay(a.origin, a.direction, 0, rand_seed);
nextRand(rand_seed);
float3 result_b = TraceColorRay(b.origin, b.direction, 0, rand_seed);
nextRand(rand_seed);
float3 result_c = TraceColorRay(c.origin, c.direction, 0, rand_seed);
nextRand(rand_seed);
float3 result_d = TraceColorRay(d.origin, d.direction, 0, rand_seed);
float3 result = (result_a + result_b + result_c + result_d) / 4;
#else
Ray ray = GenerateCameraRay(DispatchRaysIndex().xy, camera_position, inv_projection_view, float2(0, 0), rand_seed);
float3 result = TraceColorRay(ray.origin, ray.direction, 0, rand_seed);
#endif
if (any(isnan(result)))
{
result = float3(1000, 0, 0);
}
float4 prev = gOutput[DispatchRaysIndex().xy];
float4 color = (frame_idx * prev + float4(result, 1)) / (frame_idx + 1); // accumulate
gOutput[DispatchRaysIndex().xy] = color;
}
[shader("miss")]
void MissEntry(inout FullRTHitInfo payload)
{
payload.color = skybox.SampleLevel(s0, WorldRayDirection(), 0).rgb;
}
[shader("closesthit")]
void ClosestHitEntry(inout FullRTHitInfo payload, in MyAttributes attr)
{
// Calculate the essentials
const Offset offset = g_offsets[InstanceID()];
const Material material = g_materials[offset.material_idx];
const float3 hit_pos = HitWorldPosition();
const float index_offset = offset.idx_offset;
const float vertex_offset = offset.vertex_offset;
// Find first index location
const uint index_size = 4;
const uint indices_per_triangle = 3;
const uint triangle_idx_stride = indices_per_triangle * index_size;
uint base_idx = PrimitiveIndex() * triangle_idx_stride;
base_idx += index_offset * 4; // offset the start
uint3 indices = Load3x32BitIndices(g_indices, base_idx);
indices += float3(vertex_offset, vertex_offset, vertex_offset); // offset the start
// Gather triangle vertices
const Vertex v0 = g_vertices[indices.x];
const Vertex v1 = g_vertices[indices.y];
const Vertex v2 = g_vertices[indices.z];
// Variables
const float3 V = normalize(payload.origin - hit_pos);
// Calculate actual "fragment" attributes.
const float3 frag_pos = HitAttribute(v0.pos, v1.pos, v2.pos, attr);
const float3 normal = normalize(HitAttribute(v0.normal, v1.normal, v2.normal, attr));
const float3 tangent = HitAttribute(v0.tangent, v1.tangent, v2.tangent, attr);
const float3 bitangent = HitAttribute(v0.bitangent, v1.bitangent, v2.bitangent, attr);
float2 uv = HitAttribute(float3(v0.uv, 0), float3(v1.uv, 0), float3(v2.uv, 0), attr).xy;
uv.y = 1.0f - uv.y;
float mip_level = payload.depth;
OutputMaterialData output_data = InterpretMaterialDataRT(material.data,
g_textures[material.albedo_id],
g_textures[material.normal_id],
g_textures[material.roughness_id],
g_textures[material.metalicness_id],
g_textures[material.emissive_id],
g_textures[material.ao_id],
mip_level,
s0,
uv);
float3 albedo = output_data.albedo;
float roughness = output_data.roughness;
float metal = output_data.metallic;
float3 emissive = output_data.emissive;
float ao = output_data.ao;
float3 N = 0;
float3 fN = 0;
if (payload.depth > 0)
{
N = normalize(mul(ObjectToWorld3x4(), float4(normal, 0)));
fN = N;
}
else
{
N = 0;
fN = CalcPeturbedNormal(normal, output_data.normal, tangent, bitangent, V, N);
}
nextRand(payload.seed);
payload.color = ggxIndirect(hit_pos, fN, N, V, albedo, metal, roughness, ao, payload.seed, payload.depth + 1);
payload.color += ggxDirect(hit_pos, fN, N, V, albedo, metal, roughness, payload.seed, payload.depth + 1);
payload.color += emissive;
}
[shader("closesthit")]
void ShadowClosestHitEntry(inout ShadowHitInfo hit, MyAttributes bary)
{
hit.is_hit = true;
}
[shader("miss")]
void ShadowMissEntry(inout ShadowHitInfo hit : SV_RayPayload)
{
hit.is_hit = false;
}
#endif //__DXR_RAYTRACING_HLSL__
================================================
FILE: resources/shaders/dxr_reflection_entries.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_REFLECTION_ENTRIES_HLSL__
#define __DXR_REFLECTION_ENTRIES_HLSL__
#include "rand_util.hlsl"
#include "pbr_util.hlsl"
#include "material_util.hlsl"
#include "lighting.hlsl"
#include "dxr_texture_lod.hlsl"
// Definitions for:
// - Vertex, Material, Offset
// - Ray, RayCone, ReflectionHitInfo
#include "dxr_structs.hlsl"
// Definitions for:
// - HitWorldPosition, Load3x32BitIndices, unpack_position, HitAttribute
#include "dxr_functions.hlsl"
//Reflections
[shader("closesthit")]
void ReflectionHit(inout ReflectionHitInfo payload, in Attributes attr)
{
// Calculate the essentials
const Offset offset = g_offsets[InstanceID()];
const Material material = g_materials[offset.material_idx];
const float3 hit_pos = HitWorldPosition();
const float index_offset = offset.idx_offset;
const float vertex_offset = offset.vertex_offset;
const float3x4 model_matrix = ObjectToWorld3x4();
// Find first index location
const uint index_size = 4;
const uint indices_per_triangle = 3;
const uint triangle_idx_stride = indices_per_triangle * index_size;
uint base_idx = PrimitiveIndex() * triangle_idx_stride;
base_idx += index_offset * 4; // offset the start
uint3 indices = Load3x32BitIndices(g_indices, base_idx);
indices += float3(vertex_offset, vertex_offset, vertex_offset); // offset the start
// Gather triangle vertices
const Vertex v0 = g_vertices[indices.x];
const Vertex v1 = g_vertices[indices.y];
const Vertex v2 = g_vertices[indices.z];
//Direction & position
float3 V = normalize(payload.origin - hit_pos);
//Normal mapping
const float3 frag_pos = HitAttribute(v0.pos, v1.pos, v2.pos, attr);
float3 normal = normalize(HitAttribute(v0.normal, v1.normal, v2.normal, attr));
float3 tangent = HitAttribute(v0.tangent, v1.tangent, v2.tangent, attr);
float3 bitangent = HitAttribute(v0.bitangent, v1.bitangent, v2.bitangent, attr);
//Get data from VBO
float2 uv = HitAttribute(float3(v0.uv, 0), float3(v1.uv, 0), float3(v2.uv, 0), attr).xy;
uv.y = 1.0f - uv.y;
// Propogate the ray cone
payload.cone = Propagate(payload.cone, 0, length(payload.origin - hit_pos));
// Calculate the texture LOD level
// float mip_level = ComputeTextureLOD(
// payload.cone,
// V,
// normalize(mul(model_matrix, float4(normal, 0))),
// mul(model_matrix, float4(v0.pos, 1)),
// mul(model_matrix, float4(v1.pos, 1)),
// mul(model_matrix, float4(v2.pos, 1)),
// v0.uv,
// v1.uv,
// v2.uv,
// g_textures[material.albedo_id]);
//TODO: Fixme
float mip_level = 0;
OutputMaterialData output_data = InterpretMaterialDataRT(material.data,
g_textures[material.albedo_id],
g_textures[material.normal_id],
g_textures[material.roughness_id],
g_textures[material.metalicness_id],
g_textures[material.emissive_id],
g_textures[material.ao_id],
mip_level,
s0,
uv);
float3 albedo = output_data.albedo;
float roughness = output_data.roughness;
float metal = output_data.metallic;
float3 emissive = output_data.emissive;
float ao = output_data.ao;
// Normals
float3 fN = CalcPeturbedNormal(normal, output_data.normal, tangent, bitangent, V);
float3 flipped_N = fN * -1;
const float3 sampled_irradiance = irradiance_map.SampleLevel(s0, flipped_N, 0).xyz;
// TODO: reflections in reflections
const float3 F = F_SchlickRoughness(max(dot(fN, V), 0.0), metal, albedo, roughness);
float3 kS = F;
float3 kD = 1.0 - kS;
kD *= 1.0 - metal;
const float2 sampled_brdf = brdf_lut.SampleLevel(s0, float2(max(dot(fN, V), 0.01f), roughness), 0).rg;
//Reflection in reflections
float4 dir_t = float4(0, 0, 0, 0);
float3 reflection = DoReflection(hit_pos, V, fN, payload.seed, payload.depth + 1, roughness, metal, payload.cone, dir_t).xyz;
//Lighting
#undef SOFT_SHADOWS
float3 lighting = shade_pixel(hit_pos, V, albedo, metal, roughness, emissive, fN, payload.seed, shadow_sample_count, payload.depth + 1, CALLINGPASS_REFLECTIONS);
#define SOFT_SHADOWS
float3 specular = reflection * (kS * sampled_brdf.x + sampled_brdf.y);
float3 diffuse = albedo * sampled_irradiance;
float3 ambient = (kD * diffuse + specular) * ao;
// Output the final reflections here
payload.color = ambient + lighting;
payload.hit_t = RayTCurrent();
}
//Reflection skybox
[shader("miss")]
void ReflectionMiss(inout ReflectionHitInfo payload)
{
payload.color = skybox.SampleLevel(s0, WorldRayDirection(), 0);
payload.hit_t = RayTCurrent();
}
#endif //__DXR_REFLECTION_ENTRIES_HLSL__
================================================
FILE: resources/shaders/dxr_reflection_functions.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_REFLECTION_FUNCTIONS_HLSL__
#define __DXR_REFLECTION_FUNCTIONS_HLSL__
#include "dxr_global.hlsl"
#include "dxr_structs.hlsl"
// Definitions for:
// - Vertex, Material, Offset
// - Ray, RayCone, ReflectionHitInfo
#include "dxr_structs.hlsl"
// Definitions for:
// - HitWorldPosition, Load3x32BitIndices, unpack_position, HitAttribute
#include "dxr_functions.hlsl"
#include "pbr_util.hlsl"
float3 TraceReflectionRay(float3 origin, float3 norm, float3 direction, uint rand_seed, uint depth, RayCone cone, inout float4 dir_t)
{
if (depth >= MAX_RECURSION)
{
return skybox.SampleLevel(s0, direction, 0).rgb;
}
origin += norm * EPSILON;
ReflectionHitInfo payload = {origin, float3(0,0,1), rand_seed, depth, 0, cone};
// Define a ray, consisting of origin, direction, and the min-max distance values
RayDesc ray;
ray.Origin = origin;
ray.Direction = direction;
ray.TMin = 0;
ray.TMax = 10000.0;
bool nan = isnan(origin.x) == true || isnan(origin.y) == true || isnan(origin.z) == true;
nan = nan || isnan(direction.x) == true || isnan(direction.y) == true || isnan(direction.z) == true;
if(nan)
{
return skybox.SampleLevel(s0, direction, 0).rgb;
}
// Trace the ray
TraceRay(
Scene,
RAY_FLAG_NONE,
//RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH
//RAY_FLAG_CULL_BACK_FACING_TRIANGLES,
0xFF, // InstanceInclusionMask
0, // RayContributionToHitGroupIndex
1, // MultiplierForGeometryContributionToHitGroupIndex
0, // miss shader index
ray,
payload);
dir_t = float4(direction, payload.hit_t);
return payload.color;
}
float4 DoReflection(float3 wpos, float3 V, float3 N, uint rand_seed, uint depth, float roughness, float metallic, RayCone cone, inout float4 dir_t)
{
// Calculate ray info
float3 reflected = reflect(-V, N);
// Shoot an importance sampled ray
#ifndef PERFECT_MIRROR_REFLECTIONS
// Shoot perfect mirror ray if enabled or if it's a recursion or it's almost a perfect mirror
if (depth > 0 || roughness < 0.05f)
return float4(TraceReflectionRay(wpos, N, reflected, rand_seed, depth, cone, dir_t), 1);
#ifdef GROUND_TRUTH_REFLECTIONS
float3 reflection = float3(0.f, 0.f, 0.f);
float weight_sum = 0.f;
float sampled_count = 0.f;
float pdf_weight = 0.f; /* Used for further weighting by spatial reconstruction */
float3 total_hit = float3(0.f, 0.f, 0.f);
//[unroll]
for (uint i = 0; i < max(MAX_GT_REFLECTION_SAMPLES * metallic, 2); ++i) {
nextRand(rand_seed);
float2 xi = hammersley2d(rand_seed, 8192);
float pdf = 0.f;
float3 H = importanceSamplePdf(xi, roughness, N, pdf);
float3 L = reflect(-V, H);
float NdotL = max(dot(N, L), 0.f);
if (NdotL <= 0.f) {
nextRand(rand_seed);
xi = hammersley2d(rand_seed, 8192);
H = importanceSamplePdf(xi, roughness, N, pdf);
L = reflect(-V, H);
NdotL = max(dot(N, L), 0.f);
}
if (NdotL >= 0.f) {
float weight = brdf_weight(V, L, N, roughness) / pdf;
float4 ray_dir_t = float4(0.f, 0.f, 0.f, 0.f);
reflection += TraceReflectionRay(wpos, N, L, rand_seed, depth, cone, ray_dir_t) * weight;
weight_sum += weight;
pdf_weight += pdf;
total_hit += ray_dir_t.xyz * ray_dir_t.w;
++sampled_count;
}
}
total_hit /= sampled_count;
dir_t = float4(normalize(total_hit), length(total_hit));
return float4(reflection / weight_sum, pdf_weight / sampled_count);
#else
//Calculate an importance sampled ray
nextRand(rand_seed);
float2 xi = hammersley2d(rand_seed, 8192);
float pdf = 0;
float3 H = importanceSamplePdf(xi, roughness, N, pdf);
float3 L = reflect(-V, H);
float NdotL = max(dot(N, L), 0.f);
if(NdotL <= 0.f)
{
nextRand(rand_seed);
xi = hammersley2d(rand_seed, 8192);
H = importanceSamplePdf(xi, roughness, N, pdf);
L = reflect(-V, H);
NdotL = max(dot(N, L), 0.f);
}
float3 reflection = float3(0.f, 0.f, 0.f);
if (NdotL >= 0.f)
{
reflection = TraceReflectionRay(wpos, N, L, rand_seed, depth, cone, dir_t);
}
#ifndef DISABLE_SPATIAL_RECONSTRUCTION
return float4(reflection, pdf);
#else
return float4(reflection, -1.f);
#endif
#endif
#else
// Shoot perfect mirror ray if enabled or if it's a recursion or it's almost a perfect mirror
return float4(TraceReflectionRay(wpos, N, reflected, rand_seed, depth, cone, dir_t), -1.f);
#endif
}
#endif //__DXR_REFLECTION_FUNCTIONS_HLSL__
================================================
FILE: resources/shaders/dxr_reflection_main.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_REFLECTION_MAIN_HLSL__
#define __DXR_REFLECTION_MAIN_HLSL__
#define LIGHTS_REGISTER register(t2)
#include "rand_util.hlsl"
#include "pbr_util.hlsl"
#include "material_util.hlsl"
#include "lighting.hlsl"
#include "dxr_texture_lod.hlsl"
// Definitions for:
// - Vertex, Material, Offset
// - Ray, RayCone, ReflectionHitInfo
#include "dxr_structs.hlsl"
// Definitions for:
// - HitWorldPosition, Load3x32BitIndices, unpack_position, HitAttribute
#include "dxr_functions.hlsl"
RWTexture2D output_reflection : register(u0); // rgb: reflection, a: pdf
RWTexture2D output_shadow : register(u1); // r: shadow factor
RWTexture2D output_dir_t_buffer : register(u2); // xyz: direction, w: hitT; dirT to calculate hit position
ByteAddressBuffer g_indices : register(t1);
StructuredBuffer g_vertices : register(t3);
StructuredBuffer g_materials : register(t4);
StructuredBuffer g_offsets : register(t5);
Texture2D g_textures[1000] : register(t10);
Texture2D gbuffer_albedo : register(t1010);
Texture2D gbuffer_normal : register(t1011);
Texture2D gbuffer_depth : register(t1012);
TextureCube skybox : register(t6);
Texture2D brdf_lut : register(t8);
TextureCube irradiance_map : register(t9);
SamplerState s0 : register(s0);
typedef BuiltInTriangleIntersectionAttributes Attributes;
cbuffer CameraProperties : register(b0)
{
float4x4 inv_view;
float4x4 inv_projection;
float4x4 inv_vp;
float frame_idx;
float intensity;
float epsilon;
unsigned int shadow_sample_count;
};
#include "dxr_reflection_functions.hlsl"
#include "dxr_reflection_entries.hlsl"
#include "dxr_shadow_entries.hlsl"
[shader("raygeneration")]
void ReflectionRaygenEntry()
{
uint rand_seed = initRand(DispatchRaysIndex().x + DispatchRaysIndex().y * DispatchRaysDimensions().x, frame_idx);
// Texture UV coordinates [0, 1]
float2 uv = float2(DispatchRaysIndex().xy + 0.5) / float2(DispatchRaysDimensions().xy);
// Screen coordinates [0, resolution] (inverted y)
int2 screen_co = DispatchRaysIndex().xy;
// Get g-buffer information
float4 albedo_roughness = gbuffer_albedo.SampleLevel(s0, uv, 0);
float4 normal_metallic = gbuffer_normal.SampleLevel(s0, uv, 0);
// Unpack G-Buffer
float depth = gbuffer_depth.SampleLevel(s0, uv, 0).x;
float3 wpos = unpack_position(float2(uv.x, 1.f - uv.y), depth, inv_vp);
float3 albedo = albedo_roughness.rgb;
float roughness = albedo_roughness.w;
float3 normal = normal_metallic.xyz;
float metallic = normal_metallic.w;
// Do lighting
float3 cpos = float3(inv_view[0][3], inv_view[1][3], inv_view[2][3]);
float3 V = normalize(cpos - wpos);
if (length(normal) == 0) //TODO: Could be optimized by only marking pixels that need lighting, but that would require execute rays indirect
{
// A value of 1 in the output buffer, means that there is shadow
// So, the far plane pixels are set to 0
output_reflection[screen_co] = float4(0, 0, 0, 0);
output_shadow[screen_co] = 0;
output_dir_t_buffer[screen_co] = float4(0, 0, 0, 0);
return;
}
normal = lerp(normal, -normal, dot(normal, V) < 0);
// Describe the surface for mip level generation
SurfaceHit sfhit;
sfhit.pos = wpos;
sfhit.normal = normal;
sfhit.dist = length(cpos - wpos);
sfhit.surface_spread_angle = ComputeSurfaceSpreadAngle(gbuffer_depth, gbuffer_normal, inv_vp, wpos, normal);
// Compute the initial ray cone from the gbuffers.
RayCone cone = ComputeRayConeFromGBuffer(sfhit, 1.39626, DispatchRaysDimensions().y);
// Get reflection result
float4 dir_t = float4(0, 0, 0, 0);
float4 reflection_result = min(DoReflection(wpos, V, normal, rand_seed, 0, roughness, metallic, cone, dir_t), 10000);
// xyz: reflection, a: shadow factor
output_reflection[screen_co] = reflection_result;
output_dir_t_buffer[screen_co] = dir_t;
}
#endif //__DXR_REFLECTION_MAIN_HLSL__
================================================
FILE: resources/shaders/dxr_shadow_entries.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_SHADOW_ENTRIES_HLSL__
#define __DXR_SHADOW_ENTRIES_HLSL__
#include "pbr_util.hlsl"
#include "material_util.hlsl"
// Definitions for:
// - Vertex, Material, Offset
// - Ray, RayCone, ReflectionHitInfo
#include "dxr_structs.hlsl"
[shader("closesthit")]
void ShadowClosestHitEntry(inout ShadowHitInfo hit, Attributes bary)
{
hit.is_hit = true;
}
[shader("miss")]
void ShadowMissEntry(inout ShadowHitInfo hit : SV_RayPayload)
{
hit.is_hit = false;
}
#endif //__DXR_SHADOW_ENTRIES_HLSL__
================================================
FILE: resources/shaders/dxr_shadow_functions.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_SHADOWS_FUNCTIONS__
#define __DXR_SHADOWS_FUNCTIONS__
#include "dxr_global.hlsl"
#include "dxr_structs.hlsl"
bool TraceShadowRay(float3 origin, float3 direction, float far, uint calling_pass, unsigned int depth)
{
if (depth >= MAX_RECURSION)
{
return false;
}
// Define a ray, consisting of origin, direction, and the min-max distance values
RayDesc ray;
ray.Origin = origin;
ray.Direction = direction;
ray.TMin = 0;
ray.TMax = far;
ShadowHitInfo payload = { false, 0 };
uint ray_contr_idx = 1;
uint miss_idx = 1;
if (calling_pass == CALLINGPASS_SHADOWS)
{
ray_contr_idx = 0;
miss_idx = 0;
}
// Trace the ray
TraceRay(
Scene,
RAY_FLAG_NONE,
~0, // InstanceInclusionMask
ray_contr_idx, // RayContributionToHitGroupIndex
0, // MultiplierForGeometryContributionToHitGroupIndex
miss_idx, // miss shader index is set to idx but can probably be anything.
ray,
payload);
return payload.is_hit;
}
// Get shadow factor
float GetShadowFactor(float3 wpos, float3 light_dir, float light_size, float t_max, uint sample_count, uint depth, uint calling_pass, inout uint rand_seed)
{
float shadow_factor = 0.0f;
#ifdef SOFT_SHADOWS
for (uint i = 0; i < sample_count; ++i)
{
//float3 offset = normalize(float3(nextRand(rand_seed), nextRand(rand_seed), nextRand(rand_seed))) - 0.5;
float3 dir = perturbDirectionVector(rand_seed, light_dir, light_size);
float3 ray_direction = normalize(dir);
bool shadow = TraceShadowRay(wpos, ray_direction, t_max, calling_pass, depth);
shadow_factor += lerp(1.0, 0.0, shadow);
}
shadow_factor /= float(sample_count);
#else //SOFT_SHADOWS
bool shadow = TraceShadowRay(wpos, light_dir, t_max, calling_pass, depth);
shadow_factor = !shadow;
#endif //SOFT_SHADOWS
return shadow_factor;
}
#endif //__DXR_SHADOWS_FUNCTIONS__
================================================
FILE: resources/shaders/dxr_shadow_main.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_SHADOW_MAIN_HLSL__
#define __DXR_SHADOW_MAIN_HLSL__
#define LIGHTS_REGISTER register(t2)
#include "rand_util.hlsl"
#include "pbr_util.hlsl"
#include "math.hlsl"
#include "material_util.hlsl"
#include "lighting.hlsl"
#include "dxr_texture_lod.hlsl"
#include "dxr_global.hlsl"
// Definitions for:
// - Vertex, Material, Offset
// - Ray, RayCone, ReflectionHitInfo
#include "dxr_structs.hlsl"
// Definitions for:
// - HitWorldPosition, Load3x32BitIndices, unpack_position, HitAttribute
#include "dxr_functions.hlsl"
RWTexture2D output_refl_shadow : register(u0); // xyz: reflection, a: shadow factor
ByteAddressBuffer g_indices : register(t1);
StructuredBuffer g_vertices : register(t3);
StructuredBuffer g_materials : register(t4);
StructuredBuffer g_offsets : register(t5);
Texture2D g_textures[1000] : register(t10);
Texture2D gbuffer_albedo : register(t1010);
Texture2D gbuffer_normal : register(t1011);
Texture2D gbuffer_depth : register(t1012);
TextureCube skybox : register(t6);
Texture2D brdf_lut : register(t8);
TextureCube irradiance_map : register(t9);
SamplerState s0 : register(s0);
typedef BuiltInTriangleIntersectionAttributes Attributes;
cbuffer CameraProperties : register(b0)
{
float4x4 inv_view;
float4x4 inv_projection;
float4x4 inv_vp;
float frame_idx;
float intensity;
float epsilon;
unsigned int shadow_sample_count;
};
#include "dxr_shadow_functions.hlsl"
#include "dxr_shadow_entries.hlsl"
[shader("raygeneration")]
void ShadowRaygenEntry()
{
uint rand_seed = initRand(DispatchRaysIndex().x + DispatchRaysIndex().y * DispatchRaysDimensions().x, frame_idx);
// Texture UV coordinates [0, 1]
float2 uv = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy - 1);
// Screen coordinates [0, resolution] (inverted y)
int2 screen_co = DispatchRaysIndex().xy;
// Get g-buffer information
float4 albedo_roughness = gbuffer_albedo[screen_co];
float4 normal_metallic = gbuffer_normal[screen_co];
// Unpack G-Buffer
float depth = gbuffer_depth[screen_co].x;
float3 wpos = unpack_position(float2(uv.x, 1.f - uv.y), depth, inv_vp);
float3 normal = normal_metallic.xyz;
// Do lighting
float3 cpos = float3(inv_view[0][3], inv_view[1][3], inv_view[2][3]);
float3 V = normalize(cpos - wpos);
if (length(normal) == 0) //TODO: Could be optimized by only marking pixels that need lighting, but that would require execute rays indirect
{
// A value of 1 in the output buffer, means that there is shadow
// So, the far plane pixels are set to 0
output_refl_shadow[screen_co] = float4(1, 1, 1, 1);
return;
}
wpos += normal * epsilon;
// Get shadow factor
float4 shadow_result = DoShadowAllLights(wpos, V, normal, normal_metallic.w, albedo_roughness.w, albedo_roughness.xyz, shadow_sample_count, 0, CALLINGPASS_SHADOWS, rand_seed);
// xyz: reflection, a: shadow factor
output_refl_shadow[screen_co] = shadow_result;
}
#endif //__DXR_SHADOW_MAIN_HLSL__
================================================
FILE: resources/shaders/dxr_structs.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_STRUCTS_HLSL__
#define __DXR_STRUCTS_HLSL__
struct Vertex
{
float3 pos;
float2 uv;
float3 normal;
float3 tangent;
float3 bitangent;
};
struct MaterialData
{
float3 color;
float metallic;
float roughness;
float emissive_multiplier;
float is_double_sided;
float use_alpha_masking;
float albedo_uv_scale;
float normal_uv_scale;
float roughness_uv_scale;
float metallic_uv_scale;
float emissive_uv_scale;
float ao_uv_scale;
float padding;
uint flags;
};
struct Material
{
uint albedo_id;
uint normal_id;
uint roughness_id;
uint metalicness_id;
uint emissive_id;
uint ao_id;
float2 padding;
MaterialData data;
};
struct Offset
{
uint material_idx;
uint idx_offset;
uint vertex_offset;
};
struct Ray
{
float3 origin;
float3 direction;
};
struct RayCone
{
float width;
float spread_angle;
};
struct ReflectionHitInfo
{
float3 origin;
float3 color;
unsigned int seed;
unsigned int depth;
float hit_t;
RayCone cone;
};
struct ShadowHitInfo
{
float is_hit;
float thisvariablesomehowmakeshybridrenderingwork_killme;
};
struct PathTracingHitInfo
{
float3 color;
unsigned int seed;
float3 origin;
unsigned int depth;
};
struct PathTracingHitInfoCone
{
float3 color;
unsigned int seed;
float3 origin;
unsigned int depth;
RayCone cone;
};
struct FullRTHitInfo
{
float3 color;
unsigned int seed;
float3 origin;
unsigned int depth;
};
struct SurfaceHit
{
float3 pos;
float3 normal;
float surface_spread_angle;
float dist;
};
#endif //__DXR_STRUCTS_HLSL__
================================================
FILE: resources/shaders/dxr_texture_lod.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __DXR_TEXTURE_LOD_HLSL__
#define __DXR_TEXTURE_LOD_HLSL__
//Definition for RayCone
#include "dxr_structs.hlsl"
// numbers prefixed with Cha mean its chapter x.x
// numbers prefixed with Fig means its figure x.x
// pa Fig 20.5
float ComputeTriangleArea(float3 P0, float3 P1, float3 P2)
{
return length(cross((P1 - P0), (P2 - P0)));
}
// ta Fig 20.4
float ComputeTextureCoordsArea(float2 UV0, float2 UV1, float2 UV2, Texture2D T)
{
float w, h;
T.GetDimensions(w, h);
return abs((UV1.x - UV0.x) * (UV2.y - UV0.y) - (UV2.x - UV0.x) * (UV1.y - UV0.y)); // Removed with and height to get mipmapping working in my code.
return w * h * abs((UV1.x - UV0.x) * (UV2.y - UV0.y) - (UV2.x - UV0.x) * (UV1.y - UV0.y)); // Proper formula from Fig 20.4
}
// Ch 20.6
float GetTriangleLODConstant(float3 P0, float3 P1, float3 P2, float2 UV0, float2 UV1, float2 UV2, Texture2D T)
{
float P_a = ComputeTriangleArea(P0, P1, P2);
float T_a = ComputeTextureCoordsArea(UV0, UV1, UV2, T);
return 0.5 * log2(T_a / P_a);
}
// Ch 20.6
float ComputeTextureLOD(RayCone cone, float3 V, float3 N, float3 P0, float3 P1, float3 P2, float2 UV0, float2 UV1, float2 UV2, Texture2D T)
{
float w, h;
T.GetDimensions(w, h);
float lambda = GetTriangleLODConstant(P0, P1, P2, UV0, UV1, UV2, T);
lambda += log2(abs(cone.width));
lambda += 0.5 * log2(w * h);
lambda -= log2(abs(dot(V, N)));
return lambda;
}
// Fig 20.30
float PixelSpreadAngle(float vertical_fov, float output_height)
{
return atan((2.f * tan(vertical_fov / 2.f)) / output_height);
}
float3 dumb_ddx(Texture2D t, float3 v)
{
float2 pixel = DispatchRaysIndex().xy;
float3 top_left = t[float2(pixel.x, pixel.y)].xyz;
float3 top_right = t[float2(pixel.x+1, pixel.y)].xyz;
float3 bottom_left = t[float2(pixel.x, pixel.y+1)].xyz;
float3 bottom_right = t[float2(pixel.x+1, pixel.y+1)].xyz;
float3 v1 = top_right - top_left;
return v1;
}
float3 dumb_ddy(Texture2D t, float3 v)
{
float2 pixel = DispatchRaysIndex().xy;
float3 top_left = t[float2(pixel.x, pixel.y)].xyz;
float3 top_right = t[float2(pixel.x+1, pixel.y)].xyz;
float3 bottom_left = t[float2(pixel.x, pixel.y+1)].xyz;
float3 bottom_right = t[float2(pixel.x+1, pixel.y+1)].xyz;
float3 v2 = bottom_left - top_left;
return v2;
}
float3 dumb_ddx_depth(Texture2D t, float4x4 inv_vp, float3 v)
{
float2 uv = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy - 1);
uv.y = 1.f - uv.y;
float2 pixel = DispatchRaysIndex().xy;
float3 top_left = t[float2(pixel.x, pixel.y)].xyz;
float3 top_right = t[float2(pixel.x+1, pixel.y)].xyz;
float3 bottom_left = t[float2(pixel.x, pixel.y+1)].xyz;
float3 bottom_right = t[float2(pixel.x+1, pixel.y+1)].xyz;
// Get world space position
const float4 ndc = float4(uv * 2.0 - 1.0, top_left.x, 1.0);
float4 wpos = mul(inv_vp, ndc);
float3 retval = (wpos.xyz / wpos.w).xyz;
const float4 _ndc = float4(uv * 2.0 - 1.0, top_right.x, 1.0);
float4 _wpos = mul(inv_vp, _ndc);
float3 _retval = (_wpos.xyz / _wpos.w).xyz;
return _retval - retval;
}
float3 dumb_ddy_depth(Texture2D t, float4x4 inv_vp, float3 v)
{
float2 uv = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy - 1);
uv.y = 1.f - uv.y;
float2 pixel = DispatchRaysIndex().xy;
float3 top_left = t[float2(pixel.x, pixel.y)].xyz;
float3 top_right = t[float2(pixel.x+1, pixel.y)].xyz;
float3 bottom_left = t[float2(pixel.x, pixel.y+1)].xyz;
float3 bottom_right = t[float2(pixel.x+1, pixel.y+1)].xyz;
// Get world space position
const float4 ndc = float4(uv * 2.0 - 1.0, bottom_left.x, 1.0);
float4 wpos = mul(inv_vp, ndc);
float3 retval = (wpos.xyz / wpos.w).xyz;
const float4 _ndc = float4(uv * 2.0 - 1.0, top_right.x, 1.0);
float4 _wpos = mul(inv_vp, _ndc);
float3 _retval = (_wpos.xyz / _wpos.w).xyz;
return retval - _retval;
}
float3 dumb_ddx_depth2(Texture2D t, float4x4 inv_vp, float3 v)
{
float2 uv = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy - 1);
uv.y = 1.f - uv.y;
float2 pixel = DispatchRaysIndex().xy;
float3 top_left = t[float2(pixel.x, pixel.y)].xyz;
float3 top_right = t[float2(pixel.x+1, pixel.y)].xyz;
float3 bottom_left = t[float2(pixel.x, pixel.y+1)].xyz;
float3 bottom_right = t[float2(pixel.x+1, pixel.y+1)].xyz;
float3 v1 = top_right - top_left;
// Get world space position
const float4 ndc = float4(uv * 2.0 - 1.0, v1.x, 1.0);
float4 wpos = mul(inv_vp, ndc);
float3 retval = (wpos.xyz / wpos.w).xyz;
return retval;
}
float3 dumb_ddy_depth2(Texture2D t, float4x4 inv_vp, float3 v)
{
float2 uv = float2(DispatchRaysIndex().xy) / float2(DispatchRaysDimensions().xy - 1);
uv.y = 1.f - uv.y;
float2 pixel = DispatchRaysIndex().xy;
float3 top_left = t[float2(pixel.x, pixel.y)].xyz;
float3 top_right = t[float2(pixel.x+1, pixel.y)].xyz;
float3 bottom_left = t[float2(pixel.x, pixel.y+1)].xyz;
float3 bottom_right = t[float2(pixel.x+1, pixel.y+1)].xyz;
float3 v2 = bottom_left - top_right;
// Get world space position
const float4 ndc = float4(uv * 2.0 - 1.0, v2.x, 1.0);
float4 wpos = mul(inv_vp, ndc);
float3 retval = (wpos.xyz / wpos.w).xyz;
return retval;
}
// Fig 20.23
float ComputeSurfaceSpreadAngle(Texture2D g_P, Texture2D g_N, /*Texture2D g_DY, Texture2D g_DY2,*/ float4x4 inv_vp, float3 P, float3 N)
{
float2 pixel = DispatchRaysIndex().xy;
float3 aPx = dumb_ddx_depth2(g_P, inv_vp, P);
float3 aPy = dumb_ddy_depth2(g_P, inv_vp, P);
//float3 aPx = dumb_ddx(g_P, P);
//float3 aPy = dumb_ddy(g_P, P);
float3 aNx = dumb_ddx(g_N, N);
float3 aNy = dumb_ddy(g_N, N);
float k1 = 1;
float k2 = 0;
float s = sign(dot(aPx, aNx) + dot(aPy, aNy));
// s = g_DY2[pixel].x; // Sign calculated in the deferred main shader.
// s = 1 // Sets the sign to convex only. can fix a lot of issues.
return 2.f * k1 * s * sqrt(dot(aNx, aNx) + dot(aNy, aNy)) + k2;
}
// Ch 20.6
RayCone Propagate(RayCone cone, float surface_spread_angle, float hit_dist)
{
RayCone new_cone;
new_cone.width = cone.spread_angle * hit_dist + cone.width;
new_cone.spread_angle = cone.spread_angle + surface_spread_angle;
return new_cone;
}
// Ch 20.6
RayCone ComputeRayConeFromGBuffer(SurfaceHit hit, float vertical_fov, float height)
{
RayCone cone;
cone.width = 0;
cone.spread_angle = PixelSpreadAngle(vertical_fov, height);
return Propagate(cone, hit.surface_spread_angle, hit.dist);
}
#endif //__DXR_TEXTURE_LOD_HLSL__
================================================
FILE: resources/shaders/fullscreen_quad.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __FULLSCREEN_QUAD_HLSL__
#define __FULLSCREEN_QUAD_HLSL__
struct VS_OUTPUT
{
float4 pos : SV_POSITION;
float2 uv : TEXCOORD;
};
VS_OUTPUT main_vs(float2 pos : POSITION)
{
VS_OUTPUT output;
output.pos = float4(pos.x, pos.y, 0.0f, 1.0f);
output.uv = 0.5 * (pos.xy + float2(1.0, 1.0));
return output;
}
#endif //__FULLSCREEN_QUAD_HLSL__
================================================
FILE: resources/shaders/generate_mips_cs.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Compute shader to generate mipmaps for a given texture.
* Source: https://github.com/Microsoft/DirectX-Graphics-Samples/blob/master/MiniEngine/Core/Shaders/GenerateMipsCS.hlsli
*/
#define BLOCK_SIZE 8
// When reducing the size of a texture, it could be that downscaling the texture
// will result in a less than exactly 50% (1/2) of the original texture size.
// This happens if either the width, or the height (or both) dimensions of the texture
// are odd. For example, downscaling a 5x3 texture will result in a 2x1 texture which
// has a 60% reduction in the texture width and 66% reduction in the height.
// When this happens, we need to take more samples from the source texture to
// determine the pixel value in the destination texture.
#define WIDTH_HEIGHT_EVEN 0 // Both the width and the height of the texture are even.
#define WIDTH_ODD_HEIGHT_EVEN 1 // The texture width is odd and the height is even.
#define WIDTH_EVEN_HEIGHT_ODD 2 // The texture width is even and teh height is odd.
#define WIDTH_HEIGHT_ODD 3 // Both the width and height of the texture are odd.
struct ComputeShaderInput
{
uint3 GroupID : SV_GroupID; // 3D index of the thread group in the dispatch.
uint3 GroupThreadID : SV_GroupThreadID; // 3D index of local thread ID in a thread group.
uint3 DispatchThreadID : SV_DispatchThreadID; // 3D index of global thread ID in the dispatch.
uint GroupIndex : SV_GroupIndex; // Flattened local index of the thread within a thread group.
};
cbuffer GenerateMipsCB : register(b0)
{
uint SrcMipLevel; // Texture level of source mip
uint NumMipLevels; // Number of OutMips to write: [1-4]
uint SrcDimension; // Width and height of the source texture are even or odd.
uint Padding; // Pad to 16 byte alignment.
float2 TexelSize; // 1.0 / OutMip1.Dimensions
}
// Source mip map.
Texture2D SrcMip : register(t0);
// Write up to 4 mip map levels.
RWTexture2D OutMip1 : register(u0);
RWTexture2D OutMip2 : register(u1);
RWTexture2D OutMip3 : register(u2);
RWTexture2D OutMip4 : register(u3);
// Linear clamp sampler.
SamplerState LinearClampSampler : register(s0);
// The reason for separating channels is to reduce bank conflicts in the
// local data memory controller. A large stride will cause more threads
// to collide on the same memory bank.
groupshared float gs_R[64];
groupshared float gs_G[64];
groupshared float gs_B[64];
groupshared float gs_A[64];
void StoreColor(uint Index, float4 Color)
{
gs_R[Index] = Color.r;
gs_G[Index] = Color.g;
gs_B[Index] = Color.b;
gs_A[Index] = Color.a;
}
float4 LoadColor(uint Index)
{
return float4(gs_R[Index], gs_G[Index], gs_B[Index], gs_A[Index]);
}
float3 LinearToSRGB(float3 x)
{
// This is exactly the sRGB curve
//return x < 0.0031308 ? 12.92 * x : 1.055 * pow(abs(x), 1.0 / 2.4) - 0.055;
// This is cheaper but nearly equivalent
return x < 0.0031308 ? 12.92 * x : 1.13005 * sqrt(abs(x - 0.00228)) - 0.13448 * x + 0.005719;
}
float4 PackColor(float4 Linear)
{
#if defined(CONVERT_TO_SRGB)
return float4(LinearToSRGB(Linear.rgb), Linear.a);
#else
return Linear;
#endif
}
[numthreads(BLOCK_SIZE, BLOCK_SIZE, 1)]
void main(ComputeShaderInput IN)
{
float4 Src1 = (float4)0;
// One bilinear sample is insufficient when scaling down by more than 2x.
// You will slightly undersample in the case where the source dimension
// is odd. This is why it's a really good idea to only generate mips on
// power-of-two sized textures. Trying to handle the undersampling case
// will force this shader to be slower and more complicated as it will
// have to take more source texture samples.
// Determine the path to use based on the dimension of the
// source texture.
// 0b00(0): Both width and height are even.
// 0b01(1): Width is odd, height is even.
// 0b10(2): Width is even, height is odd.
// 0b11(3): Both width and height are odd.
switch (SrcDimension)
{
case WIDTH_HEIGHT_EVEN:
{
float2 UV = TexelSize * (IN.DispatchThreadID.xy + 0.5);
Src1 = SrcMip.SampleLevel(LinearClampSampler, UV, SrcMipLevel);
}
break;
case WIDTH_ODD_HEIGHT_EVEN:
{
// > 2:1 in X dimension
// Use 2 bilinear samples to guarantee we don't undersample when downsizing by more than 2x
// horizontally.
float2 UV1 = TexelSize * (IN.DispatchThreadID.xy + float2(0.25, 0.5));
float2 Off = TexelSize * float2(0.5, 0.0);
Src1 = 0.5 * (SrcMip.SampleLevel(LinearClampSampler, UV1, SrcMipLevel) +
SrcMip.SampleLevel(LinearClampSampler, UV1 + Off, SrcMipLevel));
}
break;
case WIDTH_EVEN_HEIGHT_ODD:
{
// > 2:1 in Y dimension
// Use 2 bilinear samples to guarantee we don't undersample when downsizing by more than 2x
// vertically.
float2 UV1 = TexelSize * (IN.DispatchThreadID.xy + float2(0.5, 0.25));
float2 Off = TexelSize * float2(0.0, 0.5);
Src1 = 0.5 * (SrcMip.SampleLevel(LinearClampSampler, UV1, SrcMipLevel) +
SrcMip.SampleLevel(LinearClampSampler, UV1 + Off, SrcMipLevel));
}
break;
case WIDTH_HEIGHT_ODD:
{
// > 2:1 in in both dimensions
// Use 4 bilinear samples to guarantee we don't undersample when downsizing by more than 2x
// in both directions.
float2 UV1 = TexelSize * (IN.DispatchThreadID.xy + float2(0.25, 0.25));
float2 Off = TexelSize * 0.5;
Src1 = SrcMip.SampleLevel(LinearClampSampler, UV1, SrcMipLevel);
Src1 += SrcMip.SampleLevel(LinearClampSampler, UV1 + float2(Off.x, 0.0), SrcMipLevel);
Src1 += SrcMip.SampleLevel(LinearClampSampler, UV1 + float2(0.0, Off.y), SrcMipLevel);
Src1 += SrcMip.SampleLevel(LinearClampSampler, UV1 + float2(Off.x, Off.y), SrcMipLevel);
Src1 *= 0.25;
}
break;
}
OutMip1[IN.DispatchThreadID.xy] = PackColor(Src1);
// A scalar (constant) branch can exit all threads coherently.
if (NumMipLevels == 1)
return;
// Without lane swizzle operations, the only way to share data with other
// threads is through LDS.
StoreColor(IN.GroupIndex, Src1);
// This guarantees all LDS writes are complete and that all threads have
// executed all instructions so far (and therefore have issued their LDS
// write instructions.)
GroupMemoryBarrierWithGroupSync();
// With low three bits for X and high three bits for Y, this bit mask
// (binary: 001001) checks that X and Y are even.
if ((IN.GroupIndex & 0x9) == 0)
{
float4 Src2 = LoadColor(IN.GroupIndex + 0x01);
float4 Src3 = LoadColor(IN.GroupIndex + 0x08);
float4 Src4 = LoadColor(IN.GroupIndex + 0x09);
Src1 = 0.25 * (Src1 + Src2 + Src3 + Src4);
OutMip2[IN.DispatchThreadID.xy / 2] = PackColor(Src1);
StoreColor(IN.GroupIndex, Src1);
}
if (NumMipLevels == 2)
return;
GroupMemoryBarrierWithGroupSync();
// This bit mask (binary: 011011) checks that X and Y are multiples of four.
if ((IN.GroupIndex & 0x1B) == 0)
{
float4 Src2 = LoadColor(IN.GroupIndex + 0x02);
float4 Src3 = LoadColor(IN.GroupIndex + 0x10);
float4 Src4 = LoadColor(IN.GroupIndex + 0x12);
Src1 = 0.25 * (Src1 + Src2 + Src3 + Src4);
OutMip3[IN.DispatchThreadID.xy / 4] = PackColor(Src1);
StoreColor(IN.GroupIndex, Src1);
}
if (NumMipLevels == 3)
return;
GroupMemoryBarrierWithGroupSync();
// This bit mask would be 111111 (X & Y multiples of 8), but only one
// thread fits that criteria.
if (IN.GroupIndex == 0)
{
float4 Src2 = LoadColor(IN.GroupIndex + 0x04);
float4 Src3 = LoadColor(IN.GroupIndex + 0x20);
float4 Src4 = LoadColor(IN.GroupIndex + 0x24);
Src1 = 0.25 * (Src1 + Src2 + Src3 + Src4);
OutMip4[IN.DispatchThreadID.xy / 8] = PackColor(Src1);
}
}
================================================
FILE: resources/shaders/lighting.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __LIGHTING_HLSL__
#define __LIGHTING_HLSL__
#define CALLINGPASS_SHADOWS 0
#define CALLINGPASS_REFLECTIONS 1
#define CALLINGPASS_PATHTRACING 2
#define CALLINGPASS_FULLRAYTRACING 3
#include "dxr_shadow_functions.hlsl"
struct Light
{
float3 pos; //Position in world space for spot & point
float rad; //Radius for point, height for spot
float3 col; //Color
uint tid; //Type id; light_type_x
float3 dir; //Direction for spot & directional
float ang; //Angle for spot; in radians
float3 padding;
float light_size;
};
StructuredBuffer lights : LIGHTS_REGISTER;
static uint light_type_point = 0;
static uint light_type_directional = 1;
static uint light_type_spot = 2;
float calc_attenuation(Light light, float3 L, float light_dist)
{
uint tid = light.tid & 3;
float min_cos = cos(light.ang);
float max_cos = lerp(min_cos, 1, 0.5f);
float cos_angle = dot(light.dir, L);
return lerp(smoothstep(min_cos, max_cos, cos_angle), 1.0f - smoothstep(0, light.rad, light_dist), tid != light_type_spot);
}
//Copied version for testing stuff
float3 shade_light(float3 pos, float3 V, float3 albedo, float3 normal, float metallic, float roughness, Light light)
{
uint tid = light.tid & 3;
//Light direction (constant with directional, position dependent with other)
float3 L = (lerp(light.pos - pos, light.dir, tid == light_type_directional));
float light_dist = length(L);
L /= light_dist;
float attenuation = calc_attenuation(light, L, light_dist);
float3 radiance = light.col * attenuation;
float3 lighting = BRDF(L, V, normal, metallic, roughness, albedo, radiance);
return lighting;
}
float3 shade_pixel(float3 pos, float3 V, float3 albedo, float metallic, float roughness, float3 emissive, float3 normal, float3 irradiance, float ao, float3 reflection, float2 brdf, float3 shadow_factor, bool uses_luminance)
{
float3 res = float3(0.0f, 0.0f, 0.0f);
uint light_count = lights[0].tid >> 2; //Light count is stored in 30 upper-bits of first light
if(!uses_luminance)
{
for (uint i = 0; i < light_count; i++)
{
res += shade_light(pos, V, albedo, normal, metallic, roughness, lights[i]);
}
}
else
{
res = albedo * shadow_factor;
}
// Ambient Lighting using Irradiance for Diffuse
float3 kS = F_SchlickRoughness(max(dot(normal, V), 0.0f), metallic, albedo, roughness);
float3 kD = 1.0f - kS;
kD *= 1.0f - metallic;
float3 diffuse = irradiance * albedo;
// Image-Based Lighting using Prefiltered Environment Map and BRDF LUT for Specular
float3 prefiltered_color = reflection;
float2 sampled_brdf = brdf;
float3 specular = prefiltered_color * (kS * sampled_brdf.x + sampled_brdf.y);
//float3 specular = reflection * kS;
float3 ambient = (kD * diffuse + specular) * ao;
return ambient + res + emissive;
}
float3 shade_light(float3 pos, float3 V, float3 albedo, float3 normal, float metallic, float roughness, Light light, inout uint rand_seed, uint shadow_sample_count, uint depth, uint calling_pass)
{
uint tid = light.tid & 3;
//Light direction (constant with directional, position dependent with other)
float3 L = (lerp(light.pos - pos, light.dir, tid == light_type_directional));
float light_dist = length(L);
L /= light_dist;
float attenuation = calc_attenuation(light, L, light_dist);
// Maybe change hard-coded 100000 to be dynamic according to the scene size?
float t_max = lerp(light_dist, 100000, tid == light_type_directional);
float3 radiance = light.col * attenuation;
float3 lighting = BRDF(L, V, normal, metallic, roughness, albedo, radiance);
float3 wpos = pos + (normal * EPSILON);
float shadow_factor = GetShadowFactor(wpos, L, light.light_size, t_max, shadow_sample_count, depth, calling_pass, rand_seed);
lighting *= shadow_factor;
return lighting;
}
float3 shade_pixel(float3 pos, float3 V, float3 albedo, float metallic, float roughness, float3 emissive, float3 normal, inout uint rand_seed, uint shadow_sample_count, uint depth, uint calling_pass)
{
uint light_count = lights[0].tid >> 2; //Light count is stored in 30 upper-bits of first light
float3 res = float3(0, 0, 0);
[unroll]
for (uint i = 0; i < light_count; i++)
{
res += shade_light(pos, V, albedo, normal, metallic, roughness, lights[i], rand_seed, shadow_sample_count, depth, calling_pass);
}
return res + emissive;
}
float4 DoShadowAllLights(float3 wpos, float3 V, float3 normal, float metallic, float roughness, float3 albedo, uint shadow_sample_count, uint depth, uint calling_pass, inout float rand_seed)
{
uint light_count = lights[0].tid >> 2; //Light count is stored in 30 upper-bits of first light
float4 res = float4(0.0, 0.0, 0.0, 0.0);
uint sampled_lights = 0;
for (uint i = 0; i < light_count; i++)
{
// Get light and light type
Light light = lights[i];
uint tid = light.tid & 3;
//Light direction (constant with directional, position dependent with other)
float3 L = (lerp(light.pos - wpos, light.dir, tid == light_type_directional));
float light_dist = length(L);
L /= light_dist;
float dir_dot = dot(L, normal);
if (dir_dot < 0.0f)
{
continue;
}
float attenuation = calc_attenuation(light, L, light_dist);
if (light_dist > light.rad && tid != light_type_directional)
{
continue;
}
float3 radiance = attenuation * light.col;
float3 lighting = BRDF(L, V, normal, metallic, roughness, float3(1.0, 1.0, 1.0), radiance) /* / max(albedo, float3(0.001, 0.001, 0.001)) */;
// Get maxium ray length (depending on type)
float t_max = lerp(light_dist, 100000, tid == light_type_directional);
// Add shadow factor to final result
float shadow = GetShadowFactor(wpos, L, light.light_size, t_max, shadow_sample_count, depth, calling_pass, rand_seed);
res.w += shadow;
res.rgb += lighting * shadow;
sampled_lights++;
}
// return final res
res.w = res.w / float(sampled_lights);
return res;
}
#endif //__LIGHTING_HLSL__
================================================
FILE: resources/shaders/material_util.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __MATERIAL_UTIL_HLSL__
#define __MATERIAL_UTIL_HLSL__
#define MATERIAL_HAS_ALBEDO_TEXTURE 1<<0
#define MATERIAL_HAS_NORMAL_TEXTURE 1<<1
#define MATERIAL_HAS_ROUGHNESS_TEXTURE 1<<2
#define MATERIAL_HAS_METALLIC_TEXTURE 1<<3
#define MATERIAL_HAS_EMISSIVE_TEXTURE 1<<4
#define MATERIAL_HAS_AO_TEXTURE 1<<5
#include "dxr_structs.hlsl"
struct OutputMaterialData
{
float3 albedo;
float alpha;
float roughness;
float3 normal;
float metallic;
float3 emissive;
float ao;
};
OutputMaterialData InterpretMaterialData(MaterialData data,
Texture2D material_albedo,
Texture2D material_normal,
Texture2D material_roughness,
Texture2D material_metallic,
Texture2D material_emissive,
Texture2D material_ambient_occlusion,
SamplerState s0,
float2 uv
)
{
OutputMaterialData output;
float use_albedo_texture = float((data.flags & MATERIAL_HAS_ALBEDO_TEXTURE) != 0);
float use_roughness_texture = float((data.flags & MATERIAL_HAS_ROUGHNESS_TEXTURE) != 0);
float use_metallic_texture = float((data.flags & MATERIAL_HAS_METALLIC_TEXTURE) != 0);
float use_normal_texture = float((data.flags & MATERIAL_HAS_NORMAL_TEXTURE) != 0);
float use_emissive_texture = float((data.flags & MATERIAL_HAS_EMISSIVE_TEXTURE) != 0);
float use_ao_texture = float((data.flags & MATERIAL_HAS_AO_TEXTURE) != 0);
float4 albedo = lerp(float4(data.color, 1), material_albedo.Sample(s0, uv * data.albedo_uv_scale), use_albedo_texture);
#ifdef COMPRESSED
float roughness = lerp(data.roughness, max(0.05f, material_roughness.Sample(s0, uv * data.roughness_uv_scale).y), use_roughness_texture);
float metallic = lerp(data.metallic, material_metallic.Sample(s0, uv * data.metallic_uv_scale).z, use_metallic_texture);
#else
float roughness = lerp(data.roughness, max(0.05f, material_roughness.Sample(s0, uv * data.roughness_uv_scale).x), use_roughness_texture);
float metallic = lerp(data.metallic, material_metallic.Sample(s0, uv * data.metallic_uv_scale).x, use_metallic_texture);
#endif
float3 tex_normal = lerp(float3(0.0f, 0.0f, 1.0f), material_normal.Sample(s0, uv * data.normal_uv_scale).rgb * 2.0f - float3(1.0f, 1.0f, 1.0f), use_normal_texture);
float3 emissive = lerp(float3(0.0f, 0.0f, 0.0f), material_emissive.Sample(s0, uv * data.emissive_uv_scale).xyz, use_emissive_texture);
float ao = lerp(1.0f, material_ambient_occlusion.Sample(s0, uv * data.ao_uv_scale).x, use_ao_texture);
output.albedo = pow(albedo.xyz, 2.2f);
output.alpha = albedo.w;
output.roughness = roughness;
output.normal = tex_normal;
output.metallic = metallic;
output.emissive = pow(emissive,2.2f) * data.emissive_multiplier;
output.ao = ao;
return output;
}
OutputMaterialData InterpretMaterialDataRT(MaterialData data,
Texture2D material_albedo,
Texture2D material_normal,
Texture2D material_roughness,
Texture2D material_metallic,
Texture2D material_emissive,
Texture2D material_ambient_occlusion,
float mip_level,
SamplerState s0,
float2 uv)
{
OutputMaterialData output;
float use_albedo_texture = float((data.flags & MATERIAL_HAS_ALBEDO_TEXTURE) != 0);
float use_roughness_texture = float((data.flags & MATERIAL_HAS_ROUGHNESS_TEXTURE) != 0);
float use_metallic_texture = float((data.flags & MATERIAL_HAS_METALLIC_TEXTURE) != 0);
float use_normal_texture = float((data.flags & MATERIAL_HAS_NORMAL_TEXTURE) != 0);
float use_emissive_texture = float((data.flags & MATERIAL_HAS_EMISSIVE_TEXTURE) != 0);
float use_ao_texture = float((data.flags & MATERIAL_HAS_AO_TEXTURE) != 0);
const float4 albedo = lerp(float4(data.color, 1),
material_albedo.SampleLevel(s0, uv * (data.albedo_uv_scale), mip_level),
use_albedo_texture);
#ifdef COMPRESSED
const float roughness = lerp(data.roughness, max(0.05, material_roughness.SampleLevel(s0, uv * data.roughness_uv_scale, mip_level).z), use_roughness_texture);
const float metallic = lerp(data.metallic, material_metallic.SampleLevel(s0, uv * data.metallic_uv_scale, mip_level).y, use_metallic_texture);
#else
const float roughness = lerp(data.roughness, max(0.05, material_roughness.SampleLevel(s0, uv * data.roughness_uv_scale, mip_level).x), use_roughness_texture);
const float metallic = lerp(data.metallic, material_metallic.SampleLevel(s0, uv * data.metallic_uv_scale, mip_level).x, use_metallic_texture);
#endif
const float3 normal_t = lerp(float3(0.0, 0.0, 1.0),
material_normal.SampleLevel(s0, uv * data.normal_uv_scale, mip_level).xyz * 2 - 1,
use_normal_texture);
float3 emissive = lerp(float3(0.0f, 0.0f, 0.0f),
material_emissive.SampleLevel(s0, uv * data.emissive_uv_scale, mip_level).xyz, use_emissive_texture);
float ao = lerp(1.0f,
material_ambient_occlusion.SampleLevel(s0, uv * data.ao_uv_scale, mip_level).x, use_ao_texture);
output.albedo = pow(albedo.xyz, 2.2f);
output.alpha = albedo.w;
output.roughness = roughness;
output.normal = normal_t;
output.metallic = metallic;
output.emissive = pow(emissive, 2.2f) * data.emissive_multiplier;
output.ao = ao;
return output;
}
#endif //__MATERIAL_UTIL_HLSL__
================================================
FILE: resources/shaders/math.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __MATH_HLSL__
#define __MATH_HLSL__
#define M_PI 3.14159265358979
float linterp(float t) {
return saturate(1.0 - abs(2.0 * t - 1.0));
}
float remap(float t, float a, float b)
{
return saturate((t - a) / (b - a));
}
float4 spectrum_offset(float t)
{
float4 ret;
float lo = step(t, 0.5);
float hi = 1.0 - lo;
float w = linterp(remap(t, 1.0 / 6.0, 5.0 / 6.0));
ret = float4(lo, 1.0, hi, 1.) * float4(1.0 - w, w, 1.0 - w, 1.);
return pow(ret, float4(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2));
}
#endif //__MATH_HLSL__
================================================
FILE: resources/shaders/pbr_brdf_lut.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "rand_util.hlsl"
#include "pbr_util.hlsl"
RWTexture2D output : register(u0);
float2 IntegrateBRDF(float NdotV, float roughness)
{
float3 V;
V.x = sqrt(1.0f - NdotV * NdotV);
V.y = 0.0f;
V.z = NdotV;
float A = 0.0f;
float B = 0.0f;
float3 N = float3(0.0f, 0.0f, 1.0f);
const uint SAMPLE_COUNT = 1024u;
for (uint i = 0; i < SAMPLE_COUNT; ++i)
{
float2 Xi = hammersley2d(i, SAMPLE_COUNT);
float3 H = importanceSample_GGX(Xi, roughness, N);
float3 L = normalize(2.0f * dot(V, H) * H - V);
float NdotL = max(L.z, 0.0f);
float NdotH = max(H.z, 0.0f);
float VdotH = max(dot(V, H), 0.0f);
float NdotV = max(dot(N, V), 0.0f);
if (NdotL > 0.0f)
{
float G = GeometrySmith_IBL(NdotV, NdotL, roughness);
float G_Vis = (G * VdotH) / (NdotH * NdotV);
float Fc = pow(1.0f - VdotH, 5.0f);
A += (1.0f - Fc) * G_Vis;
B += Fc * G_Vis;
}
}
A /= float(SAMPLE_COUNT);
B /= float(SAMPLE_COUNT);
return float2(A, B);
}
[numthreads(16, 16, 1)]
void main_cs(uint3 dt_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
float2 screen_coord = int2(dt_id.x, dt_id.y) + 0.5f;
float2 uv = screen_coord / screen_size;
output[dt_id.xy] = IntegrateBRDF(uv.x, uv.y);
}
================================================
FILE: resources/shaders/pbr_cubemap_conversion.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
struct VS_INPUT
{
float3 pos : POSITION;
//float2 uv : TEXCOORD;
//float3 normal : NORMAL;
//float3 tangent : TANGENT;
//float3 bitangent : BITANGENT;
};
struct VS_OUTPUT
{
float4 pos : SV_POSITION;
float3 local_pos : LOCPOS;
};
cbuffer PassIndex : register (b0)
{
int idx;
}
cbuffer CameraProperties : register(b1)
{
float4x4 projection;
float4x4 view[6];
};
VS_OUTPUT main_vs(VS_INPUT input)
{
VS_OUTPUT output;
output.local_pos = input.pos.xyz;
float4x4 vp = mul(projection, view[idx]);
output.pos = mul(vp, float4(output.local_pos, 1.0f));
return output;
}
struct PS_OUTPUT
{
float4 color;
};
Texture2D equirectangular_texture : register(t0);
SamplerState s0 : register(s0);
float2 SampleSphericalMap(float3 v)
{
float2 inv_atan = float2(0.1591f, 0.3183f);
float2 uv = float2(atan2(v.z, v.x), asin(v.y));
uv *= inv_atan;
uv += 0.5f;
return uv;
}
PS_OUTPUT main_ps(VS_OUTPUT input) : SV_TARGET
{
PS_OUTPUT output;
float2 uv = SampleSphericalMap(normalize(input.local_pos));
float3 color = equirectangular_texture.Sample(s0, uv).rgb;
output.color = float4(color, 1.0f);
return output;
}
================================================
FILE: resources/shaders/pbr_cubemap_convolution.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
struct VS_INPUT
{
float3 pos : POSITION;
float2 uv : TEXCOORD;
float3 normal : NORMAL;
float3 tangent : TANGENT;
float3 bitangent : BITANGENT;
};
struct VS_OUTPUT
{
float4 pos : SV_POSITION;
float3 local_pos : LOCPOS;
};
cbuffer PassIndex : register (b0)
{
int idx;
}
cbuffer CameraProperties : register(b1)
{
float4x4 projection;
float4x4 view[6];
};
VS_OUTPUT main_vs(VS_INPUT input)
{
VS_OUTPUT output;
output.local_pos = input.pos.xyz;
float4x4 vp = mul(projection, view[idx]);
output.pos = mul(vp, float4(output.local_pos, 1.0f));
return output;
}
struct PS_OUTPUT
{
float4 color;
};
TextureCube environment_cubemap : register(t0);
SamplerState s0 : register(s0);
PS_OUTPUT main_ps(VS_OUTPUT input) : SV_TARGET
{
PS_OUTPUT output;
const float PI = 3.14159265359f;
float3 normal = normalize(input.local_pos);
float3 irradiance = float3(0.0f, 0.0f, 0.0f);
float3 up = float3(0.0f, 1.0f, 0.0f);
float3 right = cross(up, normal);
up = cross(normal, right);
float sample_delta = 0.025f;
float nr_samples = 0.0f;
for (float phi = 0.0f; phi < 2.0f * PI; phi += sample_delta)
{
for (float theta = 0.0f; theta < 0.5f * PI; theta += sample_delta)
{
float cos_theta = cos(theta);
float sin_theta = sin(theta);
float3 tangent_sample = float3(sin_theta * cos(phi), sin_theta * sin(phi), cos_theta);
float3 sample_vec = tangent_sample.x * right + tangent_sample.y * up + tangent_sample.z * normal;
irradiance += environment_cubemap.Sample(s0, sample_vec).rgb * cos_theta * sin_theta;
nr_samples++;
}
}
irradiance = PI * irradiance * (1.0f / float(nr_samples));
output.color = float4(irradiance.rgb, 1.0f);
return output;
}
================================================
FILE: resources/shaders/pbr_prefilter_env_map.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "rand_util.hlsl"
#include "pbr_util.hlsl"
TextureCube src_texture : register(t0);
RWTexture2D dst_texture : register(u0);
SamplerState s0 : register(s0);
cbuffer CB : register(b0)
{
float2 texture_size;
float2 skybox_res;
float roughness;
uint cubemap_face;
}
[numthreads(8, 8, 1)]
void main_cs(uint3 dt_id : SV_DispatchThreadID)
{
float2 position = float2(dt_id.xy + 0.5f) / texture_size;
position.y = 1.0f - position.y;
position = (position - 0.5f) * 2.0f;
float3 direction = float3(0.0f, 0.0f, 0.0f);
float3 up = float3(0.0f, 0.0f, 0.0f);
switch (cubemap_face)
{
case 0: direction = float3(1.0f, position.y, -position.x); up = float3(0.0f, 1.0f, 0.0f); break; // +X
case 1: direction = float3(-1.0f, position.y, position.x); up = float3(0.0f, 1.0f, 0.0f); break; // -X
case 2: direction = float3(position.x, 1.0f, -position.y); up = float3(0.0f, 0.0f, -1.0f); break; // +Y
case 3: direction = float3(position.x, -1.0f, position.y); up = float3(0.0f, 0.0f, 1.0f); break; // -Y
case 4: direction = float3(position.x, position.y, 1.0f); up = float3(0.0f, 1.0f, 0.0f); break; // +Z
case 5: direction = float3(-position.x, position.y, -1.0f); up = float3(0.0f, 1.0f, 0.0f); break; // -Z
}
float3 N = normalize(direction);
float3 right = normalize(cross(up, N));
up = cross(N, right);
float3 R = N;
float3 V = R;
const uint SAMPLE_COUNT = 1024u;
float total_weight = 0.0f;
float3 prefiltered_color = float3(0.0f, 0.0f, 0.0f);
for (uint i = 0u; i < SAMPLE_COUNT; i++)
{
float2 Xi = hammersley2d(i, SAMPLE_COUNT);
float3 H = importanceSample_GGX(Xi, roughness, N);
float3 L = normalize(2.0f * dot(V, H) * H - V);
float NdotL = max(dot(N, L), 0.0f);
if (NdotL > 0.0f)
{
float NdotH = max(dot(N, H), 0.0f);
float HdotV = max(dot(H, V), 0.0f);
float D = D_GGX(NdotH, roughness);
float pdf = D * NdotH / (4.0f * HdotV) + 0.0001f;
float sa_texel = 4.0f * M_PI / (6.0f * skybox_res.x * skybox_res.y);
float sa_sample = 1.0f / (float(SAMPLE_COUNT) * pdf + 0.0001f);
float mip_level = roughness == 0.0f ? 0.0f : 0.5f * log2(sa_sample / sa_texel);
prefiltered_color += src_texture.SampleLevel(s0, L, mip_level).rgb * NdotL;
total_weight += NdotL;
}
}
prefiltered_color = prefiltered_color / total_weight;
//Write the final color into the destination texture.
dst_texture[dt_id.xy] = float4(prefiltered_color, 1.0f);
}
================================================
FILE: resources/shaders/pbr_util.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PBR_UTILS_HLSL__
#define __PBR_UTILS_HLSL__
#include "math.hlsl"
#include "rand_util.hlsl"
// Based omn http://byteblacksmith.com/improvements-to-the-canonical-one-liner-glsl-rand-for-opengl-es-2-0/
float random(float2 co)
{
float a = 12.9898;
float b = 78.233;
float c = 43758.5453;
float dt = dot(co.xy, float2(a, b));
float sn = fmod(dt, 3.14);
return frac(sin(sn) * c);
}
// Radical inverse based on http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
float2 hammersley2d(uint i, uint num)
{
uint bits = (i << 16u) | (i >> 16u);
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
float rdi = float(bits) * 2.3283064365386963e-10;
return float2(float(i) / float(num), rdi);
}
// Based on http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_slides.pdf
float3 importanceSample_GGX(float2 Xi, float roughness, float3 normal)
{
// Maps a 2D point to a hemisphere with spread based on roughness
float alpha = roughness * roughness;
//float phi = 2.f * M_PI * Xi.x + random(normal.xz) * 0.1;
float phi = 2.f * M_PI * Xi.x;
float cosTheta = sqrt((1.f - Xi.y) / (1.f + (alpha*alpha - 1.f) * Xi.y));
float sinTheta = sqrt(1.f - cosTheta * cosTheta);
float3 H;
H.x = sinTheta * cos(phi);
H.y = sinTheta * sin(phi);
H.z = cosTheta;
// Tangent space
float3 up = abs(normal.z) < 0.999 ? float3(0.f, 0.f, 1.f) : float3(1.f, 0.f, 0.f);
float3 tangentX = normalize(cross(up, normal));
float3 tangentY = cross(normal, tangentX);
// Convert to world Space
return normalize(tangentX * H.x + tangentY * H.y + normal * H.z);
}
// Normal distribution
float D_GGX(float dotNH, float roughness)
{
float alpha = roughness * roughness;
float alpha2 = alpha * alpha;
float denom = dotNH * dotNH * (alpha2 - 1.0) + 1.0;
return (alpha2)/(M_PI * denom * denom);
}
// Get a GGX half vector / microfacet normal, sampled according to the distribution computed by
// the function ggxNormalDistribution() above.
//
// When using this function to sample, the probability density is pdf = D * NdotH / (4 * HdotV)
float3 getGGXMicrofacet(inout uint randSeed, float roughness, float3 hitNorm)
{
// Get our uniform random numbers
float2 randVal = float2(nextRand(randSeed), nextRand(randSeed));
// Get an orthonormal basis from the normal
float3 B = getPerpendicularVector(hitNorm);
float3 T = cross(B, hitNorm);
// GGX NDF sampling
float a2 = roughness * roughness;
float cosThetaH = sqrt(max(0.0f, (1.0 - randVal.x) / ((a2 - 1.0) * randVal.x + 1)));
float sinThetaH = sqrt(max(0.0f, 1.0f - cosThetaH * cosThetaH));
float phiH = randVal.y * M_PI * 2.0f;
// Get our GGX NDF sample (i.e., the half vector)
return T * (sinThetaH * cos(phiH)) + B * (sinThetaH * sin(phiH)) + hitNorm * cosThetaH;
}
// Geometric Shadowing function
float G_SchlicksmithGGX(float NdotL, float NdotV, float roughness)
{
float r = (roughness + 1.0f);
float k = (r*r) / 8.0f;
float GL = NdotL / (NdotL * (1.0f - k) + k);
float GV = NdotV / (NdotV * (1.0f - k) + k);
return GL * GV;
}
float GeometrySchlickGGX_IBL(float NdotV, float roughness_squared)
{
// Different k for IBL
float k = roughness_squared / 2.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
}
// ----------------------------------------------------------------------------
float GeometrySmith_IBL(float NdotV, float NdotL, float roughness)
{
float roughness_squared = roughness * roughness;
float ggx2 = GeometrySchlickGGX_IBL(NdotV, roughness_squared);
float ggx1 = GeometrySchlickGGX_IBL(NdotL, roughness_squared);
return ggx1 * ggx2;
}
// Fresnel function
float3 F_Schlick(float cos_theta, float metallic, float3 material_color)
{
float3 F0 = lerp(float3(0.04, 0.04, 0.04), material_color, metallic); // * material.specular
float3 F = F0 + (1.0 - F0) * pow(1.0 - cos_theta, 5.0);
return F;
}
float3 F_SchlickRoughness(float cos_theta, float metallic, float3 material_color, float roughness)
{
float3 F0 = lerp(float3(0.04f, 0.04f, 0.04f), material_color, metallic); // * material.specular
float3 F = F0 + (max(float3(1.0f - roughness, 1.0f - roughness, 1.0f - roughness), F0) - F0) * pow(1.0f - cos_theta, 5.0f);
return F;
}
float3 BRDF(float3 L, float3 V, float3 N, float metallic, float roughness, float3 albedo, float3 radiance)
{
// Precalculate vectors and dot products
float3 H = normalize(V + L);
float dotNV = clamp(dot(N, V), 0.0, 1.0);
float dotNL = clamp(dot(N, L), 0.0, 1.0);
float dotNH = clamp(dot(N, H), 0.0, 1.0);
// Light color fixed
float3 color = float3(0.0, 0.0, 0.0);
if (dotNL > 0.0)
{
float rroughness = max(0.05f, roughness);
// D = Normal distribution (Distribution of the microfacets)
float D = D_GGX(dotNH, roughness);
// G = Geometric shadowing term (Microfacets shadowing)
float G = G_SchlicksmithGGX(dotNL, dotNV, roughness);
// F = Fresnel factor (Reflectance depending on angle of incidence)
float3 F = F_Schlick(dotNH, metallic, albedo);
float3 spec = (D * F * G) / ((4.0 * dotNL * dotNV + 0.001f));
float3 kD = (float3(1, 1, 1) - F) * (1.0 - metallic);
color += (kD * albedo / M_PI + spec) * radiance * dotNL;
}
return color;
}
static const float2 inv_atan = float2(0.1591f, 0.3183f);
float2 SampleSphericalMap(float3 v)
{
float2 uv = float2(atan2(v.z, v.x), asin(v.y * -1.f));
uv *= inv_atan;
uv += 0.5f;
return uv;
}
// Brian Karis, Epic Games "Real Shading in Unreal Engine 4"
// Modified version to do pdf and tangent to world conversions
float3 importanceSamplePdf(float2 xi, float a, float3 N, inout float pdf) {
float m = a * a;
float m2 = m * m;
float phi = 2 * M_PI * xi.x;
float cosTheta = sqrt((1.0 - xi.y) / (1.0 + (m2 - 1.0) * xi.y));
float sinTheta = sqrt(max(1e-5, 1.0 - cosTheta * cosTheta));
float3 H;
H.x = sinTheta * cos(phi);
H.y = sinTheta * sin(phi);
H.z = cosTheta;
float d = (cosTheta * m2 - cosTheta) * cosTheta + 1;
float D = m2 / (M_PI * d * d);
pdf = D * cosTheta;
float3 up = lerp(float3(1.0, 0.0, 0.0), float3(0.0, 0.0, 1.0), float(abs(N.z) < 0.999));
float3 T = normalize(cross(up, N));
float3 B = cross(N, T);
return normalize(T * H.x + B * H.y + N * H.z);
}
//Get weight from roughness, view direction, light direction and normal (view space)
float brdf_weight(float3 V, float3 L, float3 N, float roughness) {
float3 H = normalize(V + L);
float NdotH = saturate(dot(N, H));
float NdotL = saturate(dot(N, L));
float NdotV = saturate(dot(N, V));
float G = G_SchlicksmithGGX(NdotL, NdotV, roughness); //This causes issues
float D = D_GGX(NdotH, roughness);
float weight = G * D * M_PI / 4;
return max(weight, 1e-5); //Perfect mirrors can have weights too
}
#endif
================================================
FILE: resources/shaders/pp_bloom_blur.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_BLOOM_BLUR_HLSL__
#define __PP_BLOOM_BLUR_HLSL__
#include "pp_dof_util.hlsl"
#include "pp_bloom_util.hlsl"
Texture2D source : register(t0);
RWTexture2D output : register(u0);
SamplerState s0 : register(s0);
cbuffer BloomDirection : register(b0)
{
int blur_direction;
float sigma_amt;
};
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y) + 0.5f;
float2 texel_size = 1.0f / screen_size;
float2 uv = (screen_coord) / screen_size;
float sigma = sigma_amt - 1.0f;
float2 blur_dir = float2(0.0f, 1.0f);
if (blur_direction == 1)
{
blur_dir = float2(1.0f, 0.0f);
}
float4 color = 0;
float weightSum = 0.0f;
for (int i = -7; i < 7; i++)
{
float weight = CalcGaussianWeight(i, sigma);
weightSum += weight;
float2 o_uv = saturate((screen_coord + (blur_dir * i)) / screen_size);
float4 s = source.SampleLevel(s0, o_uv, 0);
color += s * weight;
}
output[int2(dispatch_thread_id.xy)] = color;
}
#endif //__PP_BLOOM_BLUR_HLSL__
================================================
FILE: resources/shaders/pp_bloom_blur_horizontal.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_BLOOM_BLUR_HORIZONTAL_HLSL__
#define __PP_BLOOM_BLUR_HORIZONTAL_HLSL__
#include "pp_dof_util.hlsl"
#include "pp_bloom_util.hlsl"
Texture2D source : register(t0);
RWTexture2D output : register(u0);
RWTexture2D output_qes : register(u1);
SamplerState s0 : register(s0);
cbuffer BloomDirection : register(b0)
{
float2 blur_direction;
float _pad;
float sigma;
};
float4 GetBlurFactor(float2 screen_coord, float res_scale)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
float2 blur_dir = float2(1.0f, 0.0f);
float r_sigma = 3.0f;
float4 color = 0;
float weightSum = 0.0f;
for (int i = -7; i < 7; i++)
{
float weight = CalcGaussianWeight(i, r_sigma);
weightSum += weight;
float2 o_uv = saturate((screen_coord + (blur_dir * i)) / (screen_size / res_scale));
float4 s = source.SampleLevel(s0, o_uv, 0);
color += s * weight;
}
return color;
}
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y) + 0.5f;
float4 color = 0;
if (screen_coord.x > screen_size.x)
{
if (screen_coord.x > (screen_size.x * 1.875f))
{
color = GetBlurFactor(screen_coord - screen_size * 1.875f, 16.0f);
}
if (screen_coord.x > (screen_size.x * 1.75))
{
color = GetBlurFactor(screen_coord - screen_size * 1.75f, 8.0f);
}
else if (screen_coord.x > (screen_size.x * 1.5))
{
color = GetBlurFactor(screen_coord - screen_size * 1.5f, 4.0f);
}
else
{
color = GetBlurFactor(screen_coord - screen_size, 2.0f);
}
output_qes[screen_coord - int2(screen_size)] = color;
}
else
{
color = GetBlurFactor(screen_coord, 1.0f);
output[screen_coord] = color;
}
}
#endif //__PP_BLOOM_BLUR_HORIZONTAL_HLSL__
================================================
FILE: resources/shaders/pp_bloom_blur_vertical.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_BLOOM_BLUR_VERTICAL_HLSL__
#define __PP_BLOOM_BLUR_VERTICAL_HLSL__
#include "pp_dof_util.hlsl"
#include "pp_bloom_util.hlsl"
Texture2D source : register(t0);
Texture2D source_qes : register(t1);
RWTexture2D output : register(u0);
RWTexture2D output_qes : register(u1);
SamplerState s0 : register(s0);
cbuffer BloomDirection : register(b0)
{
float2 blur_direction;
float _pad;
float sigma;
};
float4 GetBlurFactor(float2 screen_coord, float res_scale)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
float2 blur_dir = float2(0.0f, 1.0f);
float r_sigma = 3.0f;
float4 color = 0;
float weightSum = 0.0f;
for (int i = -7; i < 7; i++)
{
float weight = CalcGaussianWeight(i, r_sigma);
weightSum += weight;
float2 o_uv = saturate((screen_coord + (blur_dir * i)) / (screen_size / res_scale));
float4 s = source.SampleLevel(s0, o_uv, 0);
color += s * weight;
}
return color;
}
float4 GetBlurFactorQES(float2 screen_coord)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
float2 blur_dir = float2(0.0f, 1.0f);
float r_sigma = 3.0f;
float4 color = 0;
float weightSum = 0.0f;
for (int i = -7; i < 7; i++)
{
float weight = CalcGaussianWeight(i, r_sigma);
weightSum += weight;
float4 s = source_qes[screen_coord + blur_dir * i].rgba;
color += s * weight;
}
return color;
}
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y) + 0.5f;
float4 color = 0;
if (screen_coord.x > screen_size.x)
{
color = GetBlurFactorQES(screen_coord - screen_size);
output_qes[screen_coord - int2(screen_size)] = color;
}
else
{
color = GetBlurFactor(screen_coord, 1.0f);
output[screen_coord] = color;
}
}
#endif //__PP_BLOOM_BLUR_VERTICAL_HLSL__
================================================
FILE: resources/shaders/pp_bloom_composition.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_BLOOM_COMPOSITION_HLSL__
#define __PP_BLOOM_COMPOSITION_HLSL__
#include "pp_hdr_util.hlsl"
Texture2D source_main : register(t0);
Texture2D source_bloom_half : register(t1);
Texture2D source_bloom_qes : register(t2);
RWTexture2D output : register(u0);
SamplerState linear_sampler : register(s0);
SamplerState point_sampler : register(s1);
cbuffer Bloomproperties : register(b0)
{
int enable_bloom;
};
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y) + 0.5f;
float2 texel_size = 1.0f / screen_size;
float2 uv = screen_coord / screen_size;
float2 uv_half = (screen_coord / 2 ) / screen_size;
float2 uv_quarter = (screen_coord / 4) / screen_size + 0.5f;
float2 uv_eighth = (screen_coord / 8) / screen_size + 0.75f;
float3 finalcolor = float3(0, 0, 0);
float bloom_intensity = 1.f;
if (enable_bloom > 0)
{
finalcolor += source_bloom_half.SampleLevel(linear_sampler, uv, 0).rgb;
finalcolor += source_bloom_qes.SampleLevel(linear_sampler, uv_half, 0).rgb;
finalcolor += source_bloom_qes.SampleLevel(linear_sampler, uv_quarter, 0).rgb;
finalcolor += source_bloom_qes.SampleLevel(linear_sampler, uv_eighth, 0).rgb;
finalcolor *= 0.25f;
}
finalcolor += source_main.SampleLevel(point_sampler, uv, 0).rgb;
output[int2(dispatch_thread_id.xy)] = float4(finalcolor, 1.0f);
}
#endif //__PP_BLOOM_COMPOSITION_HLSL__
================================================
FILE: resources/shaders/pp_bloom_extract_bright.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_BLOOM_EXTRACT_BRIGHT_HLSL__
#define __PP_BLOOM_EXTRACT_BRIGHT_HLSL__
#include "pp_dof_util.hlsl"
Texture2D source : register(t0);
Texture2D g_emissive : register(t1);
Texture2D g_depth : register(t2);
RWTexture2D output_bright : register(u0);
SamplerState s0 : register(s0);
SamplerState s1 : register(s1);
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output_bright.GetDimensions(screen_size.x, screen_size.y);
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y) + 0.5f;
float2 uv = screen_coord / screen_size;
float4 out_bright = float4(0.0f, 0.0f, 0.0f, 1.0f);
float3 final_color = source.SampleLevel(s1, uv, 0).rgb;
float brightness = dot(final_color, float3(0.2126f, 0.7152f, 0.0722f));
for (int i = -1; i < 2; ++i)
{
uv = float2(screen_coord.x + i, screen_coord.y + i) / screen_size;
if (brightness > 1.0f && g_depth.SampleLevel(s1, uv, 0).r < 1)
{
out_bright = saturate(float4(final_color, 1.0f));
}
out_bright += float4(g_emissive.SampleLevel(s0, uv, 0).rgb, 1.0f);
}
out_bright /= 3;
output_bright[int2(dispatch_thread_id.xy)] = out_bright;
}
#endif //__PP_BLOOM_EXTRACT_BRIGHT_HLSL__
================================================
FILE: resources/shaders/pp_bloom_util.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_BLOOM_UTIL_HLSL__
#define __PP_BLOOM_UTIL_HLSL__
static const float gaussian_weights[15] = { 0.023089f, 0.034587f, 0.048689f, 0.064408f, 0.080066f, 0.093531f, 0.102673f, 0.105915f, 0.102673f, 0.093531f, 0.080066f, 0.064408f, 0.048689f, 0.034587f, 0.023089f };
#endif //__PP_BLOOM_UTIL_HLSL__
================================================
FILE: resources/shaders/pp_dof_bokeh.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_DOF_BOKEH_HLSL__
#define __PP_DOF_BOKEH_HLSL__
#include "pp_dof_properties.hlsl"
#include "pp_dof_util.hlsl"
Texture2D source_near : register(t0);
Texture2D source_far : register(t1);
Texture2D near_mask :register(t2);
RWTexture2D output_near : register(u0);
RWTexture2D output_far : register(u1);
SamplerState s0 : register(s0);
SamplerState s1 : register(s1);
cbuffer CameraProperties : register(b0)
{
float f_number;
float shape_curve;
float bokeh_poly_amount;
uint num_blades;
float m_padding;
float2 m_bokeh_shape_modifier;
int enable_dof;
};
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
source_near.GetDimensions(screen_size.x, screen_size.y);
screen_size -= 1.0f;
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y);
float2 texel_size = 1.0f / screen_size;
float2 uv = screen_coord / (screen_size) ;
const uint NUMSAMPLES = NUMDOFSAMPLES * NUMDOFSAMPLES;
const float MAXKERNELSIZE = MAXBOKEHSIZE * 0.5f;
const float SHAPECURVE = 2.0f;
float4 fgcolor = float4(0, 0, 0, 0);
float4 bgcolor = float4(0, 0, 0, 0);
//Kernel gather method credits to Matt Pettineo and David Neubelt.
if (enable_dof > 0)
{
float far_coc = source_far.SampleLevel(s1, uv, 0).w;
float near_coc = source_near.SampleLevel(s1, uv, 0).w;
float kernel_radius = MAXKERNELSIZE * far_coc;
[branch]
if (kernel_radius > 0.5f)
{
float weightsum = 0.0001f;
[unroll]
for (uint i = 0; i < NUMSAMPLES; ++i)
{
float lensX = saturate((i % NUMDOFSAMPLES) / max(NUMDOFSAMPLES - 1.0f, 1.0f));
float lensY = saturate((i / NUMDOFSAMPLES) / max(NUMDOFSAMPLES - 1.0f, 1.0f));
float2 kernel_offset = SquareToConcentricDiskMapping(lensX, lensY, float(num_blades), bokeh_poly_amount) * m_bokeh_shape_modifier;
float4 s = source_far.SampleLevel(s0, (screen_coord + kernel_offset * kernel_radius) / screen_size, 0.0f);
float samplecoc = s.w;
s *= saturate(1.0f + (samplecoc - far_coc));
s *= (1.0f - shape_curve) + pow(max(length(kernel_offset), 0.01f), SHAPECURVE) * shape_curve;
bgcolor += s;
}
bgcolor /= NUMSAMPLES;
}
else
{
bgcolor = source_far.SampleLevel(s0, uv, 0);
}
float nearMask = SampleTextureBSpline(near_mask, s0, uv).x;
nearMask = saturate(nearMask * 1.0f);
near_coc = max(near_coc, nearMask);
kernel_radius = near_coc * MAXKERNELSIZE;
[branch]
if (kernel_radius > 0.25f)
{
float weightsum = 0.0001f;
[unroll]
for (uint i = 0; i < NUMSAMPLES; ++i)
{
float lensX = saturate((i % NUMDOFSAMPLES) / max(NUMDOFSAMPLES - 1.0f, 1.0f));
float lensY = saturate((i / NUMDOFSAMPLES) / max(NUMDOFSAMPLES - 1.0f, 1.0f));
float2 kernel_offset = SquareToConcentricDiskMapping(lensX, lensY, float(num_blades), bokeh_poly_amount) * m_bokeh_shape_modifier;
float4 s = source_near.SampleLevel(s0, (screen_coord + kernel_offset * kernel_radius) / screen_size , 0.0f);
float samplecoc = saturate(s.w * MAXKERNELSIZE);
fgcolor.xyz += s.xyz * s.w;
float samplealpha = 1.0f;
samplealpha *= saturate(s.w * 1.0f);
fgcolor.w += samplealpha;
weightsum += s.w;
}
fgcolor.xyz /= weightsum;
fgcolor.w = saturate(fgcolor.w * (1.0f / NUMSAMPLES));
fgcolor.w = max(fgcolor.w, source_near.SampleLevel(s0, uv, 0).w);
}
else
{
fgcolor = float4(source_near.SampleLevel(s1, uv, 0).rgb, 0.0f);
}
}
output_near[int2(dispatch_thread_id.xy)] = fgcolor;
output_far[int2(dispatch_thread_id.xy)] = bgcolor;
}
#endif //__PP_DOF_BOKEH_HLSL__
================================================
FILE: resources/shaders/pp_dof_bokeh_post_filter.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_DOF_BOKEH_POST_FILTER_HLSL__
#define __PP_DOF_BOKEH_POST_FILTER_HLSL__
Texture2D source_near : register(t0);
Texture2D source_far : register(t1);
RWTexture2D output_near : register(u0);
RWTexture2D output_far : register(u1);
SamplerState s0 : register(s0);
SamplerState s1 : register(s1);
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output_near.GetDimensions(screen_size.x, screen_size.y);
screen_size -= 1.0f;
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y);
float2 uv = screen_coord / screen_size;
float nearcoc = source_near.SampleLevel(s1, uv, 0).a;
float farcoc = source_far.SampleLevel(s1, uv, 0).a;
static const int SampleRadius = 2;
static const int SampleDiameter = SampleRadius * 2 + 1;
float3 near_color = 0;
float3 far_color = 0;
[unroll]
for (int y = -SampleRadius; y <= SampleRadius; ++y)
{
[unroll]
for (int x = -SampleRadius; x <= SampleRadius; ++x)
{
near_color += source_near.SampleLevel(s0, (screen_coord + float2(x, y)) / screen_size, 0).rgb;
far_color += source_far.SampleLevel(s0, (screen_coord + float2(x, y)) / screen_size, 0).rgb;
}
}
near_color /= float(SampleDiameter * SampleDiameter);
far_color /= float(SampleDiameter * SampleDiameter);
output_near[int2(dispatch_thread_id.xy)] = float4(near_color, nearcoc);
output_far[int2(dispatch_thread_id.xy)] = float4(far_color, farcoc);
}
#endif //__PP_DOF_BOKEH_POST_FILTER_HLSL__
================================================
FILE: resources/shaders/pp_dof_coc.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_DOF_COC_HLSL__
#define __PP_DOF_COC_HLSL__
#include "pp_dof_properties.hlsl"
#include "pp_dof_util.hlsl"
Texture2D gbuffer_depth : register(t0);
RWTexture2D output : register(u0);
SamplerState s0 : register(s0);
cbuffer CameraProperties : register(b0)
{
float4x4 projection;
float focal_length;
float f_number;
float film_size;
float focus_dist;
float2 m_pad;
int enable_dof;
float dof_range;
};
float GetCoC(float lineardepth, float focusdist)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
float fstop = focal_length / f_number * 0.5f;
////// Compute CoC in meters
float coc = -fstop * (focal_length * (focusdist - lineardepth)) / (lineardepth * (focusdist - focal_length));
//// Convert to pixels
coc = (coc / film_size) * screen_size.x;
coc = clamp(coc / (MAXCOCSIZE * dof_range), -1.f, 1.f);
return coc;
}
float GetAutoFocusDepth(float2 screen_dimensions)
{
float depth_focus = gbuffer_depth[float2(0.5f * screen_dimensions.x, 0.5f * screen_dimensions.y)].r;
depth_focus += gbuffer_depth[float2(0.51f * screen_dimensions.x, 0.51f * screen_dimensions.y)].r;
depth_focus += gbuffer_depth[float2(0.49f * screen_dimensions.x, 0.51f * screen_dimensions.y)].r;
depth_focus += gbuffer_depth[float2(0.51f * screen_dimensions.x, 0.49f * screen_dimensions.y)].r;
depth_focus += gbuffer_depth[float2(0.49f * screen_dimensions.x, 0.49f * screen_dimensions.y)].r;
depth_focus += gbuffer_depth[float2(0.52f * screen_dimensions.x, 0.52f * screen_dimensions.y)].r;
depth_focus += gbuffer_depth[float2(0.48f * screen_dimensions.x, 0.52f * screen_dimensions.y)].r;
depth_focus += gbuffer_depth[float2(0.52f * screen_dimensions.x, 0.48f * screen_dimensions.y)].r;
depth_focus += gbuffer_depth[float2(0.48f * screen_dimensions.x, 0.48f * screen_dimensions.y)].r;
depth_focus = (depth_focus / 9.0f);
return depth_focus;
}
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
screen_size -= 1.0f;
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y);
float2 uv = screen_coord / screen_size;
float sample_depth = gbuffer_depth.SampleLevel(s0, uv, 0).r;
float focus_depth = GetAutoFocusDepth(screen_size);
sample_depth = GetLinearDepth(sample_depth) * FFAR;
float coc = GetCoC(sample_depth, focus_dist);
if (focus_dist < 1)
{
focus_depth = GetLinearDepth(focus_depth) * FFAR;
coc = GetCoC(sample_depth, focus_depth);
}
if (enable_dof == 0)
{
coc = 0.0f;
}
float2 result = float2(coc, gbuffer_depth.SampleLevel(s0, uv, 0).r);
output[int2(dispatch_thread_id.xy)] = result;
}
#endif //__PP_DOF_COC_HLSL__
================================================
FILE: resources/shaders/pp_dof_composition.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_DOF_COMPOSITION_HLSL__
#define __PP_DOF_COMPOSITION_HLSL__
#include "pp_dof_properties.hlsl"
Texture2D source : register(t0);
RWTexture2D output : register(u0);
Texture2D bokeh_near : register(t1);
Texture2D bokeh_far : register(t2);
Texture2D coc_buffer : register(t3);
SamplerState s0 : register(s0);
SamplerState s1 : register(s1);
float GetDownSampledCoC(float2 uv , float2 texel_size)
{
float4 offset = texel_size.xyxy * float2(-0.5f, 0.5f).xxyy;
float coc0 = coc_buffer.SampleLevel(s1, uv + offset.xy, 0);
float coc1 = coc_buffer.SampleLevel(s1, uv + offset.zy, 0);
float coc2 = coc_buffer.SampleLevel(s1, uv + offset.xw, 0);
float coc3 = coc_buffer.SampleLevel(s1, uv + offset.zw, 0);
float coc_min = min(min(min(coc0, coc1), coc2), coc3);
float coc_max = max(max(max(coc0, coc1), coc2), coc3);
float coc = coc_max >= -coc_min ? coc_max : coc_min;
return coc;
}
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output.GetDimensions(screen_size.x, screen_size.y);
screen_size -= 1.0f;
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y);
float2 texel_size = 1.0 / screen_size;
float2 uv = (screen_coord) / (screen_size);
float coc = coc_buffer.SampleLevel(s0, uv, 0);
float3 original_sample = source.SampleLevel(s0, uv, 0).rgb;
float4 near_sample = bokeh_near.SampleLevel(s1, uv, 0);
float4 far_sample = bokeh_far.SampleLevel(s1, uv, 0);
float near_w = bokeh_near.SampleLevel(s0, uv, 0).a;
float3 near = near_sample.rgb;
float3 far = original_sample.rgb;
if (far_sample.w > 0.0f)
{
far = far_sample.rgb / far_sample.w;
}
float far_blend = saturate(saturate(coc) * MAXCOCSIZE - 0.5f);
float3 result = lerp(original_sample, far.rgb, far_blend);
float near_blend = saturate(near_sample.w * 2.0f);
result = lerp(result, near.rgb, smoothstep(0.0f, 1.0f, near_blend));
output[int2(dispatch_thread_id.xy)] = float4(result, coc);
}
#endif //__PP_DOF_COMPOSITION_HLSL__
================================================
FILE: resources/shaders/pp_dof_compute_near_mask.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//=================================================================================================
//
// Baking Lab
// by MJP and David Neubelt
// http://mynameismjp.wordpress.com/
//
// All code licensed under the MIT license
//
//=================================================================================================
#ifndef __PP_DOF_COMPUTE_NEAR_MASK_HLSL__
#define __PP_DOF_COMPUTE_NEAR_MASK_HLSL__
#include "pp_dof_properties.hlsl"
#include "pp_dof_util.hlsl"
Texture2D input : register(t0);
RWTexture2D output : register(u0);
SamplerState s0 : register(s0);
//=================================================================================================
// Constants
//=================================================================================================
static const uint NumThreads = 16 * 16;
// -- shared memory
groupshared float Samples[NumThreads];
//=================================================================================================
// Computes a downscaled mask for the near field
//=================================================================================================
[numthreads(32, 32, 1)]
void main_cs(in uint3 GroupID : SV_GroupID, in uint3 GroupThreadID : SV_GroupThreadID,
in uint ThreadIndex : SV_GroupIndex)
{
uint2 textureSize;
input.GetDimensions(textureSize.x, textureSize.y);
uint2 samplePos = GroupID.xy * 16 + GroupThreadID.xy;
samplePos = min(samplePos, textureSize - 1);
float cocSample = input[samplePos].w;
// -- store in shared memory
Samples[ThreadIndex] = cocSample;
GroupMemoryBarrierWithGroupSync();
// -- reduce
[unroll]
for (uint s = NumThreads / 2; s > 0; s >>= 1)
{
if (ThreadIndex < s)
Samples[ThreadIndex] = max(Samples[ThreadIndex], Samples[ThreadIndex + s]);
GroupMemoryBarrierWithGroupSync();
}
if (ThreadIndex == 0)
output[GroupID.xy] = Samples[0];
}
#endif //__PP_DOF_COC_HLSL__
================================================
FILE: resources/shaders/pp_dof_dilate.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_DOF_DILATE_HLSL__
#define __PP_DOF_DILATE_HLSL__
#include "pp_dof_properties.hlsl"
#include "pp_dof_util.hlsl"
Texture2D source_near : register(t0);
RWTexture2D output_near : register(u0);
SamplerState s0 : register(s0);
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output_near.GetDimensions(screen_size.x, screen_size.y);
screen_size -= 1.0f;
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y);
float2 uv = (screen_coord) / screen_size;
static const int sample_radius = 3;
float output = source_near.SampleLevel(s0, uv , 0).r;
[unroll]
for (int y = -sample_radius; y <= sample_radius; ++y)
{
[unroll]
for (int x = -sample_radius; x <= sample_radius; ++x)
{
output = max(output, source_near.SampleLevel(s0, saturate((screen_coord + float2(x, y)) / screen_size), 0).r);
}
}
output_near[int2(dispatch_thread_id.xy)] = output;
}
#endif //__PP_DOF_DILATE_HLSL__
================================================
FILE: resources/shaders/pp_dof_downscale.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_DOF_DOWNSCALE_HLSL__
#define __PP_DOF_DOWNSCALE_HLSL__
#include "pp_dof_util.hlsl"
Texture2D source : register(t0);
RWTexture2D output_near : register(u0);
RWTexture2D output_far : register(u1);
Texture2D cocbuffer : register(t1);
SamplerState s0 : register(s0);
SamplerState s1 : register(s1);
float GetDownSampledCoC(float2 uv, float2 texelSize)
{
float4 offset = texelSize.xyxy * float2(-0.5f, 0.5f).xxyy;
float coc0 = cocbuffer.SampleLevel(s1, uv + offset.xy, 0).r;
float coc1 = cocbuffer.SampleLevel(s1, uv + offset.zy, 0).r;
float coc2 = cocbuffer.SampleLevel(s1, uv + offset.xw, 0).r;
float coc3 = cocbuffer.SampleLevel(s1, uv + offset.zw, 0).r;
float coc4 = cocbuffer.SampleLevel(s1, uv, 0).r;
float cocMin = min(min(min(coc0, coc1), coc2), coc3);
float cocMax = max(max(max(coc0, coc1), coc2), coc3);
float coc = cocMax >= -cocMin ? cocMax : cocMin;
return coc;
}
[numthreads(16, 16, 1)]
void main_cs(int3 dispatch_thread_id : SV_DispatchThreadID)
{
float2 screen_size = float2(0.f, 0.f);
output_far.GetDimensions(screen_size.x, screen_size.y);
screen_size -= 1.0f;
float2 screen_coord = int2(dispatch_thread_id.x, dispatch_thread_id.y);
float2 texel_size = 1.0f / screen_size;
float4 offset = texel_size.xyxy * float2(-0.5f, 0.5f).xxyy;
float2 uv = screen_coord / (screen_size);
float3 source11 = source.SampleLevel(s0, uv, 0).rgb;
float3 source0 = source.SampleLevel(s0, uv + offset.xy, 0).rgb;
float3 source1 = source.SampleLevel(s0, uv + offset.zy, 0).rgb;
float3 source2 = source.SampleLevel(s0, uv + offset.xw, 0).rgb;
float3 source3 = source.SampleLevel(s0, uv + offset.zw, 0).rgb;
float3 finalcolor = (source11 + source0 + source1 + source2 + source3) * 0.2f;
finalcolor = source.SampleLevel(s0, uv, 0).rgb;
float coc = GetDownSampledCoC(uv, texel_size);
float4 out_near = max(0,float4(finalcolor, 1.0f) * max(-coc, 0.0f));
out_near.rgb = finalcolor;
coc = cocbuffer.SampleLevel(s1, uv, 0).r;
float4 out_far = max(0,float4(finalcolor, 1.0f) * max(coc, 0.0f));
output_near[int2(dispatch_thread_id.xy)] = out_near;
output_far[int2(dispatch_thread_id.xy)] = out_far;
}
#endif //__PP_DOF_DOWNSCALE_HLSL__
================================================
FILE: resources/shaders/pp_dof_properties.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_DOF_PROPERTIES_HLSL__
#define __PP_DOF_PROPERTIES_HLSL__
static const float MAXBOKEHSIZE = 21.f;
static const float MAXCOCSIZE = 4.0f;
static const uint NUMDOFSAMPLES = 9;
#endif //__PP_DOF_PROPERTIES_HLSL__
================================================
FILE: resources/shaders/pp_dof_util.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_DOF_UTIL_HLSL__
#define __PP_DOF_UTIL_HLSL__
static const float FNEAR = 0.1f;
static const float FFAR = 10000.f;
static const float PI = 3.141592654f;
static const float PI2 = 6.283185308f;
float WeighCoC(float coc, float radius)
{
//return coc >= radius;
return saturate((coc - radius + 2) / 2);
}
float WeighColor(float3 color)
{
return 1 / (1 + max(max(color.r, color.g), color.b));
}
float GetLinearDepth(float depth)
{
float z = (2 * FNEAR) / (FFAR + FNEAR - (depth * (FFAR - FNEAR)));
return z;
}
// Calculates the gaussian blur weight for a given distance and sigmas
float CalcGaussianWeight(int sampleDist, float sigma)
{
float g = 1.0f / sqrt(2.0f * 3.14159 * sigma * sigma);
return (g * exp(-(sampleDist * sampleDist) / (2 * sigma * sigma)));
}
// ------------------------------------------------------------------------------------------------
// Samples a texture with B-spline (bicubic) filtering
// ------------------------------------------------------------------------------------------------
float4 SampleTextureBSpline(in Texture2D textureMap, in SamplerState linearSampler, in float2 uv) {
float2 texSize;
textureMap.GetDimensions(texSize.x, texSize.y);
float2 invTexSize = 1.0f / texSize;
float2 a = frac(uv * texSize - 0.5f);
float2 a2 = a * a;
float2 a3 = a2 * a;
float2 w0 = (1.0f / 6.0f) * (-a3 + 3 * a2 - 3 * a + 1);
float2 w1 = (1.0f / 6.0f) * (3 * a3 - 6 * a2 + 4);
float2 w2 = (1.0f / 6.0f) * (-3 * a3 + 3 * a2 + 3 * a + 1);
float2 w3 = (1.0f / 6.0f) * a3;
float2 g0 = w0 + w1;
float2 g1 = w2 + w3;
float2 h0 = 1.0f - (w1 / (w0 + w1)) + a;
float2 h1 = 1.0f - (w3 / (w2 + w3)) - a;
float2 ex = float2(invTexSize.x, 0.0f);
float2 ey = float2(0.0f, invTexSize.y);
w0 = 0.5f;
w1 = 0.5f;
g0 = 0.5f;
float2 uv10 = uv + h0.x * ex;
float2 uv00 = uv - h1.x * ex;
float2 uv11 = uv10 + h0.y * ey;
float2 uv01 = uv00 + h0.y * ey;
uv10 = uv10 - h1.y * ey;
uv00 = uv00 - h1.y * ey;
uv00 = uv + float2(-0.75f, -0.75f) * invTexSize;
uv10 = uv + float2(0.75f, -0.75f) * invTexSize;
uv01 = uv + float2(-0.75f, 0.75f) * invTexSize;
uv11 = uv + float2(0.75f, 0.75f) * invTexSize;
float4 sample00 = textureMap.SampleLevel(linearSampler, uv00, 0.0f);
float4 sample10 = textureMap.SampleLevel(linearSampler, uv10, 0.0f);
float4 sample01 = textureMap.SampleLevel(linearSampler, uv01, 0.0f);
float4 sample11 = textureMap.SampleLevel(linearSampler, uv11, 0.0f);
sample00 = lerp(sample00, sample01, g0.y);
sample10 = lerp(sample10, sample11, g0.y);
return lerp(sample00, sample10, g0.x);
}
// Maps a value inside the square [0,1]x[0,1] to a value in a disk of radius 1 using concentric squares.
// This mapPIng preserves area, bi continuity, and minimizes deformation.
// Based off the algorithm "A Low Distortion Map Between Disk and Square" by Peter Shirley and
// Kenneth Chiu. Also includes polygon morphing modification from "CryEngine3 Graphics Gems"
// by Tiago Sousa
float2 SquareToConcentricDiskMapping(float x, float y, float numSides, float polygonAmount)
{
float phi, r;
// -- (a,b) is now on [-1,1]2
float a = 2.0f * x - 1.0f;
float b = 2.0f * y - 1.0f;
if (a > -b) // region 1 or 2
{
if (a > b) // region 1, also |a| > |b|
{
r = a;
phi = (PI / 4.0f) * (b / a);
}
else // region 2, also |b| > |a|
{
r = b;
phi = (PI / 4.0f) * (2.0f - (a / b));
}
}
else // region 3 or 4
{
if (a < b) // region 3, also |a| >= |b|, a != 0
{
r = -a;
phi = (PI / 4.0f) * (4.0f + (b / a));
}
else // region 4, |b| >= |a|, but a==0 and b==0 could occur.
{
r = -b;
if (abs(b) > 0.0f)
phi = (PI / 4.0f) * (6.0f - (a / b));
else
phi = 0;
}
}
const float N = numSides;
float polyModifier = cos(PI / N) / cos(phi - (PI2 / N) * floor((N * phi + PI) / PI2));
r *= lerp(1.0f, polyModifier, polygonAmount);
float2 result;
result.x = r * cos(phi);
result.y = r * sin(phi);
return result;
}
#endif //__PP_DOF_UTIL_HLSL__
================================================
FILE: resources/shaders/pp_fxaa.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_FXAA_HLSL__
#define __PP_FXAA_HLSL__
#ifndef FXAA_REDUCE_MIN
#define FXAA_REDUCE_MIN (1.0/ 128.0)
#endif
#ifndef FXAA_REDUCE_MUL
#define FXAA_REDUCE_MUL (1.0 / 8.0)
#endif
#ifndef FXAA_SPAN_MAX
#define FXAA_SPAN_MAX 8.0
#endif
//optimized version for mobile, where dependent
//texture reads can be a bottleneck
float4 fxaa(Texture2D tex, SamplerState s, float2 fragCoord, float2 resolution,
float2 v_rgbNW, float2 v_rgbNE,
float2 v_rgbSW, float2 v_rgbSE,
float2 v_rgbM) {
float4 color;
float2 inverseVP = float2(1.0 / resolution.x, 1.0 / resolution.y);
float3 rgbNW = tex.SampleLevel(s, v_rgbNW, 0).xyz;
float3 rgbNE = tex.SampleLevel(s, v_rgbNE, 0).xyz;
float3 rgbSW = tex.SampleLevel(s, v_rgbSW, 0).xyz;
float3 rgbSE = tex.SampleLevel(s, v_rgbSE, 0).xyz;
float4 texColor = tex.SampleLevel(s, v_rgbM, 0);
float3 rgbM = texColor.xyz;
float3 luma = float3(0.299, 0.587, 0.114);
float lumaNW = dot(rgbNW, luma);
float lumaNE = dot(rgbNE, luma);
float lumaSW = dot(rgbSW, luma);
float lumaSE = dot(rgbSE, luma);
float lumaM = dot(rgbM, luma);
float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
float2 dir;
dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *
(0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);
float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
dir = min(float2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
max(float2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
dir * rcpDirMin)) * inverseVP;
float3 rgbA = 0.5 * (
tex.SampleLevel(s, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5), 0).xyz +
tex.SampleLevel(s, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5), 0).xyz);
float3 rgbB = rgbA * 0.5 + 0.25 * (
tex.SampleLevel(s, fragCoord * inverseVP + dir * -0.5, 0).xyz +
tex.SampleLevel(s, fragCoord * inverseVP + dir * 0.5, 0).xyz);
float lumaB = dot(rgbB, luma);
if ((lumaB < lumaMin) || (lumaB > lumaMax))
color = float4(rgbA, texColor.a);
else
color = float4(rgbB, texColor.a);
return color;
}
void texcoords(float2 fragCoord, float2 resolution,
out float2 v_rgbNW, out float2 v_rgbNE,
out float2 v_rgbSW, out float2 v_rgbSE,
out float2 v_rgbM) {
float2 inverseVP = 1.0 / resolution.xy;
v_rgbNW = (fragCoord + float2(-1.0, -1.0)) * inverseVP;
v_rgbNE = (fragCoord + float2(1.0, -1.0)) * inverseVP;
v_rgbSW = (fragCoord + float2(-1.0, 1.0)) * inverseVP;
v_rgbSE = (fragCoord + float2(1.0, 1.0)) * inverseVP;
v_rgbM = float2(fragCoord * inverseVP);
}
float4 SampleFXAA(Texture2D tex, SamplerState s, float2 frag_coord, float2 resolution)
{
float2 v_rgbNW;
float2 v_rgbNE;
float2 v_rgbSW;
float2 v_rgbSE;
float2 v_rgbM;
texcoords(frag_coord, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);
return fxaa(tex, s, frag_coord, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);
}
#endif //__PP_FXAA_HLSL__
================================================
FILE: resources/shaders/pp_hdr_util.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_HDR_UTIL_HLSL__
#define __PP_HDR_UTIL_HLSL__
float3 linearToneMapping(float3 color, float exposure, float gamma)
{
color = clamp(exposure * color, 0.f, 1.f);
color = pow(color, 1.f / gamma);
return color;
}
float3 simpleReinhardToneMapping(float3 color, float exposure, float gamma)
{
color *= exposure / (1. + color / exposure);
color = pow(color, 1. / gamma);
return color;
}
float3 lumaBasedReinhardToneMapping(float3 color, float gamma)
{
float luma = dot(color, float3(0.2126, 0.7152, 0.0722));
float toneMappedLuma = luma / (1. + luma);
color *= toneMappedLuma / luma;
color = pow(color, (1. / gamma));
return color;
}
float3 whitePreservingLumaBasedReinhardToneMapping(float3 color, float gamma)
{
float white = 2.;
float luma = dot(color, float3(0.2126, 0.7152, 0.0722));
float toneMappedLuma = luma * (1. + luma / (white*white)) / (1. + luma);
color *= toneMappedLuma / luma;
color = pow(color, (1. / gamma));
return color;
}
float3 RomBinDaHouseToneMapping(float3 color, float gamma)
{
color = exp(-1.0 / (2.72*color + 0.15));
color = pow(color, (1. / gamma));
return color;
}
float3 filmicToneMapping(float3 color)
{
color = max(float3(0., 0., 0.), color - float3(0.004, 0.004, 0.004));
color = (color * (6.2 * color + .5)) / (color * (6.2 * color + 1.7) + 0.06);
return color;
}
float3 GrayscaleToneMapping(float3 color) {
float gray = 0.299 * color.r + 0.587 * color.g + 0.114 * color.b;
color.r = gray;
color.g = gray;
color.b = gray;
return color;
}
float3 ACESToneMapping(float3 color, float exposure, float gamma)
{
color = clamp(exposure * color, 0.f, 1.f);
color = pow(color, 1.f / gamma);
float a = 2.51f;
float b = 0.03f;
float c = 2.43f;
float d = 0.59f;
float e = 0.14f;
return saturate((color*(a*color+b))/(color*(c*color+d)+e));
}
float3 Uncharted2ToneMapping(float3 color, float gamma, float exposure)
{
float A = 0.15;
float B = 0.50;
float C = 0.10;
float D = 0.20;
float E = 0.02;
float F = 0.30;
float W = 11.2;
color *= exposure;
color = (((color*2) * (A * (color*2) + C * B) + D * E) / ((color*2) * (A * (color*2) + B) + D * F)) - E / F;
float white = ((W * (A * W + C * B) + D * E) / (W * (A * W + B) + D * F)) - E / F;
color /= white;
color = pow(color, (1. / gamma));
return color;
}
float4x4 brightnessMatrix(float brightness)
{
return float4x4(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
brightness, brightness, brightness, 1);
}
float3 ApplyHue(float3 color, float hue_in) {
float3 result = color;
const float4 kRGBToYPrime = float4(0.299, 0.587, 0.114, 0.0);
const float4 kRGBToI = float4(0.596, -0.275, -0.321, 0.0);
const float4 kRGBToQ = float4(0.212, -0.523, 0.311, 0.0);
const float4 kYIQToR = float4(1.0, 0.956, 0.621, 0.0);
const float4 kYIQToG = float4(1.0, -0.272, -0.647, 0.0);
const float4 kYIQToB = float4(1.0, -1.107, 1.704, 0.0);
float YPrime = dot(color, kRGBToYPrime);
float I = dot(color, kRGBToI);
float Q = dot(color, kRGBToQ);
float hue = atan2(Q, I);
float chroma = sqrt(I * I + Q * Q);
hue += hue_in;
Q = chroma * sin(hue);
I = chroma * cos(hue);
float4 yIQ = float4(YPrime, I, Q, 0.0);
result.r = dot(yIQ, kYIQToR);
result.g = dot(yIQ, kYIQToG);
result.b = dot(yIQ, kYIQToB);
return result;
}
float4x4 ContrastMatrix(float contrast)
{
float t = (1.0 - contrast) / 2.0;
return float4x4(contrast, 0, 0, 0,
0, contrast, 0, 0,
0, 0, contrast, 0,
t, t, t, 1);
}
float3 AllTonemappingAlgorithms(float3 color, float rotation, float exposure, float gamma) {
float3 result = color;
float n = 8;
int i = int(n * (rotation / 2));
if (i == 0) result = linearToneMapping(color, exposure, gamma);
if (i == 1) result = simpleReinhardToneMapping(color, exposure, gamma);
if (i == 2) result = lumaBasedReinhardToneMapping(color, gamma);
if (i == 3) result = whitePreservingLumaBasedReinhardToneMapping(color, gamma);
if (i == 4) result = RomBinDaHouseToneMapping(color, gamma);
if (i == 5) result = filmicToneMapping(color);
if (i == 6) result = ACESToneMapping(color, exposure, gamma);
if (i == 7) result = Uncharted2ToneMapping(color, gamma, exposure);
if (i == 8) result = GrayscaleToneMapping(color);
return result;
}
#endif //__PP_HDR_UTIL_HLSL__
================================================
FILE: resources/shaders/pp_tonemapping.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_TONEMAPPING_HLSL__
#define __PP_TONEMAPPING_HLSL__
#include "pp_util.hlsl"
#include "pp_hdr_util.hlsl"
Texture2D input : register(t0);
RWTexture2D output : register(u0);
SamplerState s0 : register(s0);
cbuffer CameraProperties : register(b0)
{
float hdr;
};
[numthreads(16, 16, 1)]
void main(uint3 DTid : SV_DispatchThreadID)
{
float2 resolution;
input.GetDimensions(resolution.x, resolution.y);
float2 uv = (float2(DTid.xy + 0.5f) / resolution);
float gamma = 2.2;
float exposure = 1;
float3 color = input.SampleLevel(s0, uv, 0).rgb;
//color = SampleFXAA(input, s0, DTid.xy + 0.5f, resolution);
//uv = ZoomUV(uv, 0.75);
//float3 color = input.SampleLevel(s0, BarrelDistortUV(uv, 2), 0);
//float3 color = ChromaticAberrationV2(input, s0, uv, 0.2, 0.96f).rgb;
if (hdr == 0)
{
//color = linearToneMapping(color, exposure, gamma);
//color = simpleReinhardToneMapping(color, exposure, gamma);
//color = lumaBasedReinhardToneMapping(color, gamma);
//color = whitePreservingLumaBasedReinhardToneMapping(color, gamma);
//color = RomBinDaHouseToneMapping(color, gamma);
//color = filmicToneMapping(color);
//color = Uncharted2ToneMapping(color, gamma, exposure);
//color = GrayscaleToneMapping(color);
color = ACESToneMapping(color, exposure, gamma);
//color = AllTonemappingAlgorithms(color.rgb, uv.x + uv.y, exposure, gamma);
//color = Vignette(color, uv, 1.5, 0.5, 0.5);
}
output[DTid.xy] = float4(color, 1);
}
#endif //__PP_TONEMAPPING_HLSL__
================================================
FILE: resources/shaders/pp_util.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __PP_UTIL_HLSL__
#define __PP_UTIL_HLSL__
#include "pp_fxaa.hlsl"
#include "math.hlsl"
float3 Vignette(float3 input, float2 pos, float radius, float softness, float strength)
{
float len = length(pos * 2 - 1);
float vignette = smoothstep(radius, radius - softness, len);
return lerp(input, input * vignette, strength);
}
// Old lens_effects.hlsl file
float2 barrelDistortion(float2 coord, float amt) {
float2 cc = coord - 0.5;
float dist = dot(cc, cc);
return coord + cc * dist * amt;
}
static const int num_iter = 11;
static const float reci_num_iter_f = 1.0 / float(num_iter);
// Old naive chromatic aberration.
float4 ChromaticAberration(Texture2D tex, SamplerState s, float2 uv, float strength) {
float2 r_offset = float2(strength, 0);
float2 g_offset = float2(-strength, 0);
float2 b_offset = float2(0, 0);
float4 r = float4(1, 1, 1, 1);
r.x = tex.SampleLevel(s, uv + r_offset, 0).x;
r.y = tex.SampleLevel(s, uv + g_offset, 0).y;
r.z = tex.SampleLevel(s, uv + b_offset, 0).z;
r.a = tex.SampleLevel(s, uv, 0).a;
return r;
}
// Zoom into a image.
float2 ZoomUV(float2 uv, float zoom)
{
return (uv * zoom) + ((1 - (zoom)) / 2);
}
float4 ChromaticAberrationV2(Texture2D tex, SamplerState s, float2 uv, float strength, float zoom) {
uv = ZoomUV(uv, zoom);
float4 sumcol = 0.0;
float4 sumw = 0.0;
float2 resolution;
tex.GetDimensions(resolution.x, resolution.y);
for (int i = 0; i < num_iter; ++i)
{
float t = float(i) * reci_num_iter_f;
float4 w = spectrum_offset(t);
sumw += w;
//sumcol += w * tex.SampleLevel(s, barrelDistortion(uv, 0.6 * strength*t ), 0);
sumcol += w * SampleFXAA(tex, s, barrelDistortion(uv, 0.6 * strength * t) * resolution, resolution);
}
return sumcol / sumw;
}
float2 BarrelDistortUV(float2 uv, float kcube)
{
float k = -0.15;
float r2 = (uv.x - 0.5) * (uv.x - 0.5) + (uv.y - 0.5) * (uv.y - 0.5);
float f = 0;
//only compute the cubic distortion if necessary
if (kcube == 0.0)
{
f = 1 + r2 * k;
}
else
{
f = 1 + r2 * (k + kcube * sqrt(r2));
};
// get the right pixel for the current position
float x = f * (uv.x - 0.5) + 0.5;
float y = f * (uv.y - 0.5) + 0.5;
return float2(x, y);
}
#endif //__PP_UTIL_HLSL__
================================================
FILE: resources/shaders/rand_util.hlsl
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __RAND_UTIL_HLSL__
#define __RAND_UTIL_HLSL__
#include "math.hlsl"
// Initialize random seed
uint initRand(uint val0, uint val1, uint backoff = 16)
{
uint v0 = val0, v1 = val1, s0 = 0;
[unroll]
for (uint n = 0; n < backoff; n++)
{
s0 += 0x9e3779b9;
v0 += ((v1 << 4) + 0xa341316c) ^ (v1 + s0) ^ ((v1 >> 5) + 0xc8013ea4);
v1 += ((v0 << 4) + 0xad90777d) ^ (v0 + s0) ^ ((v0 >> 5) + 0x7e95761e);
}
return v0;
}
// Get 'random' value [0, 1]
float nextRand(inout uint s)
{
s = (1664525u * s + 1013904223u);
return float(s & 0x00FFFFFF) / float(0x01000000);
}
float3 rand_in_unit_sphere(inout uint rng_state)
{
float z = nextRand(rng_state) * 2.0f - 1.0f;
float t = nextRand(rng_state) * 2.0f * M_PI;
float r = sqrt(max(0.0, 1.0f - z * z));
float x = r * cos(t);
float y = r * sin(t);
float3 res = float3(x, y, z);
res *= pow(nextRand(rng_state), 1.0 / 3.0);
return res;
}
float3 getPerpendicularVector(float3 u)
{
float3 a = abs(u);
uint xm = ((a.x - a.y)<0 && (a.x - a.z)<0) ? 1 : 0;
uint ym = (a.y - a.z)<0 ? (1 ^ xm) : 0;
uint zm = 1 ^ (xm | ym);
return cross(u, float3(xm, ym, zm));
}
// Get a cosine-weighted random vector centered around a specified normal direction.
float3 getCosHemisphereSample(inout uint randSeed, float3 hitNorm)
{
// Get 2 random numbers to select our sample with
float2 randVal = float2(nextRand(randSeed), nextRand(randSeed));
// Cosine weighted hemisphere sample from RNG
float3 bitangent = getPerpendicularVector(hitNorm);
float3 tangent = cross(bitangent, hitNorm);
float r = sqrt(randVal.x);
float phi = 2.0f * M_PI * randVal.y;
// Get our cosine-weighted hemisphere lobe sample direction
return tangent * (r * cos(phi).x) + bitangent * (r * sin(phi)) + hitNorm.xyz * sqrt(max(0.0, 1.0f - randVal.x));
}
// Get a uniform weighted random vector centered around a specified normal direction.
float3 getUniformHemisphereSample(inout uint randSeed, float3 hitNorm)
{
// Get 2 random numbers to select our sample with
float2 randVal = float2(nextRand(randSeed), nextRand(randSeed));
// Cosine weighted hemisphere sample from RNG
float3 bitangent = getPerpendicularVector(hitNorm);
float3 tangent = cross(bitangent, hitNorm);
float r = sqrt(max(0.0f,1.0f - randVal.x*randVal.x));
float phi = 2.0f * M_PI * randVal.y;
// Get our cosine-weighted hemisphere lobe sample direction
return tangent * (r * cos(phi).x) + bitangent * (r * sin(phi)) + hitNorm.xyz * randVal.x;
}
float3 getUniformHemisphereSample(inout uint randSeed, float3 hitNorm, float angle)
{
// Get 2 random numbers to select our sample with
float2 randVal = float2(nextRand(randSeed), nextRand(randSeed));
// Cosine weighted hemisphere sample from RNG
float3 bitangent = getPerpendicularVector(hitNorm);
float3 tangent = cross(bitangent, hitNorm);
float r = sqrt(max(0.0f, 1.0f - randVal.x * randVal.x)) * sin(angle);
float phi = 2.0f * M_PI * randVal.y;
// Get our cosine-weighted hemisphere lobe sample direction
return tangent * (r * cos(phi).x) + bitangent * (r * sin(phi)) + hitNorm.xyz * cos(asin(r));
}
float3 perturbDirectionVector(inout uint randSeed, float3 direction, float angle)
{
float s = nextRand(randSeed);
float r = nextRand(randSeed);
float h = cos(angle);
float phi = 2.0f * M_PI * s;
float z = h + (1.0f - h) * r;
float sinT = sqrt(1.0f - z * z);
float x = cos(phi) * sinT;
float y = sin(phi) * sinT;
float3 bitangent = getPerpendicularVector(direction);
float3 tangent = cross(bitangent, direction);
return bitangent * x + tangent * y + direction * z;
}
#endif // __RAND_UTIL_HLSL__
================================================
FILE: resources/sponza_lights.json
================================================
{
"lights": [
{
"angle": 69.0,
"color": [
0.9999899864196777,
0.9999899864196777,
1.0
],
"pos": [
0.0,
3.562610149383545,
0.0,
0.0
],
"radius": 200.0,
"rot": [
0.0,
0.0,
0.0,
0.0
],
"size": 0.0,
"type": 0
},
{
"angle": 0.0,
"color": [
1.0,
0.0,
0.0
],
"pos": [
-4.0,
1.0,
-7.193277359008789,
0.0
],
"radius": 5.0,
"rot": [
-1.0399991273880005,
7.299992084503174,
0.0,
0.0
],
"size": 0.0,
"type": 0
},
{
"angle": 0.0,
"color": [
0.0,
1.0,
0.0
],
"pos": [
4.0,
1.0,
-7.192999839782715,
0.0
],
"radius": 5.0,
"rot": [
0.0,
0.0,
0.0,
0.0
],
"size": 0.0,
"type": 0
}
]
}
================================================
FILE: resources/viknell_lights.json
================================================
{
"lights": [
{
"angle": 69.0,
"color": [
0.0,
0.0,
1.0
],
"pos": [
0.75,
0.0,
0.75,
0.0
],
"radius": 6.0,
"rot": [
0.0,
0.0,
0.0,
0.0
],
"size": 0.0,
"type": 0
},
{
"angle": 0.0,
"color": [
1.0,
0.0,
0.0
],
"pos": [
-0.75,
0.0,
0.75,
0.0
],
"radius": 5.0,
"rot": [
0.0,
0.0,
0.0,
0.0
],
"size": 0.0,
"type": 0
}
]
}
================================================
FILE: scripts/JenkinsWebhook.bat
================================================
@echo off
set "str=%~1"
"C:\Program Files\cURL\bin\curl.exe" -X POST --data "{ \"content\": \"%str%\", \"username\": \"Jenkins\" }" -H "Content-Type: application/json" https://discordapp.com/api/webhooks/488672255321309185/GdU9rve6wW5rcbk6xcDx4TX8AKez5Yfej8kfKco17qRvHTlTuB6bdziQIDDYBHW8HuES
@echo on
================================================
FILE: src/constant_buffer_pool.cpp
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "constant_buffer_pool.hpp"
namespace wr
{
ConstantBufferPool::ConstantBufferPool(std::size_t size_in_bytes) : m_size_in_bytes(size_in_bytes)
{
}
ConstantBufferHandle* ConstantBufferPool::Create(std::size_t buffer_size)
{
std::lock_guard lock(m_mutex);
return AllocateConstantBuffer(buffer_size);
}
void ConstantBufferPool::Update(ConstantBufferHandle* handle, size_t size, size_t offset, std::uint8_t * data)
{
std::lock_guard lock(m_mutex);
WriteConstantBufferData(handle, size, offset, data);
}
void ConstantBufferPool::Destroy(ConstantBufferHandle* handle)
{
std::lock_guard lock(m_mutex);
DeallocateConstantBuffer(handle);
}
void ConstantBufferPool::Update(ConstantBufferHandle * handle, size_t size, size_t offset, size_t frame_idx, std::uint8_t * data)
{
std::lock_guard lock(m_mutex);
WriteConstantBufferData(handle, size, offset, frame_idx, data);
}
} /* wr */
================================================
FILE: src/constant_buffer_pool.hpp
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include
#include
#include
#include
#include
#include "util/defines.hpp"
namespace wr
{
class ConstantBufferPool;
struct ConstantBufferHandle
{
ConstantBufferPool* m_pool;
};
class ConstantBufferPool
{
public:
explicit ConstantBufferPool(std::size_t size_in_bytes);
virtual ~ConstantBufferPool() = default;
ConstantBufferPool(ConstantBufferPool const &) = delete;
ConstantBufferPool& operator=(ConstantBufferPool const &) = delete;
ConstantBufferPool(ConstantBufferPool&&) = delete;
ConstantBufferPool& operator=(ConstantBufferPool&&) = delete;
[[nodiscard]] ConstantBufferHandle* Create(std::size_t buffer_size);
void Update(ConstantBufferHandle* handle, size_t size, size_t offset, std::uint8_t* data);
void Update(ConstantBufferHandle* handle, size_t size, size_t offset, size_t frame_idx, std::uint8_t* data);
void Destroy(ConstantBufferHandle* handle);
virtual void Evict() = 0;
virtual void MakeResident() = 0;
protected:
virtual ConstantBufferHandle* AllocateConstantBuffer(std::size_t buffer_size) = 0;
virtual void WriteConstantBufferData(ConstantBufferHandle* handle, size_t size, size_t offset, std::uint8_t* data) = 0;
virtual void WriteConstantBufferData(ConstantBufferHandle* handle, size_t size, size_t offset, size_t frame_idx, std::uint8_t* data) = 0;
virtual void DeallocateConstantBuffer(ConstantBufferHandle* handle) = 0;
std::size_t m_size_in_bytes;
std::mutex m_mutex;
};
} /* wr */
================================================
FILE: src/d3d12/d3d12_acceleration_structure..cpp
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "d3d12_functions.hpp"
#include
#include "d3d12_defines.hpp"
#include "d3d12_rt_descriptor_heap.hpp"
namespace wr::d3d12
{
/*!
NOTE!
Top level has scratch and instance descs.
blas does not!!!!!!!!
*/
namespace internal
{
inline void AllocateUAVBuffer(Device* device, UINT64 size, ID3D12Resource** resource, D3D12_RESOURCE_STATES initial_state = D3D12_RESOURCE_STATE_COMMON, const wchar_t* name = nullptr)
{
auto heap_properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT);
auto buffer_desc = CD3DX12_RESOURCE_DESC::Buffer(size, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS);
TRY(device->m_native->CreateCommittedResource(
&heap_properties,
D3D12_HEAP_FLAG_NONE,
&buffer_desc,
initial_state,
nullptr,
IID_PPV_ARGS(resource)));
if (name)
{
NAME_D3D12RESOURCE((*resource), name);
}
}
inline void AllocateUploadBuffer(Device* device, void* data, UINT64 size, ID3D12Resource** resource, const wchar_t* name = nullptr)
{
auto heap_properties = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
auto buffer_desc = CD3DX12_RESOURCE_DESC::Buffer(size);
TRY(device->m_native->CreateCommittedResource(
&heap_properties,
D3D12_HEAP_FLAG_NONE,
&buffer_desc,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(resource)));
if (name)
{
NAME_D3D12RESOURCE((*resource), name);
}
void *mapped_data;
(*resource)->Map(0, nullptr, &mapped_data);
memcpy(mapped_data, data, size);
(*resource)->Unmap(0, nullptr);
}
inline void UpdateUploadbuffer(void* data, UINT64 size, ID3D12Resource* resource)
{
void *mapped_data;
resource->Map(0, nullptr, &mapped_data);
memcpy(mapped_data, data, size);
resource->Unmap(0, nullptr);
}
WRAPPED_GPU_POINTER CreateFallbackWrappedPointer(
Device* device,
DescriptorHeap* heap,
std::uint32_t index,
ID3D12Resource* resource,
UINT buffer_num_elements)
{
if (GetRaytracingType(device) != RaytracingType::FALLBACK)
{
LOGW("CreateFallbackWrappedPointer got called but the device isn't setup for fallback.");
}
D3D12_UNORDERED_ACCESS_VIEW_DESC rawBufferUavDesc = {};
rawBufferUavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER;
rawBufferUavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_RAW;
rawBufferUavDesc.Format = DXGI_FORMAT_R32_TYPELESS;
rawBufferUavDesc.Buffer.NumElements = buffer_num_elements;
d3d12::DescHeapCPUHandle bottom_level_descriptor;
// Only compute fallback requires a valid descriptor index when creating a wrapped pointer.
UINT desc_heap_idx = index; // TODO don't hardcode this.
if (!device->m_fallback_native->UsingRaytracingDriver())
{
for (auto frame_idx = 0; frame_idx < d3d12::settings::num_back_buffers; frame_idx++)
{
bottom_level_descriptor = d3d12::GetCPUHandle(heap, frame_idx, 0); // TODO: Don't harcode this.
d3d12::Offset(bottom_level_descriptor, desc_heap_idx, heap->m_increment_size);
device->m_native->CreateUnorderedAccessView(resource, nullptr, &rawBufferUavDesc, bottom_level_descriptor.m_native);
}
}
return device->m_fallback_native->GetWrappedPointerSimple(desc_heap_idx, resource->GetGPUVirtualAddress());
}
inline void UpdatePrebuildInfo(Device* device, AccelerationStructure& as, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS inputs)
{
if (GetRaytracingType(device) == RaytracingType::NATIVE)
{
device->m_native->GetRaytracingAccelerationStructurePrebuildInfo(&inputs, &as.m_prebuild_info);
}
else if (GetRaytracingType(device) == RaytracingType::FALLBACK)
{
device->m_fallback_native->GetRaytracingAccelerationStructurePrebuildInfo(&inputs, &as.m_prebuild_info);
}
if (!(as.m_prebuild_info.ResultDataMaxSizeInBytes > 0)) LOGW("Result data max size in bytes is more than zero. accel structure");
}
inline void BuildAS(Device* device, CommandList* cmd_list, DescriptorHeap* desc_heap, D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC const & desc)
{
auto BuildAccelerationStructure = [&](auto * raytracingCommandList)
{
raytracingCommandList->BuildRaytracingAccelerationStructure(&desc, 0, nullptr);
};
// Build acceleration structure.
if (GetRaytracingType(device) == RaytracingType::NATIVE)
{
BuildAccelerationStructure(cmd_list->m_native);
}
else if (GetRaytracingType(device) == RaytracingType::FALLBACK)
{
// Set the descriptor heaps to be used during acceleration structure build for the Fallback Layer.
d3d12::BindDescriptorHeap(cmd_list, desc_heap, desc_heap->m_create_info.m_type, 0, true); //TODO: note this non frame idx
BuildAccelerationStructure(cmd_list->m_native_fallback);
}
}
inline void CreateInstancesForTLAS(Device* device, AccelerationStructure& tlas, DescriptorHeap* desc_heap, std::vector blas_list, std::uint32_t frame_idx, bool update)
{
// Falback layer heap offset
auto fallback_heap_idx = d3d12::settings::fallback_ptrs_offset;
// Create the instances to the bottom level instances.
if (GetRaytracingType(device) == RaytracingType::NATIVE)
{
std::vector instance_descs;
for (auto it : blas_list)
{
auto blas = it.m_as;
auto material = it.m_material;
auto transform = it.m_transform;
D3D12_RAYTRACING_INSTANCE_DESC instance_desc = {};
XMStoreFloat3x4(reinterpret_cast(instance_desc.Transform), transform);
instance_desc.InstanceMask = 1;
instance_desc.InstanceID = material;
instance_desc.AccelerationStructure = blas.m_natives[frame_idx]->GetGPUVirtualAddress();
instance_descs.push_back(instance_desc);
}
if (update)
{
internal::UpdateUploadbuffer(instance_descs.data(), sizeof(D3D12_RAYTRACING_INSTANCE_DESC) * blas_list.size(), tlas.m_instance_descs[frame_idx]);
}
else
{
for (auto& inst_desc : tlas.m_instance_descs)
{
internal::AllocateUploadBuffer(device, instance_descs.data(), sizeof(D3D12_RAYTRACING_INSTANCE_DESC) * blas_list.size(), &inst_desc, L"InstanceDescs");
}
}
}
else if (GetRaytracingType(device) == RaytracingType::FALLBACK)
{
std::vector instance_descs;
for (auto it : blas_list)
{
auto blas = it.m_as;
auto material = it.m_material;
auto transform = it.m_transform;
D3D12_RAYTRACING_FALLBACK_INSTANCE_DESC instance_desc = {};
XMStoreFloat3x4(reinterpret_cast(instance_desc.Transform), transform);
instance_desc.InstanceMask = 1;
instance_desc.InstanceID = material;
std::uint32_t num_buffer_elements = static_cast(blas.m_prebuild_info.ResultDataMaxSizeInBytes) / sizeof(std::uint32_t);
instance_desc.AccelerationStructure = internal::CreateFallbackWrappedPointer(device, desc_heap, fallback_heap_idx, blas.m_natives[frame_idx], num_buffer_elements);
instance_descs.push_back(instance_desc);
fallback_heap_idx++;
}
if (update)
{
internal::UpdateUploadbuffer(instance_descs.data(), sizeof(D3D12_RAYTRACING_FALLBACK_INSTANCE_DESC) * instance_descs.size(), tlas.m_instance_descs[frame_idx]);
}
else
{
for (auto& inst_desc : tlas.m_instance_descs)
{
internal::AllocateUploadBuffer(device, instance_descs.data(), sizeof(D3D12_RAYTRACING_FALLBACK_INSTANCE_DESC) * instance_descs.size(), &inst_desc, L"InstanceDescs");
}
}
}
// Create a wrapped pointer to the acceleration structure.
if (GetRaytracingType(device) == RaytracingType::FALLBACK)
{
std::uint32_t num_buffer_elements = static_cast(tlas.m_prebuild_info.ResultDataMaxSizeInBytes) / sizeof(std::uint32_t);
tlas.m_fallback_tlas_ptr = internal::CreateFallbackWrappedPointer(device, desc_heap, fallback_heap_idx, tlas.m_natives[0], num_buffer_elements);
}
}
inline void CopyInstDescResource(CommandList* cmd_list, AccelerationStructure& as, std::uint32_t source_index, std::uint32_t target_index)
{
cmd_list->m_native->CopyResource(as.m_instance_descs[target_index], as.m_instance_descs[source_index]);
}
inline void CopyAS(Device* device, CommandList* cmd_list, AccelerationStructure& as, std::uint32_t source_index, std::uint32_t target_index)
{
if (GetRaytracingType(device) == RaytracingType::NATIVE)
{
cmd_list->m_native->CopyRaytracingAccelerationStructure(as.m_natives[target_index]->GetGPUVirtualAddress(), as.m_natives[source_index]->GetGPUVirtualAddress(), D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_CLONE);
}
else if (GetRaytracingType(device) == RaytracingType::FALLBACK)
{
cmd_list->m_native_fallback->CopyRaytracingAccelerationStructure(as.m_natives[target_index]->GetGPUVirtualAddress(), as.m_natives[source_index]->GetGPUVirtualAddress(), D3D12_RAYTRACING_ACCELERATION_STRUCTURE_COPY_MODE_CLONE);
}
}
} /* internal */
#include
[[nodiscard]] AccelerationStructure CreateBottomLevelAccelerationStructures(Device* device,
CommandList* cmd_list,
DescriptorHeap* desc_heap,
std::vector geometry)
{
AccelerationStructure blas = {};
std::vector geometry_descs(geometry.size());
for (auto i = 0; i < geometry.size(); i++)
{
auto geom = geometry[i];
geometry_descs[i].Type = D3D12_RAYTRACING_GEOMETRY_TYPE_TRIANGLES;
if (auto index_buffer = geom.index_buffer.value_or(nullptr))
{
geometry_descs[i].Triangles.IndexBuffer = index_buffer->m_buffer->GetGPUVirtualAddress() + (geom.m_indices_offset * index_buffer->m_stride_in_bytes);
geometry_descs[i].Triangles.IndexCount = geom.m_num_indices;
geometry_descs[i].Triangles.IndexFormat = DXGI_FORMAT_R32_UINT;
geometry_descs[i].Triangles.Transform3x4 = 0;
}
else
{
geometry_descs[i].Triangles.IndexBuffer = 0;
geometry_descs[i].Triangles.IndexCount = 0;
geometry_descs[i].Triangles.IndexFormat = DXGI_FORMAT_UNKNOWN;
geometry_descs[i].Triangles.Transform3x4 = 0;
}
geometry_descs[i].Triangles.VertexFormat = DXGI_FORMAT_R32G32B32_FLOAT;
geometry_descs[i].Triangles.VertexCount = geom.m_num_vertices;
geometry_descs[i].Triangles.VertexBuffer.StartAddress = geom.vertex_buffer->m_buffer->GetGPUVirtualAddress() + (geom.m_vertices_offset * geom.m_vertex_stride);
geometry_descs[i].Triangles.VertexBuffer.StrideInBytes = geom.m_vertex_stride;
geometry_descs[i].Flags = D3D12_RAYTRACING_GEOMETRY_FLAG_OPAQUE;
}
D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS build_flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE;
// Get prebuild info bottom level
D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS bottom_level_inputs;
bottom_level_inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL;
bottom_level_inputs.NumDescs = static_cast(geometry.size());
bottom_level_inputs.pGeometryDescs = geometry_descs.data();
bottom_level_inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
bottom_level_inputs.Flags = build_flags;
// Get bottom level prebuild info
internal::UpdatePrebuildInfo(device, blas, bottom_level_inputs);
// Allocate scratch resource
internal::AllocateUAVBuffer(device,
blas.m_prebuild_info.ScratchDataSizeInBytes,
&blas.m_scratch,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
L"Acceleration Structure Scratch Resource");
// Allocate resources for acceleration structures.
for (auto& as : blas.m_natives) {
D3D12_RESOURCE_STATES initial_resource_state = D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE;
if (GetRaytracingType(device) == RaytracingType::FALLBACK)
{
initial_resource_state = device->m_fallback_native->GetAccelerationStructureResourceState();
}
internal::AllocateUAVBuffer(device, blas.m_prebuild_info.ResultDataMaxSizeInBytes, &as, initial_resource_state, L"BottomLevelAccelerationStructure");
}
// Bottom Level Acceleration Structure desc
D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC bottom_level_build_desc = {};
{
bottom_level_build_desc.Inputs = bottom_level_inputs;
bottom_level_build_desc.ScratchAccelerationStructureData = blas.m_scratch->GetGPUVirtualAddress();
bottom_level_build_desc.DestAccelerationStructureData = blas.m_natives[0]->GetGPUVirtualAddress();
}
internal::BuildAS(device, cmd_list, desc_heap, bottom_level_build_desc);
d3d12::UAVBarrierAS(cmd_list, blas, 0);
for (std::uint8_t i = 1; i < settings::num_back_buffers; i++)
{
internal::CopyAS(device, cmd_list, blas, 0, i);
}
return blas;
}
AccelerationStructure CreateTopLevelAccelerationStructure(Device* device,
CommandList* cmd_list,
DescriptorHeap* desc_heap,
std::vector blas_list)
{
AccelerationStructure tlas = {};
D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS build_flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE;
D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS top_level_inputs;
top_level_inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
top_level_inputs.Flags = build_flags;
top_level_inputs.NumDescs = static_cast(blas_list.size());
top_level_inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL;
// Get prebuild info top level
internal::UpdatePrebuildInfo(device, tlas, top_level_inputs);
// Allocate scratch resource
internal::AllocateUAVBuffer(device,
tlas.m_prebuild_info.ScratchDataSizeInBytes,
&tlas.m_scratch,
D3D12_RESOURCE_STATE_UNORDERED_ACCESS,
L"Acceleration Structure Scratch Resource");
// Allocate acceleration structure buffer
for (auto& as : tlas.m_natives) {
D3D12_RESOURCE_STATES initial_resoruce_state = D3D12_RESOURCE_STATE_RAYTRACING_ACCELERATION_STRUCTURE;
if (GetRaytracingType(device) == RaytracingType::FALLBACK)
{
initial_resoruce_state = device->m_fallback_native->GetAccelerationStructureResourceState();
}
internal::AllocateUAVBuffer(device, tlas.m_prebuild_info.ResultDataMaxSizeInBytes, &as, initial_resoruce_state, L"TopLevelAccelerationStructure");
}
// Create the instances to the bottom level instances
if (!blas_list.empty())
{
internal::CreateInstancesForTLAS(device, tlas, desc_heap, blas_list, 0, false);
}
// Top Level Acceleration Structure desc
D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC top_level_build_desc = {};
{
if (!blas_list.empty())
{
top_level_inputs.InstanceDescs = tlas.m_instance_descs[0]->GetGPUVirtualAddress();
}
top_level_build_desc.Inputs = top_level_inputs;
top_level_build_desc.DestAccelerationStructureData = tlas.m_natives[0]->GetGPUVirtualAddress();
top_level_build_desc.ScratchAccelerationStructureData = tlas.m_scratch->GetGPUVirtualAddress();
}
internal::BuildAS(device, cmd_list, desc_heap, top_level_build_desc);
d3d12::UAVBarrierAS(cmd_list, tlas, 0);
for (std::uint8_t i = 1; i < settings::num_back_buffers; i++)
{
internal::CopyAS(device, cmd_list, tlas, 0, i);
}
return tlas;
}
void DestroyAccelerationStructure(AccelerationStructure& structure)
{
SAFE_RELEASE(structure.m_scratch);
for (auto& as : structure.m_natives)
{
SAFE_RELEASE(as);
}
for (auto& inst_desc : structure.m_instance_descs)
{
SAFE_RELEASE(inst_desc);
}
}
void UAVBarrierAS(CommandList* cmd_list, AccelerationStructure const & structure, std::uint32_t frame_idx)
{
auto barrier = CD3DX12_RESOURCE_BARRIER::UAV(structure.m_natives[frame_idx]);
cmd_list->m_native->ResourceBarrier(1, &barrier);
}
void UpdateTopLevelAccelerationStructure(AccelerationStructure& tlas, Device* device,
CommandList* cmd_list,
DescriptorHeap* desc_heap,
std::vector blas_list,
std::uint32_t frame_idx)
{
D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS build_flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE | D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_ALLOW_UPDATE;
D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_INPUTS top_level_inputs;
top_level_inputs.DescsLayout = D3D12_ELEMENTS_LAYOUT_ARRAY;
top_level_inputs.Flags = build_flags;
top_level_inputs.NumDescs = static_cast(blas_list.size());
top_level_inputs.Type = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL;
D3D12_RAYTRACING_ACCELERATION_STRUCTURE_PREBUILD_INFO old_prebuild_info = tlas.m_prebuild_info;
internal::UpdatePrebuildInfo(device, tlas, top_level_inputs);
top_level_inputs.Flags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PERFORM_UPDATE;
bool rebuild_accel_structure = old_prebuild_info.ResultDataMaxSizeInBytes != tlas.m_prebuild_info.ResultDataMaxSizeInBytes ||
old_prebuild_info.ScratchDataSizeInBytes != tlas.m_prebuild_info.ScratchDataSizeInBytes ||
old_prebuild_info.UpdateScratchDataSizeInBytes != tlas.m_prebuild_info.UpdateScratchDataSizeInBytes;
if (rebuild_accel_structure)
{
LOGW("Complete AS rebuild triggered. This might break versioining");
tlas = CreateTopLevelAccelerationStructure(device, cmd_list, desc_heap, blas_list);
}
else
{
// Create the instances to the bottom level instances.
if (!blas_list.empty())
{
internal::CreateInstancesForTLAS(device, tlas, desc_heap, blas_list, frame_idx, true);
}
// Top Level Acceleration Structure desc
D3D12_BUILD_RAYTRACING_ACCELERATION_STRUCTURE_DESC top_level_build_desc = {};
{
auto barrier = CD3DX12_RESOURCE_BARRIER::UAV(tlas.m_natives[frame_idx]);
cmd_list->m_native->ResourceBarrier(1, &barrier);
if (!blas_list.empty())
{
top_level_inputs.InstanceDescs = tlas.m_instance_descs[frame_idx]->GetGPUVirtualAddress();
}
top_level_build_desc.Inputs = top_level_inputs;
top_level_build_desc.SourceAccelerationStructureData = tlas.m_natives[frame_idx]->GetGPUVirtualAddress(); //TODO: Benchmark performance when taking the previous source.
top_level_build_desc.DestAccelerationStructureData = tlas.m_natives[frame_idx]->GetGPUVirtualAddress();
top_level_build_desc.ScratchAccelerationStructureData = tlas.m_scratch->GetGPUVirtualAddress();
}
internal::BuildAS(device, cmd_list, desc_heap, top_level_build_desc);
}
}
void SetName(AccelerationStructure& acceleration_structure, std::wstring name)
{
for (auto& as : acceleration_structure.m_natives)
{
as->SetName((name + L" - Acceleration Structure").c_str());
}
for (auto& inst_desc : acceleration_structure.m_instance_descs)
{
if (inst_desc)
{
inst_desc->SetName((name + L" - Acceleration Structure").c_str());
}
}
}
void CreateOrUpdateTLAS(Device* device, CommandList* cmd_list, bool& requires_init, d3d12::AccelerationStructure& out_tlas,
std::vector blas_list, std::uint32_t frame_idx)
{
d3d12::DescriptorHeap* heap = static_cast(cmd_list)->m_rt_descriptor_heap->GetHeap();
if (d3d12::GetRaytracingType(device) == RaytracingType::FALLBACK)
{
if (requires_init)
{
out_tlas = d3d12::CreateTopLevelAccelerationStructure(device, cmd_list, heap, blas_list);
requires_init = false;
}
else
{
d3d12::UpdateTopLevelAccelerationStructure(out_tlas, device, cmd_list, heap, blas_list, frame_idx);
}
}
}
} /* wr::d3d12 */
================================================
FILE: src/d3d12/d3d12_command_list.cpp
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "d3d12_functions.hpp"
#include "d3d12_dynamic_descriptor_heap.hpp"
#include "d3d12_rt_descriptor_heap.hpp"
#include "d3d12_texture_resources.hpp"
#include "../util/log.hpp"
#include "d3d12_defines.hpp"
namespace wr::d3d12
{
CommandList* CreateCommandList(Device* device, unsigned int num_allocators, CmdListType type)
{
auto* cmd_list = new CommandList();
const auto n_device = device->m_native;
auto& n_cmd_list = cmd_list->m_native;
cmd_list->m_allocators.resize(num_allocators);
// Create the allocators
for (auto& allocator : cmd_list->m_allocators)
{
TRY_M(n_device->CreateCommandAllocator((D3D12_COMMAND_LIST_TYPE)type, IID_PPV_ARGS(&allocator)),
"Failed to create command allocator");
NAME_D3D12RESOURCE(allocator);
}
// Create the command lists
TRY_M(device->m_native->CreateCommandList(
0,
(D3D12_COMMAND_LIST_TYPE)type,
cmd_list->m_allocators[0],
NULL,
IID_PPV_ARGS(&n_cmd_list)
), "Failed to create command list");
NAME_D3D12RESOURCE(n_cmd_list);
n_cmd_list->Close(); // TODO: Can be optimized away.
if (GetRaytracingType(device) == RaytracingType::FALLBACK)
{
device->m_fallback_native->QueryRaytracingCommandList(n_cmd_list, IID_PPV_ARGS(&cmd_list->m_native_fallback));
}
//Create the heaps
for (int i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++i)
{
cmd_list->m_dynamic_descriptor_heaps[i] = std::make_unique(device, static_cast(i));
cmd_list->m_descriptor_heaps[i] = nullptr;
}
cmd_list->m_rt_descriptor_heap = std::make_shared(device, DescriptorHeapType::DESC_HEAP_TYPE_CBV_SRV_UAV);
return cmd_list;
}
void SetName(CommandList* cmd_list, std::string const& name)
{
SetName(cmd_list, std::wstring(name.begin(), name.end()));
}
void SetName(CommandList* cmd_list, std::wstring const& name)
{
cmd_list->m_native->SetName(name.c_str());
for (auto& allocator : cmd_list->m_allocators)
{
allocator->SetName((name + L" Allocator").c_str());
}
}
void Begin(CommandList* cmd_list, unsigned int frame_idx)
{
// TODO: move resetting to when the command list is executed. This is how vulkan does it.
TRY_M(cmd_list->m_allocators[frame_idx]->Reset(),
"Failed to reset cmd allocators");
// Only reset with pipeline state if using bundles since only then this will impact fps.
// Otherwise its just easier to pass NULL and suffer the insignificant performance loss.
TRY_M(cmd_list->m_native->Reset(cmd_list->m_allocators[frame_idx], NULL),
"Failed to reset command list.");
for (int i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++i)
{
cmd_list->m_dynamic_descriptor_heaps[i]->Reset();
cmd_list->m_descriptor_heaps[i] = nullptr;
}
cmd_list->m_rt_descriptor_heap->Reset(frame_idx);
}
void End(CommandList* cmd_list)
{
cmd_list->m_native->Close();
}
void ExecuteBundle(CommandList* cmd_list, CommandList* bundle)
{
cmd_list->m_native->ExecuteBundle(bundle->m_native);
}
void ExecuteIndirect(CommandList* cmd_list, CommandSignature* cmd_signature, IndirectCommandBuffer* buffer, uint32_t frame_idx)
{
cmd_list->m_native->ExecuteIndirect(cmd_signature->m_native, static_cast(buffer->m_num_commands), buffer->m_native[frame_idx], 0, nullptr, 0);
}
void BindRenderTarget(CommandList* cmd_list, RenderTarget* render_target, bool clear, bool clear_depth)
{
std::vector handles;
handles.resize(render_target->m_render_targets.size());
for (auto i = 0; i < handles.size(); i++)
{
handles[i] = CD3DX12_CPU_DESCRIPTOR_HANDLE(render_target->m_rtv_descriptor_heap->GetCPUDescriptorHandleForHeapStart(), i, render_target->m_rtv_descriptor_increment_size);
}
CD3DX12_CPU_DESCRIPTOR_HANDLE dsv_handle;
if (render_target->m_create_info.m_create_dsv_buffer)
{
dsv_handle = render_target->m_depth_stencil_resource_heap->GetCPUDescriptorHandleForHeapStart();
}
cmd_list->m_native->OMSetRenderTargets(static_cast(handles.size()), handles.data(), false, render_target->m_create_info.m_create_dsv_buffer ? &dsv_handle : nullptr);
if (clear)
{
for (auto& handle : handles)
{
cmd_list->m_native->ClearRenderTargetView(handle, render_target->m_create_info.m_clear_color, 0, nullptr);
}
}
if (clear_depth && render_target->m_create_info.m_create_dsv_buffer)
{
cmd_list->m_native->ClearDepthStencilView(dsv_handle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
}
}
void BindRenderTargetVersioned(CommandList* cmd_list, RenderTarget* render_target, unsigned int frame_idx, bool clear, bool clear_depth)
{
CD3DX12_CPU_DESCRIPTOR_HANDLE rtv_handle(render_target->m_rtv_descriptor_heap->GetCPUDescriptorHandleForHeapStart(),
frame_idx % render_target->m_render_targets.size(), render_target->m_rtv_descriptor_increment_size);
CD3DX12_CPU_DESCRIPTOR_HANDLE dsv_handle;
if (render_target->m_create_info.m_create_dsv_buffer)
{
dsv_handle = render_target->m_depth_stencil_resource_heap->GetCPUDescriptorHandleForHeapStart();
}
cmd_list->m_native->OMSetRenderTargets(1, &rtv_handle, false, render_target->m_create_info.m_create_dsv_buffer ? &dsv_handle : nullptr);
if (clear)
{
cmd_list->m_native->ClearRenderTargetView(rtv_handle, render_target->m_create_info.m_clear_color, 0, nullptr);
}
if (clear_depth && render_target->m_create_info.m_create_dsv_buffer)
{
cmd_list->m_native->ClearDepthStencilView(dsv_handle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
}
}
void BindRenderTargetOnlyDepth(CommandList* cmd_list, RenderTarget* render_target, bool clear)
{
CD3DX12_CPU_DESCRIPTOR_HANDLE dsv_handle;
if (render_target->m_create_info.m_create_dsv_buffer)
{
dsv_handle = render_target->m_depth_stencil_resource_heap->GetCPUDescriptorHandleForHeapStart();
}
cmd_list->m_native->OMSetRenderTargets(0, nullptr, false, render_target->m_create_info.m_create_dsv_buffer ? &dsv_handle : nullptr);
if (clear)
{
cmd_list->m_native->ClearDepthStencilView(dsv_handle, D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr);
}
}
void BindPipeline(CommandList* cmd_list, PipelineState* pipeline_state) // TODO: Binding the root signature seperatly can improve perf if done right.
{
cmd_list->m_native->SetPipelineState(pipeline_state->m_native);
cmd_list->m_native->SetGraphicsRootSignature(pipeline_state->m_root_signature->m_native);
for (int i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++i)
{
cmd_list->m_dynamic_descriptor_heaps[i]->ParseRootSignature(*pipeline_state->m_root_signature);
}
}
void BindDescriptorHeap(CommandList* cmd_list, DescriptorHeap* heap, DescriptorHeapType type, unsigned int frame_idx, bool fallback)
{
std::uint32_t heap_idx = frame_idx % heap->m_create_info.m_versions;
if (cmd_list->m_descriptor_heaps[static_cast(type)] != heap->m_native[heap_idx])
{
cmd_list->m_descriptor_heaps[static_cast(type)] = heap->m_native[heap_idx];
BindDescriptorHeaps(cmd_list, fallback);
}
}
void BindDescriptorHeaps(CommandList* cmd_list, bool fallback)
{
std::uint32_t num_heaps = 0;
ID3D12DescriptorHeap* n_heaps[D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES] = {};
for (uint32_t i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++i)
{
ID3D12DescriptorHeap* heap = cmd_list->m_descriptor_heaps[i];
if (heap)
{
n_heaps[num_heaps++] = heap;
}
}
if (fallback)
{
cmd_list->m_native_fallback->SetDescriptorHeaps(num_heaps, n_heaps);
}
else
{
cmd_list->m_native->SetDescriptorHeaps(num_heaps, n_heaps);
}
}
void BindComputePipeline(CommandList* cmd_list, PipelineState * pipeline_state)
{
if (pipeline_state->m_desc.m_type != PipelineType::COMPUTE_PIPELINE)
LOGW("Tried to bind a graphics pipeline as a compute pipeline");
cmd_list->m_native->SetPipelineState(pipeline_state->m_native);
cmd_list->m_native->SetComputeRootSignature(pipeline_state->m_root_signature->m_native);
for (int i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++i)
{
cmd_list->m_dynamic_descriptor_heaps[i]->ParseRootSignature(*pipeline_state->m_root_signature);
}
}
void BindRaytracingPipeline(CommandList* cmd_list, StateObject* state_object, bool fallback)
{
cmd_list->m_native->SetComputeRootSignature(state_object->m_global_root_signature->m_native);
if (fallback)
{
cmd_list->m_native_fallback->SetPipelineState1(state_object->m_fallback_native);
}
else
{
cmd_list->m_native->SetPipelineState1(state_object->m_native);
}
cmd_list->m_rt_descriptor_heap->ParseRootSignature(*state_object->m_global_root_signature);
}
void BindViewport(CommandList* cmd_list, Viewport const & viewport)
{
cmd_list->m_native->RSSetViewports(1, &viewport.m_viewport);
cmd_list->m_native->RSSetScissorRects(1, &viewport.m_scissor_rect);
}
void BindVertexBuffer(CommandList* cmd_list, StagingBuffer* buffer, std::size_t offset, std::size_t size, std::size_t stride)
{
if (!buffer->m_gpu_address)
{
LOGC("No GPU address found. Has the buffer beens staged?");
}
D3D12_VERTEX_BUFFER_VIEW view;
view.BufferLocation = buffer->m_gpu_address + offset;
view.StrideInBytes = static_cast(stride);
view.SizeInBytes = static_cast(size);
cmd_list->m_native->IASetVertexBuffers(0, 1, &view);
}
void BindIndexBuffer(CommandList* cmd_list, StagingBuffer* buffer, std::uint32_t offset, std::uint32_t size)
{
if (!buffer->m_gpu_address)
{
throw "No GPU address found. Has the buffer beens staged?";
}
D3D12_INDEX_BUFFER_VIEW view;
view.BufferLocation = buffer->m_gpu_address + offset;
view.Format = DXGI_FORMAT_R32_UINT;
view.SizeInBytes = size;
cmd_list->m_native->IASetIndexBuffer(&view);
}
void BindConstantBuffer(CommandList* cmd_list, HeapResource* buffer, unsigned int root_parameter_idx, unsigned int frame_idx)
{
cmd_list->m_native->SetGraphicsRootConstantBufferView(root_parameter_idx, buffer->m_gpu_addresses[frame_idx]);
}
void Bind32BitConstants(CommandList* cmd_list, const void* data_to_set, unsigned int num_of_values_to_set, unsigned int dest_offset_in_32bit_values, unsigned int root_parameter_idx)
{
cmd_list->m_native->SetGraphicsRoot32BitConstants(root_parameter_idx, num_of_values_to_set, data_to_set, dest_offset_in_32bit_values);
}
void BindCompute32BitConstants(CommandList* cmd_list, const void* data_to_set, unsigned int num_of_values_to_set, unsigned int dest_offset_in_32bit_values, unsigned int root_parameter_idx)
{
cmd_list->m_native->SetComputeRoot32BitConstants(root_parameter_idx, num_of_values_to_set, data_to_set, dest_offset_in_32bit_values);
}
void BindComputeConstantBuffer(CommandList * cmd_list, HeapResource* buffer, unsigned int root_parameter_idx, unsigned int frame_idx)
{
cmd_list->m_native->SetComputeRootConstantBufferView(root_parameter_idx,
buffer->m_gpu_addresses[frame_idx]);
}
void BindComputeShaderResourceView(CommandList * cmd_list, ID3D12Resource* resource, unsigned int root_parameter_idx)
{
cmd_list->m_native->SetComputeRootShaderResourceView(root_parameter_idx, resource->GetGPUVirtualAddress());
}
void BindComputeUnorederedAccessView(CommandList * cmd_list, ID3D12Resource* resource, unsigned int root_parameter_idx)
{
cmd_list->m_native->SetComputeRootUnorderedAccessView(root_parameter_idx, resource->GetGPUVirtualAddress());
}
void BindDescriptorTable(CommandList* cmd_list, DescHeapGPUHandle& handle, unsigned int root_param_index)
{
cmd_list->m_native->SetGraphicsRootDescriptorTable(root_param_index, handle.m_native);
}
void BindComputeDescriptorTable(CommandList * cmd_list, DescHeapGPUHandle & handle, unsigned int root_param_index)
{
cmd_list->m_native->SetComputeRootDescriptorTable(root_param_index, handle.m_native);
}
void SetPrimitiveTopology(CommandList* cmd_list, D3D12_PRIMITIVE_TOPOLOGY topology)
{
cmd_list->m_native->IASetPrimitiveTopology(topology);
}
void Draw(CommandList* cmd_list, std::uint32_t vertex_count, std::uint32_t inst_count, std::uint32_t vertex_start)
{
for (int i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++i)
{
cmd_list->m_dynamic_descriptor_heaps[i]->CommitStagedDescriptorsForDraw(*cmd_list);
}
cmd_list->m_native->DrawInstanced(vertex_count, inst_count, vertex_start, 0);
}
void DrawIndexed(CommandList* cmd_list, std::uint32_t idx_count, std::uint32_t inst_count, std::uint32_t idx_start, std::uint32_t vertex_start)
{
for (int i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++i)
{
cmd_list->m_dynamic_descriptor_heaps[i]->CommitStagedDescriptorsForDraw(*cmd_list);
}
cmd_list->m_native->DrawIndexedInstanced(idx_count, inst_count, idx_start, vertex_start, 0);
}
void Dispatch(CommandList * cmd_list, unsigned int thread_group_count_x, unsigned int thread_group_count_y, unsigned int thread_group_count_z)
{
for (int i = 0; i < D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES; ++i)
{
cmd_list->m_dynamic_descriptor_heaps[i]->CommitStagedDescriptorsForDispatch(*cmd_list);
}
cmd_list->m_native->Dispatch(thread_group_count_x, thread_group_count_y, thread_group_count_z);
}
void Transition(CommandList* cmd_list, RenderTarget* render_target, unsigned int frame_index, ResourceState from, ResourceState to)
{
CD3DX12_RESOURCE_BARRIER end_transition = CD3DX12_RESOURCE_BARRIER::Transition(
render_target->m_render_targets[frame_index % render_target->m_render_targets.size()],
(D3D12_RESOURCE_STATES)from,
(D3D12_RESOURCE_STATES)to
);
cmd_list->m_native->ResourceBarrier(1, &end_transition);
}
void Transition(CommandList* cmd_list, RenderTarget* render_target, ResourceState from, ResourceState to)
{
std::vector barriers;
barriers.resize(render_target->m_num_render_targets);
for (auto i = 0u; i < render_target->m_num_render_targets; i++)
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
render_target->m_render_targets[i],
(D3D12_RESOURCE_STATES)from,
(D3D12_RESOURCE_STATES)to
);
barriers[i] = barrier;
}
cmd_list->m_native->ResourceBarrier(static_cast(barriers.size()), barriers.data());
}
void Transition(CommandList* cmd_list, TextureResource* texture, ResourceState from, ResourceState to)
{
if (texture->m_subresource_states[0] != to)
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(texture->m_resource,
(D3D12_RESOURCE_STATES)from,
(D3D12_RESOURCE_STATES)to);
std::fill(texture->m_subresource_states.begin(), texture->m_subresource_states.end(), to);
cmd_list->m_native->ResourceBarrier(1, &barrier);
}
}
void Transition(CommandList* cmd_list, TextureResource* texture, ResourceState from, ResourceState to, unsigned int first_subresource, unsigned int num_subresources)
{
if (num_subresources < D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES)
{
for (uint32_t i = 0; i < num_subresources; ++i)
{
TransitionSubresource(cmd_list, texture, from, to, first_subresource + i);
}
}
else
{
Transition(cmd_list, texture, from, to);
}
}
void TransitionSubresource(CommandList* cmd_list, TextureResource* texture, ResourceState from, ResourceState to, unsigned int subresource)
{
if (texture->m_subresource_states[subresource] != to)
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(texture->m_resource,
(D3D12_RESOURCE_STATES)from,
(D3D12_RESOURCE_STATES)to, subresource);
texture->m_subresource_states[subresource] = to;
cmd_list->m_native->ResourceBarrier(1, &barrier);
}
}
void Transition(CommandList* cmd_list, std::vector const& textures, ResourceState from, ResourceState to)
{
std::vector barriers;
for (auto texture : textures)
{
if (texture->m_subresource_states[0] != to)
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
texture->m_resource,
(D3D12_RESOURCE_STATES)from,
(D3D12_RESOURCE_STATES)to
);
std::fill(texture->m_subresource_states.begin(), texture->m_subresource_states.end(), to);
barriers.push_back(barrier);
}
}
cmd_list->m_native->ResourceBarrier(static_cast(barriers.size()), barriers.data());
}
void Transition(CommandList* cmd_list, IndirectCommandBuffer* buffer, ResourceState from, ResourceState to, uint32_t frame_idx)
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
buffer->m_native[frame_idx],
(D3D12_RESOURCE_STATES)from,
(D3D12_RESOURCE_STATES)to
);
cmd_list->m_native->ResourceBarrier(1, &barrier);
}
void Transition(CommandList* cmd_list, StagingBuffer* buffer, ResourceState from, ResourceState to)
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
buffer->m_buffer,
(D3D12_RESOURCE_STATES)from,
(D3D12_RESOURCE_STATES)to
);
cmd_list->m_native->ResourceBarrier(1, &barrier);
}
void TransitionDepth(CommandList* cmd_list, RenderTarget* render_target, ResourceState from, ResourceState to)
{
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Transition(
render_target->m_depth_stencil_buffer,
(D3D12_RESOURCE_STATES)from,
(D3D12_RESOURCE_STATES)to
);
cmd_list->m_native->ResourceBarrier(1, &barrier);
}
void UAVBarrier(CommandList* cmd_list, std::vector const & resources)
{
std::vector barriers;
barriers.reserve(resources.size());
for (auto& resource : resources)
{
barriers.emplace_back(CD3DX12_RESOURCE_BARRIER::UAV(resource->m_resource));
}
cmd_list->m_native->ResourceBarrier(static_cast(barriers.size()), barriers.data());
}
void UAVBarrier(CommandList* cmd_list, std::vector const & resources)
{
std::vector barriers;
barriers.reserve(resources.size());
for (auto& resource : resources)
{
barriers.emplace_back(CD3DX12_RESOURCE_BARRIER::UAV(resource));
}
cmd_list->m_native->ResourceBarrier(static_cast(barriers.size()), barriers.data());
}
void Alias(CommandList* cmd_list, TextureResource* resource_before, TextureResource* resource_after)
{
auto before = (resource_before) ? resource_before->m_resource : nullptr;
auto after = (resource_after) ? resource_after->m_resource : nullptr;
CD3DX12_RESOURCE_BARRIER barrier = CD3DX12_RESOURCE_BARRIER::Aliasing(before, after);
cmd_list->m_native->ResourceBarrier(1, &barrier);
}
void Destroy(CommandList* cmd_list)
{
SAFE_RELEASE(cmd_list->m_native);
SAFE_RELEASE(cmd_list->m_native_fallback)
for (auto& allocator : cmd_list->m_allocators)
{
SAFE_RELEASE(allocator);
}
delete cmd_list;
}
CommandSignature* CreateCommandSignature(Device* device, RootSignature* root_signature, std::vector arg_descs, size_t byte_stride)
{
auto cmd_sig = new CommandSignature();
D3D12_COMMAND_SIGNATURE_DESC cmd_signature_desc = {};
cmd_signature_desc.pArgumentDescs = arg_descs.data();
cmd_signature_desc.NumArgumentDescs = static_cast(arg_descs.size());
cmd_signature_desc.ByteStride = static_cast(byte_stride);
TRY_M(device->m_native->CreateCommandSignature(&cmd_signature_desc, root_signature->m_native, IID_PPV_ARGS(&cmd_sig->m_native))
, "Failed to create command signature");
return cmd_sig;
}
void DispatchRays(CommandList* cmd_list, ShaderTable* hitgroup_table, ShaderTable* miss_table, ShaderTable* raygen_table, std::uint32_t width, std::uint32_t height, std::uint32_t depth, unsigned int frame_idx)
{
D3D12_DISPATCH_RAYS_DESC desc = {};
if (hitgroup_table != nullptr)
{
desc.HitGroupTable.StartAddress = hitgroup_table->m_resource->GetGPUVirtualAddress();
desc.HitGroupTable.SizeInBytes = hitgroup_table->m_resource->GetDesc().Width;
desc.HitGroupTable.StrideInBytes = hitgroup_table->m_shader_record_size;
}
desc.MissShaderTable.StartAddress = miss_table->m_resource->GetGPUVirtualAddress();
desc.MissShaderTable.SizeInBytes = miss_table->m_resource->GetDesc().Width;
desc.MissShaderTable.StrideInBytes = miss_table->m_shader_record_size;
desc.RayGenerationShaderRecord.StartAddress = raygen_table->m_resource->GetGPUVirtualAddress();
desc.RayGenerationShaderRecord.SizeInBytes = raygen_table->m_resource->GetDesc().Width;
// Dimensions of the image to render, identical to a window dimensions
desc.Width = width;
desc.Height = height;
desc.Depth = depth;
cmd_list->m_rt_descriptor_heap->CommitStagedDescriptorsForDispatch(*cmd_list, frame_idx);
if (cmd_list->m_native_fallback)
{
cmd_list->m_native_fallback->DispatchRays(&desc);
}
else
{
cmd_list->m_native->DispatchRays(&desc);
}
}
void SetName(CommandSignature * cmd_signature, std::wstring name)
{
cmd_signature->m_native->SetName(name.c_str());
}
void Destroy(CommandSignature* cmd_signature)
{
SAFE_RELEASE(cmd_signature->m_native);
delete cmd_signature;
}
} /* wr::d3d12 */
================================================
FILE: src/d3d12/d3d12_command_queue.cpp
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "d3d12_functions.hpp"
#include "../util/log.hpp"
#include "d3d12_defines.hpp"
namespace wr::d3d12
{
CommandQueue* CreateCommandQueue(Device* device, CmdListType type)
{
auto cmd_queue = new CommandQueue();
const auto n_device = device->m_native;
D3D12_COMMAND_QUEUE_DESC cmd_queue_desc = {};
cmd_queue_desc.Flags = settings::enable_gpu_timeout ? D3D12_COMMAND_QUEUE_FLAG_NONE : D3D12_COMMAND_QUEUE_FLAG_DISABLE_GPU_TIMEOUT;
cmd_queue_desc.Type = static_cast(type);
TRY_M(n_device->CreateCommandQueue(&cmd_queue_desc, IID_PPV_ARGS(&cmd_queue->m_native)),
"Failed to create DX12 command queue.");
NAME_D3D12RESOURCE(cmd_queue->m_native);
return cmd_queue;
}
void Execute(CommandQueue* cmd_queue, std::vector const & cmd_lists, Fence* fence)
{
std::vector native_lists;
native_lists.resize(cmd_lists.size());
for (auto i = 0; i < native_lists.size(); i++)
{
native_lists[i] = cmd_lists[i]->m_native;
}
cmd_queue->m_native->ExecuteCommandLists(static_cast(native_lists.size()), native_lists.data());
fence->m_fence_value++;
Signal(fence, cmd_queue);
}
void Destroy(CommandQueue* cmd_queue)
{
SAFE_RELEASE(cmd_queue->m_native);
delete cmd_queue;
}
void SetName(CommandQueue * cmd_queue, std::wstring name)
{
cmd_queue->m_native->SetName(name.c_str());
}
} /* wr::d3d12 */
================================================
FILE: src/d3d12/d3d12_constant_buffer_pool.cpp
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "d3d12_constant_buffer_pool.hpp"
#include "d3d12_functions.hpp"
#include "d3d12_settings.hpp"
#include "d3d12_renderer.hpp"
#include "d3d12_defines.hpp"
namespace wr
{
D3D12ConstantBufferPool::D3D12ConstantBufferPool(D3D12RenderSystem& render_system, std::size_t size_in_bytes) :
ConstantBufferPool(SizeAlignTwoPower(size_in_bytes, 65536)),
m_render_system(render_system)
{
m_heap = d3d12::CreateHeap_SBO(render_system.m_device, SizeAlignTwoPower(size_in_bytes, 65536), ResourceType::BUFFER, d3d12::settings::num_back_buffers);
SetName(m_heap, L"Default SBO Heap");
d3d12::MapHeap(m_heap);
}
D3D12ConstantBufferPool::~D3D12ConstantBufferPool()
{
d3d12::Destroy(m_heap);
for (int i = 0; i < m_constant_buffer_handles.size(); ++i)
{
delete m_constant_buffer_handles[i];
}
}
void D3D12ConstantBufferPool::Evict()
{
d3d12::Evict(m_heap);
}
void D3D12ConstantBufferPool::MakeResident()
{
d3d12::MakeResident(m_heap);
}
ConstantBufferHandle* D3D12ConstantBufferPool::AllocateConstantBuffer(std::size_t buffer_size)
{
D3D12ConstantBufferHandle* handle = new D3D12ConstantBufferHandle();
handle->m_pool = this;
handle->m_native = d3d12::AllocConstantBuffer(m_heap, buffer_size);
if (handle->m_native == nullptr)
{
delete handle;
return nullptr;
}
m_constant_buffer_handles.push_back(handle);
return handle;
}
void D3D12ConstantBufferPool::WriteConstantBufferData(ConstantBufferHandle * handle, size_t size, size_t offset, std::uint8_t * data)
{
auto frame_index = m_render_system.GetFrameIdx();
std::uint8_t* cpu_address = static_cast(handle)->m_native->m_cpu_addresses->operator[](frame_index);
memcpy(cpu_address + offset, data, size);
}
void D3D12ConstantBufferPool::WriteConstantBufferData(ConstantBufferHandle * handle, size_t size, size_t offset, size_t frame_idx, std::uint8_t * data)
{
auto frame_index = frame_idx;
std::uint8_t* cpu_address = static_cast(handle)->m_native->m_cpu_addresses->operator[](frame_index);
memcpy(cpu_address + offset, data, size);
}
void D3D12ConstantBufferPool::DeallocateConstantBuffer(ConstantBufferHandle* handle)
{
d3d12::DeallocConstantBuffer(m_heap, static_cast(handle)->m_native);
std::vector::iterator it;
for (it = m_constant_buffer_handles.begin(); it != m_constant_buffer_handles.end(); ++it)
{
if ((*it) == handle)
{
break;
}
}
if (it != m_constant_buffer_handles.end())
{
m_constant_buffer_handles.erase(it);
delete handle;
}
}
} /* wr */
================================================
FILE: src/d3d12/d3d12_constant_buffer_pool.hpp
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "../constant_buffer_pool.hpp"
#include "d3d12_structs.hpp"
namespace wr
{
struct D3D12ConstantBufferHandle : ConstantBufferHandle
{
d3d12::HeapResource* m_native;
};
class D3D12RenderSystem;
class D3D12ConstantBufferPool : public ConstantBufferPool
{
public:
explicit D3D12ConstantBufferPool(D3D12RenderSystem& render_system, std::size_t size_in_bytes);
~D3D12ConstantBufferPool() final;
void Evict() final;
void MakeResident() final;
protected:
ConstantBufferHandle* AllocateConstantBuffer(std::size_t buffer_size) final;
void WriteConstantBufferData(ConstantBufferHandle* handle, size_t size, size_t offset, std::uint8_t* data) final;
void WriteConstantBufferData(ConstantBufferHandle* handle, size_t size, size_t offset, size_t frame_idx, std::uint8_t* data) final;
void DeallocateConstantBuffer(ConstantBufferHandle* handle) final;
std::vector m_constant_buffer_handles;
d3d12::Heap* m_heap;
D3D12RenderSystem& m_render_system;
};
} /* wr */
================================================
FILE: src/d3d12/d3d12_defines.hpp
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "../util/log.hpp"
#pragma warning(push, 0)
#define D3DX12_INC d3dx12_rt.h
/*Helper function to get readable error messages from HResults
code originated from https://docs.microsoft.com/en-us/windows/desktop/cossdk/interpreting-error-codes
*/
inline std::string HResultToString(HRESULT hr)
{
if (FACILITY_WINDOWS == HRESULT_FACILITY(hr))
{
hr = HRESULT_CODE(hr);
}
TCHAR* sz_err_msg;
if (FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&sz_err_msg, 0, NULL) != 0)
{
std::string retval = sz_err_msg;
LocalFree(sz_err_msg);
return(retval);
}
else
{
return(std::string("[Could not find a description for error # %#x.", hr));
}
}
//! Checks whether the d3d12 object exists before releasing it.
#define SAFE_RELEASE(obj) { if ( obj ) { obj->Release(); obj = NULL; } }
//! Handles a hresult.
#define TRY(result) if (FAILED(result)) { LOGC("An hresult returned a error!. File: " + std::string(__FILE__) + " Line: " + std::to_string(__LINE__) + " HRResult: " + HResultToString(result)); }
//! Handles a hresult and outputs a specific message.
#define TRY_M(result, msg) if (FAILED(result)) { LOGC(static_cast(msg) + " HRResult: " + HResultToString(result)); }
//! This macro is used to name d3d12 resources.
#define NAME_D3D12RESOURCE(r, n) { auto temp = std::string(__FILE__); \
r->SetName(std::wstring(std::wstring(n) + L" (line: " + std::to_wstring(__LINE__) + L" file: " + std::wstring(temp.begin(), temp.end())).c_str()); }
//! This macro is used to name d3d12 resources with a placeholder name. TODO: "Unamed Resource" should be "Unamed [typename]"
#define NAME_D3D12RESOURCE(r) { auto temp = std::string(__FILE__); \
r->SetName(std::wstring(L"Unnamed Resource (line: " + std::to_wstring(__LINE__) + L" file: " + std::wstring(temp.begin(), temp.end())).c_str()); }
// Particular version automatically rounds the alignment to a two power.
template
constexpr inline T SizeAlignTwoPower(T size, A alignment)
{
return (size + (alignment - 1U)) & ~(alignment - 1U);
}
// Particular version always aligns to the provided alignment
template
constexpr inline T SizeAlignAnyAlignment(T size, A alignment)
{
return (size / alignment + (size%alignment > 0))*alignment;
}
#pragma warning(pop)
================================================
FILE: src/d3d12/d3d12_descriptor_heap.cpp
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "d3d12_functions.hpp"
#include "../util/log.hpp"
#include "d3d12_defines.hpp"
namespace wr::d3d12
{
DescriptorHeap* CreateDescriptorHeap(Device* device, desc::DescriptorHeapDesc const & descriptor)
{
auto heap = new DescriptorHeap();
const auto n_device = device->m_native;
heap->m_create_info = descriptor;
heap->m_increment_size = n_device->GetDescriptorHandleIncrementSize(static_cast(descriptor.m_type));
heap->m_native.resize(descriptor.m_versions);
for (uint32_t i = 0; i < descriptor.m_versions; ++i)
{
D3D12_DESCRIPTOR_HEAP_DESC heap_desc;
heap_desc.NumDescriptors = descriptor.m_num_descriptors;
heap_desc.Type = (D3D12_DESCRIPTOR_HEAP_TYPE)descriptor.m_type;
heap_desc.Flags = descriptor.m_shader_visible ? D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE : D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
heap_desc.NodeMask = 0;
TRY_M(n_device->CreateDescriptorHeap(&heap_desc, IID_PPV_ARGS(&heap->m_native[i])), "Couldn't create descriptor heap");
}
return heap;
}
DescHeapGPUHandle GetGPUHandle(DescriptorHeap* desc_heap, unsigned int frame_idx, unsigned int index)
{
DescHeapGPUHandle retval;
retval.m_native = desc_heap->m_native[frame_idx % desc_heap->m_create_info.m_versions]->GetGPUDescriptorHandleForHeapStart();
if (index > 0)
{
Offset(retval, index, desc_heap->m_increment_size);
}
return retval;
}
DescHeapCPUHandle GetCPUHandle(DescriptorHeap* desc_heap, unsigned int frame_idx, unsigned int index)
{
DescHeapCPUHandle retval;
retval.m_native = desc_heap->m_native[frame_idx % desc_heap->m_create_info.m_versions]->GetCPUDescriptorHandleForHeapStart();
if (index > 0)
{
Offset(retval, index, desc_heap->m_increment_size);
}
return retval;
}
void SetName(DescriptorHeap * desc_heap, std::wstring name)
{
for (int i = 0; i < desc_heap->m_native.size(); i++)
{
desc_heap->m_native[i]->SetName((name + L" Descriptor Version " + std::to_wstring(i)).c_str());
}
}
void Offset(DescHeapGPUHandle& handle, unsigned int index, unsigned int increment_size)
{
handle.m_native.ptr += static_cast(index) * static_cast(increment_size);
}
void Offset(DescHeapCPUHandle& handle, unsigned int index, unsigned int increment_size)
{
handle.m_native.ptr += static_cast(index) * static_cast(increment_size);
}
void Destroy(DescriptorHeap* desc_heap)
{
for (auto desc : desc_heap->m_native)
{
SAFE_RELEASE(desc);
}
delete desc_heap;
}
} /* wr::d3d12 */
================================================
FILE: src/d3d12/d3d12_descriptors_allocations.cpp
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "d3d12_descriptors_allocations.hpp"
#include "d3d12_renderer.hpp"
#include "d3d12_functions.hpp"
#include "../util/log.hpp"
// DESCRIPTOR ALLOCATION FUNCTIONS
namespace wr
{
DescriptorAllocation::DescriptorAllocation()
: m_descriptor{ 0 }
, m_num_handles(0)
, m_descriptor_size(0)
, m_page(nullptr)
{}
DescriptorAllocation::DescriptorAllocation(d3d12::DescHeapCPUHandle descriptor,
uint32_t num_handles,
uint32_t descriptor_size,
std::shared_ptr page)
: m_descriptor(descriptor)
, m_num_handles(num_handles)
, m_descriptor_size(descriptor_size)
, m_page(page)
{}
DescriptorAllocation::~DescriptorAllocation()
{
Free();
}
DescriptorAllocation::DescriptorAllocation(DescriptorAllocation&& allocation)
: m_descriptor(allocation.m_descriptor)
, m_num_handles(allocation.m_num_handles)
, m_descriptor_size(allocation.m_descriptor_size)
, m_page(std::move(allocation.m_page))
{
allocation.m_descriptor.m_native.ptr = 0;
allocation.m_num_handles = 0;
allocation.m_descriptor_size = 0;
}
DescriptorAllocation& DescriptorAllocation::operator=(DescriptorAllocation&& other)
{
// Free this descriptor if it points to anything.
Free();
m_descriptor = other.m_descriptor;
m_num_handles = other.m_num_handles;
m_descriptor_size = other.m_descriptor_size;
m_page = std::move(other.m_page);
other.m_descriptor.m_native.ptr = 0;
other.m_num_handles = 0;
other.m_descriptor_size = 0;
return *this;
}
void DescriptorAllocation::Free()
{
if (!IsNull() && m_page)
{
m_page->Free(std::move(*this));
m_descriptor.m_native.ptr = 0;
m_num_handles = 0;
m_descriptor_size = 0;
m_page.reset();
}
}
// Check if this a valid descriptor.
bool DescriptorAllocation::IsNull() const
{
return m_descriptor.m_native.ptr == 0;
}
// Get a descriptor at a particular offset in the allocation.
d3d12::DescHeapCPUHandle DescriptorAllocation::GetDescriptorHandle(uint32_t offset) const
{
if (offset > m_num_handles)
{
LOGC("Specified offset is greater than the number of handles in this Descriptor Allocation");
}
return { m_descriptor.m_native.ptr + (m_descriptor_size * offset) };
}
uint32_t DescriptorAllocation::GetNumHandles() const
{
return m_num_handles;
}
std::shared_ptr DescriptorAllocation::GetDescriptorAllocatorPage() const
{
return m_page;
}
}
// DESCRIPTOR ALLOCATOR PAGE FUNCTIONS
namespace wr
{
DescriptorAllocatorPage::DescriptorAllocatorPage(D3D12RenderSystem& render_system, DescriptorHeapType type, uint32_t num_descriptors)
: m_render_system(render_system)
, m_heap_type(type)
, m_num_descriptors_in_heap(num_descriptors)
{
d3d12::desc::DescriptorHeapDesc desc;
desc.m_type = m_heap_type;
desc.m_num_descriptors = m_num_descriptors_in_heap;
desc.m_versions = 1;
desc.m_shader_visible = false;
m_descriptor_heap = d3d12::CreateDescriptorHeap(m_render_system.m_device, desc);
m_base_descriptor = d3d12::GetCPUHandle(m_descriptor_heap, 0);
m_num_free_handles = m_num_descriptors_in_heap;
// Initialize the free lists
AddNewBlock(0, m_num_free_handles);
}
DescriptorAllocatorPage::~DescriptorAllocatorPage()
{
d3d12::Destroy(m_descriptor_heap);
m_num_free_handles = 0;
m_num_descriptors_in_heap = 0;
m_freelist_by_offset.clear();
m_freelist_by_size.clear();
}
DescriptorHeapType DescriptorAllocatorPage::GetHeapType() const
{
return m_heap_type;
}
uint32_t DescriptorAllocatorPage::NumFreeHandles() const
{
return m_num_free_handles;
}
bool DescriptorAllocatorPage::HasSpace(uint32_t num_descriptors) const
{
return m_freelist_by_size.lower_bound(num_descriptors) != m_freelist_by_size.end();
}
void DescriptorAllocatorPage::AddNewBlock(uint32_t offset, uint32_t num_descriptors)
{
auto offsetIt = m_freelist_by_offset.emplace(offset, num_descriptors);
auto sizeIt = m_freelist_by_size.emplace(num_descriptors, offsetIt.first);
offsetIt.first->second.m_freelist_by_size_itr = sizeIt;
}
DescriptorAllocation DescriptorAllocatorPage::Allocate(uint32_t num_descriptors)
{
std::lock_guard lock(m_allocation_mutex);
// There are less than the requested number of descriptors left in the heap.
// Return a NULL descriptor and try another heap.
if (num_descriptors > m_num_free_handles)
{
return DescriptorAllocation();
}
// Get the first block that is large enough to satisfy the request.
auto smallestBlockIt = m_freelist_by_size.lower_bound(num_descriptors);
if (smallestBlockIt == m_freelist_by_size.end())
{
// There was no free block that could satisfy the request.
return DescriptorAllocation();
}
// The size of the smallest block that satisfies the request.
auto blockSize = smallestBlockIt->first;
// The pointer to the same entry in the FreeListByOffset map.
auto offsetIt = smallestBlockIt->second;
// The offset in the descriptor heap.
auto offset = offsetIt->first;
// Remove the existing free block from the free list.
m_freelist_by_size.erase(smallestBlockIt);
m_freelist_by_offset.erase(offsetIt);
// Compute the new free block that results from splitting this block.
auto newOffset = offset + num_descriptors;
auto newSize = blockSize - num_descriptors;
if (newSize > 0)
{
// If the allocation didn't exactly match the requested size,
// return the left-over to the free list.
AddNewBlock(newOffset, newSize);
}
// Decrement free handles.
m_num_free_handles -= num_descriptors;
d3d12::DescHeapCPUHandle new_handle;
new_handle.m_native = CD3DX12_CPU_DESCRIPTOR_HANDLE(m_base_descriptor.m_native, offset, m_descriptor_heap->m_increment_size);
return DescriptorAllocation(new_handle, num_descriptors, m_descriptor_heap->m_increment_size, shared_from_this());
}
uint32_t DescriptorAllocatorPage::ComputeOffset(d3d12::DescHeapCPUHandle handle)
{
return static_cast(handle.m_native.ptr - m_base_descriptor.m_native.ptr) / m_descriptor_heap->m_increment_size;
}
void DescriptorAllocatorPage::Free(DescriptorAllocation&& allocation_handle)
{
// Compute the offset of the descriptor within the descriptor heap.
auto offset = ComputeOffset(allocation_handle.GetDescriptorHandle());
std::lock_guard lock(m_allocation_mutex);
// Don't add the block directly to the free list until the frame has completed.
m_stale_descriptors.emplace(offset, allocation_handle.GetNumHandles(), m_render_system.GetFrameIdx());
}
void DescriptorAllocatorPage::FreeBlock(uint32_t offset, uint32_t num_descriptors)
{
// Find the first element whose offset is greater than the specified offset.
// This is the block that should appear after the block that is being freed.
auto next_block_it = m_freelist_by_offset.upper_bound(offset);
// Find the block that appears before the block being freed.
auto prev_block_it = next_block_it;
// If it's not the first block in the list.
if (prev_block_it != m_freelist_by_offset.begin())
{
// Go to the previous block in the list.
--prev_block_it;
}
else
{
// Otherwise, just set it to the end of the list to indicate that no
// block comes before the one being freed.
prev_block_it = m_freelist_by_offset.end();
}
// Add the number of free handles back to the heap.
// This needs to be done before merging any blocks since merging
// blocks modifies the numDescriptors variable.
m_num_free_handles += num_descriptors;
if (prev_block_it != m_freelist_by_offset.end() &&
offset == prev_block_it->first + prev_block_it->second.m_size)
{
// The previous block is exactly behind the block that is to be freed.
//
// PrevBlock.Offset Offset
// | |
// |<-----PrevBlock.Size----->|<------Size-------->|
//
// Increase the block size by the size of merging with the previous block.
offset = prev_block_it->first;
num_descriptors += prev_block_it->second.m_size;
// Remove the previous block from the free list.
m_freelist_by_size.erase(prev_block_it->second.m_freelist_by_size_itr);
m_freelist_by_offset.erase(prev_block_it);
}
if (next_block_it != m_freelist_by_offset.end() &&
offset + num_descriptors == next_block_it->first)
{
// The next block is exactly in front of the block that is to be freed.
//
// Offset NextBlock.Offset
// | |
// |<------Size-------->|<-----NextBlock.Size----->|
// Increase the block size by the size of merging with the next block.
num_descriptors += next_block_it->second.m_size;
// Remove the next block from the free list.
m_freelist_by_size.erase(next_block_it->second.m_freelist_by_size_itr);
m_freelist_by_offset.erase(next_block_it);
}
// Add the freed block to the free list.
AddNewBlock(offset, num_descriptors);
}
void DescriptorAllocatorPage::ReleaseStaleDescriptors()
{
std::lock_guard lock(m_allocation_mutex);
while (!m_stale_descriptors.empty() && m_stale_descriptors.front().m_frame_number <= m_render_system.GetFrameIdx())
{
auto& staleDescriptor = m_stale_descriptors.front();
// The offset of the descriptor in the heap.
auto offset = staleDescriptor.m_offset;
// The number of descriptors that were allocated.
auto numDescriptors = staleDescriptor.m_size;
FreeBlock(offset, numDescriptors);
m_stale_descriptors.pop();
}
}
}
// DESCRIPTOR ALLOCATOR FUNCTIONS
namespace wr
{
DescriptorAllocator::DescriptorAllocator(D3D12RenderSystem& render_system, DescriptorHeapType type, uint32_t num_descriptors_per_heap)
: m_render_system(render_system)
, m_heap_type(type)
, m_num_descriptors_per_heap(num_descriptors_per_heap)
{
}
DescriptorAllocator::~DescriptorAllocator()
{
ReleaseStaleDescriptors();
for (auto heap : m_heap_pool)
{
heap.reset();
}
}
std::shared_ptr DescriptorAllocator::CreateAllocatorPage()
{
auto new_page = std::make_shared(m_render_system, m_heap_type, m_num_descriptors_per_heap);
m_heap_pool.emplace_back(new_page);
m_available_heaps.insert(m_heap_pool.size() - 1);
return new_page;
}
DescriptorAllocation DescriptorAllocator::Allocate(uint32_t num_dscriptors)
{
std::lock_guard lock(m_allocation_mutex);
DescriptorAllocation allocation;
for (auto iter = m_available_heaps.begin(); iter != m_available_heaps.end(); ++iter)
{
auto allocator_page = m_heap_pool[*iter];
allocation = allocator_page->Allocate(num_dscriptors);
if (allocator_page->NumFreeHandles() == 0)
{
iter = m_available_heaps.erase(iter);
}
// A valid allocation has been found.
if (!allocation.IsNull())
{
break;
}
}
// No available heap could satisfy the requested number of descriptors.
if (allocation.IsNull())
{
m_num_descriptors_per_heap = std::max(m_num_descriptors_per_heap, num_dscriptors);
auto new_page = CreateAllocatorPage();
allocation = new_page->Allocate(num_dscriptors);
}
return allocation;
}
void DescriptorAllocator::ReleaseStaleDescriptors()
{
std::lock_guard lock(m_allocation_mutex);
for (size_t i = 0; i < m_heap_pool.size(); ++i)
{
auto page = m_heap_pool[i];
page->ReleaseStaleDescriptors();
if (page->NumFreeHandles() > 0)
{
m_available_heaps.insert(i);
}
}
}
}
================================================
FILE: src/d3d12/d3d12_descriptors_allocations.hpp
================================================
/*!
* Copyright 2019 Breda University of Applied Sciences and Team Wisp (Viktor Zoutman, Emilio Laiso, Jens Hagen, Meine Zeinstra, Tahar Meijs, Koen Buitenhuis, Niels Brunekreef, Darius Bouma, Florian Schut)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "d3d12_structs.hpp"
#include "d3d12_enums.hpp"
#include
#include
#include
#include
#include