Cycles: make multiple importance sampling for lamps an option per lamp now,
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 30 Jan 2013 15:57:15 +0000 (15:57 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 30 Jan 2013 15:57:15 +0000 (15:57 +0000)
disabled by default for backwards compatibility.
http://wiki.blender.org/index.php/Doc:2.6/Manual/Render/Cycles/Integrator

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

index 3661274..5f585fc 100644 (file)
@@ -462,8 +462,8 @@ class CyclesMaterialSettings(bpy.types.PropertyGroup):
                 type=cls,
                 )
         cls.sample_as_light = BoolProperty(
-                name="Sample as Lamp",
-                description="Use direct light sampling for this material, "
+                name="Multiple Importance Sample",
+                description="Use multiple importance sampling for this material, "
                             "disabling may reduce overall noise for large "
                             "objects that emit little light compared to other light sources",
                 default=True,
@@ -499,6 +499,12 @@ class CyclesLampSettings(bpy.types.PropertyGroup):
                 min=1, max=10000,
                 default=1,
                 )
+        cls.use_multiple_importance_sampling = BoolProperty(
+                name="Multiple Importance Sample",
+                description="Use multiple importance sampling for the lamp, "
+                            "reduces noise for area lamps and sharp glossy materials",
+                default=False,
+                )
 
     @classmethod
     def unregister(cls):
@@ -514,8 +520,8 @@ class CyclesWorldSettings(bpy.types.PropertyGroup):
                 type=cls,
                 )
         cls.sample_as_light = BoolProperty(
-                name="Sample as Lamp",
-                description="Use direct light sampling for the environment, "
+                name="Multiple Importance Sample",
+                description="Use multiple importance sampling for the environment, "
                             "enabling for non-solid colors is recommended",
                 default=False,
                 )
index a42b69d..ad9253f 100644 (file)
@@ -574,6 +574,8 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
         col = split.column()
         col.prop(clamp, "cast_shadow")
 
+        layout.prop(clamp, "use_multiple_importance_sampling")
+
         if lamp.type == 'HEMI':
             layout.label(text="Not supported, interpreted as sun lamp.")
 
@@ -807,9 +809,10 @@ class CyclesMaterial_PT_settings(CyclesButtonsPanel, Panel):
         col.prop(mat, "diffuse_color", text="Viewport Color")
 
         col = split.column()
-        col.prop(cmat, "sample_as_light")
         col.prop(mat, "pass_index")
 
+        layout.prop(cmat, "sample_as_light")
+
 
 class CyclesTexture_PT_context(CyclesButtonsPanel, Panel):
     bl_label = ""
index e9bcea7..a9d37db 100644 (file)
@@ -156,6 +156,7 @@ void BlenderSync::sync_light(BL::Object b_parent, int persistent_id[OBJECT_PERSI
        /* shadow */
        PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles");
        light->cast_shadow = get_boolean(clamp, "cast_shadow");
+       light->use_mis = get_boolean(clamp, "use_multiple_importance_sampling");
        light->samples = get_int(clamp, "samples");
 
        /* tag */
index 54bc071..e234d54 100644 (file)
@@ -93,7 +93,7 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
        }
 
        /* return lamp index for MIS */
-       if(ls.use_mis)
+       if(ls.shader & SHADER_USE_MIS)
                *lamp = ls.lamp;
        else
                *lamp= ~0;
@@ -114,7 +114,7 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
 
        shader_bsdf_eval(kg, sd, ls.D, eval, &bsdf_pdf);
 
-       if(ls.use_mis) {
+       if(ls.shader & SHADER_USE_MIS) {
                /* multiple importance sampling */
                float mis_weight = power_heuristic(ls.pdf, bsdf_pdf);
                light_eval *= mis_weight;
index 6ba3e43..8b32b7b 100644 (file)
@@ -31,7 +31,6 @@ typedef struct LightSample {
        int prim;                       /* primitive id for triangle/curve ligths */
        int shader;                     /* shader id */
        int lamp;                       /* lamp id */
-       int use_mis;            /* for lamps with size zero */
        LightType type;         /* type of light */
 } LightSample;
 
@@ -218,11 +217,10 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
 
        LightType type = (LightType)__float_as_int(data0.x);
        ls->type = type;
-#ifdef __LAMP_MIS__
-       ls->use_mis = true;
-#else
-       ls->use_mis = false;
-#endif
+       ls->shader = __float_as_int(data1.x);
+       ls->object = ~0;
+       ls->prim = ~0;
+       ls->lamp = lamp;
 
        if(type == LIGHT_DISTANT) {
                /* distant light */
@@ -233,10 +231,6 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
 
                if(radius > 0.0f)
                        D = distant_light_sample(D, radius, randu, randv);
-#ifdef __LAMP_MIS__
-               else
-                       ls->use_mis = false;
-#endif
 
                ls->P = D;
                ls->Ng = D;
@@ -257,9 +251,6 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
                ls->D = -D;
                ls->t = FLT_MAX;
                ls->eval_fac = 1.0f;
-#ifndef __LAMP_MIS__
-               ls->use_mis = true;
-#endif
        }
 #endif
        else {
@@ -271,10 +262,6 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
                        if(radius > 0.0f)
                                /* sphere light */
                                ls->P += sphere_light_sample(P, ls->P, radius, randu, randv);
-#ifdef __LAMP_MIS__
-                       else
-                               ls->use_mis = false;
-#endif
 
                        ls->D = normalize_len(ls->P - P, &ls->t);
                        ls->Ng = -ls->D;
@@ -304,13 +291,6 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
 
                        float invarea = data2.x;
 
-                       if(invarea == 0.0f) {
-#ifdef __LAMP_MIS__
-                               ls->use_mis = false;
-#endif
-                               invarea = 1.0f;
-                       }
-
                        ls->eval_fac = 0.25f*invarea;
                        ls->pdf = invarea;
                }
@@ -318,11 +298,6 @@ __device void lamp_light_sample(KernelGlobals *kg, int lamp,
                ls->eval_fac *= kernel_data.integrator.inv_pdf_lights;
                ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t);
        }
-
-       ls->shader = __float_as_int(data1.x);
-       ls->object = ~0;
-       ls->prim = ~0;
-       ls->lamp = lamp;
 }
 
 __device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float t, LightSample *ls)
