Foundation
Loading...
Searching...
No Matches
LightBVH.hpp
Go to the documentation of this file.
1#pragma once
2#include <Core/Container.hpp>
3#include <Core/Logging.hpp>
4#include <Math/Math.hpp>
5#include <Math/Quantize.hpp>
6#include <algorithm>
7#include <bit>
8#include <cmath>
9#include <cstdint>
10#include <numbers>
11#include "GPUScene.hpp"
12
13using namespace Foundation;
14using namespace Core;
15using namespace Math;
16
17inline constexpr float kLightBVHInvalidCosConeAngle = -1.0f;
18inline constexpr uint32_t kLightBVHMaxDepth = 64u;
19inline constexpr uint32_t kLightBVHLightCountBits = 4u;
20inline constexpr uint32_t kLightBVHLightOffsetBits = 31u - kLightBVHLightCountBits;
21inline constexpr uint32_t kLightBVHMaxLightsPerLeaf = 1u << kLightBVHLightCountBits;
22inline constexpr uint32_t kLightBVHMaxLightOffset = 1u << kLightBVHLightOffsetBits;
23inline constexpr uint32_t kLightBVHLeafBit = 1u << 31;
24inline constexpr float kLightBVHMinSunAngularRadius = 1e-4f;
25
26enum class LightBVHSplitHeuristic : uint32_t
27{
28 Equal = 0u,
29 BinnedSAH = 1u,
30 BinnedSAOH = 2u,
31};
32
43
53
55{
56 uint32_t data[8]{};
57};
58static_assert(sizeof(GSLightBVHNode) == 32);
59
60inline bool LightBVHNodeIsLeaf(LightBVHNode const& node)
61{
62 return (node.header & kLightBVHLeafBit) != 0u;
63}
64
65inline uint32_t LightBVHNodeRightChild(LightBVHNode const& node)
66{
67 return node.header; // MSB clear for internal nodes
68}
69
70inline uint32_t LightBVHNodeLightCount(LightBVHNode const& node)
71{
72 return (node.header >> kLightBVHLightOffsetBits) & ((1u << kLightBVHLightCountBits) - 1u);
73}
74
75inline uint32_t LightBVHNodeLightOffset(LightBVHNode const& node)
76{
77 return node.header & ((1u << kLightBVHLightOffsetBits) - 1u);
78}
79
80inline void LightBVHNodeSetAABB(LightBVHNode& node, float3 const& aabbMin, float3 const& aabbMax)
81{
82 node.origin = (aabbMax + aabbMin) * 0.5f;
83 node.extent = (aabbMax - aabbMin) * 0.5f;
84}
85
86inline void LightBVHNodeGetAABB(LightBVHNode const& node, float3& aabbMin, float3& aabbMax)
87{
88 aabbMin = node.origin - node.extent;
89 aabbMax = node.origin + node.extent;
90}
91
92inline void LightBVHNodeSetInternal(LightBVHNode& node, uint32_t rightChildIdx)
93{
94 node.header = rightChildIdx;
95}
96
97inline void LightBVHNodeSetLeaf(LightBVHNode& node, uint32_t lightCount, uint32_t lightOffset)
98{
99 node.header = kLightBVHLeafBit | (lightCount << kLightBVHLightOffsetBits) | lightOffset;
100}
101
102inline uint16_t PackLightBVHExtent(float extent)
103{
104 extent = std::max(extent, 0.0f);
105 uint16_t packed = quantizeFP16(extent);
106 if (dequantizeFP16(packed) < extent && packed < 0x7c00u)
107 ++packed;
108 return packed;
109}
110
111inline uint32_t PackLightBVHConeDirection(float3 direction)
112{
113 if (length(direction) <= 1e-12f)
114 return 0u;
115 direction /= std::abs(direction.x) + std::abs(direction.y) + std::abs(direction.z);
116 float2 oct = direction.z >= 0.0f
117 ? direction.xy()
118 : (float2(1.0f) - abs(direction.yx())) * sign(direction.xy() + float2(1e-6f));
119 uint32_t x = static_cast<uint16_t>(quantizeSnorm(oct.x, 16));
120 uint32_t y = static_cast<uint16_t>(quantizeSnorm(oct.y, 16));
121 return x | (y << 16u);
122}
123
124inline float3 UnpackLightBVHConeDirection(uint32_t packed)
125{
126 int16_t x = static_cast<int16_t>(packed & 0xffffu);
127 int16_t y = static_cast<int16_t>(packed >> 16u);
128 float2 oct = clamp(float2(static_cast<float>(x), static_cast<float>(y)) * (1.0f / 32767.0f),
129 float2(-1.0f), float2(1.0f));
130 float3 normal(oct, 1.0f - std::abs(oct.x) - std::abs(oct.y));
131 float2 xy = normal.z >= 1e-6f
132 ? oct
133 : (float2(1.0f) - abs(oct.yx())) * sign(oct + float2(1e-6f));
134 return normalize(float3(xy.x, xy.y, normal.z));
135}
136
138{
139 GSLightBVHNode packed{};
140 packed.data[0] = node.header;
141 packed.data[1] = std::bit_cast<uint32_t>(node.origin.x);
142 packed.data[2] = std::bit_cast<uint32_t>(node.origin.y);
143 packed.data[3] = std::bit_cast<uint32_t>(node.origin.z);
144 uint32_t extentX = PackLightBVHExtent(node.extent.x);
145 uint32_t extentY = PackLightBVHExtent(node.extent.y);
146 uint32_t extentZ = PackLightBVHExtent(node.extent.z);
147 float angle = std::clamp(node.cosConeAngle, -1.0f, 1.0f);
148 uint32_t packedDirection = PackLightBVHConeDirection(node.coneDirection);
149 if (angle > kLightBVHInvalidCosConeAngle && length(node.coneDirection) > 1e-12f)
150 {
151 float3 decodedDirection = UnpackLightBVHConeDirection(packedDirection);
152 float directionError = std::acos(std::clamp(dot(normalize(node.coneDirection), decodedDirection), -1.0f, 1.0f));
153 float widenedAngle = std::min(std::acos(angle) + directionError, std::numbers::pi_v<float>);
154 angle = widenedAngle < std::numbers::pi_v<float> ? std::cos(widenedAngle)
156 }
157 uint32_t packedAngle = static_cast<uint32_t>((angle + 1.0f) * 32767.0f);
158 packed.data[4] = extentX | (extentY << 16u);
159 packed.data[5] = extentZ | (packedAngle << 16u);
160 packed.data[6] = packedDirection;
161 packed.data[7] = std::bit_cast<uint32_t>(node.flux);
162 return packed;
163}
164
166{
167 LightBVHNode node{};
168 node.header = packed.data[0];
169 node.origin = float3(std::bit_cast<float>(packed.data[1]), std::bit_cast<float>(packed.data[2]),
170 std::bit_cast<float>(packed.data[3]));
171 node.extent = float3(dequantizeFP16(static_cast<uint16_t>(packed.data[4])),
172 dequantizeFP16(static_cast<uint16_t>(packed.data[4] >> 16u)),
173 dequantizeFP16(static_cast<uint16_t>(packed.data[5])));
174 node.cosConeAngle = static_cast<float>(packed.data[5] >> 16u) * (1.0f / 32767.0f) - 1.0f;
175 node.coneDirection = UnpackLightBVHConeDirection(packed.data[6]);
176 node.flux = std::bit_cast<float>(packed.data[7]);
177 return node;
178}
179
181
183{
184 uint32_t treeHeight = 0;
185 uint32_t minDepth = 0;
186 uint32_t byteSize = 0;
187 uint32_t internalNodeCount = 0;
188 uint32_t leafNodeCount = 0;
189 uint32_t finiteLightCount = 0;
190 uint32_t globalLightCount = 0;
191};
192
215
216[[nodiscard]] inline uint32_t GSLightTypeCPU(GSLight const& light)
217{
218 return light.flags & kGSLightTypeMask;
219}
220
221[[nodiscard]] inline bool IsDistantLightType(uint32_t type)
222{
223 return type == kGSLightTypeDirectional || type == kGSLightTypeEnvironment;
224}
225
226[[nodiscard]] inline bool IsFiniteLightType(uint32_t type)
227{
228 return type == kGSLightTypePoint || type == kGSLightTypeSpot || type == kGSLightTypeDisk ||
229 type == kGSLightTypeRect;
230}
231
232[[nodiscard]] inline bool HasLightEmission(GSLight const& light)
233{
234 return light.power > 0.0f && any(greaterThan(light.color, float3(0.0f)));
235}
236// NOTE: Must match ComputeLightProposalWeight in ICommon.slang
237[[nodiscard]] inline float ComputeLightProposalWeight(GSLight const& light)
238{
239 float colorWeight = (std::abs(light.color.x) + std::abs(light.color.y) + std::abs(light.color.z)) / 3.0f;
240 float radiometricWeight = std::max(0.0f, light.power) * colorWeight;
241 uint32_t type = GSLightTypeCPU(light);
242 if (type == kGSLightTypeDirectional)
243 {
244 return radiometricWeight;
245 }
246 if (type == kGSLightTypeEnvironment)
247 {
248 return radiometricWeight * light.params.y * std::numbers::pi_v<float>;
249 }
250 if (type == kGSLightTypePoint)
251 return radiometricWeight * (4.0f * std::numbers::pi_v<float>);
252 if (type == kGSLightTypeSpot)
253 {
254 float cosInner = std::clamp(std::max(light.params.y, light.params.z), -1.0f, 1.0f);
255 float cosOuter = std::clamp(std::min(light.params.y, light.params.z), -1.0f, cosInner);
256 float solidAngle = 2.0f * std::numbers::pi_v<float> *
257 ((1.0f - cosInner) + (cosInner - cosOuter) / 5.0f);
258 return radiometricWeight * solidAngle;
259 }
260 if (type == kGSLightTypeDisk || type == kGSLightTypeRect)
261 {
262 float area = type == kGSLightTypeDisk
263 ? std::numbers::pi_v<float> * light.params.x * light.params.y
264 : 4.0f * length(cross(light.dpdu, light.dpdv));
265 float sides = (light.flags & to_integer(GSLightFlagsBits::TwoSided)) != 0u ? 2.0f : 1.0f;
266 return radiometricWeight * area * std::numbers::pi_v<float> * sides;
267 }
268 return 0.0f;
269}
270
271void ComputeAnalyticalLightBounds(GSLight const& light, float3& aabbMin, float3& aabbMax, float3& center,
272 float3& coneDirection, float& cosConeAngle);
273
275 LightBVHOptions const& options, Allocator* alloc);
276
277[[nodiscard]] bool ValidateLightBVH(LightBVHBuild const& bvh, Span<GSLight const> lights,
278 Span<GSEmissiveCluster const> clusters, String* outError = nullptr);
279
280[[nodiscard]] bool LightBVHRunBuilderSelfTests(Allocator* alloc, String* outError = nullptr);
void LightBVHNodeSetLeaf(LightBVHNode &node, uint32_t lightCount, uint32_t lightOffset)
Definition LightBVH.hpp:97
bool LightBVHNodeIsLeaf(LightBVHNode const &node)
Definition LightBVH.hpp:60
void LightBVHNodeSetInternal(LightBVHNode &node, uint32_t rightChildIdx)
Definition LightBVH.hpp:92
LightBVHNode UnpackLightBVHNode(GSLightBVHNode const &packed)
Definition LightBVH.hpp:165
LightBVHBuild BuildLightBVH(Span< GSLight const > lights, Span< GSEmissiveCluster const > clusters, LightBVHOptions const &options, Allocator *alloc)
Definition LightBVH.cpp:693
bool IsDistantLightType(uint32_t type)
Definition LightBVH.hpp:221
uint32_t PackLightBVHConeDirection(float3 direction)
Definition LightBVH.hpp:111
float3 UnpackLightBVHConeDirection(uint32_t packed)
Definition LightBVH.hpp:124
GSLightBVHNode PackLightBVHNode(LightBVHNode const &node)
Definition LightBVH.hpp:137
uint32_t LightBVHNodeLightOffset(LightBVHNode const &node)
Definition LightBVH.hpp:75
LightBVHSplitHeuristic
Definition LightBVH.hpp:27
constexpr float kLightBVHMinSunAngularRadius
Definition LightBVH.hpp:24
uint32_t LightBVHNodeRightChild(LightBVHNode const &node)
Definition LightBVH.hpp:65
constexpr uint32_t kLightBVHLeafBit
Definition LightBVH.hpp:23
constexpr uint32_t kLightBVHMaxLightsPerLeaf
Definition LightBVH.hpp:21
bool HasLightEmission(GSLight const &light)
Definition LightBVH.hpp:232
uint32_t LightBVHNodeLightCount(LightBVHNode const &node)
Definition LightBVH.hpp:70
void LightBVHNodeSetAABB(LightBVHNode &node, float3 const &aabbMin, float3 const &aabbMax)
Definition LightBVH.hpp:80
void ComputeAnalyticalLightBounds(GSLight const &light, float3 &aabbMin, float3 &aabbMax, float3 &center, float3 &coneDirection, float &cosConeAngle)
Definition LightBVH.cpp:627
constexpr uint32_t kLightBVHMaxLightOffset
Definition LightBVH.hpp:22
uint16_t PackLightBVHExtent(float extent)
Definition LightBVH.hpp:102
constexpr float kLightBVHInvalidCosConeAngle
Definition LightBVH.hpp:17
void LightBVHNodeGetAABB(LightBVHNode const &node, float3 &aabbMin, float3 &aabbMax)
Definition LightBVH.hpp:86
bool ValidateLightBVH(LightBVHBuild const &bvh, Span< GSLight const > lights, Span< GSEmissiveCluster const > clusters, String *outError=nullptr)
Definition LightBVH.cpp:815
constexpr uint32_t kLightBVHMaxDepth
Definition LightBVH.hpp:18
uint32_t GSLightTypeCPU(GSLight const &light)
Definition LightBVH.hpp:216
constexpr uint32_t kLightBVHLightCountBits
Definition LightBVH.hpp:19
float ComputeLightProposalWeight(GSLight const &light)
Definition LightBVH.hpp:237
bool IsFiniteLightType(uint32_t type)
Definition LightBVH.hpp:226
constexpr uint32_t kLightBVHLightOffsetBits
Definition LightBVH.hpp:20
bool LightBVHRunBuilderSelfTests(Allocator *alloc, String *outError=nullptr)
Definition LightBVH.cpp:1027
constexpr uint32_t kGSLightTypeDisk
Definition GPUScene.hpp:34
constexpr uint32_t kGSLightTypeEnvironment
Definition GPUScene.hpp:30
constexpr uint32_t kGSLightTypeMask
Definition GPUScene.hpp:29
constexpr uint32_t kGSLightTypeDirectional
Definition GPUScene.hpp:31
constexpr uint32_t kGSLightTypeSpot
Definition GPUScene.hpp:33
constexpr uint32_t kGSLightTypeRect
Definition GPUScene.hpp:35
constexpr uint32_t kGSLightTypePoint
Definition GPUScene.hpp:32
Allocator interface (noexcept)
Definition Allocator.hpp:29
std::vector< T, StlAllocator< T > > Vector
std::vector with explicit Foundation::Core::StlAllocator constructor
Definition Container.hpp:149
std::basic_string< char, std::char_traits< char >, StlDefaultAllocator< char > > String
Alias for std::basic_string<char>, without an explicit allocator constructor.
Definition Container.hpp:120
std::span< T > Span
Alias for std::span
Definition Container.hpp:62
vec2 float2
Definition Math.hpp:27
float dequantizeFP16(unsigned short h)
Definition Quantize.cpp:54
int32_t quantizeSnorm(float v, int32_t N)
Definition Quantize.hpp:48
vec3 float3
Definition Math.hpp:26
unsigned short quantizeFP16(float v)
Definition Quantize.cpp:10
Definition Allocator.hpp:6
Definition LightBVH.hpp:55
uint32_t data[8]
Definition LightBVH.hpp:56
Definition GPUScene.hpp:131
float3 dpdu
Definition GPUScene.hpp:140
float3 dpdv
Definition GPUScene.hpp:141
float power
Definition GPUScene.hpp:134
float4 params
Definition GPUScene.hpp:139
float3 color
Definition GPUScene.hpp:133
uint32_t flags
Definition GPUScene.hpp:132
Definition GPUScene.hpp:40
Definition LightBVH.hpp:194
bool valid
Definition LightBVH.hpp:207
Vector< LightBVHRefitLevel > refitLevels
Definition LightBVH.hpp:202
uint32_t finiteLightIndexCount
Definition LightBVH.hpp:206
Vector< GSLightBVHNode > gpuNodes
Definition LightBVH.hpp:197
Vector< uint32_t > lightIndices
Definition LightBVH.hpp:198
Allocator * allocator
Definition LightBVH.hpp:195
uint32_t distantRootNode
Definition LightBVH.hpp:204
LightBVHBuild(Allocator *alloc)
Definition LightBVH.hpp:209
LightBVHStats stats
Definition LightBVH.hpp:203
uint32_t distantNodeCount
Definition LightBVH.hpp:205
Vector< uint64_t > lightBitmasks
Definition LightBVH.hpp:199
Vector< uint32_t > nodeIndices
Definition LightBVH.hpp:201
Vector< LightBVHNode > nodes
Definition LightBVH.hpp:196
Vector< uint32_t > globalLightIndices
Definition LightBVH.hpp:200
Definition LightBVH.hpp:45
float3 coneDirection
Definition LightBVH.hpp:50
float3 extent
Definition LightBVH.hpp:48
float flux
Definition LightBVH.hpp:49
uint32_t header
Definition LightBVH.hpp:46
float3 origin
Definition LightBVH.hpp:47
float cosConeAngle
Definition LightBVH.hpp:51
Definition LightBVH.hpp:34
bool useVolumeOverSA
Definition LightBVH.hpp:39
uint32_t binCount
Definition LightBVH.hpp:36
bool splitAlongLargest
Definition LightBVH.hpp:38
LightBVHSplitHeuristic splitHeuristic
Definition LightBVH.hpp:35
float volumeEpsilon
Definition LightBVH.hpp:37
bool useLightingCones
Definition LightBVH.hpp:41
bool usePreintegration
Definition LightBVH.hpp:40
Definition LightBVH.hpp:183
uint32_t byteSize
Definition LightBVH.hpp:186
uint32_t treeHeight
Definition LightBVH.hpp:184
uint32_t globalLightCount
Definition LightBVH.hpp:190
uint32_t leafNodeCount
Definition LightBVH.hpp:188
uint32_t minDepth
Definition LightBVH.hpp:185
uint32_t finiteLightCount
Definition LightBVH.hpp:189
uint32_t internalNodeCount
Definition LightBVH.hpp:187