Cycles: first step for implementation of non-progressive sampler that handles
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 13 Jun 2012 11:44:48 +0000 (11:44 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Wed, 13 Jun 2012 11:44:48 +0000 (11:44 +0000)
direct and indirect lighting differently. Rather than picking one light for each
point on the path, it now loops over all lights for direct lighting. For indirect
lighting it still picks a random light each time.

It gives control over the number of AA samples, and the number of Diffuse, Glossy,
Transmission, AO, Mesh Light, Background and Lamp samples for each AA sample.

This helps tuning render performance/noise and tends to give less noise for renders
dominated by direct lighting.

This sampling mode only works on the CPU, and still needs proper tile rendering
to show progress (will follow tommorrow or so), because each AA sample can be quite
slow now and so the delay between each update wil be too long.

14 files changed:
intern/cycles/blender/addon/properties.py
intern/cycles/blender/addon/ui.py
intern/cycles/blender/blender_object.cpp
intern/cycles/blender/blender_sync.cpp
intern/cycles/kernel/kernel_emission.h
intern/cycles/kernel/kernel_light.h
intern/cycles/kernel/kernel_path.h
intern/cycles/kernel/kernel_shader.h
intern/cycles/kernel/kernel_types.h
intern/cycles/render/integrator.cpp
intern/cycles/render/integrator.h
intern/cycles/render/light.cpp
intern/cycles/render/light.h
intern/cycles/render/scene.cpp

index 3ade04c4658c61e7d197431fffae7a6d699b0b9f..7ce3b949bb1e2e11160b25dd7a2ca5eaa5066011 100644 (file)
@@ -57,6 +57,12 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
                 default='GPU_COMPATIBLE',
                 )
 
+        cls.progressive = BoolProperty(
+                name="Progressive",
+                description="Use progressive sampling of lighting",
+                default=True,
+                )
+
         cls.samples = IntProperty(
                 name="Samples",
                 description="Number of samples to render for each pixel",
@@ -80,6 +86,49 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
                 default=False,
                 )
 
+        cls.aa_samples = IntProperty(
+                name="AA Samples",
+                description="Number of antialiasing samples to render for each pixel",
+                min=1, max=10000,
+                default=4,
+                )
+        cls.preview_aa_samples = IntProperty(
+                name="AA Samples",
+                description="Number of antialiasing samples to in viewport, unlimited if 0",
+                min=1, max=10000,
+                default=4,
+                )
+        cls.diffuse_samples = IntProperty(
+                name="Diffuse Samples",
+                description="Number of diffuse bounce samples to render for each AA sample",
+                min=1, max=10000,
+                default=1,
+                )
+        cls.glossy_samples = IntProperty(
+                name="Glossy Samples",
+                description="Number of glossy bounce samples to render for each AA sample",
+                min=1, max=10000,
+                default=1,
+                )
+        cls.transmission_samples = IntProperty(
+                name="Transmission Samples",
+                description="Number of transmission bounce samples to render for each AA sample",
+                min=1, max=10000,
+                default=1,
+                )
+        cls.ao_samples = IntProperty(
+                name="Ambient Occlusion Samples",
+                description="Number of ambient occlusion samples to render for each AA sample",
+                min=1, max=10000,
+                default=1,
+                )
+        cls.mesh_light_samples = IntProperty(
+                name="Mesh Light Samples",
+                description="Number of mesh emission light samples to render for each AA sample",
+                min=1, max=10000,
+                default=1,
+                )
+
         cls.no_caustics = BoolProperty(
                 name="No Caustics",
                 description="Leave out caustics, resulting in a darker image with less noise",
@@ -340,6 +389,12 @@ class CyclesLampSettings(bpy.types.PropertyGroup):
                 description="Lamp casts shadows",
                 default=True,
                 )
+        cls.samples = IntProperty(
+                name="Samples",
+                description="Number of light samples to render for each AA sample",
+                min=1, max=10000,
+                default=1,
+                )
 
     @classmethod
     def unregister(cls):
@@ -365,6 +420,12 @@ class CyclesWorldSettings(bpy.types.PropertyGroup):
                 min=4, max=8096,
                 default=256,
                 )
+        cls.samples = IntProperty(
+                name="Samples",
+                description="Number of light samples to render for each AA sample",
+                min=1, max=10000,
+                default=4,
+                )
 
     @classmethod
     def unregister(cls):
index 3b906bb4bdf0327c53225ccab8cae2c676171535..6f2b33b28154ff50ba45e057655dc0e7d31b5daa 100644 (file)
@@ -44,8 +44,48 @@ class CyclesButtonsPanel():
         return rd.engine == 'CYCLES'
 
 
-class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
-    bl_label = "Integrator"
+class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel):
+    bl_label = "Sampling"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw(self, context):
+        layout = self.layout
+
+        scene = context.scene
+        cscene = scene.cycles
+
+        split = layout.split()
+
+        col = split.column()
+        sub = col.column(align=True)
+        sub.active = cscene.device == 'CPU'
+        sub.prop(cscene, "progressive")
+
+        sub = col.column(align=True)
+        sub.prop(cscene, "seed")
+        sub.prop(cscene, "sample_clamp")
+
+        if cscene.progressive or cscene.device != 'CPU':
+            col = split.column(align=True)
+            col.label(text="Samples:")
+            col.prop(cscene, "samples", text="Render")
+            col.prop(cscene, "preview_samples", text="Preview")
+        else:
+            sub = col.column(align=True)
+            sub.label(text="AA Samples:")
+            sub.prop(cscene, "aa_samples", text="Render")
+            sub.prop(cscene, "preview_aa_samples", text="Preview")
+
+            col = split.column(align=True)
+            col.label(text="Samples:")
+            col.prop(cscene, "diffuse_samples", text="Diffuse")
+            col.prop(cscene, "glossy_samples", text="Glossy")
+            col.prop(cscene, "transmission_samples", text="Transmission")
+            col.prop(cscene, "ao_samples", text="AO")
+            col.prop(cscene, "mesh_light_samples", text="Mesh Light")
+
+class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel):
+    bl_label = "Light Paths"
     bl_options = {'DEFAULT_CLOSED'}
 
     def draw(self, context):
