[Bf-blender-cvs] [2e17c3f3a10] gsoc-2018-many-light-sampling: Added simple construction and sampling code for light BVH

Erik Englesson noreply at git.blender.org
Fri Jun 1 16:18:27 CEST 2018


Commit: 2e17c3f3a10bb2f6a62b1e8d5d236c437f7ae4e8
Author: Erik Englesson
Date:   Thu May 31 08:25:44 2018 +0200
Branches: gsoc-2018-many-light-sampling
https://developer.blender.org/rB2e17c3f3a10bb2f6a62b1e8d5d236c437f7ae4e8

Added simple construction and sampling code for light BVH

The light BVH is created on the host out of all emissive
triangles and all lights in the scene. The nodes of the
light BVH is then copied to the device where it is used
when sampling lights. When a light is asked for it
traverses the light BVH randomly to find a single light.

This is still very much in development.

===================================================================

M	CMakeLists.txt
M	intern/cycles/kernel/kernel_light.h
M	intern/cycles/kernel/kernel_textures.h
M	intern/cycles/render/CMakeLists.txt
M	intern/cycles/render/light.cpp
M	intern/cycles/render/light.h
A	intern/cycles/render/light_tree.cpp
A	intern/cycles/render/light_tree.h
M	intern/cycles/render/scene.cpp
M	intern/cycles/render/scene.h

===================================================================

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6ffe87da673..0b9cfd551a4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -212,6 +212,7 @@ option(WITH_BUILDINFO     "Include extra build details (only disable for develop
 if(${CMAKE_VERSION} VERSION_LESS 2.8.8)
 	# add_library OBJECT arg unsupported
 	set(WITH_BUILDINFO OFF)
+set(WITH_BUILDINFO OFF)
 endif()
 set(BUILDINFO_OVERRIDE_DATE "" CACHE STRING "Use instead of the current date for reproducable builds (empty string disables this option)")
 set(BUILDINFO_OVERRIDE_TIME "" CACHE STRING "Use instead of the current time for reproducable builds (empty string disables this option)")
@@ -407,7 +408,7 @@ mark_as_advanced(CYCLES_CUDA_BINARIES_ARCH)
 unset(PLATFORM_DEFAULT)
 option(WITH_CYCLES_LOGGING	"Build Cycles with logging support" ON)
 option(WITH_CYCLES_DEBUG	"Build Cycles with extra debug capabilities" OFF)
-option(WITH_CYCLES_NATIVE_ONLY	"Build Cycles with native kernel only (which fits current CPU, use for development only)" OFF)
+option(WITH_CYCLES_NATIVE_ONLY	"Build Cycles with native kernel only (which fits current CPU, use for development only)" ON)
 mark_as_advanced(WITH_CYCLES_CUBIN_COMPILER)
 mark_as_advanced(WITH_CYCLES_LOGGING)
 mark_as_advanced(WITH_CYCLES_DEBUG)
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index ec7203d36eb..e540cdf9523 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -503,7 +503,7 @@ ccl_device float lamp_light_pdf(KernelGlobals *kg, const float3 Ng, const float3
 
 	if(cos_pi <= 0.0f)
 		return 0.0f;
-	
+
 	return t*t/cos_pi;
 }
 
@@ -1078,6 +1078,88 @@ ccl_device bool light_select_reached_max_bounces(KernelGlobals *kg, int index, i
 	return (bounce > kernel_tex_fetch(__lights, index).max_bounces);
 }
 
+ccl_device float calc_node_importance(KernelGlobals *kg, float3 P, int node_offset)
+{
+    float4 node0 = kernel_tex_fetch(__light_tree_nodes, node_offset + 0);
+    float4 node1 = kernel_tex_fetch(__light_tree_nodes, node_offset + 1);
+    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
+    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];
+    float theta_e = node2[3];
+    float3 axis = make_float3(node3[0], node3[1], node3[2]);
+    float3 centroid = 0.5f*(bboxMax + bboxMin);
+
+    float3 centroidToP = P-centroid;
+    float theta = acosf(dot(axis,normalize(centroidToP)));
+    float theta_u = 0; // TODO: Figure out how to calculate this one
+    float d2 = len_squared(centroidToP);
+
+    return energy * cosf(clamp(theta - theta_o - theta_u, 0.0, theta_e))/d2;
+}
+
+ccl_device void update_parent_node(KernelGlobals *kg, int node_offset,
+                                   int *childOffset, int *distribution_id,
+                                   int *nemitters)
+{
+    float4 node        = kernel_tex_fetch(__light_tree_nodes, node_offset);
+    (*childOffset)     = __float_as_int(node[1]);
+    (*distribution_id) = __float_as_int(node[2]);
+    (*nemitters)       = __float_as_int(node[3]);
+}
+
+ccl_device int sample_light_bvh(KernelGlobals *kg, float3 P, float randu)
+{
+    int index = -1;
+
+    /* read in first part of root node of light BVH */
+    int secondChildOffset, distribution_id, nemitters;
+    update_parent_node(kg, 0, &secondChildOffset, &distribution_id, &nemitters);
+
+    int offset = 0;
+    do{
+
+        /* Found a leaf - Choose which light to use */
+        if(nemitters > 0){ // Found a leaf
+             if(nemitters == 1){
+                 index = distribution_id;
+             } else { // Leaf with several lights. Pick one randomly.
+                 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;
+             }
+             break;
+        } else { // Interior node, pick left or right randomly
+
+            /* calculate probability of going down left node */
+            int child_offsetL = offset + 4;
+            int child_offsetR = 4*secondChildOffset;
+            float I_L = calc_node_importance(kg, P, child_offsetL);
+            float I_R = calc_node_importance(kg, P, child_offsetR);
+            float P_L = I_L / ( I_L + I_R);
+
+            /* choose which node to go down */
+            light_distribution_sample(kg, &randu); // TODO: Rescale random number in a better way
+            if(randu <= P_L){ // Going down left node
+                offset = child_offsetL;
+            } else { // Going down right node
+                offset = child_offsetR;
+            }
+
+            /* update parent node info for next iteration */
+            update_parent_node(kg, offset, &secondChildOffset,
+                               &distribution_id, &nemitters);
+        }
+
+
+    } while(1);
+
+    return index;
+}
+
 ccl_device_noinline bool light_sample(KernelGlobals *kg,
                                       float randu,
                                       float randv,
@@ -1087,7 +1169,8 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
                                       LightSample *ls)
 {
 	/* sample index */
-	int index = light_distribution_sample(kg, &randu);
+	//int index = light_distribution_sample(kg, &randu);
+	int index = sample_light_bvh(kg, P, randu);
 
 	/* fetch light data */
 	const ccl_global KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, index);
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h
index a7b8c492ee9..ddd96842352 100644
--- a/intern/cycles/kernel/kernel_textures.h
+++ b/intern/cycles/kernel/kernel_textures.h
@@ -64,6 +64,7 @@ KERNEL_TEX(KernelLightDistribution, __light_distribution)
 KERNEL_TEX(KernelLight, __lights)
 KERNEL_TEX(float2, __light_background_marginal_cdf)
 KERNEL_TEX(float2, __light_background_conditional_cdf)
