Skip to content

Hlsl path tracer example #863

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
wants to merge 43 commits into
base: hlsl_bxdfs
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 41 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
02d6d0f
initial example
keptsecret Feb 4, 2025
129b50e
use bxdf creation params struct
keptsecret Feb 6, 2025
74261dc
triangle and rectangle shapes
keptsecret Feb 7, 2025
ab3ae20
more sampling methods
keptsecret Feb 10, 2025
355cfec
spherical rectangle
keptsecret Feb 11, 2025
ebf8fca
merge pcg fix from upstream
keptsecret Feb 12, 2025
11180f4
fix aniso cache bug
keptsecret Feb 17, 2025
4516051
init func to modify bxdf params directly
keptsecret Feb 18, 2025
d9a00c9
bug fixes
keptsecret Feb 20, 2025
ffe9029
fix sampling bugs #2
keptsecret Feb 21, 2025
cee192e
update to master
keptsecret Feb 21, 2025
b207312
fix rank type trait for matrix/vector
keptsecret Feb 21, 2025
673f788
merge hlsl bxdfs, resolve conflict
keptsecret Feb 25, 2025
69a257d
temporary fix for dxc bug issue 7154
keptsecret Feb 25, 2025
866e6d7
some bug fixes again
keptsecret Feb 26, 2025
85e955f
fix wrong template usage
keptsecret Feb 27, 2025
3b167ab
merge changes from hlsl_bxdf
keptsecret Feb 28, 2025
19e3a35
merge master/bxdf fixes, resolve conflicts
keptsecret Mar 3, 2025
6b5bf06
Merge branch 'hlsl_bxdfs' into hlsl_path_tracer_example
keptsecret Mar 4, 2025
7b574da
Merge branch 'hlsl_bxdfs' into hlsl_path_tracer_example
keptsecret Mar 4, 2025
1c773d9
fix typo
keptsecret Mar 4, 2025
326c885
Merge branch 'hlsl_bxdfs' into hlsl_path_tracer_example
keptsecret Mar 5, 2025
6132a4e
Merge branch 'revert-some-device-limits' into hlsl_path_tracer_example
keptsecret Mar 6, 2025
0bd26c7
Merge branch 'master' into hlsl_path_tracer_example
keptsecret Mar 6, 2025
ebb1b15
Merge branch 'hlsl_bxdfs' into hlsl_path_tracer_example
keptsecret Mar 7, 2025
7cb977d
Merge branch 'hlsl_bxdfs' into hlsl_path_tracer_example
keptsecret Mar 7, 2025
67c525e
Merge branch 'master' into hlsl_path_tracer_example
keptsecret Mar 10, 2025
a8f209e
Merge branch 'hlsl_bxdfs' into hlsl_path_tracer_example
keptsecret Mar 11, 2025
e8d2ed8
fixed some func usage to nbl ver
keptsecret Mar 14, 2025
c47f446
specify template args
keptsecret Mar 17, 2025
642e46d
fix merge conflicts
keptsecret Mar 17, 2025
1137b6b
update to latest example
keptsecret Mar 17, 2025
5cd4e6c
merge math, fix conflict
keptsecret Mar 19, 2025
7e8dd81
latest example
keptsecret Mar 19, 2025
f86dd0c
Merge remote-tracking branch 'origin/intrinsics_adjustments' into hls…
keptsecret Mar 21, 2025
b154638
fix use of static const in func
keptsecret Mar 21, 2025
7892563
added more morton order stuff
keptsecret Mar 24, 2025
b21b789
latest example
keptsecret Mar 28, 2025
1f461ff
merge master, fix conflicts
keptsecret Apr 3, 2025
df2321a
merge hlsl_bxdfs, fix conflicts
keptsecret Jun 26, 2025
26adf95
latest example
keptsecret Jun 27, 2025
0d80626
Merge branch 'hlsl_bxdfs' into hlsl_path_tracer_example
keptsecret Jun 27, 2025
36910c6
latest example fixes
keptsecret Jun 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples_tests
17 changes: 17 additions & 0 deletions include/nbl/builtin/glsl/utils/morton.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ uint nbl_glsl_morton_decode2d8bComponent(in uint x)
return x;
}