@@ -62,12 +102,6 @@ class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
         split = layout.split()
 
         col = split.column()
-        sub = col.column(align=True)
-        sub.label(text="Samples:")
-        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:")
@@ -75,6 +109,11 @@ class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
         sub.prop(cscene, "transparent_min_bounces", text="Min")
         sub.prop(cscene, "use_transparent_shadows", text="Shadows")
 
+        col.separator()
+
+        col.prop(cscene, "no_caustics")
+        col.prop(cscene, "blur_glossy")
+
         col = split.column()
 
         sub = col.column(align=True)
@@ -83,16 +122,10 @@ class CyclesRender_PT_integrator(CyclesButtonsPanel, Panel):
         sub.prop(cscene, "min_bounces", text="Min")
 
         sub = col.column(align=True)
-        sub.label(text="Light Paths:")
         sub.prop(cscene, "diffuse_bounces", text="Diffuse")
         sub.prop(cscene, "glossy_bounces", text="Glossy")
         sub.prop(cscene, "transmission_bounces", text="Transmission")
 
-        col.separator()
-
-        col.prop(cscene, "no_caustics")
-        col.prop(cscene, "blur_glossy")
-
 
 class CyclesRender_PT_motion_blur(CyclesButtonsPanel, Panel):
     bl_label = "Motion Blur"
@@ -467,6 +500,7 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
 
         lamp = context.lamp
         clamp = lamp.cycles
+        cscene = context.scene.cycles
 
         layout.prop(lamp, "type", expand=True)
 
@@ -485,6 +519,9 @@ class CyclesLamp_PT_lamp(CyclesButtonsPanel, Panel):
                 sub.prop(lamp, "size", text="Size X")
                 sub.prop(lamp, "size_y", text="Size Y")
 
+        if not cscene.progressive and cscene.device == 'CPU':
+            col.prop(clamp, "samples")
+
         col = split.column()
         col.prop(clamp, "cast_shadow")
 
@@ -604,13 +641,16 @@ class CyclesWorld_PT_settings(CyclesButtonsPanel, Panel):
 
         world = context.world
         cworld = world.cycles
+        cscene = context.scene.cycles
 
         col = layout.column()
 
         col.prop(cworld, "sample_as_light")
-        row = col.row()
-        row.active = cworld.sample_as_light
-        row.prop(cworld, "sample_map_resolution")
+        sub = col.row(align=True)
+        sub.active = cworld.sample_as_light
+        sub.prop(cworld, "sample_map_resolution")
+        if not cscene.progressive and cscene.device == 'CPU':
+            sub.prop(cworld, "samples")
 
 
 class CyclesMaterial_PT_surface(CyclesButtonsPanel, Panel):
