[Bf-blender-cvs] [36cfc9e9fdc] gsoc-2018-many-light-sampling: Cycles: First iteration on split traversal

Erik Englesson noreply at git.blender.org
Fri Jul 6 15:36:55 CEST 2018


Commit: 36cfc9e9fdc12beeec3545854bb2ccbb23ef17c6
Author: Erik Englesson
Date:   Tue Jul 3 10:36:58 2018 +0200
Branches: gsoc-2018-many-light-sampling
https://developer.blender.org/rB36cfc9e9fdc12beeec3545854bb2ccbb23ef17c6

Cycles: First iteration on split traversal

This makes it possible to sample and evaluate several
lights in a single tree traversal. Should sample highly
specular lights better too. Can only be used in branched
path tracing.

This commit contains the following:
* GUI for setting the splitting threshold
* Recursive split traversal
  - Split method based on solid angle and BSDF peak
  - At leafs the path radiance is accumulated to L
  - Have created a simplified GGX eval that is not
    currently being used.
* Refactor of common code

This is in development.

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

M	intern/cycles/blender/addon/presets.py
M	intern/cycles/blender/addon/properties.py
M	intern/cycles/blender/addon/ui.py
M	intern/cycles/blender/blender_sync.cpp
M	intern/cycles/kernel/closure/bsdf_microfacet.h
M	intern/cycles/kernel/kernel_light.h
M	intern/cycles/kernel/kernel_path_surface.h
M	intern/cycles/kernel/kernel_types.h
M	intern/cycles/render/integrator.h
M	intern/cycles/render/light.cpp

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

diff --git a/intern/cycles/blender/addon/presets.py b/intern/cycles/blender/addon/presets.py
index ca9edd0c600..85e075a5167 100644
--- a/intern/cycles/blender/addon/presets.py
+++ b/intern/cycles/blender/addon/presets.py
@@ -69,6 +69,7 @@ class AddPresetSampling(AddPresetBase, Operator):
         "cycles.volume_samples",
         "cycles.use_square_samples",
         "cycles.use_light_bvh",
+        "cycles.splitting_threshold",
         "cycles.progressive",
         "cycles.seed",
         "cycles.sample_clamp_direct",
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index dac9844a11c..b2df2c927e9 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -195,6 +195,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
                 default=False,
                 )
 
+        cls.splitting_threshold = FloatProperty(
+                name="Splitting",
+                description="Threshold for splitting. 0.0=one light, 1.0=all lights",
+                min=0.0, max=1.0,
+                default=0.0,
+                )
+
         cls.samples = IntProperty(
                 name="Samples",
                 description="Number of samples to render for each pixel",
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index bb1b7bee1f4..f7ceddba4a5 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -214,6 +214,10 @@ class CYCLES_RENDER_PT_sampling(CyclesButtonsPanel, Panel):
         row = layout.row(align=True)
         row.label(text="Experimental:")
         row.prop(cscene, "use_light_bvh", text="Light BVH")
+        if cscene.use_light_bvh and use_branched_path(context):
+            row = layout.row(align=True)
+            row.label(text="") # create empty column
+            row.prop(cscene, "splitting_threshold", text="Splitting")
 
         draw_samples_info(layout, context)
 
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 49acba9304d..74169a30f53 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -282,6 +282,7 @@ void BlenderSync::sync_integrator()
 	                                                  Integrator::PATH);
 
 	integrator->use_light_bvh = get_boolean(cscene, "use_light_bvh");
+	integrator->splitting_threshold = get_float(cscene, "splitting_threshold");
 	integrator->sample_all_lights_direct = get_boolean(cscene, "sample_all_lights_direct");
 	integrator->sample_all_lights_indirect = get_boolean(cscene, "sample_all_lights_indirect");
 	integrator->light_sampling_threshold = get_float(cscene, "light_sampling_threshold");
diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h
index 2dd59354058..369beee1d2c 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet.h
@@ -391,6 +391,81 @@ ccl_device void bsdf_microfacet_ggx_blur(ShaderClosure *sc, float roughness)
 	bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
 }
 
