Refactor: renaming a few light-tree-related variables

primitives -> emitters, `index` -> `node_index`
This commit is contained in:
Weizhen Huang
2023-04-04 13:09:01 +02:00
parent 6f60b09f51
commit e58a05ca68
7 changed files with 130 additions and 133 deletions

View File

@@ -117,7 +117,7 @@ ccl_device_noinline bool light_sample(KernelGlobals kg,
if (kernel_data.integrator.use_light_tree) {
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
emitter_index);
prim = kemitter->prim;
prim = kemitter->prim_id;
mesh_light = kemitter->mesh_light;
}
else

View File

@@ -184,7 +184,7 @@ ccl_device bool compute_emitter_centroid_and_dir(KernelGlobals kg,
ccl_private float3 &centroid,
ccl_private packed_float3 &dir)
{
const int prim_id = kemitter->prim;
const int prim_id = kemitter->prim_id;
if (prim_id < 0) {
const ccl_global KernelLight *klight = &kernel_data_fetch(lights, ~prim_id);
centroid = klight->co;
@@ -264,7 +264,7 @@ ccl_device void light_tree_emitter_importance(KernelGlobals kg,
return;
}
const int prim_id = kemitter->prim;
const int prim_id = kemitter->prim_id;
if (in_volume_segment) {
const float3 D = N_or_D;
@@ -344,12 +344,12 @@ ccl_device void light_tree_node_importance(KernelGlobals kg,
{
max_importance = 0.0f;
min_importance = 0.0f;
if (knode->num_prims == 1) {
if (knode->num_emitters == 1) {
/* At a leaf node with only one emitter. */
light_tree_emitter_importance<in_volume_segment>(
kg, P, N_or_D, t, has_transmission, -knode->child_index, max_importance, min_importance);
}
else if (knode->num_prims != 0) {
else if (knode->num_emitters != 0) {
const BoundingCone bcone = knode->bcone;
const BoundingBox bbox = knode->bbox;
@@ -452,13 +452,13 @@ ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg,
int selected_index = -1;
/* Mark emitters with zero importance. Used for resevoir when total minimum importance = 0. */
kernel_assert(knode->num_prims <= sizeof(uint) * 8);
kernel_assert(knode->num_emitters <= sizeof(uint) * 8);
uint has_importance = 0;
const bool sample_max = (rand > 0.5f); /* Sampling using the maximum importance. */
rand = rand * 2.0f - float(sample_max);
for (int i = 0; i < knode->num_prims; i++) {
for (int i = 0; i < knode->num_emitters; i++) {
int current_index = -knode->child_index + i;
/* maximum importance = importance[0], minimum importance = importance[1] */
float importance[2];
@@ -491,7 +491,7 @@ ccl_device int light_tree_cluster_select_emitter(KernelGlobals kg,
}
else {
selected_index = -1;
for (int i = 0; i < knode->num_prims; i++) {
for (int i = 0; i < knode->num_emitters; i++) {
int current_index = -knode->child_index + i;
sample_resevoir(current_index,
float(has_importance & 1),
@@ -615,12 +615,12 @@ ccl_device_noinline bool light_tree_sample(KernelGlobals kg,
/* We need to be able to find the probability of selecting a given light for MIS. */
ccl_device float light_tree_pdf(
KernelGlobals kg, const float3 P, const float3 N, const int path_flag, const int prim)
KernelGlobals kg, const float3 P, const float3 N, const int path_flag, const int emitter)
{
const bool has_transmission = (path_flag & PATH_RAY_MIS_HAD_TRANSMISSION);
/* Target emitter info. */
const int target_emitter = (prim >= 0) ? kernel_data_fetch(triangle_to_tree, prim) :
kernel_data_fetch(light_to_tree, ~prim);
const int target_emitter = (emitter >= 0) ? kernel_data_fetch(triangle_to_tree, emitter) :
kernel_data_fetch(light_to_tree, ~emitter);
ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
target_emitter);
const int target_leaf = kemitter->parent_index;
@@ -667,7 +667,7 @@ ccl_device float light_tree_pdf(
float total_max_importance = 0.0f;
float total_min_importance = 0.0f;
int num_has_importance = 0;
for (int i = 0; i < kleaf->num_prims; i++) {
for (int i = 0; i < kleaf->num_emitters; i++) {
const int emitter = -kleaf->child_index + i;
float max_importance, min_importance;
light_tree_emitter_importance<false>(

View File

@@ -306,7 +306,7 @@ ccl_device_forceinline bool triangle_light_tree_parameters(
const int object = kemitter->mesh_light.object_id;
float3 vertices[3];
triangle_world_space_vertices(kg, object, kemitter->prim, -1.0f, vertices);
triangle_world_space_vertices(kg, object, kemitter->prim_id, -1.0f, vertices);
bool shape_above_surface = false;
for (int i = 0; i < 3; i++) {

View File

@@ -1379,7 +1379,7 @@ typedef struct KernelLightTreeNode {
* and the negative value indexes into the first child of the light array.
* Otherwise, it's an index to the node's second child. */
int child_index;
int num_prims; /* leaf nodes need to know the number of primitives stored. */
int num_emitters; /* leaf nodes need to know the number of emitters stored. */
/* Bit trail. */
uint bit_trail;
@@ -1397,8 +1397,8 @@ typedef struct KernelLightTreeEmitter {
/* Energy. */
float energy;
/* prim_id denotes the location in the lights or triangles array. */
int prim;
/* The location in the lights or triangles array. */
int prim_id;
MeshLight mesh_light;
EmissionSampling emission_sampling;

View File

@@ -446,9 +446,9 @@ void LightManager::device_update_tree(Device *,
progress.set_status("Updating Lights", "Computing tree");
/* Add both lights and emissive triangles to this vector for light tree construction. */
vector<LightTreePrimitive> light_prims;
light_prims.reserve(kintegrator->num_distribution);
vector<LightTreePrimitive> distant_lights;
vector<LightTreeEmitter> emitters;
emitters.reserve(kintegrator->num_distribution);
vector<LightTreeEmitter> distant_lights;
distant_lights.reserve(kintegrator->num_distant_lights);
vector<uint> object_lookup_offsets(scene->objects.size());
@@ -463,7 +463,7 @@ void LightManager::device_update_tree(Device *,
distant_lights.emplace_back(scene, ~device_light_index, scene_light_index);
}
else {
light_prims.emplace_back(scene, ~device_light_index, scene_light_index);
emitters.emplace_back(scene, ~device_light_index, scene_light_index);
}
device_light_index++;
@@ -497,7 +497,7 @@ void LightManager::device_update_tree(Device *,
scene->default_surface;
if (shader->emission_sampling != EMISSION_SAMPLING_NONE) {
light_prims.emplace_back(scene, i, object_id);
emitters.emplace_back(scene, i, object_id);
}
}
@@ -505,15 +505,15 @@ void LightManager::device_update_tree(Device *,
object_id++;
}
/* Append distant lights to the end of `light_prims` */
std::move(distant_lights.begin(), distant_lights.end(), std::back_inserter(light_prims));
/* Append distant lights to the end of `emitters` */
std::move(distant_lights.begin(), distant_lights.end(), std::back_inserter(emitters));
/* Update integrator state. */
kintegrator->use_direct_light = !light_prims.empty();
kintegrator->use_direct_light = !emitters.empty();
/* TODO: For now, we'll start with a smaller number of max lights in a node.
* More benchmarking is needed to determine what number works best. */
LightTree light_tree(light_prims, kintegrator->num_distant_lights, 8);
LightTree light_tree(emitters, kintegrator->num_distant_lights, 8);
/* We want to create separate arrays corresponding to triangles and lights,
* which will be used to index back into the light tree for PDF calculations. */
@@ -528,8 +528,7 @@ void LightManager::device_update_tree(Device *,
/* First initialize the light tree's nodes. */
KernelLightTreeNode *light_tree_nodes = dscene->light_tree_nodes.alloc(light_tree.size());
KernelLightTreeEmitter *light_tree_emitters = dscene->light_tree_emitters.alloc(
light_prims.size());
KernelLightTreeEmitter *light_tree_emitters = dscene->light_tree_emitters.alloc(emitters.size());
/* Copy the light tree nodes to an array in the device. */
/* The nodes are arranged in a depth-first order, meaning the left child of each inner node
@@ -545,39 +544,39 @@ void LightManager::device_update_tree(Device *,
LightTreeNode *right_node_stack[32];
int stack_id = 0;
const LightTreeNode *node = light_tree.get_root();
for (int index = 0; index < light_tree.size(); index++) {
light_tree_nodes[index].energy = node->measure.energy;
for (int node_index = 0; node_index < light_tree.size(); node_index++) {
light_tree_nodes[node_index].energy = node->measure.energy;
light_tree_nodes[index].bbox.min = node->measure.bbox.min;
light_tree_nodes[index].bbox.max = node->measure.bbox.max;
light_tree_nodes[node_index].bbox.min = node->measure.bbox.min;
light_tree_nodes[node_index].bbox.max = node->measure.bbox.max;
light_tree_nodes[index].bcone.axis = node->measure.bcone.axis;
light_tree_nodes[index].bcone.theta_o = node->measure.bcone.theta_o;
light_tree_nodes[index].bcone.theta_e = node->measure.bcone.theta_e;
light_tree_nodes[node_index].bcone.axis = node->measure.bcone.axis;
light_tree_nodes[node_index].bcone.theta_o = node->measure.bcone.theta_o;
light_tree_nodes[node_index].bcone.theta_e = node->measure.bcone.theta_e;
light_tree_nodes[index].bit_trail = node->bit_trail;
light_tree_nodes[index].num_prims = node->num_prims;
light_tree_nodes[node_index].bit_trail = node->bit_trail;
light_tree_nodes[node_index].num_emitters = node->num_emitters;
/* Here we need to make a distinction between interior and leaf nodes. */
if (node->is_leaf()) {
light_tree_nodes[index].child_index = -node->first_prim_index;
light_tree_nodes[node_index].child_index = -node->first_emitter_index;
for (int i = 0; i < node->num_prims; i++) {
int emitter_index = i + node->first_prim_index;
LightTreePrimitive &prim = light_prims[emitter_index];
for (int i = 0; i < node->num_emitters; i++) {
int emitter_index = i + node->first_emitter_index;
LightTreeEmitter &emitter = emitters[emitter_index];
light_tree_emitters[emitter_index].energy = prim.measure.energy;
light_tree_emitters[emitter_index].theta_o = prim.measure.bcone.theta_o;
light_tree_emitters[emitter_index].theta_e = prim.measure.bcone.theta_e;
light_tree_emitters[emitter_index].energy = emitter.measure.energy;
light_tree_emitters[emitter_index].theta_o = emitter.measure.bcone.theta_o;
light_tree_emitters[emitter_index].theta_e = emitter.measure.bcone.theta_e;
if (prim.is_triangle()) {
light_tree_emitters[emitter_index].mesh_light.object_id = prim.object_id;
if (emitter.is_triangle()) {
light_tree_emitters[emitter_index].mesh_light.object_id = emitter.object_id;
int shader_flag = 0;
Object *object = scene->objects[prim.object_id];
Object *object = scene->objects[emitter.object_id];
Mesh *mesh = static_cast<Mesh *>(object->get_geometry());
Shader *shader = static_cast<Shader *>(
mesh->get_used_shaders()[mesh->get_shader()[prim.prim_id]]);
mesh->get_used_shaders()[mesh->get_shader()[emitter.prim_id]]);
if (!(object->get_visibility() & PATH_RAY_CAMERA)) {
shader_flag |= SHADER_EXCLUDE_CAMERA;
@@ -598,19 +597,20 @@ void LightManager::device_update_tree(Device *,
shader_flag |= SHADER_EXCLUDE_SHADOW_CATCHER;
}
light_tree_emitters[emitter_index].prim = prim.prim_id + mesh->prim_offset;
light_tree_emitters[emitter_index].prim_id = emitter.prim_id + mesh->prim_offset;
light_tree_emitters[emitter_index].mesh_light.shader_flag = shader_flag;
light_tree_emitters[emitter_index].emission_sampling = shader->emission_sampling;
triangle_array[prim.prim_id + object_lookup_offsets[prim.object_id]] = emitter_index;
triangle_array[emitter.prim_id + object_lookup_offsets[emitter.object_id]] =
emitter_index;
}
else {
light_tree_emitters[emitter_index].prim = prim.prim_id;
light_tree_emitters[emitter_index].prim_id = emitter.prim_id;
light_tree_emitters[emitter_index].mesh_light.shader_flag = 0;
light_tree_emitters[emitter_index].mesh_light.object_id = OBJECT_NONE;
light_tree_emitters[emitter_index].emission_sampling = EMISSION_SAMPLING_FRONT_BACK;
light_array[~prim.prim_id] = emitter_index;
light_array[~emitter.prim_id] = emitter_index;
}
light_tree_emitters[emitter_index].parent_index = index;
light_tree_emitters[emitter_index].parent_index = node_index;
}
/* Retrieve from the stacks. */
@@ -618,12 +618,12 @@ void LightManager::device_update_tree(Device *,
break;
}
stack_id--;
light_tree_nodes[left_index_stack[stack_id]].child_index = index + 1;
light_tree_nodes[left_index_stack[stack_id]].child_index = node_index + 1;
node = right_node_stack[stack_id];
}
else {
/* Fill in the stacks. */
left_index_stack[stack_id] = index;
left_index_stack[stack_id] = node_index;
right_node_stack[stack_id] = node->children[LightTree::right].get();
node = node->children[LightTree::left].get();
stack_id++;

View File

@@ -72,7 +72,7 @@ OrientationBounds merge(const OrientationBounds &cone_a, const OrientationBounds
return OrientationBounds({new_axis, theta_o, theta_e});
}
LightTreePrimitive::LightTreePrimitive(Scene *scene, int prim_id, int object_id)
LightTreeEmitter::LightTreeEmitter(Scene *scene, int prim_id, int object_id)
: prim_id(prim_id), object_id(object_id)
{
if (is_triangle()) {
@@ -100,7 +100,7 @@ LightTreePrimitive::LightTreePrimitive(Scene *scene, int prim_id, int object_id)
float area = triangle_area(vertices[0], vertices[1], vertices[2]);
measure.energy = area * average(shader->emission_estimate);
/* NOTE: the original implementation used the bounding box centroid, but primitive centroid
/* NOTE: the original implementation used the bounding box centroid, but triangle centroid
* seems to work fine */
centroid = (vertices[0] + vertices[1] + vertices[2]) / 3.0f;
@@ -208,28 +208,28 @@ LightTreePrimitive::LightTreePrimitive(Scene *scene, int prim_id, int object_id)
}
}
LightTree::LightTree(vector<LightTreePrimitive> &prims,
LightTree::LightTree(vector<LightTreeEmitter> &emitters,
const int &num_distant_lights,
uint max_lights_in_leaf)
{
if (prims.empty()) {
if (emitters.empty()) {
return;
}
max_lights_in_leaf_ = max_lights_in_leaf;
const int num_prims = prims.size();
const int num_local_lights = num_prims - num_distant_lights;
const int num_emitters = emitters.size();
const int num_local_lights = num_emitters - num_distant_lights;
root_ = create_node(LightTreePrimitivesMeasure::empty, 0);
root_ = create_node(LightTreeMeasure::empty, 0);
/* All local lights are grouped to the left child as an inner node. */
recursive_build(left, root_.get(), 0, num_local_lights, &prims, 0, 1);
recursive_build(left, root_.get(), 0, num_local_lights, &emitters, 0, 1);
task_pool.wait_work();
/* All distant lights are grouped to the right child as a leaf node. */
root_->children[right] = create_node(LightTreePrimitivesMeasure::empty, 1);
for (int i = num_local_lights; i < num_prims; i++) {
root_->children[right]->add(prims[i]);
root_->children[right] = create_node(LightTreeMeasure::empty, 1);
for (int i = num_local_lights; i < num_emitters; i++) {
root_->children[right]->add(emitters[i]);
}
root_->children[right]->make_leaf(num_local_lights, num_distant_lights);
}
@@ -238,50 +238,50 @@ void LightTree::recursive_build(const Child child,
LightTreeNode *parent,
const int start,
const int end,
vector<LightTreePrimitive> *prims,
vector<LightTreeEmitter> *emitters,
const uint bit_trail,
const int depth)
{
BoundBox centroid_bounds = BoundBox::empty;
for (int i = start; i < end; i++) {
centroid_bounds.grow((*prims)[i].centroid);
centroid_bounds.grow((*emitters)[i].centroid);
}
parent->children[child] = create_node(LightTreePrimitivesMeasure::empty, bit_trail);
parent->children[child] = create_node(LightTreeMeasure::empty, bit_trail);
LightTreeNode *node = parent->children[child].get();
/* Find the best place to split the primitives into 2 nodes.
/* Find the best place to split the emitters into 2 nodes.
* If the best split cost is no better than making a leaf node, make a leaf instead. */
int split_dim = -1, middle;
if (should_split(*prims, start, middle, end, node->measure, centroid_bounds, split_dim)) {
if (should_split(*emitters, start, middle, end, node->measure, centroid_bounds, split_dim)) {
if (split_dim != -1) {
/* Partition the primitives between start and end based on the centroids. */
std::nth_element(prims->begin() + start,
prims->begin() + middle,
prims->begin() + end,
[split_dim](const LightTreePrimitive &l, const LightTreePrimitive &r) {
/* Partition the emitters between start and end based on the centroids. */
std::nth_element(emitters->begin() + start,
emitters->begin() + middle,
emitters->begin() + end,
[split_dim](const LightTreeEmitter &l, const LightTreeEmitter &r) {
return l.centroid[split_dim] < r.centroid[split_dim];
});
}
/* Recursively build the left branch. */
if (middle - start > MIN_PRIMS_PER_THREAD) {
if (middle - start > MIN_EMITTERS_PER_THREAD) {
task_pool.push(
[=] { recursive_build(left, node, start, middle, prims, bit_trail, depth + 1); });
[=] { recursive_build(left, node, start, middle, emitters, bit_trail, depth + 1); });
}
else {
recursive_build(left, node, start, middle, prims, bit_trail, depth + 1);
recursive_build(left, node, start, middle, emitters, bit_trail, depth + 1);
}
/* Recursively build the right branch. */
if (end - middle > MIN_PRIMS_PER_THREAD) {
if (end - middle > MIN_EMITTERS_PER_THREAD) {
task_pool.push([=] {
recursive_build(right, node, middle, end, prims, bit_trail | (1u << depth), depth + 1);
recursive_build(right, node, middle, end, emitters, bit_trail | (1u << depth), depth + 1);
});
}
else {
recursive_build(right, node, middle, end, prims, bit_trail | (1u << depth), depth + 1);
recursive_build(right, node, middle, end, emitters, bit_trail | (1u << depth), depth + 1);
}
}
else {
@@ -289,16 +289,16 @@ void LightTree::recursive_build(const Child child,
}
}
bool LightTree::should_split(const vector<LightTreePrimitive> &prims,
bool LightTree::should_split(const vector<LightTreeEmitter> &emitters,
const int start,
int &middle,
const int end,
LightTreePrimitivesMeasure &measure,
LightTreeMeasure &measure,
const BoundBox &centroid_bbox,
int &split_dim)
{
middle = (start + end) / 2;
const int num_prims = end - start;
const int num_emitters = end - start;
const float3 extent = centroid_bbox.size();
const float max_extent = max4(extent.x, extent.y, extent.z, 0.0f);
@@ -313,18 +313,18 @@ bool LightTree::should_split(const vector<LightTreePrimitive> &prims,
const float inv_extent = 1 / (centroid_bbox.size()[dim]);
/* Fill in buckets with primitives. */
/* Fill in buckets with emitters. */
std::array<LightTreeBucket, LightTreeBucket::num_buckets> buckets;
for (int i = start; i < end; i++) {
const LightTreePrimitive &prim = prims[i];
const LightTreeEmitter &emitter = emitters[i];
/* Place primitive into the appropriate bucket, where the centroid box is split into equal
/* Place emitter into the appropriate bucket, where the centroid box is split into equal
* partitions. */
int bucket_idx = LightTreeBucket::num_buckets *
(prim.centroid[dim] - centroid_bbox.min[dim]) * inv_extent;
(emitter.centroid[dim] - centroid_bbox.min[dim]) * inv_extent;
bucket_idx = clamp(bucket_idx, 0, LightTreeBucket::num_buckets - 1);
buckets[bucket_idx].add(prim);
buckets[bucket_idx].add(emitter);
}
/* Precompute the left bucket measure cumulatively. */
@@ -338,12 +338,12 @@ bool LightTree::should_split(const vector<LightTreePrimitive> &prims,
/* Calculate node measure by summing up the bucket measure. */
measure = left_buckets.back().measure + buckets.back().measure;
/* Do not try to split if there are only one primitive. */
if (num_prims < 2) {
/* Do not try to split if there are only one emitter. */
if (num_emitters < 2) {
return false;
}
/* Degenerate case with co-located primitives. */
/* Degenerate case with co-located emitters. */
if (is_zero(centroid_bbox.size())) {
break;
}
@@ -375,13 +375,12 @@ bool LightTree::should_split(const vector<LightTreePrimitive> &prims,
}
}
}
return min_cost < total_cost || num_prims > max_lights_in_leaf_;
return min_cost < total_cost || num_emitters > max_lights_in_leaf_;
}
__forceinline LightTreePrimitivesMeasure operator+(const LightTreePrimitivesMeasure &a,
const LightTreePrimitivesMeasure &b)
__forceinline LightTreeMeasure operator+(const LightTreeMeasure &a, const LightTreeMeasure &b)
{
LightTreePrimitivesMeasure c(a);
LightTreeMeasure c(a);
c.add(b);
return c;
}

View File

@@ -58,25 +58,25 @@ OrientationBounds merge(const OrientationBounds &cone_a, const OrientationBounds
/* Light Tree uses the bounding box, the orientation bounding cone, and the energy of a cluster to
* compute the Surface Area Orientation Heuristic (SAOH). */
struct LightTreePrimitivesMeasure {
struct LightTreeMeasure {
BoundBox bbox = BoundBox::empty;
OrientationBounds bcone = OrientationBounds::empty;
float energy = 0.0f;
enum empty_t { empty = 0 };
__forceinline LightTreePrimitivesMeasure() = default;
__forceinline LightTreeMeasure() = default;
__forceinline LightTreePrimitivesMeasure(empty_t) {}
__forceinline LightTreeMeasure(empty_t) {}
__forceinline LightTreePrimitivesMeasure(const BoundBox &bbox,
const OrientationBounds &bcone,
const float &energy)
__forceinline LightTreeMeasure(const BoundBox &bbox,
const OrientationBounds &bcone,
const float &energy)
: bbox(bbox), bcone(bcone), energy(energy)
{
}
__forceinline LightTreePrimitivesMeasure(const LightTreePrimitivesMeasure &other)
__forceinline LightTreeMeasure(const LightTreeMeasure &other)
: bbox(other.bbox), bcone(other.bcone), energy(other.energy)
{
}
@@ -86,7 +86,7 @@ struct LightTreePrimitivesMeasure {
return energy == 0;
}
__forceinline void add(const LightTreePrimitivesMeasure &measure)
__forceinline void add(const LightTreeMeasure &measure)
{
if (!measure.is_zero()) {
bbox.grow(measure.bbox);
@@ -104,21 +104,20 @@ struct LightTreePrimitivesMeasure {
}
};
LightTreePrimitivesMeasure operator+(const LightTreePrimitivesMeasure &a,
const LightTreePrimitivesMeasure &b);
LightTreeMeasure operator+(const LightTreeMeasure &a, const LightTreeMeasure &b);
/* Light Tree Primitive
/* Light Tree Emitter
* Struct that indexes into the scene's triangle and light arrays. */
struct LightTreePrimitive {
struct LightTreeEmitter {
/* `prim_id >= 0` is an index into an object's local triangle index,
* otherwise `-prim_id-1`(`~prim`) is an index into device lights array. */
int prim_id;
int object_id;
float3 centroid;
LightTreePrimitivesMeasure measure;
LightTreeMeasure measure;
LightTreePrimitive(Scene *scene, int prim_id, int object_id);
LightTreeEmitter(Scene *scene, int prim_id, int object_id);
__forceinline bool is_triangle() const
{
@@ -129,20 +128,20 @@ struct LightTreePrimitive {
/* Light Tree Bucket
* Struct used to determine splitting costs in the light BVH. */
struct LightTreeBucket {
LightTreePrimitivesMeasure measure;
LightTreeMeasure measure;
int count = 0;
static const int num_buckets = 12;
LightTreeBucket() = default;
LightTreeBucket(const LightTreePrimitivesMeasure &measure, const int &count)
LightTreeBucket(const LightTreeMeasure &measure, const int &count)
: measure(measure), count(count)
{
}
void add(const LightTreePrimitive &prim)
void add(const LightTreeEmitter &emitter)
{
measure.add(prim.measure);
measure.add(emitter.measure);
count++;
}
};
@@ -151,34 +150,34 @@ LightTreeBucket operator+(const LightTreeBucket &a, const LightTreeBucket &b);
/* Light Tree Node */
struct LightTreeNode {
LightTreePrimitivesMeasure measure;
LightTreeMeasure measure;
uint bit_trail;
int num_prims = -1; /* The number of primitives a leaf node stores. A negative
number indicates it is an inner node. */
int first_prim_index; /* Leaf nodes contain an index to first primitive. */
int num_emitters = -1; /* The number of emitters a leaf node stores. A negative number indicates
it is an inner node. */
int first_emitter_index; /* Leaf nodes contain an index to first emitter. */
unique_ptr<LightTreeNode> children[2]; /* Inner node has two children. */
LightTreeNode() = default;
LightTreeNode(const LightTreePrimitivesMeasure &measure, const uint &bit_trial)
LightTreeNode(const LightTreeMeasure &measure, const uint &bit_trial)
: measure(measure), bit_trail(bit_trial)
{
}
__forceinline void add(const LightTreePrimitive &prim)
__forceinline void add(const LightTreeEmitter &emitter)
{
measure.add(prim.measure);
measure.add(emitter.measure);
}
void make_leaf(const int &first_prim_index, const int &num_prims)
void make_leaf(const int &first_emitter_index, const int &num_emitters)
{
this->first_prim_index = first_prim_index;
this->num_prims = num_prims;
this->first_emitter_index = first_emitter_index;
this->num_emitters = num_emitters;
}
__forceinline bool is_leaf() const
{
return num_prims >= 0;
return num_emitters >= 0;
}
};
@@ -198,7 +197,7 @@ class LightTree {
right = 1,
};
LightTree(vector<LightTreePrimitive> &prims,
LightTree(vector<LightTreeEmitter> &emitters,
const int &num_distant_lights,
uint max_lights_in_leaf);
@@ -213,8 +212,7 @@ class LightTree {
};
/* NOTE: Always use this function to create a new node so the number of nodes is in sync. */
unique_ptr<LightTreeNode> create_node(const LightTreePrimitivesMeasure &measure,
const uint &bit_trial)
unique_ptr<LightTreeNode> create_node(const LightTreeMeasure &measure, const uint &bit_trial)
{
num_nodes_++;
return make_unique<LightTreeNode>(measure, bit_trial);
@@ -223,22 +221,22 @@ class LightTree {
private:
/* Thread. */
TaskPool task_pool;
/* Do not spawn a thread if less than this amount of primitives are to be processed. */
enum { MIN_PRIMS_PER_THREAD = 4096 };
/* Do not spawn a thread if less than this amount of emitters are to be processed. */
enum { MIN_EMITTERS_PER_THREAD = 4096 };
void recursive_build(Child child,
LightTreeNode *parent,
int start,
int end,
vector<LightTreePrimitive> *prims,
vector<LightTreeEmitter> *emitters,
uint bit_trail,
int depth);
bool should_split(const vector<LightTreePrimitive> &prims,
bool should_split(const vector<LightTreeEmitter> &emitters,
const int start,
int &middle,
const int end,
LightTreePrimitivesMeasure &measure,
LightTreeMeasure &measure,
const BoundBox &centroid_bbox,
int &split_dim);
};