index 9c98cacc9b8eb6d752fa9c75b99b316414dd8afa..d5b884cfccd46ca822c8f607fcb0bc1368e2e2b2 100644 (file)
@@ -154,6 +154,7 @@ void BlenderSync::sync_light(BL::Object b_parent, int b_index, BL::Object b_ob,
        /* shadow */
        PointerRNA clamp = RNA_pointer_get(&b_lamp.ptr, "cycles");
        light->cast_shadow = get_boolean(clamp, "cast_shadow");
+       light->samples = get_int(clamp, "samples");
 
        /* tag */
        light->tag_update(scene);
@@ -178,6 +179,7 @@ void BlenderSync::sync_background_light()
                        {
                                light->type = LIGHT_BACKGROUND;
                                light->map_resolution  = get_int(cworld, "sample_map_resolution");
+                               light->samples  = get_int(cworld, "samples");
                                light->shader = scene->default_background;
 
                                light->tag_update(scene);
index 13040e551bdcd9e46dacdec1fdf7777cf511dcce..5640a411fd71243f600086eb4931bab2bdfa42e4 100644 (file)
@@ -168,6 +168,13 @@ void BlenderSync::sync_integrator()
        integrator->motion_blur = (!preview && r.use_motion_blur());
 #endif
 
+       integrator->diffuse_samples = get_int(cscene, "diffuse_samples");
+       integrator->glossy_samples = get_int(cscene, "glossy_samples");
+       integrator->transmission_samples = get_int(cscene, "transmission_samples");
+       integrator->ao_samples = get_int(cscene, "ao_samples");
+       integrator->mesh_light_samples = get_int(cscene, "mesh_light_samples");
+       integrator->progressive = get_boolean(cscene, "progressive");
+
        if(integrator->modified(previntegrator))
                integrator->tag_update(scene);
 }
@@ -308,15 +315,27 @@ SessionParams BlenderSync::get_session_params(BL::UserPreferences b_userpref, BL
 
        /* Background */
        params.background = background;
-                       
+
        /* samples */
-       if(background) {
-               params.samples = get_int(cscene, "samples");
+       if(get_boolean(cscene, "progressive")) {
+               if(background) {
+                       params.samples = get_int(cscene, "samples");
+               }
+               else {
+                       params.samples = get_int(cscene, "preview_samples");
+                       if(params.samples == 0)
+                               params.samples = INT_MAX;
+               }
        }
        else {
-               params.samples = get_int(cscene, "preview_samples");
-               if(params.samples == 0)
-                       params.samples = INT_MAX;
+               if(background) {
+                       params.samples = get_int(cscene, "aa_samples");
+               }
+               else {
+                       params.samples = get_int(cscene, "preview_aa_samples");
+                       if(params.samples == 0)
+                               params.samples = INT_MAX;
+               }
        }
 
        /* other parameters */
index f582ace69f0a2b1424cbaaf02b7e5fb7e948de35..53d53b4bedd498b71aed4e21aaa56dec566fca45 100644 (file)
@@ -67,7 +67,7 @@ __device bool direct_emission(KernelGlobals *kg, ShaderData *sd, int lindex,
 
        float pdf = -1.0f;
 
-#ifdef __MULTI_LIGHT__
+#ifdef __NON_PROGRESSIVE__
        if(lindex != -1) {
                /* sample position on a specified light */
                light_select(kg, lindex, randu, randv, sd->P, &ls, &pdf);
index edc302cd6e38f3a42f2eeaee3a8597463ac973b5..1084415d0cf73e30a11e62126fa4e7f33e245e6d 100644 (file)
@@ -388,6 +388,12 @@ __device float light_sample_pdf(KernelGlobals *kg, LightSample *ls, float3 I, fl
        return pdf;
 }
 
+__device int light_select_num_samples(KernelGlobals *kg, int index)
+{
+       float4 data3 = kernel_tex_fetch(__light_data, index*LIGHT_SIZE + 3);
+       return __float_as_int(data3.x);
+}
+
 __device void light_select(KernelGlobals *kg, int index, float randu, float randv, float3 P, LightSample *ls, float *pdf)
 {
        regular_light_sample(kg, index, randu, randv, P, ls, pdf);
index 8dbf66c108c08ced5d1d0fca3b71b80d6203f6ed..80d66532506c08490ec124749dbddaf26b245fad 100644 (file)
@@ -218,7 +218,7 @@ __device_inline bool shadow_blocked(KernelGlobals *kg, PathState *state, Ray *ra
        return result;
 }
 
-__device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer)
+__device float4 kernel_path_progressive(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer)
 {
        /* initialize */
        PathRadiance L;
@@ -366,26 +366,189 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
                                light_ray.time = sd.time;
 #endif
 
-#ifdef __MULTI_LIGHT__
-                               /* index -1 means randomly sample from distribution */
-                               int i = (kernel_data.integrator.num_all_lights)? 0: -1;
+                               if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+                                       /* trace shadow ray */
+                                       float3 shadow;
 
-                               for(; i < kernel_data.integrator.num_all_lights; i++) {
-#else
-                               const int i = -1;
+                                       if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
+                                               /* accumulate */
+                                               path_radiance_accum_light(&L, throughput, &L_light, shadow, state.bounce, is_lamp);
+                                       }
+                               }
+                       }
+               }
 #endif
-                                       if(direct_emission(kg, &sd, i, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
-                                               /* trace shadow ray */
-                                               float3 shadow;
 
-                                               if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
-                                                       /* accumulate */
-                                                       path_radiance_accum_light(&L, throughput, &L_light, shadow, state.bounce, is_lamp);
-                                               }
-                                       }
-#ifdef __MULTI_LIGHT__
+               /* no BSDF? we can stop here */
+               if(!(sd.flag & SD_BSDF))
+                       break;
+
+               /* sample BSDF */
+               float bsdf_pdf;
+               BsdfEval bsdf_eval;
+               float3 bsdf_omega_in;
+               differential3 bsdf_domega_in;
+               float bsdf_u = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_U);
+               float bsdf_v = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_V);
+               int label;
+
+               label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
+                       &bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
+
+               shader_release(kg, &sd);
+
+               if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
+                       break;
+
+               /* modify throughput */
+               path_radiance_bsdf_bounce(&L, &throughput, &bsdf_eval, bsdf_pdf, state.bounce, label);
+
+               /* set labels */
+               if(!(label & LABEL_TRANSPARENT)) {
+                       ray_pdf = bsdf_pdf;
+                       min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf);
+               }
+
+               /* update path state */
+               path_state_next(kg, &state, label);
+
+               /* setup ray */
+               ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);
+               ray.D = bsdf_omega_in;
+               ray.t = FLT_MAX;
+#ifdef __RAY_DIFFERENTIALS__
+               ray.dP = sd.dP;
+               ray.dD = bsdf_domega_in;
+#endif
+       }
+
+       float3 L_sum = path_radiance_sum(kg, &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);
+}
+
+#ifdef __NON_PROGRESSIVE__
+
+__device void kernel_path_indirect(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer,
+       float3 throughput, float min_ray_pdf, float ray_pdf, PathState state, int rng_offset, PathRadiance *L)
+{
+       /* path iteration */
+       for(;; rng_offset += PRNG_BOUNCE_NUM) {
+               /* intersect scene */
+               Intersection isect;
+               uint visibility = path_state_ray_visibility(kg, &state);
+
+               if(!scene_intersect(kg, &ray, visibility, &isect)) {
+#ifdef __BACKGROUND__
+                       /* sample background shader */
+                       float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf);
+                       path_radiance_accum_background(L, throughput, L_background, state.bounce);
+#endif
+
+                       break;
+               }
+
+               /* setup shading */
+               ShaderData sd;
+               shader_setup_from_ray(kg, &sd, &isect, &ray);
+               float rbsdf = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF);
+               shader_eval_surface(kg, &sd, rbsdf, state.flag);
+               shader_merge_closures(kg, &sd);
+
+               /* blurring of bsdf after bounces, for rays that have a small likelihood
+                * of following this particular path (diffuse, rough glossy) */
+               if(kernel_data.integrator.filter_glossy != FLT_MAX) {
+                       float blur_pdf = kernel_data.integrator.filter_glossy*min_ray_pdf;
+
+                       if(blur_pdf < 1.0f) {
+                               float blur_roughness = sqrtf(1.0f - blur_pdf)*0.5f;
+                               shader_bsdf_blur(kg, &sd, blur_roughness);
+                       }
+               }
+
+#ifdef __EMISSION__
+               /* emission */
+               if(sd.flag & SD_EMISSION) {
+                       float3 emission = indirect_emission(kg, &sd, isect.t, state.flag, ray_pdf);
+                       path_radiance_accum_emission(L, throughput, emission, state.bounce);
+               }
+#endif
+
+               /* path termination. this is a strange place to put the termination, it's
+                * mainly due to the mixed in MIS that we use. gives too many unneeded
+                * shader evaluations, only need emission if we are going to terminate */
+               float probability = path_state_terminate_probability(kg, &state, throughput);
+               float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
+
+               if(terminate >= probability)
+                       break;
+
+               throughput /= probability;
+
+#ifdef __AO__
+               /* ambient occlusion */
+               if(kernel_data.integrator.use_ambient_occlusion) {
+                       /* todo: solve correlation */
+                       float bsdf_u = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_U);
+                       float bsdf_v = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF_V);
+
+                       float3 ao_D;
+                       float ao_pdf;
+
+                       sample_cos_hemisphere(sd.N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
+
+                       if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
+                               Ray light_ray;
+                               float3 ao_shadow;
+
+                               light_ray.P = ray_offset(sd.P, sd.Ng);
+                               light_ray.D = ao_D;
+                               light_ray.t = kernel_data.background.ao_distance;
+#ifdef __MOTION__
+                               light_ray.time = sd.time;
+#endif
+
+                               if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow)) {
+                                       float3 ao_bsdf = shader_bsdf_diffuse(kg, &sd)*kernel_data.background.ao_factor;
+                                       path_radiance_accum_ao(L, throughput, ao_bsdf, ao_shadow, state.bounce);
                                }