uint nbl_glsl_morton_decode2d32bComponent(in uint x)
{
x &= 0x55555555u;
x = (x ^ (x >> 1u)) & 0x33333333u;
x = (x ^ (x >> 2u)) & 0x0f0f0f0fu;
x = (x ^ (x >> 4u)) & 0x00ff00ffu;
x = (x ^ (x >> 8u)) & 0x0000ffffu;
x = (x ^ (x >> 16u));
return x;
}


uvec2 nbl_glsl_morton_decode2d4b(in uint x)
{
return uvec2(nbl_glsl_morton_decode2d4bComponent(x), nbl_glsl_morton_decode2d4bComponent(x >> 1u));
Expand All @@ -32,4 +44,9 @@ uvec2 nbl_glsl_morton_decode2d8b(in uint x)
return uvec2(nbl_glsl_morton_decode2d8bComponent(x), nbl_glsl_morton_decode2d8bComponent(x >> 1u));
}

uvec2 nbl_glsl_morton_decode2d32b(in uint x)
{
return uvec2(nbl_glsl_morton_decode2d32bComponent(x), nbl_glsl_morton_decode2d32bComponent(x >> 1u));
}

#endif
80 changes: 60 additions & 20 deletions include/nbl/builtin/hlsl/cpp_compat/impl/intrinsics_impl.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ template<typename T NBL_STRUCT_CONSTRAINABLE>
struct nMax_helper;
template<typename T NBL_STRUCT_CONSTRAINABLE>
struct nClamp_helper;

template<typename T NBL_STRUCT_CONSTRAINABLE>
struct fma_helper;

#ifdef __HLSL_VERSION // HLSL only specializations

