[Bf-blender-cvs] [2cdb08f4ffb] gsoc-2018-many-light-sampling: Cycles: Background lights works with light tree

Erik Englesson noreply at git.blender.org
Fri Jun 29 10:52:52 CEST 2018


Commit: 2cdb08f4ffb3d7d24935d82ba32b1b1100ee2cd6
Author: Erik Englesson
Date:   Wed Jun 27 16:59:01 2018 +0200
Branches: gsoc-2018-many-light-sampling
https://developer.blender.org/rB2cdb08f4ffb3d7d24935d82ba32b1b1100ee2cd6

Cycles: Background lights works with light tree

Added support for background lights when using the
light tree, fixed minor bugs related to disabled lights
and trying to build the light tree without any lights.

Now samples either the light tree, distant lights or
background lights based on their energy.

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

M	intern/cycles/kernel/kernel_emission.h
M	intern/cycles/kernel/kernel_light.h
M	intern/cycles/kernel/kernel_textures.h
M	intern/cycles/kernel/kernel_types.h
M	intern/cycles/render/light.cpp
M	intern/cycles/render/light.h
M	intern/cycles/render/light_tree.cpp
M	intern/cycles/render/light_tree.h
M	intern/cycles/render/scene.cpp
M	intern/cycles/render/scene.h
M	intern/cycles/util/util_color.h

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

diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index a4d43a88166..48958846dd0 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -328,8 +328,9 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg,
 	if(!(state->flag & PATH_RAY_MIS_SKIP) && res) {
 		/* multiple importance sampling, get background light pdf for ray
 		 * direction, and compute weight with respect to BSDF pdf */
-		/* TODO: PDF should be multiplied by picking probability */
 		float pdf = background_light_pdf(kg, ray->P, ray->D);
+		int background_index = kernel_data.integrator.background_light_index;
+		pdf *= light_distribution_pdf(kg, ray->P, background_index);
 		float mis_weight = power_heuristic(state->ray_pdf, pdf);
 
 		return L*mis_weight;
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 7623c6a7e3b..46aadfd32ab 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -1015,6 +1015,45 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals *kg, int prim, i
 	}
 }
 
+/* chooses either to sample the light tree, distant or background lights by
+ * sampling a CDF based on energy */
+ccl_device int light_group_distribution_sample(KernelGlobals *kg, float *randu)
+{
+	/* This is basically std::upper_bound as used by pbrt, to find a point light or
+	 * triangle to emit from, proportional to area. a good improvement would be to
+	 * also sample proportional to power, though it's not so well defined with
+	 * arbitrary shaders. */
+	const int num_groups = LIGHTGROUP_NUM;
+	int first = 0;
+	int len = num_groups + 1;
+	float r = *randu;
+	// todo: refactor this into its own function. It is used in several places
+	while(len > 0) {
+		int half_len = len >> 1;
+		int middle = first + half_len;
+
+		if(r < kernel_tex_fetch(__light_group_sample_cdf, middle)) {
+			len = half_len;
+		}
+		else {
+			first = middle + 1;
+			len = len - half_len - 1;
+		}
+	}
+
+	/* Clamping should not be needed but float rounding errors seem to
+	 * make this fail on rare occasions. */
+	int index = clamp(first-1, 0, num_groups-1);
+
+	/* Rescale to reuse random number. this helps the 2D samples within
+	 * each area light be stratified as well. */
+	float distr_min = kernel_tex_fetch(__light_group_sample_cdf, index);
+	float distr_max = kernel_tex_fetch(__light_group_sample_cdf, index+1);
+	*randu = (r - distr_min)/(distr_max - distr_min);
+
+	return index;
+}
+
 /* Light Distribution */
 
 ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
