-
Notifications
You must be signed in to change notification settings - Fork 67
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
23
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.
Open
Changes from all commits
Commits
Show all changes
23 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
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
There are no files selected for viewing
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
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
61 changes: 61 additions & 0 deletions
61
include/nbl/builtin/hlsl/concepts/accessors/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,61 @@ | ||
| #ifndef _NBL_BUILTIN_HLSL_CONCEPTS_ACCESSORS_HIERARCHICAL_IMAGE_INCLUDED_ | ||
| #define _NBL_BUILTIN_HLSL_CONCEPTS_ACCESSORS_HIERARCHICAL_IMAGE_INCLUDED_ | ||
|
|
||
| #include "nbl/builtin/hlsl/concepts/accessors/generic_shared_data.hlsl" | ||
|
|
||
| namespace nbl | ||
| { | ||
| namespace hlsl | ||
| { | ||
| namespace sampling | ||
| { | ||
| namespace hierarchical_image | ||
| { | ||
| // declare concept | ||
| #define NBL_CONCEPT_NAME LuminanceReadAccessor | ||
| #define NBL_CONCEPT_TPLT_PRM_KINDS (typename) | ||
| #define NBL_CONCEPT_TPLT_PRM_NAMES (U) | ||
| // not the greatest syntax but works | ||
| #define NBL_CONCEPT_PARAM_0 (a,U) | ||
| #define NBL_CONCEPT_PARAM_1 (coord,uint32_t2) | ||
| #define NBL_CONCEPT_PARAM_2 (level,uint32_t) | ||
| // start concept | ||
| NBL_CONCEPT_BEGIN(3) | ||
| // need to be defined AFTER the concept begins | ||
| #define a NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 | ||
| #define coord NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 | ||
| #define level NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 | ||
| NBL_CONCEPT_END( | ||
| ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template get(coord,level)) , ::nbl::hlsl::is_same_v, float32_t)) | ||
| ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((a.template gather(coord,level)) , ::nbl::hlsl::is_same_v, float32_t4)) | ||
| ); | ||
| #undef level | ||
| #undef coord | ||
| #undef a | ||
| #include <nbl/builtin/hlsl/concepts/__end.hlsl> | ||
|
|
||
| // declare concept | ||
| #define NBL_CONCEPT_NAME HierarchicalSampler | ||
| #define NBL_CONCEPT_TPLT_PRM_KINDS (typename)(typename) | ||
| #define NBL_CONCEPT_TPLT_PRM_NAMES (HierarchicalSamplerT)(ScalarT) | ||
| // not the greatest syntax but works | ||
| #define NBL_CONCEPT_PARAM_0 (sampler,HierarchicalSamplerT) | ||
| #define NBL_CONCEPT_PARAM_1 (coord,vector<ScalarT, 2>) | ||
| // start concept | ||
| NBL_CONCEPT_BEGIN(2) | ||
| // need to be defined AFTER the concept begins | ||
| #define sampler NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 | ||
| #define coord NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 | ||
| NBL_CONCEPT_END( | ||
| ((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((sampler.template sampleUvs(coord)) , ::nbl::hlsl::is_same_v, matrix<ScalarT, 4, 2>)) | ||
| ); | ||
| #undef sampler | ||
| #undef coord | ||
| #include <nbl/builtin/hlsl/concepts/__end.hlsl> | ||
|
|
||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #endif |
166 changes: 166 additions & 0 deletions
166
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,166 @@ | ||
| // 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/concepts/accessors/hierarchical_image.hlsl> | ||
| #include <nbl/builtin/hlsl/cpp_compat/intrinsics.hlsl> | ||
|
|
||
| namespace nbl | ||
| { | ||
| namespace hlsl | ||
| { | ||
| namespace sampling | ||
| { | ||
|
|
||
| template <typename T, typename LuminanceAccessorT NBL_PRIMARY_REQUIRES(is_scalar_v<T> && hierarchical_image::LuminanceReadAccessor<LuminanceAccessorT>) | ||
| struct LuminanceMapSampler | ||
| { | ||
| using scalar_type = T; | ||
| using vector2_type = vector<scalar_type, 2>; | ||
| using vector4_type = vector<scalar_type, 4>; | ||
|
|
||
| LuminanceAccessorT _map; | ||
| uint32_t2 _mapSize; | ||
| uint32_t2 _lastWarpPixel; | ||
| bool _aspect2x1; | ||
|
|
||
| static LuminanceMapSampler<T, LuminanceAccessorT> create(NBL_CONST_REF_ARG(LuminanceAccessorT) lumaMap, uint32_t2 mapSize, bool aspect2x1, uint32_t2 warpSize) | ||
| { | ||
| LuminanceMapSampler<T, LuminanceAccessorT> result; | ||
| result._map = lumaMap; | ||
| result._mapSize = mapSize; | ||
| result._lastWarpPixel = warpSize - uint32_t2(1, 1); | ||
| result._aspect2x1 = aspect2x1; | ||
| return result; | ||
| } | ||
|
|
||
| static bool choseSecond(scalar_type first, scalar_type second, NBL_REF_ARG(float32_t) xi) | ||
| { | ||
| // numerical resilience against IEEE754 | ||
| scalar_type dummy = 0.0f; | ||
| PartitionRandVariable<scalar_type> partition; | ||
| partition.leftProb = 1.0f / (1.0f + second/ first); | ||
| return partition(xi, dummy); | ||
| } | ||
|
|
||
| vector2_type binarySearch(const uint32_t2 coord) | ||
| { | ||
| float32_t2 xi = float32_t2(coord)/ _lastWarpPixel; | ||
| uint32_t2 p = uint32_t2(0, 0); | ||
| const uint32_t2 mip2x1 = findMSB(_mapSize.x) - 1; | ||
|
|
||
| if (_aspect2x1) { | ||
| // do one split in the X axis first cause penultimate full mip would have been 2x1 | ||
| p.x = choseSecond(_map.get(uint32_t2(0, 0), mip2x1), _map.get(uint32_t2(0, 1), mip2x1), xi.x) ? 1 : 0; | ||
| } | ||
|
|
||
| for (uint32_t i = mip2x1; i != 0;) | ||
| { | ||
| --i; | ||
| p <<= 1; | ||
| const vector4_type values = _map.gather(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)) | ||
| { | ||
| 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)) | ||
| p.x |= 1; | ||
| } | ||
|
|
||
| // If we don`t add xi, the sample will clump to the lowest corner of environment map texel. We add xi to simulate uniform distribution within a pixel and make the sample continuous. This is why we compute the pdf not from the normalized luminance of the texel, instead from the reciprocal of the Jacobian. | ||
| const vector2_type directionUV = (vector2_type(p.x, p.y) + xi) / vector2_type(_mapSize); | ||
| return directionUV; | ||
| } | ||
|
|
||
| matrix<scalar_type, 4, 2> sampleUvs(uint32_t2 sampleCoord) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| const vector2_type dir0 = binarySearch(sampleCoord + vector2_type(0, 1)); | ||
| const vector2_type dir1 = binarySearch(sampleCoord + vector2_type(1, 1)); | ||
| const vector2_type dir2 = binarySearch(sampleCoord + vector2_type(1, 0)); | ||
| const vector2_type dir3 = binarySearch(sampleCoord); | ||
| return matrix<scalar_type, 4, 2>( | ||
| dir0, | ||
| dir1, | ||
| dir2, | ||
| dir3 | ||
| ); | ||
| } | ||
| }; | ||
|
|
||
| template <typename T, typename HierarchicalSamplerT, typename PostWarpT NBL_PRIMARY_REQUIRES(is_scalar_v<T> && hierarchical_image::HierarchicalSampler<HierarchicalSamplerT, T> && concepts::Warp<PostWarpT>) | ||
| struct HierarchicalImage | ||
| { | ||
| using scalar_type = T; | ||
| using vector2_type = vector<T, 2>; | ||
| using vector3_type = vector<T, 3>; | ||
| using vector4_type = vector<T, 4>; | ||
| HierarchicalSamplerT sampler; | ||
| uint32_t2 warpSize; | ||
| uint32_t2 lastWarpPixel; | ||
|
|
||
| static HierarchicalImage create(NBL_CONST_REF_ARG(HierarchicalSamplerT) sampler, uint32_t2 warpSize) | ||
| { | ||
| HierarchicalImage<T, HierarchicalSamplerT, PostWarpT> result; | ||
| result.sampler = sampler; | ||
| result.warpSize = warpSize; | ||
| result.lastWarpPixel = warpSize - uint32_t2(1, 1); | ||
| return result; | ||
| } | ||
|
|
||
|
|
||
| uint32_t2 generate(NBL_REF_ARG(scalar_type) rcpPdf, vector2_type xi) NBL_CONST_MEMBER_FUNC | ||
| { | ||
| const vector2_type texelCoord = xi * lastWarpPixel; | ||
| const vector2_type sampleCoord = (texelCoord + vector2_type(0.5f, 0.5f)) / vector2_type(warpSize.x, warpSize.y); | ||
|
|
||
| matrix<scalar_type, 4, 2> uvs = sampler.sampleUvs(sampleCoord); | ||
|
|
||
| const vector2_type interpolant = frac(texelCoord); | ||
|
|
||
| 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]; | ||
| const vector2_type uv = yDiff * interpolant.y + yVals[0]; | ||
|
|
||
| const WarpResult<float32_t3> warpResult = PostWarpT::warp(uv); | ||
|
|
||
| const scalar_type detInterpolJacobian = determinant(matrix<float32_t, 2, 2>( | ||
| lerp(xDiffs[0], xDiffs[1], interpolant.y), // first column dFdx | ||
| yDiff // second column dFdy | ||
| )); | ||
|
|
||
| rcpPdf = abs((detInterpolJacobian * scalar_type(lastWarpPixel.x * lastWarpPixel.y)) / warpResult.density); | ||
|
|
||
| return warpResult.dst; | ||
| } | ||
| }; | ||
|
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| #endif |
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,49 @@ | ||
| #ifndef _NBL_BUILTIN_HLSL_SAMPLING_CONCEPTS_WARP_INCLUDED_ | ||
| #define _NBL_BUILTIN_HLSL_SAMPLING_CONCEPTS_WARP_INCLUDED_ | ||
|
|
||
|
|
||
| namespace nbl | ||
| { | ||
| namespace hlsl | ||
| { | ||
| namespace sampling | ||
| { | ||
|
|
||
| template <typename CodomainT> | ||
| struct WarpResult | ||
| { | ||
| CodomainT dst; | ||
| float32_t density; | ||
| }; | ||
| } | ||
|
|
||
| namespace concepts | ||
| { | ||
|
|
||
| // declare concept | ||
| #define NBL_CONCEPT_NAME Warp | ||
| #define NBL_CONCEPT_TPLT_PRM_KINDS (typename) | ||
| #define NBL_CONCEPT_TPLT_PRM_NAMES (U) | ||
| // not the greatest syntax but works | ||
| #define NBL_CONCEPT_PARAM_0 (warper,U) | ||
| #define NBL_CONCEPT_PARAM_1 (xi,typename U::domain_type) | ||
| #define NBL_CONCEPT_PARAM_2 (dst,typename U::codomain_type) | ||
| // start concept | ||
| NBL_CONCEPT_BEGIN(3) | ||
| #define warper NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_0 | ||
| #define xi NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_1 | ||
| #define dst NBL_CONCEPT_PARAM_T NBL_CONCEPT_PARAM_2 | ||
| NBL_CONCEPT_END( | ||
| ((NBL_CONCEPT_REQ_TYPE)(U::domain_type)) | ||
| ); | ||
| #undef dst | ||
| #undef xi | ||
| #undef warper | ||
| #include <nbl/builtin/hlsl/concepts/__end.hlsl> | ||
|
|
||
| } | ||
|
|
||
| } | ||
| } | ||
|
|
||
| #endif |
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,73 @@ | ||
| #ifndef _NBL_BUILTIN_HLSL_SAMPLING_WARP_SPHERICAL_INCLUDED_ | ||
| #define _NBL_BUILTIN_HLSL_SAMPLING_WARP_SPHERICAL_INCLUDED_ | ||
|
|
||
| #include <nbl/builtin/hlsl/numbers.hlsl> | ||
| #include <nbl/builtin/hlsl/tgmath.hlsl> | ||
| #include <nbl/builtin/hlsl/sampling/warp.hlsl> | ||
|
|
||
| namespace nbl | ||
| { | ||
| namespace hlsl | ||
| { | ||
| namespace sampling | ||
| { | ||
| namespace warp | ||
| { | ||
|
|
||
| struct Spherical | ||
| { | ||
| using domain_type = float32_t2; | ||
| using codomain_type = float32_t3; | ||
|
|
||
| template <typename DomainT NBL_FUNC_REQUIRES(is_same_v<DomainT, domain_type>) | ||
| static WarpResult<codomain_type> warp(const DomainT uv) | ||
| { | ||
| const float32_t phi = 2 * uv.x * numbers::pi<float32_t>; | ||
| const float32_t theta = uv.y * numbers::pi<float32_t>; | ||
| float32_t3 dir; | ||
| dir.x = cos(uv.x * 2.f * numbers::pi<float32_t>); | ||
| dir.y = sqrt(1.f - dir.x * dir.x); | ||
| if (uv.x > 0.5f) dir.y = -dir.y; | ||
| const float32_t cosTheta = cos(theta); | ||
| float32_t sinTheta = (1.0 - cosTheta * cosTheta); | ||
| dir.xy *= sinTheta; | ||
| dir.z = cosTheta; | ||
| WarpResult<codomain_type> warpResult; | ||
| warpResult.dst = dir; | ||
| warpResult.density = 1 / (sinTheta * numbers::pi<float32_t> * numbers::pi<float32_t>); | ||
| return warpResult; | ||
| } | ||
|
|
||
| template <typename CodomainT NBL_FUNC_REQUIRES(is_same_v<CodomainT, codomain_type>) | ||
| static domain_type inverseWarp(const CodomainT v) | ||
| { | ||
| float32_t2 uv = float32_t2(atan(v.y, v.x), acos(v.z)); | ||
| uv.x *= (numbers::inv_pi<float32_t> * 0.5); | ||
| if (v.y < 0.0f) | ||
| uv.x += 1.0f; | ||
| uv.y *= numbers::inv_pi<float32_t>; | ||
| return uv; | ||
| } | ||
|
|
||
|
|
||
| template <typename DomainT NBL_FUNC_REQUIRES(is_same_v<DomainT, domain_type>) | ||
| static float32_t forwardDensity(const DomainT uv) | ||
| { | ||
| const float32_t theta = uv.y * numbers::pi<float32_t>; | ||
| return 1.0f / (sin(theta) * 2 * numbers::pi<float32_t> * numbers::pi<float32_t>); | ||
|
|
||
| } | ||
|
|
||
| template <typename CodomainT NBL_FUNC_REQUIRES(is_same_v<CodomainT, codomain_type>) | ||
| static float32_t backwardDensity(const CodomainT dst) | ||
| { | ||
| return 1.0f / (sqrt(1.0f - dst.z * dst.z) * 2 * numbers::pi<float32_t> * numbers::pi<float32_t>); | ||
| } | ||
| }; | ||
|
|
||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #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.
sampling namespace, anything to do with PDFs is sampling