[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