Cycles: add rejection of inf/nan samples, in principle these should not happen
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Thu, 5 Apr 2012 15:17:45 +0000 (15:17 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Thu, 5 Apr 2012 15:17:45 +0000 (15:17 +0000)
but this makes it more reliable for now.

Also add an integrator "Clamp" option, to clamp very light samples to a maximum
value. This will reduce accuracy but may help reducing noise and speed up
convergence.

intern/cycles/blender/addon/properties.py
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_sync.cpp
intern/cycles/kernel/kernel_accumulate.h
intern/cycles/kernel/kernel_path.h
intern/cycles/kernel/kernel_types.h
intern/cycles/render/integrator.cpp
intern/cycles/render/integrator.h

index da4de1aeafd5053219657a6fe5bbbc83556e49b0..d20507427b44948d3b36e82c332ff8beddd8d64f 100644 (file)
@@ -174,6 +174,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
                 default=0,
                 )
 
+        cls.sample_clamp = FloatProperty(
+                name="Clamp",
+                description="If non-zero, the maximum value for a sample, higher values will be scaled down to avoid too much noise and slow convergence at the cost of accuracy.",
+                min=0.0, max=1e8,
+                default=0.0,
+                )
+
         cls.debug_tile_size = IntProperty(
                 name="Tile Size",
                 description="",
index f22e298f52d223a775a7ffd0baf93eb0f41998f9..47aba845ba3f8c257971facc06dac8f4f0655451 100644 (file)
@@ -67,6 +67,7 @@ class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
         sub.prop(cscene, "samples", text="Render")
         sub.prop(cscene, "preview_samples", text="Preview")
         sub.prop(cscene, "seed")
+        sub.prop(cscene, "sample_clamp")
 
         sub = col.column(align=True)
         sub.label("Transparency:")
index e88f74eea68615e2fa32274a5189368da9998f09..066e5b776b8b2fdc9e98f13b6d40dad19f5e44e6 100644 (file)
@@ -157,6 +157,8 @@ void BlenderSync::sync_integrator()
 
        integrator->layer_flag = render_layer.layer;
 
+       integrator->sample_clamp = get_float(cscene, "sample_clamp");
+
        if(integrator->modified(previntegrator))
                integrator->tag_update(scene);
 }
index 7ba50973444d78256b1d7c8d54e0b475a524afb4..a78cfc4dfb761f6fbdb1a74b53f427a38edc10cb 100644 (file)
@@ -294,5 +294,49 @@ __device_inline float3 path_radiance_sum(PathRadiance *L)
 #endif
 }
 
+__device_inline void path_radiance_clamp(PathRadiance *L, float3 *L_sum, float clamp)
+{
+       float sum = fabsf(L_sum->x) + fabsf(L_sum->y) + fabsf(L_sum->z);
+
+       if(!isfinite(sum)) {
+               /* invalid value, reject */
+               *L_sum = make_float3(0.0f, 0.0f, 0.0f);
+
+#ifdef __PASSES__
+               if(L->use_light_pass) {
+                       L->direct_diffuse = make_float3(0.0f, 0.0f, 0.0f);
+                       L->direct_glossy = make_float3(0.0f, 0.0f, 0.0f);
+                       L->direct_transmission = make_float3(0.0f, 0.0f, 0.0f);
+
+                       L->indirect_diffuse = make_float3(0.0f, 0.0f, 0.0f);
+                       L->indirect_glossy = make_float3(0.0f, 0.0f, 0.0f);
+                       L->indirect_transmission = make_float3(0.0f, 0.0f, 0.0f);
+
+                       L->emission = make_float3(0.0f, 0.0f, 0.0f);
+               }
+#endif
+       }
+       else if(sum > clamp) {
+               /* value to high, scale down */
+               float scale = clamp/sum;
+
+               *L_sum *= scale;
+
+#ifdef __PASSES__
+               if(L->use_light_pass) {
+                       L->direct_diffuse *= scale;
+                       L->direct_glossy *= scale;
+                       L->direct_transmission *= scale;
+
+                       L->indirect_diffuse *= scale;
+                       L->indirect_glossy *= scale;
+                       L->indirect_transmission *= scale;
+
+                       L->emission *= scale;
+               }
+#endif
+       }
+}
+
 CCL_NAMESPACE_END
 
index f9eeccb1f117fadbdda01dc04a76c28f4dbd846f..53ce374e15072632badb4edbf995accd980d3893 100644 (file)
@@ -396,6 +396,10 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
 
        float3 L_sum = path_radiance_sum(&L);
 
+#ifdef __CLAMP_SAMPLE__
+       path_radiance_clamp(&L, &L_sum, kernel_data.integrator.sample_clamp);
+#endif
+
        kernel_write_light_passes(kg, buffer, &L, sample);
 
        return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent);
index 453d5c826e69e89138e2c6a0cbf1b34f21ffd877..391dcd12dade928ce22465c96161fe8475743549 100644 (file)
@@ -60,6 +60,7 @@ CCL_NAMESPACE_BEGIN
 #define __RAY_DIFFERENTIALS__
 #define __CAMERA_CLIPPING__
 #define __INTERSECTION_REFINE__
+#define __CLAMP_SAMPLE__
 
 #ifdef __KERNEL_SHADING__
 #define __SVM__
@@ -521,7 +522,12 @@ typedef struct KernelIntegrator {
 
        /* render layer */
        int layer_flag;
-       int pad1, pad2;
+
+       /* clamp */
+       float sample_clamp;
+
+       /* padding */
+       int pad;
 } KernelIntegrator;
 
 typedef struct KernelBVH {
index ff2afc7119bc53cb75232cbcefbddf434ff3f8d2..6e6d30f387925be2b141aa17c32b0c55737d4854 100644 (file)
@@ -43,6 +43,7 @@ Integrator::Integrator()
        no_caustics = false;
        seed = 0;
        layer_flag = ~0;
+       sample_clamp = 0.0f;
 
        need_update = true;
 }
@@ -85,6 +86,8 @@ void Integrator::device_update(Device *device, DeviceScene *dscene)
 
        kintegrator->use_ambient_occlusion =
                ((dscene->data.film.pass_flag & PASS_AO) || dscene->data.background.ao_factor != 0.0f);
+       
+       kintegrator->sample_clamp = (sample_clamp == 0.0f)? FLT_MAX: sample_clamp*3.0f;
 
        /* sobol directions table */
        int dimensions = PRNG_BASE_NUM + (max_bounce + transparent_max_bounce + 2)*PRNG_BOUNCE_NUM;
@@ -117,7 +120,8 @@ bool Integrator::modified(const Integrator& integrator)
                transparent_shadows == integrator.transparent_shadows &&
                no_caustics == integrator.no_caustics &&
                layer_flag == integrator.layer_flag &&
-               seed == integrator.seed);
+               seed == integrator.seed &&
+               sample_clamp == integrator.sample_clamp);
 }
 
 void Integrator::tag_update(Scene *scene)
index e610d670142fda087a154c2589226d13e602cd5e..abbbaca894c1c80d9c487e4489de41360fd926a1 100644 (file)
@@ -45,6 +45,8 @@ public:
        int seed;
        int layer_flag;
 
+       float sample_clamp;
+
        bool need_update;
 
        Integrator();