@@ -336,7 +311,6 @@ __device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, f
        ls->object = ~0;
        ls->prim = ~0;
        ls->lamp = lamp;
-       ls->use_mis = false; /* flag not used for eval */
 
        if(type == LIGHT_DISTANT) {
                /* distant light */
@@ -475,7 +449,7 @@ __device void triangle_light_sample(KernelGlobals *kg, int prim, int object,
        ls->object = object;
        ls->prim = prim;
        ls->lamp = ~0;
-       ls->use_mis = true;
+       ls->shader |= SHADER_USE_MIS;
        ls->t = 0.0f;
        ls->type = LIGHT_AREA;
        ls->eval_fac = 1.0f;
@@ -529,11 +503,10 @@ __device void curve_segment_light_sample(KernelGlobals *kg, int prim, int object
        ls->object = object;
        ls->prim = prim;
        ls->lamp = ~0;
-       ls->use_mis = true;
        ls->t = 0.0f;
        ls->type = LIGHT_STRAND;
        ls->eval_fac = 1.0f;
-       ls->shader = __float_as_int(v00.z);
+       ls->shader = __float_as_int(v00.z) | SHADER_USE_MIS;
 
        object_transform_light_sample(kg, ls, object, time);
 }
index 1a5df66..06276c8 100644 (file)
@@ -254,7 +254,7 @@ __device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample,
                bool hit = scene_intersect(kg, &ray, visibility, &isect);
 
 #ifdef __LAMP_MIS__
-               if(kernel_data.integrator.pdf_lights > 0.0f && !(state.flag & PATH_RAY_CAMERA)) {
+               if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
                        /* ray starting from previous non-transparent bounce */
                        Ray light_ray;
 
@@ -501,7 +501,7 @@ __device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray
                bool hit = scene_intersect(kg, &ray, visibility, &isect);
 
 #ifdef __LAMP_MIS__
-               if(kernel_data.integrator.pdf_lights > 0.0f && !(state.flag & PATH_RAY_CAMERA)) {
+               if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
                        /* ray starting from previous non-transparent bounce */
                        Ray light_ray;
 
index 1236f43..2ef3d71 100644 (file)
@@ -288,8 +288,9 @@ typedef enum ShaderFlag {
        SHADER_SMOOTH_NORMAL = (1 << 31),
        SHADER_CAST_SHADOW = (1 << 30),
        SHADER_AREA_LIGHT = (1 << 29),
+       SHADER_USE_MIS = (1 << 28),
 
-       SHADER_MASK = ~(SHADER_SMOOTH_NORMAL|SHADER_CAST_SHADOW|SHADER_AREA_LIGHT)
+       SHADER_MASK = ~(SHADER_SMOOTH_NORMAL|SHADER_CAST_SHADOW|SHADER_AREA_LIGHT|SHADER_USE_MIS)
 } ShaderFlag;
 
 /* Light Type */
@@ -680,7 +681,7 @@ typedef struct KernelIntegrator {
        int transmission_samples;
        int ao_samples;
        int mesh_light_samples;
-       int pad1;
+       int use_lamp_mis;
 } KernelIntegrator;
 
 typedef struct KernelBVH {
index 04fea19..e7fb951 100644 (file)
@@ -115,6 +115,8 @@ Light::Light()
        spot_smooth = 0.0f;
 
        cast_shadow = true;
+       use_mis = false;
+
        shader = 0;
        samples = 1;
 }
@@ -291,13 +293,19 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
 
        /* point lights */
        float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
+       bool use_lamp_mis = false;
 
        for(int i = 0; i < scene->lights.size(); i++, offset++) {
+               Light *light = scene->lights[i];
+
                distribution[offset].x = totarea;
                distribution[offset].y = __int_as_float(~(int)i);
                distribution[offset].z = 1.0f;
-               distribution[offset].w = scene->lights[i]->size;
+               distribution[offset].w = light->size;
                totarea += lightarea;
+
+               if(light->size > 0.0f && light->use_mis)
+                       use_lamp_mis = true;
        }
 
        /* normalize cumulative distribution functions */
@@ -344,6 +352,8 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
                        kintegrator->inv_pdf_lights = 1.0f/kintegrator->pdf_lights;
                }
 
+               kintegrator->use_lamp_mis = use_lamp_mis;
+
                /* CDF */
                device->tex_alloc("__light_distribution", dscene->light_distribution);
        }
@@ -355,6 +365,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
                kintegrator->pdf_triangles = 0.0f;
                kintegrator->pdf_lights = 0.0f;
                kintegrator->inv_pdf_lights = 0.0f;
+               kintegrator->use_lamp_mis = false;
        }
 }
 
@@ -484,6 +495,9 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
                        float radius = light->size;
                        float invarea = (radius > 0.0f)? 1.0f/(M_PI_F*radius*radius): 1.0f;
 
+                       if(light->use_mis && radius > 0.0f)
+                               shader_id |= SHADER_USE_MIS;
+
                        light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
                        light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, 0.0f);
                        light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
@@ -498,6 +512,9 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
                        float area = M_PI_F*radius*radius;
                        float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
 
+                       if(light->use_mis && area > 0.0f)
+                               shader_id |= SHADER_USE_MIS;
+
                        light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), dir.x, dir.y, dir.z);
                        light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, cosangle, invarea);
                        light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
@@ -505,6 +522,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
                }
                else if(light->type == LIGHT_BACKGROUND) {
                        shader_id &= ~SHADER_AREA_LIGHT;
+                       shader_id |= SHADER_USE_MIS;
 
                        light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), 0.0f, 0.0f, 0.0f);
                        light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), 0.0f, 0.0f, 0.0f);
@@ -515,7 +533,10 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
                        float3 axisu = light->axisu*(light->sizeu*light->size);
                        float3 axisv = light->axisv*(light->sizev*light->size);
                        float area = len(axisu)*len(axisv);
-                       float invarea = (area > 0.0f)? 1.0f/area: 0.0f;
+                       float invarea = (area > 0.0f)? 1.0f/area: 1.0f;
+
+                       if(light->use_mis && area > 0.0f)
+                               shader_id |= SHADER_USE_MIS;
 
                        light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
                        light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), axisu.x, axisu.y, axisu.z);
@@ -530,6 +551,9 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
                        float spot_angle = cosf(light->spot_angle*0.5f);
                        float spot_smooth = (1.0f - spot_angle)*light->spot_smooth;
 
+                       if(light->use_mis && radius > 0.0f)
+                               shader_id |= SHADER_USE_MIS;
+
                        light_data[i*LIGHT_SIZE + 0] = make_float4(__int_as_float(light->type), co.x, co.y, co.z);
                        light_data[i*LIGHT_SIZE + 1] = make_float4(__int_as_float(shader_id), radius, invarea, spot_angle);
                        light_data[i*LIGHT_SIZE + 2] = make_float4(spot_smooth, dir.x, dir.y, dir.z);
index 3cedde2..acd1692 100644 (file)
@@ -52,6 +52,7 @@ public:
        float spot_smooth;
 
        bool cast_shadow;
+       bool use_mis;
 
        int shader;
        int samples;