+/* TODO: Use this in the tree traversal splitting */
+ccl_device float3 bsdf_microfacet_ggx_eval_reflect_simple(const ShaderClosure *sc, const float3 I, const float3 omega_in)
+{
+	const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
+	float alpha_x = bsdf->alpha_x;
+	float alpha_y = bsdf->alpha_y;
+	bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
+	float3 N = bsdf->N;
+
+	if(m_refractive || alpha_x*alpha_y <= 1e-7f)
+		return make_float3(0.0f, 0.0f, 0.0f);
+
+	float cosNO = dot(N, I);
+	float cosNI = dot(N, omega_in); // pass in our conservative cosine instead of this one?
+	                                // fresnel calcs some kind of cosine with I too.
+
+	if(cosNI > 0 && cosNO > 0) {
+		/* get half vector */
+		float3 m = normalize(omega_in + I);
+		float alpha2 = alpha_x * alpha_y;
+		float D, G1o, G1i;
+
+		/* assume isotropic */
+
+		/* isotropic
+			 * eq. 20: (F*G*D)/(4*in*on)
+			 * eq. 33: first we calculate D(m) */
+		float cosThetaM = dot(N, m);
+		float cosThetaM2 = cosThetaM * cosThetaM;
+		float cosThetaM4 = cosThetaM2 * cosThetaM2;
+		float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
+
+		/* use GTR2 */
+		D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
+
+		/* eq. 34: now calculate G1(i,m) and G1(o,m) */
+		//G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
+		//G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
+
+		/* Let a2=alpha2 and cos=cosNO/cosNI then the above is equivalent to:
+		 * 2    / (    1 + sqrt(      1 + a2 * (1 - cos^2)  / cos^2 )       )       = /common denom/       =
+		 * 2    / (    1 + sqrt( (cos^2 + a2 * (1 - cos^2)) / cos^2 )       )       = /factor out 1/cos^2/ =
+		 * 2    / (    1 + sqrt(  cos^2 + a2 * (1 - cos^2)          ) / cos )       = /common denom/       =
+		 * 2    / ( (cos + sqrt(  cos^2 + a2 * (1 - cos^2)          )       ) / cos = /move cos to num/    =
+		 * 2cos / (  cos + sqrt(  cos^2 + a2 * (1 - cos^2)          )       )       = /rewrite sqrt/       =
+		 * 2cos / (  cos + sqrt(  cos^2 * (1 - a2) + a2             )       )
+		 * => removes one of the divisions
+		 *
+		 *  - Glo should contain a cosNO in its numerator but this cancels with
+		 *    cosNO in the denomenator in eq. 20.(removes another division)
+		 *  - There should be a cosNI in the denomenator of eq. 20 but I think
+		 *    this has been canceled out already since there is no cosNI in
+		 *    path_radiance_bsdf_bounce() ?
+		 *  - Both Glo and Gli should contain a 2.0 in their numerators but they
+		 *    cancel with 1/4 in eq. 20.
+		 *
+		 * => This code does three less divisions in total
+		 *  This could potentially be used in the real GGX evaluation too.
+		 */
+		G1o = 1.0f  / (cosNO + safe_sqrtf(cosNO * cosNO * (1.0f - alpha2) + alpha2));
+		G1i = cosNI / (cosNI + safe_sqrtf(cosNI * cosNI * (1.0f - alpha2) + alpha2));
+
+		float G = G1o * G1i;
+
+		/* eq. 20 */
+		float3 F = reflection_color(bsdf, omega_in, m);
+
+		float3 out = F * G * D;
+
+		return out;
+	}
+
+	return make_float3(0.0f, 0.0f, 0.0f);
+}
+
 ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf)
 {
 	const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc;
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 22804c58aa8..39d575adefa 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -1122,6 +1122,7 @@ ccl_device float calc_node_importance(KernelGlobals *kg, float3 P, int node_offs
 	float theta_u = 0; // TODO: Figure out how to calculate this one
 	float d2 = len_squared(centroidToP);
 
+	// todo: fix clamp here so it is 0 outside theta_e + theta_o ?
 	return energy * cosf(clamp(theta - theta_o - theta_u, 0.0, theta_e))/d2;
 }
 
@@ -1378,22 +1379,18 @@ ccl_device void light_distribution_sample(KernelGlobals *kg, float3 P,
 	}
 }
 
-/* picks a point on a light and computes the probability of picking this point*/
-ccl_device_noinline bool light_sample(KernelGlobals *kg,
-                                      float randu,
-                                      float randv,
-                                      float time,
-                                      float3 P,
-                                      int bounce,
-                                      LightSample *ls)
+/* picks a point on a given light and computes the probability of picking this point*/
+ccl_device void light_point_sample(KernelGlobals *kg,
+                              float randu,
+                              float randv,
+                              float time,
+                              float3 P,
+                              int bounce,
+                              int distribution_id,
+                              LightSample *ls)
 {
-	/* sample index and compute light picking pdf */
-	float pdf_factor = 0.0f;
-	int index = -1;
-	light_distribution_sample(kg, P, &randu, &index, &pdf_factor);
-
 	/* fetch light data and compute rest of light pdf */
-	const ccl_global KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, index);
+	const ccl_global KernelLightDistribution *kdistribution = &kernel_tex_fetch(__light_distribution, distribution_id);
 	int prim = kdistribution->prim;
 
 	if(prim >= 0) {
@@ -1407,13 +1404,31 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
 		int lamp = -prim-1;
 
 		if(UNLIKELY(light_select_reached_max_bounces(kg, lamp, bounce))) {
-			return false;
+			ls->pdf = 0.0f;
+			return;
 		}
 
 		if (!lamp_light_sample(kg, lamp, randu, randv, P, ls)){
-			return false;
+			ls->pdf = 0.0f;
+			return;
 		}
 	}
+}
+
+/* picks a point on a light and computes the probability of picking this point*/
+ccl_device_noinline bool light_sample(KernelGlobals *kg,
+                                      float randu,
+                                      float randv,
+                                      float time,
+                                      float3 P,
+                                      int bounce,
+                                      LightSample *ls)
+{
+	/* sample index and compute light picking pdf */
+	float pdf_factor = 0.0f;
+	int index = -1;
+	light_distribution_sample(kg, P, &randu, &index, &pdf_factor);
+	light_point_sample(kg, randu, randv, time, P, bounce, index, ls);
 
 	/* combine pdfs */
 	ls->pdf *= pdf_factor;
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index f69fadb6669..54062a1c2b7 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -14,8 +14,238 @@
  * limitations under the License.
  */
 
+#include "util/util_logging.h"
+
 CCL_NAMESPACE_BEGIN
 
+ccl_device void accum_light_contribution(KernelGlobals *kg,
+                                         ShaderData *sd,
+                                         ShaderData* emission_sd,
+                                         LightSamp

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list