+                       }
+               }
 #endif
+
+#ifdef __EMISSION__
+               if(kernel_data.integrator.use_direct_light) {
+                       /* sample illumination from lights to find path contribution */
+                       if(sd.flag & SD_BSDF_HAS_EVAL) {
+                               float light_t = path_rng(kg, rng, sample, rng_offset + PRNG_LIGHT);
+                               float light_o = path_rng(kg, rng, sample, rng_offset + PRNG_LIGHT_F);
+                               float light_u = path_rng(kg, rng, sample, rng_offset + PRNG_LIGHT_U);
+                               float light_v = path_rng(kg, rng, sample, rng_offset + PRNG_LIGHT_V);
+
+                               Ray light_ray;
+                               BsdfEval L_light;
+                               bool is_lamp;
+
+#ifdef __MOTION__
+                               light_ray.time = sd.time;
+#endif
+
+                               /* sample random light */
+                               if(direct_emission(kg, &sd, -1, light_t, light_o, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+                                       /* trace shadow ray */
+                                       float3 shadow;
+
+                                       if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
+                                               /* accumulate */
+                                               path_radiance_accum_light(L, throughput, &L_light, shadow, state.bounce, is_lamp);
+                                       }
+                               }
                        }
                }
 #endif
@@ -412,7 +575,7 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
                        break;
 
                /* modify throughput */
-               path_radiance_bsdf_bounce(&L, &throughput, &bsdf_eval, bsdf_pdf, state.bounce, label);
+               path_radiance_bsdf_bounce(L, &throughput, &bsdf_eval, bsdf_pdf, state.bounce, label);
 
                /* set labels */
                if(!(label & LABEL_TRANSPARENT)) {
@@ -432,6 +595,275 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
                ray.dD = bsdf_domega_in;
 #endif
        }
