Skip to content

Commit 7105b0c

Browse files
committed
add include/nbl/builtin/hlsl/ies/profile.hlsl and include/nbl/builtin/hlsl/ies/sampler.hlsl, wipe CIESProfile::sample, save work (won't compile!)
1 parent a7287ca commit 7105b0c

File tree

4 files changed

+263
-148
lines changed

4 files changed

+263
-148
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O.
2+
// This file is part of the "Nabla Engine".
3+
// For conditions of distribution and use, see copyright notice in nabla.h
4+
5+
#ifndef _NBL_BUILTIN_HLSL_IES_PROFILE_INCLUDED_
6+
#define _NBL_BUILTIN_HLSL_IES_PROFILE_INCLUDED_
7+
8+
#include "nbl/builtin/hlsl/cpp_compat.hlsl"
9+
10+
namespace nbl
11+
{
12+
namespace hlsl
13+
{
14+
namespace ies
15+
{
16+
17+
struct ProfileProperties
18+
{
19+
//! max 16K resolution
20+
NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_MAX_TEXTURE_SIZE = 15360u;
21+
NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_MAX_TEXTURE_HEIGHT = 8640u;
22+
23+
NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_DEFAULT_TEXTURE_WIDTH = 1024u;
24+
NBL_CONSTEXPR_STATIC_INLINE uint32_t CDC_DEFAULT_TEXTURE_HEIGHT = 1024u;
25+
26+
NBL_CONSTEXPR_STATIC_INLINE float32_t MAX_VANGLE = 180.f;
27+
NBL_CONSTEXPR_STATIC_INLINE float32_t MAX_HANGLE = 360.f;
28+
29+
enum Version : uint16_t
30+
{
31+
V_1995,
32+
V_2002,
33+
V_SIZE
34+
};
35+
36+
enum PhotometricType : uint16_t
37+
{
38+
TYPE_NONE,
39+
TYPE_C,
40+
TYPE_B,
41+
TYPE_A
42+
};
43+
44+
enum LuminairePlanesSymmetry : uint16_t
45+
{
46+
ISOTROPIC, //! Only one horizontal angle present and a luminaire is assumed to be laterally axial symmetric
47+
QUAD_SYMETRIC, //! The luminaire is assumed to be symmetric in each quadrant
48+
HALF_SYMETRIC, //! The luminaire is assumed to be symmetric about the 0 to 180 degree plane
49+
OTHER_HALF_SYMMETRIC, //! HALF_SYMETRIC case for legacy V_1995 version where horizontal angles are in range [90, 270], in that case the parser patches horizontal angles to be HALF_SYMETRIC
50+
NO_LATERAL_SYMMET //! The luminaire is assumed to exhibit no lateral symmet
51+
};
52+
53+
PhotometricType type;
54+
Version version;
55+
LuminairePlanesSymmetry symmetry;
56+
57+
float32_t maxCandelaValue; //! Max value from this->data vector
58+
float32_t totalEmissionIntegral; //! Total energy emitted
59+
float32_t avgEmmision; //! totalEmissionIntegral / <size of the emission domain where non zero emission values>
60+
};
61+
62+
}
63+
}
64+
}
65+
66+
#endif // _NBL_BUILTIN_HLSL_IES_PROFILE_INCLUDED_
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// Copyright (C) 2018-2025 - DevSH Graphics Programming Sp. z O.O.
2+
// This file is part of the "Nabla Engine".
3+
// For conditions of distribution and use, see copyright notice in nabla.h
4+
5+
#ifndef _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_
6+
#define _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_
7+
8+
#include "nbl/builtin/hlsl/cpp_compat.hlsl"
9+
#include "nbl/builtin/hlsl/numbers.hlsl"
10+
#include "nbl/builtin/hlsl/concepts.hlsl"
11+
#include "nbl/builtin/hlsl/ies/profile.hlsl"
12+
13+
namespace nbl
14+
{
15+
namespace hlsl
16+
{
17+
namespace ies
18+
{
19+
namespace concepts
20+
{
21+
#define NBL_CONCEPT_NAME IESAccessor
22+
#define NBL_CONCEPT_TPLT_PRM_KINDS (typename)
23+
#define NBL_CONCEPT_TPLT_PRM_NAMES (accessor_t)
24+
NBL_CONCEPT_BEGIN(0)
25+
#define req_key_t uint32_t
26+
#define req_key_t2 uint32_t2
27+
#define req_value_t float32_t
28+
NBL_CONCEPT_END(
29+
((NBL_CONCEPT_REQ_TYPE)(accessor_t::key_t))
30+
((NBL_CONCEPT_REQ_TYPE)(accessor_t::key_t2))
31+
((NBL_CONCEPT_REQ_TYPE)(accessor_t::value_t))
32+
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((req_key_t(0)), is_same_v, typename accessor_t::key_t))
33+
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((req_key_t2(0, 0)), is_same_v, typename accessor_t::key_t2))
34+
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((req_value_t(0)), is_same_v, typename accessor_t::value_t))
35+
36+
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().vAnglesCount()), is_same_v, req_key_t))
37+
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().hAnglesCount()), is_same_v, req_key_t))
38+
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().symmetry()), is_same_v, ProfileProperties::LuminairePlanesSymmetry))
39+
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().template vAngle<req_key_t>((req_key_t)0)), is_same_v, req_value_t))
40+
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().template hAngle<req_key_t>((req_key_t)0)), is_same_v, req_value_t))
41+
((NBL_CONCEPT_REQ_EXPR_RET_TYPE)((experimental::declval<accessor_t>().template value<req_key_t2>((req_key_t2)0)), is_same_v, req_value_t))
42+
);
43+
#undef req_key_t
44+
#undef req_key_t2
45+
#undef req_value_t
46+
#include <nbl/builtin/hlsl/concepts/__end.hlsl>
47+
48+
template<typename accessor_t>
49+
NBL_BOOL_CONCEPT IsIESAccessor = IESAccessor<accessor_t>;
50+
}
51+
52+
template<typename Accessor NBL_FUNC_REQUIRES(concepts::IsIESAccessor<Accessor>)
53+
struct CandelaSampler
54+
{
55+
using accessor_t = Accessor;
56+
using value_t = typename accessor_t::value_t;
57+
using symmetry_t = ProfileProperties::LuminairePlanesSymmetry;
58+
59+
static value_t sample(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t2 polar)
60+
{
61+
const float32_t vAngle = degrees(polar.x);
62+
const float32_t hAngle = degrees(wrapPhi(polar.y, symmetry));
63+
64+
const float32_t vABack = accessor.vAngle(accessor.vAnglesCount() - 1u);
65+
if (vAngle > vABack)
66+
return 0.f;
67+
68+
const symmetry_t symmetry = accessor.symmetry();
69+
const uint32_t j0 = getVLB(accessor, vAngle);
70+
const uint32_t j1 = getVUB(accessor, vAngle);
71+
const uint32_t i0 = (symmetry == ISOTROPIC) ? 0u : getHLB(accessor, hAngle);
72+
const uint32_t i1 = (symmetry == ISOTROPIC) ? 0u : getHUB(accessor, hAngle);
73+
74+
const float32_t uReciprocal = ((i1 == i0) ? 1.f : 1.f / (accessor.hAngle(i1) - accessor.hAngle(i0)));
75+
const float32_t vReciprocal = ((j1 == j0) ? 1.f : 1.f / (accessor.vAngle(j1) - accessor.vAngle(j0)));
76+
77+
const float32_t u = ((hAngle - accessor.hAngle(i0)) * uReciprocal);
78+
const float32_t v = ((vAngle - accessor.vAngle(j0)) * vReciprocal);
79+
80+
const float32_t s0 = (accessor.value(uint32_t2(i0, j0)) * (1.f - v) + accessor.value(uint32_t2(i0, j1)) * v);
81+
const float32_t s1 = (accessor.value(uint32_t2(i1, j0)) * (1.f - v) + accessor.value(uint32_t2(i1, j1)) * v);
82+
83+
return s0 * (1.f - u) + s1 * u;
84+
}
85+
86+
static float32_t wrapPhi(const float32_t phi, const symmetry_t symmetry)
87+
{
88+
switch (symmetry)
89+
{
90+
case ISOTROPIC: //! axial symmetry
91+
return 0.0f;
92+
case QUAD_SYMETRIC: //! phi MIRROR_REPEAT wrap onto [0, 90] degrees range
93+
{
94+
NBL_CONSTEXPR float32_t M_HALF_PI = numbers::pi<float32_t> *0.5f;
95+
float32_t wrapPhi = abs(phi); //! first MIRROR
96+
if (wrapPhi > M_HALF_PI) //! then REPEAT
97+
wrapPhi = hlsl::clamp(M_HALF_PI - (wrapPhi - M_HALF_PI), 0.f, M_HALF_PI);
98+
return wrapPhi; //! eg. maps (in degrees) 91,269,271 -> 89 and 179,181,359 -> 1
99+
}
100+
case HALF_SYMETRIC: //! phi MIRROR wrap onto [0, 180] degrees range
101+
case OTHER_HALF_SYMMETRIC: //! eg. maps (in degress) 181 -> 179 or 359 -> 1
102+
return abs(phi);
103+
case NO_LATERAL_SYMMET: //! plot onto whole (in degress) [0, 360] range
104+
{
105+
NBL_CONSTEXPR float32_t M_TWICE_PI = numbers::pi<float32_t> *2.f;
106+
return (phi < 0.f) ? (phi + M_TWICE_PI) : phi;
107+
}
108+
}
109+
return 69.f;
110+
}
111+
112+
struct impl_t
113+
{
114+
static uint32_t getVUB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle)
115+
{
116+
for (uint32_t i = 0u; i < accessor.vAnglesCount(); ++i)
117+
if (accessor.vAngle(i) > angle)
118+
return i;
119+
return accessor.vAnglesCount();
120+
}
121+
122+
static uint32_t getHUB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle)
123+
{
124+
for (uint32_t i = 0u; i < accessor.hAnglesCount(); ++i)
125+
if (accessor.hAngle(i) > angle)
126+
return i;
127+
return accessor.hAnglesCount();
128+
}
129+
};
130+
131+
static uint32_t getVLB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle)
132+
{
133+
return (uint32_t)hlsl::max((int64_t)impl_t::getVUB(accessor, angle) - 1ll, 0ll);
134+
}
135+
136+
static uint32_t getHLB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle)
137+
{
138+
return (uint32_t)hlsl::max((int64_t)impl_t::getHUB(accessor, angle) - 1ll, 0ll);
139+
}
140+
141+
static uint32_t getVUB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle)
142+
{
143+
return (uint32_t)hlsl::min((int64_t)impl_t::getVUB(accessor, angle), (int64_t)(accessor.vAnglesCount() - 1u));
144+
}
145+
146+
static uint32_t getHUB(NBL_CONST_REF_ARG(accessor_t) accessor, const float32_t angle)
147+
{
148+
return (uint32_t)hlsl::min((int64_t)impl_t::getHUB(accessor, angle), (int64_t)(accessor.hAnglesCount() - 1u));
149+
}
150+
};
151+
152+
}
153+
}
154+
}
155+
156+
#endif // _NBL_BUILTIN_HLSL_IES_SAMPLER_INCLUDED_

