提交 167e2bf9 编写于 作者: M Matt Pharr

BVHLightSampler: use bit trails to record light -> BVH node path to its leaf

This saves 4 bytes from LightBVHNode (which doesn't matter, since it goes
from 32 to 28 bytes) and potentially gives more convergent node access in
the PDF() method.
上级 62b39361
......@@ -112,7 +112,7 @@ BVHLightSampler::BVHLightSampler(pstd::span<const LightHandle> lights, Allocator
: lights(lights.begin(), lights.end(), alloc),
infiniteLights(alloc),
nodes(alloc),
lightToNodeIndex(alloc) {
lightToBitTrail(alloc) {
std::vector<std::pair<int, LightBounds>> bvhLights;
// Partition lights into _infiniteLights_ and _bvhLights_
for (size_t i = 0; i < lights.size(); ++i) {
......@@ -128,21 +128,21 @@ BVHLightSampler::BVHLightSampler(pstd::span<const LightHandle> lights, Allocator
if (bvhLights.empty())
return;
buildBVH(bvhLights, 0, bvhLights.size(), alloc);
buildBVH(bvhLights, 0, bvhLights.size(), 0, 0, alloc);
lightBVHBytes += nodes.size() * sizeof(LightBVHNode);
}
std::pair<int, LightBounds> BVHLightSampler::buildBVH(
std::vector<std::pair<int, LightBounds>> &bvhLights, int start, int end,
Allocator alloc) {
uint32_t bitTrail, int depth, Allocator alloc) {
CHECK_LT(start, end);
int nLights = end - start;
// Initialize leaf node if only a single light remains
if (nLights == 1) {
if (end - start == 1) {
int nodeIndex = nodes.size();
CompactLightBounds cb(bvhLights[start].second, allLightBounds);
nodes.push_back(LightBVHNode(bvhLights[start].first, cb));
lightToNodeIndex.Insert(lights[bvhLights[start].first], nodeIndex);
int lightIndex = bvhLights[start].first;
nodes.push_back(LightBVHNode(lightIndex, cb));
lightToBitTrail.Insert(lights[lightIndex], bitTrail);
return {nodeIndex, bvhLights[start].second};
}
......@@ -223,13 +223,15 @@ std::pair<int, LightBounds> BVHLightSampler::buildBVH(
// Allocate interior _LightBVHNode_ and recursively initialize children
int nodeIndex = nodes.size();
nodes.push_back(LightBVHNode());
std::pair<int, LightBounds> child0 = buildBVH(bvhLights, start, mid, alloc);
CHECK_LT(depth, 32);
std::pair<int, LightBounds> child0 =
buildBVH(bvhLights, start, mid, bitTrail, depth + 1, alloc);
CHECK_EQ(nodeIndex + 1, child0.first);
std::pair<int, LightBounds> child1 = buildBVH(bvhLights, mid, end, alloc);
std::pair<int, LightBounds> child1 =
buildBVH(bvhLights, mid, end, bitTrail | (1u << depth), depth + 1, alloc);
LightBounds lb = Union(child0.second, child1.second);
nodes[nodeIndex] =
LightBVHNode(child0.first, child1.first, CompactLightBounds(lb, allLightBounds));
nodes[child0.first].parentIndex = nodes[child1.first].parentIndex = nodeIndex;
return {nodeIndex, lb};
}
......@@ -238,9 +240,9 @@ std::string BVHLightSampler::ToString() const {
}
std::string LightBVHNode::ToString() const {
return StringPrintf("[ LightBVHNode lightBounds: %s parentIndex: %d "
"childOrLightIndex: %d isLeaf: %d ]",
lightBounds, parentIndex, childOrLightIndex, isLeaf);
return StringPrintf(
"[ LightBVHNode lightBounds: %s childOrLightIndex: %d isLeaf: %d ]", lightBounds,
childOrLightIndex, isLeaf);
}
// ExhaustiveLightSampler Method Definitions
......
......@@ -245,14 +245,12 @@ struct alignas(32) LightBVHNode {
LightBVHNode(int lightIndex, const CompactLightBounds &lightBounds)
: childOrLightIndex(lightIndex), lightBounds(lightBounds) {
isLeaf = true;
parentIndex = (1u << 30) - 1;
}
PBRT_CPU_GPU
LightBVHNode(int child0Index, int child1Index, const CompactLightBounds &lightBounds)
: lightBounds(lightBounds), childOrLightIndex(child1Index) {
isLeaf = false;
parentIndex = (1u << 30) - 1;
}
PBRT_CPU_GPU
......@@ -262,9 +260,8 @@ struct alignas(32) LightBVHNode {
// LightBVHNode Public Members
CompactLightBounds lightBounds;
int childOrLightIndex;
struct {
unsigned int parentIndex : 31;
unsigned int childOrLightIndex : 31;
unsigned int isLeaf : 1;
};
};
......@@ -335,33 +332,33 @@ class BVHLightSampler {
PBRT_CPU_GPU
Float PDF(const LightSampleContext &ctx, LightHandle light) const {
// Handle infinite _light_ PDF computation
if (!lightToNodeIndex.HasKey(light))
if (!lightToBitTrail.HasKey(light))
return 1.f / (infiniteLights.size() + (!nodes.empty() ? 1 : 0));
// Get leaf _LightBVHNode_ for light and test importance
int nodeIndex = lightToNodeIndex[light];
uint32_t bitTrail = lightToBitTrail[light];
Point3f p = ctx.p();
Normal3f n = ctx.ns;
if (nodes[nodeIndex].lightBounds.Importance(p, n, allLightBounds) == 0)
return 0;
// Compute light's PDF by walking up tree nodes to the root
Float pdf = 1;
while (nodeIndex != 0) {
// Get pointers to current node, parent, and parent's children
int nodeIndex = 0;
while (true) {
const LightBVHNode *node = &nodes[nodeIndex];
const LightBVHNode *parent = &nodes[node->parentIndex];
const LightBVHNode *child0 = &nodes[node->parentIndex + 1];
const LightBVHNode *child1 = &nodes[parent->childOrLightIndex];
if (node->isLeaf) {
CHECK_EQ(light, lights[node->childOrLightIndex]);
break;
}
const LightBVHNode *child0 = &nodes[nodeIndex + 1];
const LightBVHNode *child1 = &nodes[node->childOrLightIndex];
// Compute child importances and update PDF for current node
Float ci[2] = {child0->lightBounds.Importance(p, n, allLightBounds),
child1->lightBounds.Importance(p, n, allLightBounds)};
int childIndex = int(nodeIndex == parent->childOrLightIndex);
DCHECK_GT(ci[childIndex], 0);
pdf *= ci[childIndex] / (ci[0] + ci[1]);
DCHECK_GT(ci[bitTrail & 1], 0);
pdf *= ci[bitTrail & 1] / (ci[0] + ci[1]);
nodeIndex = node->parentIndex;
nodeIndex = (bitTrail & 1) ? node->childOrLightIndex : (nodeIndex + 1);
bitTrail >>= 1;
}
// Return final PDF accounting for infinite light sampling probability
......@@ -393,28 +390,26 @@ class BVHLightSampler {
// BVHLightSampler Private Methods
std::pair<int, LightBounds> buildBVH(
std::vector<std::pair<int, LightBounds>> &bvhLights, int start, int end,
Allocator alloc);
uint32_t bitTrail, int depth, Allocator alloc);
Float EvaluateCost(const LightBounds &b, const Bounds3f &bounds, int dim) const {
auto Momega = [](const LightBounds &b) {
Float theta_o = SafeACos(b.cosTheta_o), theta_e = SafeACos(b.cosTheta_e);
Float theta_w = std::min(theta_o + theta_e, Pi);
Float sinTheta_o = SafeSqrt(1 - Sqr(b.cosTheta_o));
return 2 * Pi * (1 - b.cosTheta_o) +
Pi / 2 *
(2 * theta_w * sinTheta_o - std::cos(theta_o - 2 * theta_w) -
2 * theta_o * sinTheta_o + b.cosTheta_o);
};
Float theta_o = SafeACos(b.cosTheta_o), theta_e = SafeACos(b.cosTheta_e);
Float theta_w = std::min(theta_o + theta_e, Pi);
Float sinTheta_o = SafeSqrt(1 - Sqr(b.cosTheta_o));
Float Momega = 2 * Pi * (1 - b.cosTheta_o) +
Pi / 2 *
(2 * theta_w * sinTheta_o - std::cos(theta_o - 2 * theta_w) -
2 * theta_o * sinTheta_o + b.cosTheta_o);
Float Kr = MaxComponentValue(bounds.Diagonal()) / bounds.Diagonal()[dim];
return Kr * b.phi * Momega(b) * b.bounds.SurfaceArea();
return Kr * b.phi * Momega * b.bounds.SurfaceArea();
}
// BVHLightSampler Private Members
pstd::vector<LightHandle> lights, infiniteLights;
pstd::vector<LightBVHNode> nodes;
Bounds3f allLightBounds;
HashMap<LightHandle, int, LightHandleHash> lightToNodeIndex;
HashMap<LightHandle, uint32_t, LightHandleHash> lightToBitTrail;
};
// ExhaustiveLightSampler Definition
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册