Skip to content

Created concepts for samplers, added quotient_and_pdf variants to satisfy the concepts#1001

Open
karimsayedre wants to merge 52 commits intomasterfrom
sampler-concepts
Open

Created concepts for samplers, added quotient_and_pdf variants to satisfy the concepts#1001
karimsayedre wants to merge 52 commits intomasterfrom
sampler-concepts

Conversation

@karimsayedre
Copy link
Copy Markdown
Contributor

@karimsayedre karimsayedre commented Feb 18, 2026

Examples PR

Notes:

  • The quotient_and_pdf() methods in UniformHemisphere, UniformSphere, ProjectedHemisphere, and ProjectedSphere shadow the struct type sampling::quotient_and_pdf<Q, P> from quotient_and_pdf.hlsl. DXC can't resolve the return type because the method name takes precedence over the struct name during lookup. Fixed by fully qualifying with ::nbl::hlsl::sampling::quotient_and_pdf<U, T>.
  • Obv. there's some refactoring to be done to satisfy all the concepts, so for not Basic (Level1) samplers are concept tested

…concepts

- Move codomain_and_*Pdf and domain_and_*Pdf structs into their own warp_and_pdf.hlsl header
- Keeping quotient_and_pdf.hlsl focused on importance sampling quotients for BxDFs
- Add SampleWithPDF, SampleWithRcpPDF, and SampleWithDensity concepts to validate sample types
- Used concept composition (NBL_CONCEPT_REQ_TYPE_ALIAS_CONCEPT) to build ResamplableSampler on TractableSampler and BijectiveSampler on ResamplableSampler
Comment on lines 69 to 70
if (pyramidAngles())
return 0.f;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead check for the solidAngle being 0 or below a threshold

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then you can fold pyramidAngles into the create

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved

Comment on lines 103 to 109
const scalar_type u = subTriSolidAngleRatio > numeric_limits<scalar_type>::min ? subTriSolidAngleRatio : 0.0;

const scalar_type sinBC_s_product = sinB_ * sinC_;

// 1 ULP below 1.0, ensures (1.0 - cosBC_s) is strictly positive in float
const scalar_type one_below_one = bit_cast<scalar_type>(bit_cast<uint_type>(scalar_type(1)) - uint_type(1));
const scalar_type one_below_one = ieee754::nextTowardZero(scalar_type(1.0));
const scalar_type cosBC_s = sinBC_s_product > numeric_limits<scalar_type>::min ? (cosA + cosB_ * cosC_) / sinBC_s_product : triCosC;
const scalar_type v_denom = scalar_type(1.0) - (cosBC_s < one_below_one ? cosBC_s : triCosC);
Copy link
Copy Markdown
Member

@devshgraphicsprogramming devshgraphicsprogramming Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replace the ?s with hlsl::select

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved


struct cache_type
{
// TODO: should we cache `r`?
Copy link
Copy Markdown
Member

@devshgraphicsprogramming devshgraphicsprogramming Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, what for?
the PDF is constant

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought maybe we'd need it for whatever other stuff after the generate and pdf

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well we obviously don't since the PDF is constant

Comment on lines +53 to +64
typename Linear<scalar_type>::cache_type linearYCache;

vector2_type p;
p.y = lineary.generate(u.y, linearCache);
p.y = lineary.generate(u.y, linearYCache);

const vector2_type ySliceEndPoints = vector2_type(bilinearCoeffs[0] + p.y * bilinearCoeffDiffs[0], bilinearCoeffs[1] + p.y * bilinearCoeffDiffs[1]);
Linear<scalar_type> linearx = Linear<scalar_type>::create(ySliceEndPoints);
p.x = linearx.generate(u.x, linearCache);
p.x = linearx.generate(u.x, cache.linearXCache);

cache.pdf = nbl::hlsl::mix(ySliceEndPoints[0], ySliceEndPoints[1], p.x) * fourOverTwiceAreasUnderXCurveSum;
// pre-multiply by normalization so forwardPdf is just addition
cache.normalizedStart = ySliceEndPoints[0] * fourOverTwiceAreasUnderXCurveSum;
cache.linearXCache.diffTimesX *= fourOverTwiceAreasUnderXCurveSum;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the reason I came up with this refactor #1001 (comment) was motivated exactly by doing less work in bilinear

const T twopi = T(2.0) * numbers::pi<T>;
phi += hlsl::mix(T(0.0), twopi, phi < T(0.0));
return vector_t2(_sample.z, phi / twopi);
return vector_t2(_sample.z, impl::phiSampleFromDirection(_sample.x, _sample.y));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was just a polar sampling with corrected/linear r instead of square root

Btw we should use concentric because its higher quality, since the would-be-r needs to be squared, you'd need to pass dominant from the concentric mapping back to multiply the XY coordinates by it again

then you can use sqrt(1-dominant*dominant) as the z-coordinate for the hemisphere

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved

# Conflicts:
#	examples_tests
…() for floats, separeted SMaxError into a separate file with support to other types than float
kevyuu pushed a commit that referenced this pull request Mar 31, 2026
AnastaZIuk and others added 3 commits April 1, 2026 09:03
Pick up the follow-up O1experimental VariablePointers trim that stops treating ordinary OpStore instructions as a reason to keep the capability alive. This keeps the sampler branch aligned with the updated DXC and SPIRV-Tools lane for package rebuilding and CI validation.
Restore the clamp on cosAngleAlongBC_s before the BC slerp. This removes the remaining narrow numeric drift seen in EX37 after the VariablePointers toolchain fix and brings the sampler branch workload back to a full pass in PACKAGE mode.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants