[Bf-blender-cvs] [716e138a1b8] master: Cycles: Automatically detect HDRI resolution by default and use non-square sampling map

Lukas Stockner noreply at git.blender.org
Thu Jun 14 22:30:54 CEST 2018


Commit: 716e138a1b8cb81e13f7da2da5d16763d868743a
Author: Lukas Stockner
Date:   Thu Jun 14 16:18:34 2018 +0200
Branches: master
https://developer.blender.org/rB716e138a1b8cb81e13f7da2da5d16763d868743a

Cycles: Automatically detect HDRI resolution by default and use non-square sampling map

The automatic mode checks all Enviroment Texture nodes and picks the largest image's resolution.
If there are no Enviroment Textures, it just uses the old default.

Also, the sampling map now isn't limited to square shapes. The automatic detection uses the exact image size,
the manual UI option now halves the value to get the height.

A default aspect ratio of 2:1 makes sense since this is what most HDRIs use.

Reviewers: brecht, sergey

Differential Revision: https://developer.blender.org/D3477

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

M	intern/cycles/blender/addon/properties.py
M	intern/cycles/blender/addon/ui.py
M	intern/cycles/blender/addon/version_update.py
M	intern/cycles/blender/blender_object.cpp
M	intern/cycles/kernel/kernel_emission.h
M	intern/cycles/kernel/kernel_light.h
M	intern/cycles/kernel/kernel_types.h
M	intern/cycles/render/image.cpp
M	intern/cycles/render/image.h
M	intern/cycles/render/light.cpp

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

diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 8dbd80f3747..4484dcfbfd7 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -128,6 +128,12 @@ enum_volume_interpolation = (
     ('CUBIC', "Cubic", "Smoothed high quality interpolation, but slower")
     )
 
+enum_world_mis = (
+    ('NONE', "None", "Don't sample the background, faster but might cause noise for non-solid backgrounds"),
+    ('AUTOMATIC', "Auto", "Automatically try to determine the best setting"),
+    ('MANUAL', "Manual", "Manually set the resolution of the sampling map, higher values are slower and require more memory but reduce noise")
+    )
+
 enum_device_type = (
     ('CPU', "CPU", "CPU", 0),
     ('CUDA', "CUDA", "CUDA", 1),
@@ -938,15 +944,15 @@ class CyclesWorldSettings(bpy.types.PropertyGroup):
                 description="Cycles world settings",
                 type=cls,
                 )
-        cls.sample_as_light = BoolProperty(
-                name="Multiple Importance Sample",
-                description="Use multiple importance sampling for the environment, "
-                            "enabling for non-solid colors is recommended",
-                default=True,
+        cls.sampling_method = EnumProperty(
+                name="Sampling method",
+                description="How to sample the background light",
+                items=enum_world_mis,
+                default='AUTOMATIC',
                 )
         cls.sample_map_resolution = IntProperty(
                 name="Map Resolution",
-                description="Importance map size is resolution x resolution; "
+                description="Importance map size is resolution x resolution/2; "
                             "higher values potentially produce less noise, at the cost of memory and speed",
                 min=4, max=8192,
                 default=1024,
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 707f8756f6f..2b11a2eefb0 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -1214,11 +1214,13 @@ class CYCLES_WORLD_PT_settings(CyclesButtonsPanel, Panel):
         col = split.column()
 
         col.label(text="Surface:")
-        col.prop(cworld, "sample_as_light", text="Multiple Importance")
+        col.prop(cworld, "sampling_method", text="Sampling")
 
         sub = col.column(align=True)
-        sub.active = cworld.sample_as_light
-        sub.prop(cworld, "sample_map_resolution")
+        sub.active = cworld.sampling_method != 'NONE'
+        subsub = sub.row(align=True)
+        subsub.active = cworld.sampling_method == 'MANUAL'
+        subsub.prop(cworld, "sample_map_resolution")
         if use_branched_path(context):
             subsub = sub.row(align=True)
             subsub.active = use_sample_all_lights(context)
diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py
index 292f0a1fa90..dc28bc647b5 100644
--- a/intern/cycles/blender/addon/version_update.py
+++ b/intern/cycles/blender/addon/version_update.py
@@ -377,10 +377,6 @@ def do_versions(self):
         for world in bpy.data.worlds:
             cworld = world.cycles
 
-            # World MIS
-            if not cworld.is_property_set("sample_as_light"):
-                cworld.sample_as_light = False
-
             # World MIS Samples
             if not cworld.is_property_set("samples"):
                 cworld.samples = 4
@@ -431,3 +427,12 @@ def do_versions(self):
     if bpy.data.version <= (2, 79, 3):
         # Switch to squared roughness convention
         square_roughness_nodes_insert()
+
+    for world in bpy.data.worlds:
+        cworld = world.cycles
+        # World MIS
+        if not cworld.is_property_set("sampling_method"):
+            if cworld.get("sample_as_light", False):
+                cworld.sampling_method = 'MANUAL'
+            else:
+                cworld.sampling_method = 'NONE'
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 4919bc4325f..86b04f5030c 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -227,7 +227,15 @@ void BlenderSync::sync_background_light(bool use_portal)
 	if(b_world) {
 		PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles");
 		PointerRNA cworld = RNA_pointer_get(&b_world.ptr, "cycles");
-		bool sample_as_light = get_boolean(cworld, "sample_as_light");
+
+		enum SamplingMethod {
+			SAMPLING_NONE = 0,
+			SAMPLING_AUTOMATIC,
+			SAMPLING_MANUAL,
+			SAMPLING_NUM
+		};
+		int sampling_method = get_enum(cworld, "sampling_method", SAMPLING_NUM, SAMPLING_AUTOMATIC);
+		bool sample_as_light = (sampling_method != SAMPLING_NONE);
 
 		if(sample_as_light || use_portal) {
 			/* test if we need to sync */
@@ -239,7 +247,12 @@ void BlenderSync::sync_background_light(bool use_portal)
 			    b_world.ptr.data != world_map)
 			{
 				light->type = LIGHT_BACKGROUND;
-				light->map_resolution  = get_int(cworld, "sample_map_resolution");
+				if(sampling_method == SAMPLING_MANUAL) {
+					light->map_resolution = get_int(cworld, "sample_map_resolution");
+				}
+				else {
+					light->map_resolution = 0;
+				}
 				light->shader = scene->default_background;
 				light->use_mis = sample_as_light;
 				light->max_bounces = get_int(cworld, "max_bounces");
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index a5556c3be8f..524e2467ebc 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -319,9 +319,9 @@ ccl_device_noinline float3 indirect_background(KernelGlobals *kg,
 
 #ifdef __BACKGROUND_MIS__
 	/* check if background light exists or if we should skip pdf */
-	int res = kernel_data.integrator.pdf_background_res;
+	int res_x = kernel_data.integrator.pdf_background_res_x;
 
-	if(!(state->flag & PATH_RAY_MIS_SKIP) && res) {
+	if(!(state->flag & PATH_RAY_MIS_SKIP) && res_x) {
 		/* multiple importance sampling, get background light pdf for ray
 		 * direction, and compute weight with respect to BSDF pdf */
 		float pdf = background_light_pdf(kg, ray->P, ray->D);
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index ec7203d36eb..bb182ef1f25 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -143,12 +143,13 @@ float3 background_map_sample(KernelGlobals *kg, float randu, float randv, float
 	/* for the following, the CDF values are actually a pair of floats, with the
 	 * function value as X and the actual CDF as Y.  The last entry's function
 	 * value is the CDF total. */
-	int res = kernel_data.integrator.pdf_background_res;
-	int cdf_count = res + 1;
+	int res_x = kernel_data.integrator.pdf_background_res_x;
+	int res_y = kernel_data.integrator.pdf_background_res_y;
+	int cdf_width = res_x + 1;
 
 	/* this is basically std::lower_bound as used by pbrt */
 	int first = 0;
-	int count = res;
+	int count = res_y;
 
 	while(count > 0) {
 		int step = count >> 1;
@@ -163,24 +164,24 @@ float3 background_map_sample(KernelGlobals *kg, float randu, float randv, float
 	}
 
 	int index_v = max(0, first - 1);
-	kernel_assert(index_v >= 0 && index_v < res);
+	kernel_assert(index_v >= 0 && index_v < res_y);
 
 	float2 cdf_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v);
 	float2 cdf_next_v = kernel_tex_fetch(__light_background_marginal_cdf, index_v + 1);
-	float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res);
+	float2 cdf_last_v = kernel_tex_fetch(__light_background_marginal_cdf, res_y);
 
 	/* importance-sampled V direction */
 	float dv = inverse_lerp(cdf_v.y, cdf_next_v.y, randv);
-	float v = (index_v + dv) / res;
+	float v = (index_v + dv) / res_y;
 
 	/* this is basically std::lower_bound as used by pbrt */
 	first = 0;
-	count = res;
+	count = res_x;
 	while(count > 0) {
 		int step = count >> 1;
 		int middle = first + step;
 
-		if(kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + middle).y < randu) {
+		if(kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_width + middle).y < randu) {
 			first = middle + 1;
 			count -= step + 1;
 		}
@@ -189,15 +190,15 @@ float3 background_map_sample(KernelGlobals *kg, float randu, float randv, float
 	}
 
 	int index_u = max(0, first - 1);
-	kernel_assert(index_u >= 0 && index_u < res);
+	kernel_assert(index_u >= 0 && index_u < res_x);
 
-	float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + index_u);
-	float2 cdf_next_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + index_u + 1);
-	float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_count + res);
+	float2 cdf_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_width + index_u);
+	float2 cdf_next_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_width + index_u + 1);
+	float2 cdf_last_u = kernel_tex_fetch(__light_background_conditional_cdf, index_v * cdf_width + res_x);
 
 	/* importance-sampled U direction */
 	float du = inverse_lerp(cdf_u.y, cdf_next_u.y, randu);
-	float u = (index_u + du) / res;
+	float u = (index_u + du) / res_x;
 
 	/* compute pdf */
 	float denom = cdf_last_u.x * cdf_last_v.x;
@@ -223,19 +224,21 @@ ccl_device
 float background_map_pdf(KernelGlobals *kg, float3 direction)
 {
 	float2 uv = direction_to_equirectangular(direction);
-	int res = kernel_data.integrator.pdf_background_res;
+	int res_x = kernel_data.integrator.pdf_background_res_x;
+	int res_y = kernel_data.integrator.pdf_background_res_y;
+	int cdf_width = res_x + 1;
 
 	float sin_theta = sinf(uv.y * M_PI_F);
 
 	if(sin_theta == 0.0f)
 		return 0.0f;
 
-	int index_u = clamp(float_to_int(uv.x * res), 0, res - 1);
-	int index_v = clamp(float_to_int(uv.y * res), 0, res - 1);
+	int index_u = clamp(float_to_int(uv.x * res_x), 0, res_x - 1);
+	int index_v = clamp(float_to_int(uv.y * res_y), 0, res_y - 1);
 
 	/* pdfs in V direction */
-	float2 cdf_last_u = kernel_tex_fetch(__light

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list