Refactor: renaming a few light-tree-related variables
primitives -> emitters, `index` -> `node_index`
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -184,7 +184,7 @@ ccl_device bool compute_emitter_centroid_and_dir(KernelGlobals kg,
|
||||
ccl_private float3 ¢roid,
|
||||
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>(
|
||||
|
||||
@@ -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++) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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++;
|
||||
|
||||
@@ -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 ¢roid_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;
|
||||
}
|
||||
|
||||
@@ -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 ¢roid_bbox,
|
||||
int &split_dim);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user