[Bf-blender-cvs] [4f55918a5e9] gsoc-2018-many-light-sampling: Cycles: Implemented the SAOH splitting method
Erik Englesson
noreply at git.blender.org
Fri Jun 8 15:23:42 CEST 2018
Commit: 4f55918a5e93e7ab18ea46e3874002986719518b
Author: Erik Englesson
Date: Mon Jun 4 11:37:15 2018 +0200
Branches: gsoc-2018-many-light-sampling
https://developer.blender.org/rB4f55918a5e93e7ab18ea46e3874002986719518b
Cycles: Implemented the SAOH splitting method
Previously the light bvh construction code used a simple method
to split a node into two child nodes based only on the bounding
box of the node. Now, it splits a node into two by looking at
the energy and direction of the lights inside the nodes and the
area of their bounding boxes.
Technical changes:
- Implemented orientation BVH build
- Added energy to each node based on emission
- Updated PDF calculations for lights when using the light BVH
===================================================================
M intern/cycles/kernel/kernel_light.h
M intern/cycles/render/light.cpp
M intern/cycles/render/light_tree.cpp
M intern/cycles/render/light_tree.h
===================================================================
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index e540cdf9523..0719191d5f9 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -1085,7 +1085,7 @@ ccl_device float calc_node_importance(KernelGlobals *kg, float3 P, int node_offs
float4 node2 = kernel_tex_fetch(__light_tree_nodes, node_offset + 2);
float4 node3 = kernel_tex_fetch(__light_tree_nodes, node_offset + 3);
- float energy = node0[0]; // TODO: This energy is not set correctly on host
+ float energy = node0[0];
float3 bboxMin = make_float3( node1[0], node1[1], node1[2]);
float3 bboxMax = make_float3( node1[3], node2[0], node2[1]);
float theta_o = node2[2];
@@ -1111,9 +1111,10 @@ ccl_device void update_parent_node(KernelGlobals *kg, int node_offset,
(*nemitters) = __float_as_int(node[3]);
}
-ccl_device int sample_light_bvh(KernelGlobals *kg, float3 P, float randu)
+ccl_device int sample_light_bvh(KernelGlobals *kg, float3 P, float randu, float *pdf_factor)
{
int index = -1;
+ *pdf_factor = 1.0f;
/* read in first part of root node of light BVH */
int secondChildOffset, distribution_id, nemitters;
@@ -1130,6 +1131,7 @@ ccl_device int sample_light_bvh(KernelGlobals *kg, float3 P, float randu)
light_distribution_sample(kg, &randu); // TODO: Rescale random number in a better way
int light = min((int)(randu* (float)nemitters), nemitters-1);
index = distribution_id +light;
+ *pdf_factor *= 1.0f / (float)nemitters;
}
break;
} else { // Interior node, pick left or right randomly
@@ -1145,8 +1147,10 @@ ccl_device int sample_light_bvh(KernelGlobals *kg, float3 P, float randu)
light_distribution_sample(kg, &randu); // TODO: Rescale random number in a better way
if(randu <= P_L){ // Going down left node
offset = child_offsetL;
+ *pdf_factor *= P_L;
} else { // Going down right node
offset = child_offsetR;
+ *pdf_factor *= 1.0f - P_L;
}
/* update parent node info for next iteration */
@@ -1155,7 +1159,7 @@ ccl_device int sample_light_bvh(KernelGlobals *kg, float3 P, float randu)
}
- } while(1);
+ } while(true);
return index;
}
@@ -1168,9 +1172,15 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
int bounce,
LightSample *ls)
{
+ /* TODO: Restructure PDF calculations now that the light BVH is here */
/* sample index */
- //int index = light_distribution_sample(kg, &randu);
- int index = sample_light_bvh(kg, P, randu);
+ float pdf_factor = 1.0f;
+ int index = -1;
+ if (kernel_data.integrator.use_light_bvh){
+ index = sample_light_bvh(kg, P, randu, &pdf_factor);
+ } else {
+ index = light_distribution_sample(kg, &randu);
+ }
/* fetch light data */
const ccl_global KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, index);
@@ -1182,6 +1192,7 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
triangle_light_sample(kg, prim, object, randu, randv, time, ls, P);
ls->shader |= shader_flag;
+ ls->pdf *= pdf_factor;
return (ls->pdf > 0.0f);
}
else {
@@ -1190,8 +1201,9 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
if(UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
return false;
}
-
- return lamp_light_sample(kg, lamp, randu, randv, P, ls);
+ lamp_light_sample(kg, lamp, randu, randv, P, ls);
+ ls->pdf *= pdf_factor;
+ return (ls->pdf > 0.0f);
}
}
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index aab63d9c72d..178469974aa 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -536,9 +536,10 @@ void LightManager::device_update_tree_distribution(Device *, DeviceScene *dscene
size_t num_distribution = num_triangles + num_lights;
VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
-
/* create light BVH */
+ double time_start = time_dt();
LightTree lightBVH(emissivePrims, scene->objects, scene->lights, 1);
+ VLOG(1) << "Light BVH build time: " << time_dt() - time_start;
emissivePrims.clear();
if(progress.get_cancel()) return;
@@ -627,7 +628,6 @@ void LightManager::device_update_tree_distribution(Device *, DeviceScene *dscene
distribution[offset].mesh_light.shader_flag = shader_flag;
distribution[offset].mesh_light.object_id = prim.object_id;
offset++;
- VLOG(1) << "Added a mesh light";
int triangle_id = prim.prim_id - mesh->tri_offset;
Mesh::Triangle t = mesh->get_triangle(triangle_id);
@@ -673,9 +673,6 @@ void LightManager::device_update_tree_distribution(Device *, DeviceScene *dscene
offset++;
totarea += lightarea;
- VLOG(1) << "Added a normal light";
-
-
if(light->size > 0.0f && light->use_mis)
use_lamp_mis = true;
if(light->type == LIGHT_BACKGROUND) {
@@ -719,17 +716,9 @@ void LightManager::device_update_tree_distribution(Device *, DeviceScene *dscene
/* sample one, with 0.5 probability of light or triangle */
kintegrator->num_all_lights = num_lights;
- if(trianglearea > 0.0f) {
- kintegrator->pdf_triangles = 1.0f/trianglearea;
- if(num_lights)
- kintegrator->pdf_triangles *= 0.5f;
- }
-
- if(num_lights) {
- kintegrator->pdf_lights = 1.0f/num_lights;
- if(trianglearea > 0.0f)
- kintegrator->pdf_lights *= 0.5f;
- }
+ // Let BVH traversal take care of pdf calculations
+ kintegrator->pdf_triangles = 1.0f;
+ kintegrator->pdf_lights = 1.0f;
kintegrator->use_lamp_mis = use_lamp_mis;
@@ -1160,7 +1149,7 @@ void LightManager::device_update(Device *device, DeviceScene *dscene, Scene *sce
if(useMLS) {
device_update_tree_distribution(device, dscene, scene, progress);
} else {
- device_update_distribution(device, dscene, scene, progress);
+ device_update_distribution(device, dscene, scene, progress);
}
if(progress.get_cancel()) return;
diff --git a/intern/cycles/render/light_tree.cpp b/intern/cycles/render/light_tree.cpp
index 224d98ccc39..38822201253 100644
--- a/intern/cycles/render/light_tree.cpp
+++ b/intern/cycles/render/light_tree.cpp
@@ -25,7 +25,6 @@
#include "util/util_foreach.h"
#include "util/util_logging.h"
-
CCL_NAMESPACE_BEGIN
@@ -47,17 +46,21 @@ LightTree::LightTree(const vector<Primitive>& prims_,
// Initialize buildData array
vector<BVHPrimitiveInfo> buildData;
buildData.reserve(primitives.size());
- for(int i = 0; i < primitives.size(); i++){
+ for(int i = 0; i < primitives.size(); ++i){
BoundBox bbox = get_bbox(primitives[i]);
- buildData.push_back(BVHPrimitiveInfo(i, bbox));
+ Orientation bcone = get_bcone(primitives[i]);
+ float energy = get_energy(primitives[i]);
+ buildData.push_back(BVHPrimitiveInfo(i, bbox, bcone, energy));
}
// Recursively build BVH tree
unsigned int totalNodes = 0;
vector<Primitive> orderedPrims;
orderedPrims.reserve(primitives.size());
- BVHBuildNode *root = recursive_build(buildData, 0, primitives.size(),
- &totalNodes, orderedPrims);
+
+ BVHBuildNode *root = recursive_build(0, primitives.size(), buildData,
+ totalNodes, orderedPrims);
+
primitives.swap(orderedPrims);
orderedPrims.clear();
buildData.clear();
@@ -67,40 +70,34 @@ LightTree::LightTree(const vector<Primitive>& prims_,
// Convert to linear representation of the tree
nodes.resize(totalNodes);
int offset = 0;
- flattenBVHTree(root, &offset);
+ flattenBVHTree(*root, offset);
assert(offset == totalNodes);
}
-int LightTree::flattenBVHTree(BVHBuildNode *node, int *offset){
+int LightTree::flattenBVHTree(const BVHBuildNode &node, int &offset){
- CompactNode& compactNode = nodes[*offset];
- compactNode.bounds_w = node->bbox;
+ CompactNode& compactNode = nodes[offset];
+ compactNode.bounds_w = node.bbox;
+ compactNode.bounds_o = node.bcone;
- int myOffset = (*offset)++;
- if (node->nPrimitives > 0){
+ int myOffset = offset++;
+ if (node.nPrimitives > 0){
- assert( !node->children[0] && !node->children[1] );
+ assert( !node.children[0] && !node.children[1] );
- compactNode.energy = 1.0f; // TODO: Figure out what to put here
- compactNode.prim_id = node->firstPrimOffset;
- compactNode.nemitters = node->nPrimitives;
-
- /* TODO: Make general. This is specific for point lights and does not
- * consider several light sources within same node */
- compactNode.bounds_o.axis = make_float3(1.0f,0.0f,0.0f);
- compactNode.bounds_o.theta_o = (float)M_PI;
- compactNode.bounds_o.theta_e = (float)(M_PI/2);
+ compactNode.energy = node.energy;
+ compactNode.prim_id = node.firstPrimOffset;
+ compactNode.nemitters = node.nPrimitives;
} else {
/* create interior compact node */
compactNode.nemitters = 0;
- assert( node->children[0] && node->children[1] );
- flattenBVHTree(node->children[0], offset);
- compactNode.secondChildOffset = flattenBVHTree(node->children[1],
+ assert( node.children[0] && node.children[1] );
+ flattenBVHTree(*node.children[0], offset);
+ compactNode.secondChildOffset = flattenBVHTree(*node.children[1],
offset);
- compactNode.energy = 1.0f; // TODO: Figure out what to put here
-
+ compactNode.energy = node.energy;
}
return myOffset;
@@ -125,6 +122,11 @@ BoundBox LightTree::get_bbox(const Primitive& prim)
int lamp_id = -prim.prim_id-1;
Light* lamp = lights[lamp_id];
+ if (lamp->type == LIGHT_POIN
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list