+}
+
+__device float4 kernel_path_non_progressive(KernelGlobals *kg, RNG *rng, int sample, Ray ray, __global float *buffer)
+{
+       /* initialize */
+       PathRadiance L;
+       float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
+       float L_transparent = 0.0f;
+
+       path_radiance_init(&L, kernel_data.film.use_light_pass);
+
+       float ray_pdf = 0.0f;
+       PathState state;
+       int rng_offset = PRNG_BASE_NUM;
+
+       path_state_init(&state);
+
+       for(;; rng_offset += PRNG_BOUNCE_NUM) {
+               /* intersect scene */
+               Intersection isect;
+               uint visibility = path_state_ray_visibility(kg, &state);
+
+               if(!scene_intersect(kg, &ray, visibility, &isect)) {
+                       /* eval background shader if nothing hit */
+                       if(kernel_data.background.transparent) {
+                               L_transparent += average(throughput);
+
+#ifdef __PASSES__
+                               if(!(kernel_data.film.pass_flag & PASS_BACKGROUND))
+#endif
+                                       break;
+                       }
+
+#ifdef __BACKGROUND__
+                       /* sample background shader */
+                       float3 L_background = indirect_background(kg, &ray, state.flag, ray_pdf);
+                       path_radiance_accum_background(&L, throughput, L_background, state.bounce);
+#endif
+
+                       break;
+               }
+
+               /* setup shading */
+               ShaderData sd;
+               shader_setup_from_ray(kg, &sd, &isect, &ray);
+               float rbsdf = path_rng(kg, rng, sample, rng_offset + PRNG_BSDF);
+               shader_eval_surface(kg, &sd, rbsdf, state.flag);
+               shader_merge_closures(kg, &sd);
+
+               kernel_write_data_passes(kg, buffer, &L, &sd, sample, state.flag, throughput);
+
+               /* holdout */
+#ifdef __HOLDOUT__
+               if((sd.flag & (SD_HOLDOUT|SD_HOLDOUT_MASK))) {
+                       if(kernel_data.background.transparent) {
+                               float3 holdout_weight;
+                               
+                               if(sd.flag & SD_HOLDOUT_MASK)
+                                       holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
+                               else
+                                       shader_holdout_eval(kg, &sd);
+
+                               /* any throughput is ok, should all be identical here */
+                               L_transparent += average(holdout_weight*throughput);
+                       }
+
+                       if(sd.flag & SD_HOLDOUT_MASK)
+                               break;
+               }
+#endif
+
+#ifdef __EMISSION__
+               /* emission */
+               if(sd.flag & SD_EMISSION) {
+                       float3 emission = indirect_emission(kg, &sd, isect.t, state.flag, ray_pdf);
+                       path_radiance_accum_emission(&L, throughput, emission, state.bounce);
+               }
+#endif
+
+               /* transparency termination */
+               if(state.flag & PATH_RAY_TRANSPARENT) {
+                       /* path termination. this is a strange place to put the termination, it's
+                        * mainly due to the mixed in MIS that we use. gives too many unneeded
+                        * shader evaluations, only need emission if we are going to terminate */
+                       float probability = path_state_terminate_probability(kg, &state, throughput);
+                       float terminate = path_rng(kg, rng, sample, rng_offset + PRNG_TERMINATE);
+
+                       if(terminate >= probability)
+                               break;
+
+                       throughput /= probability;
+               }
+
+#ifdef __AO__
+               /* ambient occlusion */
+               if(kernel_data.integrator.use_ambient_occlusion) {
+                       int num_samples = kernel_data.integrator.ao_samples;
+                       float ao_factor = kernel_data.background.ao_factor/num_samples;
+
+                       for(int j = 0; j < num_samples; j++) {
+                               /* todo: solve correlation */
+                               float bsdf_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_U);
+                               float bsdf_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_V);
+
+                               float3 ao_D;
+                               float ao_pdf;
+
+                               sample_cos_hemisphere(sd.N, bsdf_u, bsdf_v, &ao_D, &ao_pdf);
+
+                               if(dot(sd.Ng, ao_D) > 0.0f && ao_pdf != 0.0f) {
+                                       Ray light_ray;
+                                       float3 ao_shadow;
+
+                                       light_ray.P = ray_offset(sd.P, sd.Ng);
+                                       light_ray.D = ao_D;
+                                       light_ray.t = kernel_data.background.ao_distance;
+#ifdef __MOTION__
+                                       light_ray.time = sd.time;
+#endif
+
+                                       if(!shadow_blocked(kg, &state, &light_ray, &ao_shadow)) {
+                                               float3 ao_bsdf = shader_bsdf_diffuse(kg, &sd)*ao_factor;
+                                               path_radiance_accum_ao(&L, throughput, ao_bsdf, ao_shadow, state.bounce);
+                                       }
+                               }
+                       }
+               }
+#endif
+
+#ifdef __EMISSION__
+               /* sample illumination from lights to find path contribution */
+               if(sd.flag & SD_BSDF_HAS_EVAL) {
+                       Ray light_ray;
+                       BsdfEval L_light;
+                       bool is_lamp;
+
+#ifdef __MOTION__
+                       light_ray.time = sd.time;
+#endif
+
+                       /* lamp sampling */
+                       for(int i = 0; i < kernel_data.integrator.num_all_lights; i++) {
+                               int num_samples = light_select_num_samples(kg, i);
+                               float num_samples_inv = 1.0f/(num_samples*kernel_data.integrator.num_all_lights);
+
+                               if(kernel_data.integrator.pdf_triangles != 0.0f)
+                                       num_samples_inv *= 0.5f;
+
+                               for(int j = 0; j < num_samples; j++) {
+                                       float light_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_U);
+                                       float light_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_V);
+
+                                       if(direct_emission(kg, &sd, i, 0.0f, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+                                               /* trace shadow ray */
+                                               float3 shadow;
+
+                                               if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
+                                                       /* accumulate */
+                                                       path_radiance_accum_light(&L, throughput*num_samples_inv, &L_light, shadow, state.bounce, is_lamp);
+                                               }
+                                       }
+                               }
+                       }
+
+                       /* mesh light sampling */
+                       if(kernel_data.integrator.pdf_triangles != 0.0f) {
+                               int num_samples = kernel_data.integrator.mesh_light_samples;
+                               float num_samples_inv = 1.0f/num_samples;
+
+                               if(kernel_data.integrator.num_all_lights)
+                                       num_samples_inv *= 0.5f;
+
+                               for(int j = 0; j < num_samples; j++) {
+                                       float light_t = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT);
+                                       float light_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_U);
+                                       float light_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_LIGHT_V);
+
+                                       /* only sample triangle lights */
+                                       if(kernel_data.integrator.num_all_lights)
+                                               light_t = 0.5f*light_t;
+
+                                       if(direct_emission(kg, &sd, -1, light_t, 0.0f, light_u, light_v, &light_ray, &L_light, &is_lamp)) {
+                                               /* trace shadow ray */
+                                               float3 shadow;
+
+                                               if(!shadow_blocked(kg, &state, &light_ray, &shadow)) {
+                                                       /* accumulate */
+                                                       path_radiance_accum_light(&L, throughput*num_samples_inv, &L_light, shadow, state.bounce, is_lamp);
+                                               }
+                                       }
+                               }
+                       }
+               }
+#endif
+
+               for(int i = 0; i< sd.num_closure; i++) {
+                       const ShaderClosure *sc = &sd.closure[i];
+
+                       if(!CLOSURE_IS_BSDF(sc->type))
+                               continue;
+                       /* transparency is not handled here, but in outer loop */
+                       if(sc->type == CLOSURE_BSDF_TRANSPARENT_ID)
+                               continue;
+
+                       int num_samples;
+
+                       if(CLOSURE_IS_BSDF_DIFFUSE(sc->type))
+                               num_samples = kernel_data.integrator.diffuse_samples;
+                       else if(CLOSURE_IS_BSDF_GLOSSY(sc->type))
+                               num_samples = kernel_data.integrator.glossy_samples;
+                       else
+                               num_samples = kernel_data.integrator.transmission_samples;
+
+                       float num_samples_inv = 1.0f/num_samples;
+
+                       for(int j = 0; j < num_samples; j++) {
+                               /* sample BSDF */
+                               float bsdf_pdf;
+                               BsdfEval bsdf_eval;
+                               float3 bsdf_omega_in;
+                               differential3 bsdf_domega_in;
+                               float bsdf_u = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_U);
+                               float bsdf_v = path_rng(kg, rng, sample*num_samples + j, rng_offset + PRNG_BSDF_V);
+                               int label;
+
+                               label = shader_bsdf_sample_closure(kg, &sd, sc, bsdf_u, bsdf_v, &bsdf_eval,
+                                       &bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
+
+                               if(bsdf_pdf == 0.0f || bsdf_eval_is_zero(&bsdf_eval))
+                                       continue;
+
+                               /* modify throughput */
+                               float3 tp = throughput;
+                               path_radiance_bsdf_bounce(&L, &tp, &bsdf_eval, bsdf_pdf, state.bounce, label);
+
+                               /* set labels */
+                               float min_ray_pdf = FLT_MAX;
+
+                               if(!(label & LABEL_TRANSPARENT))
+                                       min_ray_pdf = fminf(bsdf_pdf, min_ray_pdf);
+
+                               /* modify path state */
+                               PathState ps = state;
+                               path_state_next(kg, &ps, label);
+
+                               /* setup ray */
+                               ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);
+                               ray.D = bsdf_omega_in;
+                               ray.t = FLT_MAX;
+#ifdef __RAY_DIFFERENTIALS__
+                               ray.dP = sd.dP;
+                               ray.dD = bsdf_domega_in;
+#endif
+
+                               kernel_path_indirect(kg, rng, sample*num_samples, ray, buffer,
+                                       tp*num_samples_inv, min_ray_pdf, ray_pdf, ps, rng_offset+PRNG_BOUNCE_NUM, &L);
+                       }
+               }
+
+               /* continue in case of transparency */
+               throughput *= shader_bsdf_transparency(kg, &sd);
+               shader_release(kg, &sd);
+
+               if(is_zero(throughput))
+                       break;
+
+               path_state_next(kg, &state, LABEL_TRANSPARENT);
+               ray.P = ray_offset(sd.P, -sd.Ng);
+       }
 
        float3 L_sum = path_radiance_sum(kg, &L);
 