Expand Down Expand Up @@ -134,6 +135,7 @@ template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(find_lsb_helper, findIL
#undef FIND_MSB_LSB_RETURN_TYPE

template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(bitReverse_helper, bitReverse, (T), (T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(dot_helper, dot, (T), (T)(T), typename vector_traits<T>::scalar_type)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(transpose_helper, transpose, (T), (T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(length_helper, length, (T), (T), typename vector_traits<T>::scalar_type)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(normalize_helper, normalize, (T), (T), T)
Expand Down Expand Up @@ -162,6 +164,7 @@ template<typename T, typename U> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(refract_hel
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(nMax_helper, nMax, (T), (T)(T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(nMin_helper, nMin, (T), (T)(T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(nClamp_helper, nClamp, (T), (T)(T), T)
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(fma_helper, fma, (T), (T)(T)(T), T)

#define BITCOUNT_HELPER_RETRUN_TYPE conditional_t<is_vector_v<T>, vector<int32_t, vector_traits<T>::Dimension>, int32_t>
template<typename T> AUTO_SPECIALIZE_TRIVIAL_CASE_HELPER(bitCount_helper, bitCount, (T), (T), BITCOUNT_HELPER_RETRUN_TYPE)
Expand Down Expand Up @@ -599,6 +602,16 @@ struct nClamp_helper<T>
}
};

template<typename FloatingPoint>
requires concepts::FloatingPointScalar<FloatingPoint>
struct fma_helper<FloatingPoint>
{
static FloatingPoint __call(NBL_CONST_REF_ARG(FloatingPoint) x, NBL_CONST_REF_ARG(FloatingPoint) y, NBL_CONST_REF_ARG(FloatingPoint) z)
{
return std::fma(x, y, z);
}
};

#endif // C++ only specializations

// C++ and HLSL specializations
Expand All @@ -613,25 +626,6 @@ struct bitReverseAs_helper<T NBL_PARTIAL_REQ_BOT(concepts::UnsignedIntegralScala
}
};

template<typename Vectorial>
NBL_PARTIAL_REQ_TOP(concepts::Vectorial<Vectorial>)
struct dot_helper<Vectorial NBL_PARTIAL_REQ_BOT(concepts::Vectorial<Vectorial>) >
{
using scalar_type = typename vector_traits<Vectorial>::scalar_type;

static inline scalar_type __call(NBL_CONST_REF_ARG(Vectorial) lhs, NBL_CONST_REF_ARG(Vectorial) rhs)
{
static const uint32_t ArrayDim = vector_traits<Vectorial>::Dimension;
static array_get<Vectorial, scalar_type> getter;

scalar_type retval = getter(lhs, 0) * getter(rhs, 0);
for (uint32_t i = 1; i < ArrayDim; ++i)
retval = retval + getter(lhs, i) * getter(rhs, i);

return retval;
}
};

#ifdef __HLSL_VERSION
// SPIR-V already defines specializations for builtin vector types
#define VECTOR_SPECIALIZATION_CONCEPT concepts::Vectorial<T> && !is_vector_v<T>
Expand Down Expand Up @@ -888,6 +882,52 @@ struct mix_helper<T, U NBL_PARTIAL_REQ_BOT(concepts::Vectorial<T> && concepts::B
}
};

#ifdef __HLSL_VERSION
#define DOT_HELPER_REQUIREMENT (concepts::Vectorial<Vectorial> && !is_vector_v<Vectorial>)
#else
#define DOT_HELPER_REQUIREMENT concepts::Vectorial<Vectorial>
#endif

template<typename Vectorial>
NBL_PARTIAL_REQ_TOP(DOT_HELPER_REQUIREMENT)
struct dot_helper<Vectorial NBL_PARTIAL_REQ_BOT(DOT_HELPER_REQUIREMENT) >
{
using scalar_type = typename vector_traits<Vectorial>::scalar_type;

static inline scalar_type __call(NBL_CONST_REF_ARG(Vectorial) lhs, NBL_CONST_REF_ARG(Vectorial) rhs)
{
static const uint32_t ArrayDim = vector_traits<Vectorial>::Dimension;
static array_get<Vectorial, scalar_type> getter;

scalar_type retval = getter(lhs, 0) * getter(rhs, 0);
for (uint32_t i = 1; i < ArrayDim; ++i)
retval = retval + getter(lhs, i) * getter(rhs, i);

return retval;
}
};

#undef DOT_HELPER_REQUIREMENT

template<typename T>
NBL_PARTIAL_REQ_TOP(VECTOR_SPECIALIZATION_CONCEPT)
struct fma_helper<T NBL_PARTIAL_REQ_BOT(VECTOR_SPECIALIZATION_CONCEPT) >
{
using return_t = T;
static return_t __call(NBL_CONST_REF_ARG(T) x, NBL_CONST_REF_ARG(T) y, NBL_CONST_REF_ARG(T) z)
{
using traits = hlsl::vector_traits<T>;
array_get<T, typename traits::scalar_type> getter;
array_set<T, typename traits::scalar_type> setter;

return_t output;
for (uint32_t i = 0; i < traits::Dimension; ++i)
setter(output, i, fma_helper<typename traits::scalar_type>::__call(getter(x, i), getter(y, i), getter(z, i)));

return output;
}
};

}
}
}
Expand Down
6 changes: 6 additions & 0 deletions include/nbl/builtin/hlsl/cpp_compat/intrinsics.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,12 @@ inline int32_t2 unpackDouble2x32(T val)
return NAMESPACE::unpackDouble2x32(val);
}

template<typename T>
inline T fma(NBL_CONST_REF_ARG(T) x, NBL_CONST_REF_ARG(T) y, NBL_CONST_REF_ARG(T) z)
{
return cpp_compat_intrinsics_impl::fma_helper<T>::__call(x, y, z);
}

#undef NAMESPACE

}
Expand Down
2 changes: 1 addition & 1 deletion include/nbl/builtin/hlsl/limits.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ struct num_base : type_identity<T>

// (TODO) think about what this means for HLSL
// identifies floating-point types that can represent the special value "quiet not-a-number" (NaN)
NBL_CONSTEXPR_STATIC_INLINE bool has_quiet_NaN = !is_integer;
NBL_CONSTEXPR_STATIC_INLINE bool has_quiet_NaN = !is_integer;
// identifies floating-point types that can represent the special value "signaling not-a-number" (NaN)
NBL_CONSTEXPR_STATIC_INLINE bool has_signaling_NaN = !is_integer;
// identifies the denormalization style used by the floating-point type
Expand Down
6 changes: 1 addition & 5 deletions include/nbl/builtin/hlsl/math/functions.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,7 @@ void frisvad(NBL_CONST_REF_ARG(T) normal, NBL_REF_ARG(T) tangent, NBL_REF_ARG(T)

bool partitionRandVariable(float leftProb, NBL_REF_ARG(float) xi, NBL_REF_ARG(float) rcpChoiceProb)
{
#ifdef __HLSL_VERSION
NBL_CONSTEXPR float NEXT_ULP_AFTER_UNITY = asfloat(0x3f800001u);
#else
NBL_CONSTEXPR float32_t NEXT_ULP_AFTER_UNITY = bit_cast<float32_t>(0x3f800001u);
#endif
const float32_t NEXT_ULP_AFTER_UNITY = bit_cast<float32_t>(0x3f800001u);
Comment on lines 123 to +125
Copy link
Member Author

Choose a reason for hiding this comment

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

should be templated on T instead of float and live in sampling.hlsl (named same as the folder and namespace), do as part of #811

P.S. for the constant you can use

const T NextULPAfterUnity = bit_cast<T>(++bit_cast<unsigned_int_of_size_t<sizeof(T)> >(T(1)));

Copy link
Member Author

Choose a reason for hiding this comment

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

or you can put it in sampling/basic.hlsl

const bool pickRight = xi >= leftProb * NEXT_ULP_AFTER_UNITY;

// This is all 100% correct taking into account the above NEXT_ULP_AFTER_UNITY
Expand Down
68 changes: 68 additions & 0 deletions include/nbl/builtin/hlsl/math/morton.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (C) 2018-2023 - 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_MATH_MORTON_INCLUDED_
#define _NBL_BUILTIN_HLSL_MATH_MORTON_INCLUDED_

#include "nbl/builtin/hlsl/cpp_compat.hlsl"

namespace nbl
{
namespace hlsl
{
namespace math
{

namespace impl
{

template<typename T, uint32_t bitDepth>
struct MortonComponent;

template<typename T>
struct MortonComponent<T, 8u>
{
static T decode2d(T x)
{
x &= 0x55555555u;
x = (x ^ (x >> 1u)) & 0x33333333u;
x = (x ^ (x >> 2u)) & 0x0f0f0f0fu;
x = (x ^ (x >> 4u)) & 0x00ff00ffu;
return x;
}
};

template<typename T>
struct MortonComponent<T, 32u>
{
static T decode2d(T x)
{
x &= 0x55555555u;
x = (x ^ (x >> 1u)) & 0x33333333u;
x = (x ^ (x >> 2u)) & 0x0f0f0f0fu;
x = (x ^ (x >> 4u)) & 0x00ff00ffu;
x = (x ^ (x >> 8u)) & 0x0000ffffu;
x = (x ^ (x >> 16u));
return x;
}
};

}

template<typename T, uint32_t bitDepth=sizeof(T)*8u>
struct Morton
{
using vector2_type = vector<T, 2>;
using component_type = impl::MortonComponent<T, bitDepth>;

static vector2_type decode2d(T x)
{
return vector2_type(component_type::decode2d(x), component_type::decode2d(x >> 1u));
}
};

}
}
}

#endif
Comment on lines +1 to +68
Copy link
Member Author

Choose a reason for hiding this comment

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

file will die after #860 is merged

62 changes: 62 additions & 0 deletions include/nbl/builtin/hlsl/sampling/bilinear.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (C) 2018-2023 - 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_BILINEAR_INCLUDED_
#define _NBL_BUILTIN_HLSL_SAMPLING_BILINEAR_INCLUDED_

#include <nbl/builtin/hlsl/cpp_compat.hlsl>
#include <nbl/builtin/hlsl/limits.hlsl>
#include <nbl/builtin/hlsl/sampling/linear.hlsl>

namespace nbl
{
namespace hlsl
{
namespace sampling
{

template<typename T>
struct Bilinear
{
using scalar_type = T;
using vector2_type = vector<T, 2>;
using vector3_type = vector<T, 3>;
using vector4_type = vector<T, 4>;

static Bilinear<T> create(NBL_CONST_REF_ARG(vector4_type) bilinearCoeffs)
{
Bilinear<T> retval;
retval.bilinearCoeffs = bilinearCoeffs;
return retval;
}

vector2_type generate(NBL_REF_ARG(scalar_type) rcpPdf, NBL_CONST_REF_ARG(vector2_type) _u)
Copy link
Member Author

@devshgraphicsprogramming devshgraphicsprogramming Apr 1, 2025

Choose a reason for hiding this comment

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

we need some structs like

template<typename V, typename P=float>
struct ValueAndPdf;

template<typename T, typename P=float>
struct ValueAndRcpPdf;

in sampling/basic.hlsl

do as part of #811

P.S. can require that P is a ScalarFloat

{
vector2_type u = _u;
const vector2_type twiceAreasUnderXCurve = vector2_type(bilinearCoeffs[0] + bilinearCoeffs[1], bilinearCoeffs[2] + bilinearCoeffs[3]);
Linear<scalar_type> lineary = Linear<scalar_type>::create(twiceAreasUnderXCurve);
u.y = lineary.generate(u.y);

const vector2_type ySliceEndPoints = vector2_type(nbl::hlsl::mix(bilinearCoeffs[0], bilinearCoeffs[2], u.y), nbl::hlsl::mix(bilinearCoeffs[1], bilinearCoeffs[3], u.y));
Linear<scalar_type> linearx = Linear<scalar_type>::create(ySliceEndPoints);
u.x = linearx.generate(u.x);

rcpPdf = (twiceAreasUnderXCurve[0] + twiceAreasUnderXCurve[1]) / (4.0 * nbl::hlsl::mix(ySliceEndPoints[0], ySliceEndPoints[1], u.x));

return u;
}

scalar_type pdf(NBL_CONST_REF_ARG(vector2_type) u)
{
return 4.0 * nbl::hlsl::mix(nbl::hlsl::mix(bilinearCoeffs[0], bilinearCoeffs[1], u.x), nbl::hlsl::mix(bilinearCoeffs[2], bilinearCoeffs[3], u.x), u.y) / (bilinearCoeffs[0] + bilinearCoeffs[1] + bilinearCoeffs[2] + bilinearCoeffs[3]);
}

vector4_type bilinearCoeffs;
Copy link
Member Author

Choose a reason for hiding this comment

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

document which index/component maps to which vertex of the unit square

};

}
}
}

#endif
27 changes: 27 additions & 0 deletions include/nbl/builtin/hlsl/sampling/box_muller_transform.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright (C) 2018-2023 - 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_BOX_MULLER_TRANSFORM_INCLUDED_
#define _NBL_BUILTIN_HLSL_BOX_MULLER_TRANSFORM_INCLUDED_

#include "nbl/builtin/hlsl/math/functions.hlsl"
#include "nbl/builtin/hlsl/numbers.hlsl"

namespace nbl
{
namespace hlsl
{

template<typename T>
vector<T,2> boxMullerTransform(vector<T,2> xi, T stddev)
{
T sinPhi, cosPhi;
math::sincos<T>(2.0 * numbers::pi<float> * xi.y - numbers::pi<float>, sinPhi, cosPhi);
return vector<T,2>(cosPhi, sinPhi) * nbl::hlsl::sqrt(-2.0 * nbl::hlsl::log(xi.x)) * stddev;
}
Comment on lines +16 to +22
Copy link
Member Author

Choose a reason for hiding this comment

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

turn into struct with stddev as a member


}
}

#endif
45 changes: 45 additions & 0 deletions include/nbl/builtin/hlsl/sampling/linear.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (C) 2018-2023 - 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_LINEAR_INCLUDED_
#define _NBL_BUILTIN_HLSL_SAMPLING_LINEAR_INCLUDED_

#include <nbl/builtin/hlsl/cpp_compat.hlsl>
#include <nbl/builtin/hlsl/limits.hlsl>

namespace nbl
{
namespace hlsl
{
namespace sampling
{

template<typename T>
struct Linear
{
using scalar_type = T;
using vector2_type = vector<T, 2>;

static Linear<T> create(NBL_CONST_REF_ARG(vector2_type) linearCoeffs)
{
Linear<T> retval;
retval.linearCoeffs = linearCoeffs;
return retval;
}

scalar_type generate(scalar_type u)
{
const scalar_type rcpDiff = 1.0 / (linearCoeffs[0] - linearCoeffs[1]);
const vector2_type squaredCoeffs = linearCoeffs * linearCoeffs;
return nbl::hlsl::abs(rcpDiff) < numeric_limits<scalar_type>::max ? (linearCoeffs[0] - nbl::hlsl::sqrt(nbl::hlsl::mix(squaredCoeffs[0], squaredCoeffs[1], u))) * rcpDiff : u;
}

vector2_type linearCoeffs;
};

}
}
}

#endif
Loading