-
Notifications
You must be signed in to change notification settings - Fork 69
Env map importance sampling #969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
kevyuu
wants to merge
78
commits into
master
Choose a base branch
from
env_map_importance_sampling
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,577
−528
Open
Changes from all commits
Commits
Show all changes
78 commits
Select commit
Hold shift + click to select a range
b99ae6e
Fix small bug in GenericDataAccessor definition
b9537ea
First draft of Warpmap Generation workgroup implementation
a737173
Add warp concept
64349db
Add spherical warp
e44fcf4
Remove envmap accessors.hlsl
9b29dfd
Hierarchical image sampling implementation
06ae3e4
Merge branch 'master' into env_map_importance_sampling
16ecb52
Merge branch 'master' into env_map_importance_sampling
8d682b9
Remove envmap.hlsl
890f7c6
Move to sampling namespace and implement backward density
f99c63b
Remove private, public from hierarchical_image
3ff2791
Refactor hierarchical image to keep accessor and common data as member
76ef536
Refactor hierarchical image to separate binarySearch from Hierarchica…
ef773fd
Fix Spherical warp indentation
b9467fe
Add some comment why we add xi to the sample uvs
3682604
Merge branch 'master' into env_map_importance_sampling
ac1e2f3
WIP
baca1cf
Rename uv to coord for LuminanceAccessor concepts
f12b797
Fix hierarchical_image.hlsl
0957aed
Fix typo in spherical.hlsl
1b35d34
Implement gen_luma, gen_warpmap and measure_luma shaders
665bb8d
EnvmapImportanceSampling CMakeLists
b522b4f
Initial implementation of CEnvmapImportanceSampling
3e51c69
Initial implementation of CEnvmapImportanceSampling
c72d305
Small fixes
5ee2ce7
Initial implementation of computeWarpMap
867868c
Fix arithmetic config no const specifier for method
1a66157
Define config_t from outside
d4b8105
More fixes on computeWarpMap implementation
8853738
Fix chose second to be placed inside the loop
6bde489
LuminanceReadAccessor take ScalarT as template parameter
756fbb0
gen_warpmap to gen_warp
8d64a19
Move hierarchical_image concepts to sampling subdirectory
70d8423
Add some comment regarding corner sampling
2842d29
Parameterize spherical warp and make sure all literal is in the corre…
a51848c
Refactor CEnvmapImportanceSampling to block and calculate avgLuma
58c9c13
merge master, fix conflicts
keptsecret fa94ac2
Fix warp concept and add density type to warp concept
8494124
Rename luminanceScale to lumaRGBCoefficients
b273d87
Remove measure_luma.comp.hlsl
3bc0e57
Fix some bug in hierarchical_image.hlsl
1dadf92
Rename luminanceScales to lumaRGBCoefficients
f19cbe9
Move EnvmapImportanceSampling from ext to core
fde2bba
Fix binarySearch implementation. when last is 2x1 we should check for…
81cae21
Rename private member with underscore prefix
733a4ab
Merge branch 'master' into env_map_importance_sampling
ba6be93
Update submodule to follow master branch
f04d98b
Add missed EnvmapSampler.h and cpp
df2bfc3
Rename get and gather to texelFetch and texelGather
4930e25
Merge branch 'hlsl_path_tracer_example' into env_map_importance_sampling
05b862a
Include missing files into commit
d50b50f
Merge branch 'master' into env_map_importance_sampling
1498094
Update comment on sampleUvs
39da42b
Use bitfield for lumaMapResolution in push constant
47799ab
Remove NBL_BUILD_ENVMAP_IMPORTANCE_SAMPLING option
0f69171
Fix worgroup dim for gen_warp
43b88ef
Use constant workgroup dimension instead of WORKGROUP_DIM define
9aa3113
Remove passing WORKGROUP_DIM to shader
16c374e
Remove passing WORKGROUP_DIM for gen_luma
126aa21
Add upsscale parameter for EnvmapSampler
86a00f9
Pass warpMap width and height to luminanceSampler. Check For Out of B…
7509c83
Small fixes to gen_warp shader
833b388
gen_warp get image dimension from push constant instead of OpImageQue…
ac63441
Rename HierarchicalImage to WarpmapSampler
dacf493
Add todo comment for cube map
a2b57f9
Move EnvmapSampler from core/sampling to video/sampling
3343e64
Rename LuminanceSampler to HierarchicalLuminanceSampler
834163a
Fix corner sampling logic in gen_luma and hierarchical_image.hlsl
94d1f14
Fix previous commit
23a7e12
Add some todo comment for corner sampling flag
e8930ef
Add const modifier for binarySearch
de4807f
Add some temporary struct from pr #1001
a158057
Refactor hierarchical_image naming and concepts
4dd4e1f
Fix indentation of hierarchical_image.hlsl
fe14c93
Small fixes
bb41942
Remove superfluous member from WarpmapSampler
6b87e69
Merge branch 'master' into env_map_importance_sampling
9657c66
Fix resolve.hlsl case
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
Submodule Vulkan-Headers
updated
29 files
Submodule Vulkan-Tools
updated
10 files
| +1 −1 | CMakeLists.txt | |
| +1 −1 | icd/VkICD_mock_icd.json.in | |
| +456 −542 | icd/generated/function_declarations.h | |
| +682 −761 | icd/generated/function_definitions.h | |
| +816 −1,050 | icd/generated/vk_typemap_helper.h | |
| +2 −2 | scripts/known_good.json | |
| +1 −1 | tests/icd/mock_icd_tests.cpp | |
| +11 −3 | vulkaninfo/CMakeLists.txt | |
| +1 −160 | vulkaninfo/generated/vulkaninfo.hpp | |
| +6 −11 | vulkaninfo/vulkaninfo.cpp |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Submodule examples_tests
updated
34 files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
312 changes: 312 additions & 0 deletions
312
include/nbl/builtin/hlsl/sampling/hierarchical_image.hlsl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,312 @@ | ||
| // Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O. | ||
| // This file is part of the "Nabla Engine". | ||
| // For conditions of distribution and use, see copyright notice in nabla.h | ||
|
|
||
| #ifndef _NBL_BUILTIN_HLSL_SAMPLING_HIERARCHICAL_IMAGE_INCLUDED_ | ||
| #define _NBL_BUILTIN_HLSL_SAMPLING_HIERARCHICAL_IMAGE_INCLUDED_ | ||
|
|
||
| #include <nbl/builtin/hlsl/sampling/basic.hlsl> | ||
| #include <nbl/builtin/hlsl/sampling/warp.hlsl> | ||
| #include <nbl/builtin/hlsl/sampling/hierarchical_image/accessors.hlsl> | ||
| #include <nbl/builtin/hlsl/cpp_compat/intrinsics.hlsl> | ||
|
|
||
| namespace nbl | ||
| { | ||
| namespace hlsl | ||
| { | ||
| namespace sampling | ||
| { | ||
|
|
||
| // TODO(kevinyu): Temporary struct before PR #1001 merged to master | ||
| template<typename V, typename P> | ||
| struct value_and_rcpPdf | ||
| { | ||
| using this_t = value_and_rcpPdf<V, P>; | ||
|
|
||
| static this_t create(const V _value, const P _rcpPdf) | ||
| { | ||
| this_t retval; | ||
| retval._value = _value; | ||
| retval._rcpPdf = _rcpPdf; | ||
| return retval; | ||
| } | ||
|
|
||
| V value() { return _value; } | ||
| P rcpPdf() { return _rcpPdf; } | ||
|
|
||
| V _value; | ||
| P _rcpPdf; | ||
| }; | ||
|
|
||
| template<typename V, typename P> | ||
| struct value_and_pdf | ||
| { | ||
| using this_t = value_and_pdf<V, P>; | ||
|
|
||
| static this_t create(const V _value, const P _pdf) | ||
| { | ||
| this_t retval; | ||
| retval._value = _value; | ||
| retval._pdf = _pdf; | ||
| return retval; | ||
| } | ||
|
|
||
| V value() { return _value; } | ||
| P pdf() { return _pdf; } | ||
|
|
||
| V _value; | ||
| P _pdf; | ||
| }; | ||
|
Comment on lines
+20
to
+59
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. actually PR #1027 will have the replacements for these |
||
|
|
||
| // TODO: Add an option for corner sampling or centered sampling as boolean parameter | ||
| template <typename ScalarT, typename LuminanceAccessorT | ||
| NBL_PRIMARY_REQUIRES( | ||
| is_scalar_v<ScalarT> && | ||
| hierarchical_image::LuminanceReadAccessor<LuminanceAccessorT, ScalarT> | ||
| ) | ||
| struct HierarchicalWarpGenerator | ||
| { | ||
| using scalar_type = ScalarT; | ||
| using vector2_type = vector<scalar_type, 2>; | ||
| using vector4_type = vector<scalar_type, 4>; | ||
| using domain_type = vector2_type; | ||
| using codomain_type = vector2_type; | ||
| using sample_type = value_and_pdf<codomain_type, scalar_type>; | ||
| using density_type = scalar_type; | ||
|
|
||
| LuminanceAccessorT _map; | ||
| float32_t _rcpAvgLuma; | ||
| float32_t2 _rcpWarpSize; | ||
| uint16_t2 _mapSize; | ||
| uint16_t _mip2x1 : 15; | ||
| uint16_t _aspect2x1 : 1; | ||
|
|
||
| static HierarchicalWarpGenerator<ScalarT, LuminanceAccessorT> create(NBL_CONST_REF_ARG(LuminanceAccessorT) lumaMap, uint32_t2 mapSize, bool aspect2x1) | ||
| { | ||
| HierarchicalWarpGenerator<ScalarT, LuminanceAccessorT> result; | ||
| result._map = lumaMap; | ||
| result._mapSize = mapSize; | ||
| // Note: We use mapSize.y here because the currently the map aspect ratio can only be 1x1 or 2x1 | ||
| result._mip2x1 = _static_cast<uint16_t>(findMSB(mapSize.y)); | ||
| result._aspect2x1 = aspect2x1; | ||
| return result; | ||
| } | ||
|
|
||
| static bool __choseSecond(scalar_type first, scalar_type second, NBL_REF_ARG(scalar_type) xi, NBL_REF_ARG(scalar_type) rcpPmf) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| // numerical resilience against IEEE754 | ||
| scalar_type rcpChoiceProb = scalar_type(0); | ||
| PartitionRandVariable<scalar_type> partition; | ||
| partition.leftProb = scalar_type(1) / (scalar_type(1) + (second / first)); | ||
| bool choseSecond = partition(xi, rcpChoiceProb); | ||
| rcpPmf *= rcpChoiceProb; | ||
| return choseSecond; | ||
| } | ||
|
|
||
| // Cannot use textureGather since we need to pass the mipLevel | ||
| vector4_type __texelGather(uint32_t2 coord, uint32_t level) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| assert(coord.x < _mapSize.x - 1 && coord.y < _mapSize.y - 1); | ||
| const scalar_type v0, v1, v2, v3; | ||
|
|
||
| return float32_t4( | ||
| _map.load(uint32_t3(coord, level), uint32_t2(0, 1)), | ||
| _map.load(uint32_t3(coord, level), uint32_t2(1, 1)), | ||
| _map.load(uint32_t3(coord, level), uint32_t2(1, 0)), | ||
| _map.load(uint32_t3(coord, level), uint32_t2(0, 0)) | ||
| ); | ||
| } | ||
|
|
||
| sample_type generate(vector2_type xi) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| uint32_t2 p = uint32_t2(0, 0); | ||
|
|
||
| scalar_type rcpPmf = 1; | ||
| if (_aspect2x1) { | ||
| // do one split in the X axis first cause penultimate full mip would have been 2x1 | ||
| p.x = __choseSecond(_map.load(uint32_t2(0, 0), _mip2x1), _map.load(uint32_t2(1, 0), _mip2x1), xi.x, rcpPmf) ? 1 : 0; | ||
| } | ||
|
|
||
| for (int i = _mip2x1 - 1; i >= 0; i--) | ||
| { | ||
| p <<= 1; | ||
| const vector4_type values = __texelGather(p, i); | ||
| scalar_type wx_0, wx_1; | ||
| { | ||
| const scalar_type wy_0 = values[3] + values[2]; | ||
| const scalar_type wy_1 = values[1] + values[0]; | ||
| if (__choseSecond(wy_0, wy_1, xi.y, rcpPmf)) | ||
| { | ||
| p.y |= 1; | ||
| wx_0 = values[0]; | ||
| wx_1 = values[1]; | ||
| } | ||
| else | ||
| { | ||
| wx_0 = values[3]; | ||
| wx_1 = values[2]; | ||
| } | ||
| } | ||
| if (__choseSecond(wx_0, wx_1, xi.x, rcpPmf)) | ||
| p.x |= 1; | ||
| } | ||
|
|
||
|
|
||
| // If we don`t add xi, the sample will clump to the lowest corner of environment map texel. Each time we call PartitionRandVariable(), the output xi is the new xi that determines how left and right(or top and bottom for y axis) to choose the child partition. It means that if for some input xi, the output xi = 0, then the input xi is the edge of choosing this partition and the previous partition, and vice versa, if output xi = 1, then the input xi is the edge of choosing this partition and the next partition. Hence, by adding xi to the lower corner of the texel, we create a gradual transition from one pixel to another. Without adding output xi, the calculation of jacobian using the difference of sample value would not work. | ||
| // Since we want to do corner sampling. We have to handle edge texels as corner cases. Remember, in corner sampling we map uv [0,1] to [center of first texel, center of last texel]. So when p is an edge texel, we have to remap xi. [0.5, 1] when p == 0, and [0.5, 1] when p == length - 1. | ||
| if (p.x == 0) | ||
| xi.x = xi.x * scalar_type(0.5) + scalar_type(0.5); | ||
| if (p.y == 0) | ||
| xi.y = xi.y * scalar_type(0.5) + scalar_type(0.5); | ||
| if (p.x == _mapSize.x - 1) | ||
| xi.x = xi.x * scalar_type(0.5); | ||
| if (p.y == _mapSize.y - 1) | ||
| xi.y = xi.y * scalar_type(0.5); | ||
|
|
||
| const vector2_type directionUV = (vector2_type(p.x, p.y) + xi) / _mapSize; | ||
| return sample_type::create(directionUV, (_mapSize.x * _mapSize.y) / rcpPmf); | ||
| } | ||
|
|
||
| density_type forwardPdf(domain_type xi) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| return generate(xi).pdf(); | ||
| } | ||
|
|
||
| // Doesn't comply with sampler concept. This class is extracted so can be used on warpmap generation without passing in unnecessary information like avgLuma. So, need to pass in avgLuma when calculating backwardPdf. | ||
| density_type backwardPdf(codomain_type codomainVal, scalar_type rcpAvgLuma) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| return _map.load(codomainVal) * rcpAvgLuma; | ||
| } | ||
|
|
||
| }; | ||
|
|
||
| template <typename ScalarT, typename LuminanceAccessorT, typename PostWarpT | ||
| NBL_PRIMARY_REQUIRES( | ||
| is_scalar_v<ScalarT> && | ||
| hierarchical_image::LuminanceReadAccessor<LuminanceAccessorT, ScalarT> && | ||
| concepts::Warp<PostWarpT> | ||
| ) | ||
| struct HierarchicalWarpSampler | ||
| { | ||
| using warp_generator_type = HierarchicalWarpGenerator<ScalarT, LuminanceAccessorT>; | ||
| using warp_sample_type = typename warp_generator_type::sample_type; | ||
| using scalar_type = ScalarT; | ||
| using density_type = scalar_type; | ||
| using vector2_type = vector<scalar_type, 2>; | ||
| using vector3_type = vector<scalar_type, 3>; | ||
| using vector4_type = vector<scalar_type, 4>; | ||
| using domain_type = vector2_type; | ||
| using codomain_type = vector3_type; | ||
| using sample_type = value_and_pdf<codomain_type, density_type>; | ||
|
|
||
| warp_generator_type _warpGenerator; | ||
| scalar_type _rcpAvgLuma; | ||
|
|
||
| static HierarchicalWarpSampler<ScalarT, LuminanceAccessorT, PostWarpT> create(NBL_CONST_REF_ARG(LuminanceAccessorT) lumaMap, scalar_type avgLuma, uint32_t2 mapSize, bool aspect2x1) | ||
| { | ||
| HierarchicalWarpSampler result; | ||
| result._warpGenerator = warp_generator_type::create(lumaMap, mapSize, aspect2x1); | ||
| result._rcpAvgLuma = scalar_type(1.0) / avgLuma; | ||
| return result; | ||
| } | ||
|
|
||
| sample_type generate(domain_type xi) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| const warp_sample_type warpSample = _warpGenerator.generate(xi); | ||
| const WarpResult<codomain_type> postWarpResult = PostWarpT::warp(warpSample.value()); | ||
| return sample_type::create(postWarpResult.dst, postWarpResult.density * warpSample.pdf()); | ||
| } | ||
|
|
||
| density_type forwardPdf(domain_type xi) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| const warp_sample_type warpSample = _warpGenerator.generate(xi); | ||
| return PostWarpT::forwardDensity(warpSample.value()) * warpSample.pdf(); | ||
| } | ||
|
|
||
| density_type backwardPdf(codomain_type codomainVal) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| return PostWarpT::backwardPdf(codomainVal, _rcpAvgLuma) * _warpGenerator.backwardPdf(codomainVal); | ||
| } | ||
|
|
||
| }; | ||
|
|
||
|
|
||
| template <typename ScalarT, typename LuminanceAccessorT, typename HierarchicalSamplerT, typename PostWarpT | ||
| NBL_PRIMARY_REQUIRES(is_scalar_v<ScalarT> && | ||
| concepts::accessors::GenericReadAccessor<LuminanceAccessorT, ScalarT, float32_t2> && | ||
| hierarchical_image::WarpAccessor<HierarchicalSamplerT, ScalarT> && | ||
| concepts::Warp<PostWarpT>) | ||
| struct WarpmapSampler | ||
| { | ||
| using scalar_type = ScalarT; | ||
| using vector2_type = vector<ScalarT, 2>; | ||
| using vector3_type = vector<ScalarT, 3>; | ||
| using vector4_type = vector<ScalarT, 4>; | ||
| using domain_type = vector2_type; | ||
| using codomain_type = vector3_type; | ||
| using weight_type = scalar_type; | ||
| using sample_type = value_and_pdf<codomain_type, weight_type>; | ||
|
|
||
| LuminanceAccessorT _lumaMap; | ||
| HierarchicalSamplerT _warpMap; | ||
| uint32_t _effectiveWarpArea; | ||
| scalar_type _rcpAvgLuma; | ||
|
|
||
| static WarpmapSampler create(NBL_CONST_REF_ARG(LuminanceAccessorT) lumaMap, NBL_CONST_REF_ARG(HierarchicalSamplerT) warpMap, uint32_t2 warpSize, scalar_type avgLuma) | ||
| { | ||
| WarpmapSampler<ScalarT, LuminanceAccessorT, HierarchicalSamplerT, PostWarpT> result; | ||
| result._lumaMap = lumaMap; | ||
| result._warpMap = warpMap; | ||
| result._effectiveWarpArea = (warpSize.x - 1) * (warpSize.y - 1); | ||
| result._rcpAvgLuma = ScalarT(1.0) / avgLuma; | ||
| return result; | ||
| } | ||
|
|
||
| weight_type forwardWeight(domain_type xi) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| return generate(xi).value(); | ||
| } | ||
|
|
||
| weight_type backwardWeight(codomain_type direction) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| vector2_type envmapUv = PostWarpT::inverseWarp(direction); | ||
| scalar_type luma; | ||
| _lumaMap.get(envmapUv, luma); | ||
| return luma * _rcpAvgLuma * PostWarpT::backwardDensity(direction); | ||
| } | ||
|
|
||
| sample_type generate(vector2_type xi) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| const vector2_type interpolant; | ||
| matrix<scalar_type, 4, 2> uvs; | ||
| _warpMap.gatherUv(xi, uvs, interpolant); | ||
|
|
||
| const vector2_type xDiffs[] = { | ||
| uvs[2] - uvs[3], | ||
| uvs[1] - uvs[0] | ||
| }; | ||
| const vector2_type yVals[] = { | ||
| xDiffs[0] * interpolant.x + uvs[3], | ||
| xDiffs[1] * interpolant.x + uvs[0] | ||
| }; | ||
| const vector2_type yDiff = yVals[1] - yVals[0]; | ||
| vector2_type uv = yDiff * interpolant.y + yVals[0]; | ||
|
|
||
| const WarpResult<vector3_type> warpResult = PostWarpT::warp(uv); | ||
|
|
||
| const scalar_type detInterpolJacobian = determinant(matrix<scalar_type, 2, 2>( | ||
| lerp(xDiffs[0], xDiffs[1], interpolant.y), // first column dFdx | ||
| yDiff // second column dFdy | ||
| )) * _effectiveWarpArea; | ||
|
|
||
| const scalar_type pdf = abs(warpResult.density / detInterpolJacobian); | ||
|
|
||
| return sample_type::create(warpResult.dst, pdf); | ||
| } | ||
| }; | ||
|
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| #endif | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
undo