@@ -444,6 +876,8 @@ __device float4 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int sample, R
        return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent);
 }
 
+#endif
+
 __device void kernel_path_trace(KernelGlobals *kg,
        __global float *buffer, __global uint *rng_state,
        int sample, int x, int y, int offset, int stride)
@@ -480,8 +914,16 @@ __device void kernel_path_trace(KernelGlobals *kg,
        /* integrate */
        float4 L;
 
-       if (ray.t != 0.f)
-               L = kernel_path_integrate(kg, &rng, sample, ray, buffer);
+       if (ray.t != 0.0f) {
+#ifdef __NON_PROGRESSIVE__
+               if(kernel_data.integrator.progressive)
+#endif
+                       L = kernel_path_progressive(kg, &rng, sample, ray, buffer);
+#ifdef __NON_PROGRESSIVE__
+               else
+                       L = kernel_path_non_progressive(kg, &rng, sample, ray, buffer);
+#endif
+       }
        else
                L = make_float4(0.f, 0.f, 0.f, 0.f);
 
index 53a41d58e200b8e327d764f743e840c1c4142486..bc873f4e112306d4ab6a7f54290c538790a730b3 100644 (file)
@@ -407,6 +407,25 @@ __device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
 #endif
 }
 
+__device int shader_bsdf_sample_closure(KernelGlobals *kg, const ShaderData *sd,
+       const ShaderClosure *sc, float randu, float randv, BsdfEval *bsdf_eval,
+       float3 *omega_in, differential3 *domega_in, float *pdf)
+{
+       int label;
+       float3 eval;
+
+       *pdf = 0.0f;
+#ifdef __OSL__
+       label = OSLShader::bsdf_sample(sd, sc, randu, randv, eval, *omega_in, *domega_in, *pdf);
+#else
+       label = svm_bsdf_sample(sd, sc, randu, randv, &eval, omega_in, domega_in, pdf);
+#endif
+       if(*pdf != 0.0f)
+               bsdf_eval_init(bsdf_eval, sc->type, eval*sc->weight, kernel_data.film.use_light_pass);
+
+       return label;
+}
+
 __device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughness)
 {
 #ifndef __OSL__
@@ -679,6 +698,35 @@ __device bool shader_transparent_shadow(KernelGlobals *kg, Intersection *isect)
 }
 #endif
 
+/* Merging */
+
+#ifdef __NON_PROGRESSIVE__
+__device void shader_merge_closures(KernelGlobals *kg, ShaderData *sd)
+{
+#ifndef __OSL__
+       /* merge identical closures, better when we sample a single closure at a time */
+       for(int i = 0; i < sd->num_closure; i++) {
+               ShaderClosure *sci = &sd->closure[i];
+
+               for(int j = i + 1; j < sd->num_closure; j++) {
+                       ShaderClosure *scj = &sd->closure[j];
+
+                       if(sci->type == scj->type && sci->data0 == scj->data0 && sci->data1 == scj->data1) {
+                               sci->weight += scj->weight;
+                               sci->sample_weight += scj->sample_weight;
+
+                               int size = sd->num_closure - (j+1);
+                               if(size > 0)
+                                       memmove(scj, scj+1, size*sizeof(ShaderClosure));
+
+                               sd->num_closure--;
+                       }
+               }
+       }
+#endif
+}
+#endif
+
 /* Free ShaderData */
 
 __device void shader_release(KernelGlobals *kg, ShaderData *sd)
index 77a800b0e674731775ec9d1729f2a2137f48a716..d204b114b8e5a5e51370f9a4804956e5ebc32f48 100644 (file)
@@ -43,6 +43,7 @@ CCL_NAMESPACE_BEGIN
 #ifdef WITH_OSL
 #define __OSL__
 #endif