src/nbl/asset/utils/CIESProfile.cpp

Lines changed: 1 addition & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -8,82 +8,6 @@
88
using namespace nbl;
99
using namespace asset;
1010

11-
const CIESProfile::IES_STORAGE_FORMAT CIESProfile::sample(IES_STORAGE_FORMAT theta, IES_STORAGE_FORMAT phi) const
12-
{
13-
auto wrapPhi = [&](const IES_STORAGE_FORMAT& _phi) -> IES_STORAGE_FORMAT
14-
{
15-
constexpr auto M_HALF_PI =core::HALF_PI<double>();
16-
constexpr auto M_TWICE_PI = core::PI<double>() * 2.0;
17-
18-
switch (symmetry)
19-
{
20-
case ISOTROPIC: //! axial symmetry
21-
return 0.0;
22-
case QUAD_SYMETRIC: //! phi MIRROR_REPEAT wrap onto [0, 90] degrees range
23-
{
24-
float wrapPhi = abs(_phi); //! first MIRROR
25-
26-
if (wrapPhi > M_HALF_PI) //! then REPEAT
27-
wrapPhi = std::clamp<IES_STORAGE_FORMAT>(M_HALF_PI - (wrapPhi - M_HALF_PI), 0, M_HALF_PI);
28-
29-
return wrapPhi; //! eg. maps (in degrees) 91,269,271 -> 89 and 179,181,359 -> 1
30-
}
31-
case HALF_SYMETRIC: //! phi MIRROR wrap onto [0, 180] degrees range
32-
case OTHER_HALF_SYMMETRIC:
33-
return abs(_phi); //! eg. maps (in degress) 181 -> 179 or 359 -> 1
34-
case NO_LATERAL_SYMMET: //! plot onto whole (in degress) [0, 360] range
35-
{
36-
if (_phi < 0)
37-
return _phi + M_TWICE_PI;
38-
else
39-
return _phi;
40-
}
41-
default:
42-
assert(false);
43-
return 69;
44-
}
45-
};
46-
47-
const float vAngle = core::degrees(theta), hAngle = core::degrees(wrapPhi(phi));
48-
49-
assert(vAngle >= 0.0 && vAngle <= 180.0);
50-
assert(hAngle >= 0.0 && hAngle <= 360.0);
51-
52-
if (vAngle > vAngles.back())
53-
return 0.0;
54-
55-
// bilinear interpolation
56-
auto lb = [](const core::vector<double>& angles, double angle) -> size_t
57-
{
58-
assert(!angles.empty());
59-
const size_t idx = std::upper_bound(std::begin(angles), std::end(angles), angle) - std::begin(angles);
60-
return (size_t)std::max((int64_t)idx - 1, (int64_t)0);
61-
};
62-
63-
auto ub = [](const core::vector<double>& angles, double angle) -> size_t
64-
{
65-
assert(!angles.empty());
66-
const size_t idx = std::upper_bound(std::begin(angles), std::end(angles), angle) - std::begin(angles);
67-
return std::min<size_t>(idx, angles.size() - 1);
68-
};
69-
70-
const size_t j0 = lb(vAngles, vAngle);
71-
const size_t j1 = ub(vAngles, vAngle);
72-
const size_t i0 = symmetry == ISOTROPIC ? 0 : lb(hAngles, hAngle);
73-
const size_t i1 = symmetry == ISOTROPIC ? 0 : ub(hAngles, hAngle);
74-
75-
double uResp = i1 == i0 ? 1.0 : 1.0 / (hAngles[i1] - hAngles[i0]);
76-
double vResp = j1 == j0 ? 1.0 : 1.0 / (vAngles[j1] - vAngles[j0]);
77-
78-
double u = (hAngle - hAngles[i0]) * uResp;
79-
double v = (vAngle - vAngles[j0]) * vResp;
80-
81-
double s0 = getCandelaValue(i0, j0) * (1.0 - v) + getCandelaValue(i0, j1) * (v);
82-
double s1 = getCandelaValue(i1, j0) * (1.0 - v) + getCandelaValue(i1, j1) * (v);
83-
84-
return s0 * (1.0 - u) + s1 * u;
85-
}
86-
8711
template<class ExecutionPolicy>
8812
core::smart_refctd_ptr<asset::ICPUImageView> CIESProfile::createIESTexture(ExecutionPolicy&& policy, const float flatten, const bool fullDomainFlatten, uint32_t width, uint32_t height) const
8913
{
@@ -169,7 +93,7 @@ core::smart_refctd_ptr<asset::ICPUImageView> CIESProfile::createIESTexture(Execu
16993
const auto uv = Octahedral::vector2_type(position.x * vertInv, position.y * horiInv);
17094
const auto dir = Octahedral::uvToDir(uv);
17195
const auto polar = Polar::createFromCartesian(dir);
172-
const auto intensity = sample(polar.theta, polar.phi);
96+
const auto intensity = sampler_t::sample(accessor, hlsl::uint32_t(polar.theta, polar.phi));
17397

17498
//! blend the IES texture with "flatten"
17599
double blendV = intensity * (1.0 - flatten);

0 commit comments

Comments
 (0)