@@ -1102,15 +1141,21 @@ ccl_device void light_distant_sample(KernelGlobals *kg, float3 P, float *randu,
 	int num_distant = kernel_data.integrator.num_distant_lights;
 	int light = min((int)(*randu * (float)num_distant), num_distant-1);
 
-	/* this assumes the distant lights are at the end of the distribution array */
-	// TODO: have a distant lights offset into distribution array instead
-	int num_total_lights = kernel_data.integrator.num_distribution;
-	int distant_lights_offset = num_total_lights-num_distant;
+	/* This assumes the distant lights are next to each other in the
+	 * distribution array starting at distant_lights_offset. */
+	int distant_lights_offset = kernel_data.integrator.distant_lights_offset;
 
 	*index = light + distant_lights_offset;
 	*pdf = kernel_data.integrator.inv_num_distant_lights;
 }
 
+/* picks one of the background lights and computes the probability of picking it */
+ccl_device void light_background_sample(KernelGlobals *kg, float3 P, float *randu,
+                                     int *index, float *pdf){
+	*index = kernel_data.integrator.background_light_index;
+	*pdf = 1.0f;
+}
+
 /* picks a light from the light BVH and returns its index and the probability of
  * picking this light. */
 ccl_device void light_bvh_sample(KernelGlobals *kg, float3 P, float randu,
@@ -1258,16 +1303,41 @@ ccl_device float light_distribution_pdf(KernelGlobals *kg, float3 P, int prim_id
 
 	/* compute picking pdf for this light */
 	if (kernel_data.integrator.use_light_bvh){
-		// Find mapping from distribution_id to node_id
-		int node_id = kernel_tex_fetch(__light_distribution_to_node,
-		                               distribution_id);
-		if(node_id==-1){ // Distant lights are not in any nodes
-			return (1.0f - kernel_data.integrator.bvh_sample_probability) *
-			       kernel_data.integrator.inv_num_distant_lights;
+
+		/* find out which group of lights to sample */
+		int group;
+		if(prim_id >= 0){
+			group = LIGHTGROUP_TREE;
+		} else {
+			int lamp = -prim_id-1;
+			int light_type = kernel_tex_fetch(__lights, lamp).type;
+			if(light_type == LIGHT_DISTANT){
+				group = LIGHTGROUP_DISTANT;
+			} else if(light_type == LIGHT_BACKGROUND){
+				group = LIGHTGROUP_BACKGROUND;
+			} else {
+				group = LIGHTGROUP_TREE;
+			}
+		}
+
+		/* get probabilty to sample this group of lights */
+		float group_prob = kernel_tex_fetch(__light_group_sample_prob, group);
+		float pdf = group_prob;
+
+		if(group == LIGHTGROUP_TREE){
+			// Find mapping from distribution_id to node_id
+			int node_id = kernel_tex_fetch(__light_distribution_to_node,
+			                               distribution_id);
+			pdf *= light_bvh_pdf(kg, P, node_id);
+		} else if(group == LIGHTGROUP_DISTANT) {
+			pdf *= kernel_data.integrator.inv_num_distant_lights;
+		} else if(group == LIGHTGROUP_BACKGROUND) {
+			/* there is only one background light so nothing to do here */
 		} else {
-			return kernel_data.integrator.bvh_sample_probability *
-			       light_bvh_pdf(kg, P, node_id);
+			kernel_assert(false);
 		}
+
+		return pdf;
 	} else {
 		const ccl_global KernelLightDistribution *kdistribution =
 		        &kernel_tex_fetch(__light_distribution, distribution_id);
@@ -1280,16 +1350,23 @@ ccl_device void light_distribution_sample(KernelGlobals *kg, float3 P,
                                           float *randu, int *index, float *pdf)
 {
 	if (kernel_data.integrator.use_light_bvh){
-		/* sample light BVH or distant lights */
-		float bvh_sample_prob = kernel_data.integrator.bvh_sample_probability;
-		if(*randu <= bvh_sample_prob) { // Sample light BVH
+
+		/* sample light type distribution */
+		int   group      = light_group_distribution_sample(kg, randu);
+		float group_prob = kernel_tex_fetch(__light_group_sample_prob, group);
+
+		if(group == LIGHTGROUP_TREE){
 			light_bvh_sample(kg, P, *randu, index, pdf);
-			*pdf *= bvh_sample_prob;
-		} else { // Sample distant lights
+		} else if(group == LIGHTGROUP_DISTANT) {
 			light_distant_sample(kg, P, randu, index, pdf);
-			*pdf *= (1.0f - bvh_sample_prob);
+		} else if(group == LIGHTGROUP_BACKGROUND) {
+			light_background_sample(kg, P, randu, index, pdf);
+		} else {
+			kernel_assert(false);
 		}
 
+		*pdf *= group_prob;
+
 	} else { // Sample light distribution CDF
 		*index = light_distribution_sample(kg, randu);
 		const ccl_global KernelLightDistribution *kdistribution =
@@ -1329,6 +1406,7 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
 		if(UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
 			return false;
 		}
+
 		if (!lamp_light_sample(kg, lamp, randu, randv, P, ls)){
 			return false;
 		}
diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h
index 3adfcf1c583..d73d7b78a48 100644
--- a/intern/cycles/kernel/kernel_textures.h
+++ b/intern/cycles/kernel/kernel_textures.h
@@ -68,7 +68,8 @@ KERNEL_TEX(float4, __light_tree_nodes)
 KERNEL_TEX(uint, __light_distribution_to_node)
 KERNEL_TEX(uint, __lamp_to_distribution)
 KERNEL_TEX(uint, __triangle_to_distribution)
-
+KERNEL_TEX(float, __light_group_sample_cdf)
+KERNEL_TEX(float, __light_group_sample_prob)
 
 /* particles */
 KERNEL_TEX(KernelParticle, __particles)
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 01835d20d54..d822dfad0f9 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -666,6 +666,16 @@ enum PanoramaType {
 	PANORAMA_NUM_TYPES,
 };
 
+/* Light Sampling Group */
+
+enum LightGroup {
+	LIGHTGROUP_TREE,
+	LIGHTGROUP_DISTANT,
+	LIGHTGROUP_BACKGROUND,
+
+	LIGHTGROUP_NUM,
+};
+
 /* Differential */
 
 typedef struct differential3 {
@@ -1309,12 +1319,13 @@ typedef struct KernelIntegrator {
 	int num_triangle_lights;
 	int num_distant_lights;
 	float inv_num_distant_lights;
-	float bvh_sample_probability;
 	float pdf_triangles;
 	float pdf_lights;
 	float pdf_inv_totarea;
 	int pdf_background_res;
 	float light_inv_rr_threshold;
+	int distant_lights_offset;
+	int background_light_index;
 
 	/* light portals */
 	float portal_pdf;
@@ -1375,7 +1386,6 @@ typedef struct KernelIntegrator {
 	int start_sample;
 
 	int max_closures;
-	int pad;
 } KernelIntegrator;
 static_assert_align(KernelIntegrator, 16);
 
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index da1b10e9ad3..a0af7e1213a 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -248,7 +248,86 @@ bool LightManager::object_usable_as_light(Object *object) {
 	return false;
 }
 
-void LightManager::device_update_distribution(Device *, DeviceScene *dscene, Scene *scene, Progress& progress)
+float LightManager::distant_lights_energy(const Scene *scene,
+                                          const vector<Primitive> &prims)
+{
+	float luminance = 0.0f;
+	float3 emission;
+	foreach(Primitive prim, prims){
+
+		if(prim.prim_id >= 0) continue;
+
+		const Light *lamp = scene->lights[prim.lamp_id];
+		if(lamp->type != LIGHT_DISTANT) continue;
+
+		/* get emission from shader */
+		bool is_constant_emission = lamp->shader->is_constant_emission(&emission);
+		if(!is_constant_emission) continue; // TODO: Properly handle this case
+
+		luminance += rgb_to_luminance(emission);
+	}
+
+
+	/* TODO: could project each bbox onto a disk outside the scene and sum up
+	 * all the projected areas instead if this results in too high sampling */
+
+	/* get radius of bounding sphere of scene */
+	BoundBox scene_bbox = BoundBox::empty;
+	foreach(Object *object, scene->objects) {
+		// TODO: What abou

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list