+#define __NON_PROGRESSIVE__
 #endif
 
 #ifdef __KERNEL_CUDA__
@@ -110,7 +111,6 @@ CCL_NAMESPACE_BEGIN
 //#define __MOTION__
 #endif
 
-//#define __MULTI_LIGHT__
 //#define __SOBOL_FULL_SCREEN__
 //#define __QBVH__
 
@@ -627,6 +627,15 @@ typedef struct KernelIntegrator {
 
        /* clamp */
        float sample_clamp;
+
+       /* non-progressive */
+       int progressive;
+       int diffuse_samples;
+       int glossy_samples;
+       int transmission_samples;
+       int ao_samples;
+       int mesh_light_samples;
+       int pad1, pad2;
 } KernelIntegrator;
 
 typedef struct KernelBVH {
index b26ebfd91e178733c82773d724a1f4b8f152bded..da563c9c4ec7469857c9236ccef9417947882654 100644 (file)
 
 #include "device.h"
 #include "integrator.h"
+#include "light.h"
 #include "scene.h"
 #include "sobol.h"
 
+#include "util_foreach.h"
 #include "util_hash.h"
 
 CCL_NAMESPACE_BEGIN
@@ -47,6 +49,13 @@ Integrator::Integrator()
        sample_clamp = 0.0f;
        motion_blur = false;
 
+       diffuse_samples = 1;
+       glossy_samples = 1;
+       transmission_samples = 1;
+       ao_samples = 1;
+       mesh_light_samples = 1;
+       progressive = true;
+
        need_update = true;
 }
 
@@ -54,7 +63,7 @@ Integrator::~Integrator()
 {
 }
 
-void Integrator::device_update(Device *device, DeviceScene *dscene)
+void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene)
 {
        if(!need_update)
                return;
@@ -93,8 +102,27 @@ void Integrator::device_update(Device *device, DeviceScene *dscene)
        
        kintegrator->sample_clamp = (sample_clamp == 0.0f)? FLT_MAX: sample_clamp*3.0f;
 
+       kintegrator->progressive = progressive;
+       kintegrator->diffuse_samples = diffuse_samples;
+       kintegrator->glossy_samples = glossy_samples;
+       kintegrator->transmission_samples = transmission_samples;
+       kintegrator->ao_samples = ao_samples;
+       kintegrator->mesh_light_samples = mesh_light_samples;
+
        /* sobol directions table */
-       int dimensions = PRNG_BASE_NUM + (max_bounce + transparent_max_bounce + 2)*PRNG_BOUNCE_NUM;
+       int max_samples = 1;
+
+       if(!progressive) {
+               foreach(Light *light, scene->lights)
+                       max_samples = max(max_samples, light->samples);
+
+               max_samples = max(max_samples, max(diffuse_samples, max(glossy_samples, transmission_samples)));
+               max_samples = max(max_samples, max(ao_samples, mesh_light_samples));
+       }
+
+       max_samples *= (max_bounce + transparent_max_bounce + 2);
+
+       int dimensions = PRNG_BASE_NUM + max_samples*PRNG_BOUNCE_NUM;
        uint *directions = dscene->sobol_directions.resize(SOBOL_BITS*dimensions);
 
        sobol_generate_direction_vectors((uint(*)[SOBOL_BITS])directions, dimensions);
@@ -127,6 +155,12 @@ bool Integrator::modified(const Integrator& integrator)
                layer_flag == integrator.layer_flag &&
                seed == integrator.seed &&
                sample_clamp == integrator.sample_clamp &&
+               progressive == integrator.progressive &&
+               diffuse_samples == integrator.diffuse_samples &&
+               glossy_samples == integrator.glossy_samples &&
+               transmission_samples == integrator.transmission_samples &&
+               ao_samples == integrator.ao_samples &&
+               mesh_light_samples == integrator.mesh_light_samples &&
                motion_blur == integrator.motion_blur);
 }
 
index afda41a857ddc022412ed8fcad9e6ad851e93b8c..8fb341182b74ccd882c1801b7a1f114c11b197f9 100644 (file)
@@ -49,12 +49,20 @@ public:
        float sample_clamp;
        bool motion_blur;
 
+       int diffuse_samples;
+       int glossy_samples;
+       int transmission_samples;
+       int ao_samples;
+       int mesh_light_samples;
+
+       bool progressive;
+
        bool need_update;
 
        Integrator();
        ~Integrator();
 
-       void device_update(Device *device, DeviceScene *dscene);
+       void device_update(Device *device, DeviceScene *dscene, Scene *scene);
        void device_free(Device *device, DeviceScene *dscene);
 
        bool modified(const Integrator& integrator);
index e918de990c212ea17a5c1d0620dc19e785c58075..6c03d0859a75caafd93f00f23e0e017979d8fd44 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include "device.h"
+#include "integrator.h"
 #include "light.h"
 #include "mesh.h"
 #include "object.h"
@@ -114,6 +115,7 @@ Light::Light()
 
        cast_shadow = true;
        shader = 0;
+       samples = 1;
 }
 
 void Light::tag_update(Scene *scene)
@@ -136,9 +138,6 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
 {
        progress.set_status("Updating Lights", "Computing distribution");
 
-       /* option to always sample all point lights */
-       bool multi_light = false;
-
        /* count */
        size_t num_lights = scene->lights.size();
        size_t num_triangles = 0;
@@ -169,9 +168,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
        }
 
        size_t num_distribution = num_triangles;
-
-       if(!multi_light)
-               num_distribution += num_lights;
+       num_distribution += num_lights;
 
        /* emission area */
        float4 *distribution = dscene->light_distribution.resize(num_distribution + 1);
@@ -231,16 +228,14 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
        float trianglearea = totarea;
 
        /* point lights */