+KERNEL_TEX(float4, __light_tree_nodes)
 
 /* particles */
 KERNEL_TEX(KernelParticle, __particles)
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index b7248354abd..ed689fd187a 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -20,6 +20,7 @@ set(SRC
 	image.cpp
 	integrator.cpp
 	light.cpp
+	light_tree.cpp
 	mesh.cpp
 	mesh_displace.cpp
 	mesh_subdivision.cpp
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index cbcd2564e6e..aab63d9c72d 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -19,6 +19,7 @@
 #include "render/integrator.h"
 #include "render/film.h"
 #include "render/light.h"
+#include "render/light_tree.h"
 #include "render/mesh.h"
 #include "render/object.h"
 #include "render/scene.h"
@@ -376,7 +377,6 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
 	foreach(Light *light, scene->lights) {
 		if(!light->is_enabled)
 			continue;
-
 		distribution[offset].totarea = totarea;
 		distribution[offset].prim = ~light_index;
 		distribution[offset].lamp.pad = 1.0f;
@@ -479,6 +479,302 @@ void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Sce
 	}
 }
 
+/* TODO: Refactor the code here with the code in device_update_distribution */
+void LightManager::device_update_tree_distribution(Device *, DeviceScene *dscene, Scene *scene, Progress& progress)
+{
+    progress.set_status("Updating Lights", "Computing tree distribution");
+
+    /* count */
+    size_t num_lights = 0;
+    size_t num_portals = 0;
+    size_t num_background_lights = 0;
+    size_t num_triangles = 0;
+
+    bool background_mis = false;
+
+    /* primitives array used for light BVH */
+    vector<Primitive> emissivePrims; // Cannot reserve here..?
+
+    int light_index = 0;
+    foreach(Light *light, scene->lights) {
+        if(light->is_enabled) {
+            num_lights++;
+            emissivePrims.push_back(Primitive(~light_index,-1));
+            light_index++;
+        }
+        if(light->is_portal) {
+            num_portals++;
+        }
+    }
+
+    int object_id = 0;
+    foreach(Object *object, scene->objects) {
+        if(progress.get_cancel()) return;
+
+        if(!object_usable_as_light(object)) {
+            object_id++;
+            continue;
+        }
+        /* Count emissive triangles. */
+        Mesh *mesh = object->mesh;
+        size_t mesh_num_triangles = mesh->num_triangles();
+        for(size_t i = 0; i < mesh_num_triangles; i++) {
+            int shader_index = mesh->shader[i];
+            Shader *shader = (shader_index < mesh->used_shaders.size())
+                                     ? mesh->used_shaders[shader_index]
+                                     : scene->default_surface;
+
+            if(shader->use_mis && shader->has_surface_emission) {
+                emissivePrims.push_back(Primitive(i + mesh->tri_offset, object_id));
+                num_triangles++;
+            }
+        }
+
+        object_id++;
+    }
+
+    size_t num_distribution = num_triangles + num_lights;
+    VLOG(1) << "Total " << num_distribution << " of light distribution primitives.";
+
+
+    /* create light BVH */
+    LightTree lightBVH(emissivePrims, scene->objects, scene->lights, 1);
+    emissivePrims.clear();
+    if(progress.get_cancel()) return;
+
+    /* create nodes */
+    const vector<CompactNode>& nodesVec = lightBVH.getNodes();
+    float4 *nodes = dscene->light_tree_nodes.alloc(nodesVec.size()*LIGHT_BVH_NODE_SIZE);
+
+    /* - Convert each compact node into 4xfloat4
+     * 4 for energy, secondChildoffset, prim_id, nemitters
+     * 4 for bbox.min + bbox.max[0]
+     * 4 for bbox.max[1-2], theta_o, theta_e
+     * 4 for axis + 1 pad
+     */
+    size_t offset = 0;
+    foreach (CompactNode node, nodesVec){
+        nodes[offset].x = node.energy;
+        nodes[offset].y = __int_as_float(node.secondChildOffset);
+        nodes[off

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list