-       if(!multi_light) {
-               float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
-
-               for(int i = 0; i < scene->lights.size(); i++, offset++) {
-                       distribution[offset].x = totarea;
-                       distribution[offset].y = __int_as_float(~(int)i);
-                       distribution[offset].z = 1.0f;
-                       distribution[offset].w = scene->lights[i]->size;
-                       totarea += lightarea;
-               }
+       float lightarea = (totarea > 0.0f)? totarea/scene->lights.size(): 1.0f;
+
+       for(int i = 0; i < scene->lights.size(); i++, offset++) {
+               distribution[offset].x = totarea;
+               distribution[offset].y = __int_as_float(~(int)i);
+               distribution[offset].z = 1.0f;
+               distribution[offset].w = scene->lights[i]->size;
+               totarea += lightarea;
        }
 
        /* normalize cumulative distribution functions */
@@ -259,7 +254,7 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
 
        /* update device */
        KernelIntegrator *kintegrator = &dscene->data.integrator;
-       kintegrator->use_direct_light = (totarea > 0.0f) || (multi_light && num_lights);
+       kintegrator->use_direct_light = (totarea > 0.0f);
 
        if(kintegrator->use_direct_light) {
                /* number of emissives */
@@ -269,30 +264,19 @@ void LightManager::device_update_distribution(Device *device, DeviceScene *dscen
                kintegrator->pdf_triangles = 0.0f;
                kintegrator->pdf_lights = 0.0f;
 
-               if(multi_light) {
-                       /* sample one of all triangles and all lights */
-                       kintegrator->num_all_lights = num_lights;
+               /* sample one, with 0.5 probability of light or triangle */
+               kintegrator->num_all_lights = num_lights;
 
-                       if(trianglearea > 0.0f)
-                               kintegrator->pdf_triangles = 1.0f/trianglearea;
+               if(trianglearea > 0.0f) {
+                       kintegrator->pdf_triangles = 1.0f/trianglearea;
                        if(num_lights)
-                               kintegrator->pdf_lights = 1.0f;
+                               kintegrator->pdf_triangles *= 0.5f;
                }
-               else {
-                       /* sample one, with 0.5 probability of light or triangle */
-                       kintegrator->num_all_lights = 0;
-
-                       if(trianglearea > 0.0f) {
-                               kintegrator->pdf_triangles = 1.0f/trianglearea;
-                               if(num_lights)
-                                       kintegrator->pdf_triangles *= 0.5f;
-                       }
 
-                       if(num_lights) {
-                               kintegrator->pdf_lights = 1.0f/num_lights;
-                               if(trianglearea > 0.0f)
-                                       kintegrator->pdf_lights *= 0.5f;
-                       }
+               if(num_lights) {
+                       kintegrator->pdf_lights = 1.0f/num_lights;
+                       if(trianglearea > 0.0f)
+                               kintegrator->pdf_lights *= 0.5f;
                }
 
                /* CDF */
@@ -417,6 +401,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
                float3 co = light->co;
                float3 dir = normalize(light->dir);
                int shader_id = scene->shader_manager->get_shader_id(scene->lights[i]->shader);
+               float samples = __int_as_float(light->samples);
 
                if(!light->cast_shadow)
                        shader_id &= ~SHADER_CAST_SHADOW;
@@ -427,7 +412,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
                        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), light->size, 0.0f, 0.0f);
                        light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-                       light_data[i*LIGHT_SIZE + 3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+                       light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
                }
                else if(light->type == LIGHT_DISTANT) {
                        shader_id &= ~SHADER_AREA_LIGHT;
@@ -435,7 +420,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
                        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), light->size, 0.0f, 0.0f);
                        light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-                       light_data[i*LIGHT_SIZE + 3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+                       light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
                }
                else if(light->type == LIGHT_BACKGROUND) {
                        shader_id &= ~SHADER_AREA_LIGHT;
@@ -443,7 +428,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
                        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);
                        light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
-                       light_data[i*LIGHT_SIZE + 3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+                       light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
                }
                else if(light->type == LIGHT_AREA) {
                        float3 axisu = light->axisu*(light->sizeu*light->size);
@@ -452,7 +437,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
                        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);
                        light_data[i*LIGHT_SIZE + 2] = make_float4(0.0f, axisv.x, axisv.y, axisv.z);
-                       light_data[i*LIGHT_SIZE + 3] = make_float4(0.0f, dir.x, dir.y, dir.z);
+                       light_data[i*LIGHT_SIZE + 3] = make_float4(samples, dir.x, dir.y, dir.z);
                }
                else if(light->type == LIGHT_SPOT) {
                        shader_id &= ~SHADER_AREA_LIGHT;
@@ -463,7 +448,7 @@ void LightManager::device_update_points(Device *device, DeviceScene *dscene, Sce
                        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), light->size, dir.x, dir.y);
                        light_data[i*LIGHT_SIZE + 2] = make_float4(dir.z, spot_angle, spot_smooth, 0.0f);
-                       light_data[i*LIGHT_SIZE + 3] = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+                       light_data[i*LIGHT_SIZE + 3] = make_float4(samples, 0.0f, 0.0f, 0.0f);
                }
        }
        
index fb8684fa59b57cf029d3187abbc869723379b059..3cedde2596e270cd7ce6856dfce4bc6c43195c85 100644 (file)
@@ -54,6 +54,7 @@ public:
        bool cast_shadow;
 
        int shader;
+       int samples;
 
        void tag_update(Scene *scene);
 };
index a5f90bfe34b4ed1d261b95745e8dbdb431b2e6a4..45c8a05c27df501b32fc48e8ad5c7027086b3c02 100644 (file)
@@ -160,7 +160,7 @@ void Scene::device_update(Device *device_, Progress& progress)
        if(progress.get_cancel()) return;
 
        progress.set_status("Updating Integrator");
-       integrator->device_update(device, &dscene);
+       integrator->device_update(device, &dscene, this);
 
        if(progress.get_cancel()) return;