Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@pandora.be>2012-06-13 15:44:48 +0400
committerBrecht Van Lommel <brechtvanlommel@pandora.be>2012-06-13 15:44:48 +0400
commit4ba456d1754c29b488b8304c8546af45078e8536 (patch)
tree49649b7442d58aa835a7428043130f158613521d
parentdcda234a3d93ed44189fac3716a694f4f75f366e (diff)
Cycles: first step for implementation of non-progressive sampler that handles
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.
-rw-r--r--intern/cycles/blender/addon/properties.py61
-rw-r--r--intern/cycles/blender/addon/ui.py74
-rw-r--r--intern/cycles/blender/blender_object.cpp2
-rw-r--r--intern/cycles/blender/blender_sync.cpp31
-rw-r--r--intern/cycles/kernel/kernel_emission.h2
-rw-r--r--intern/cycles/kernel/kernel_light.h6
-rw-r--r--intern/cycles/kernel/kernel_path.h480
-rw-r--r--intern/cycles/kernel/kernel_shader.h48
-rw-r--r--intern/cycles/kernel/kernel_types.h11
-rw-r--r--intern/cycles/render/integrator.cpp38
-rw-r--r--intern/cycles/render/integrator.h10
-rw-r--r--intern/cycles/render/light.cpp69
-rw-r--r--intern/cycles/render/light.h1
-rw-r--r--intern/cycles/render/scene.cpp2
14 files changed, 745 insertions, 90 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 3ade04c4658..7ce3b949bb1 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -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):
diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py
index 3b906bb4bdf..6f2b33b2815 100644
--- a/intern/cycles/blender/addon/ui.py
+++ b/intern/cycles/blender/addon/ui.py
@@ -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):
diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp
index 9c98cacc9b8..d5b884cfccd 100644
--- a/intern/cycles/blender/blender_object.cpp
+++ b/intern/cycles/blender/blender_object.cpp
@@ -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);
diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp
index 13040e551bd..5640a411fd7 100644
--- a/intern/cycles/blender/blender_sync.cpp
+++ b/intern/cycles/blender/blender_sync.cpp
@@ -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 */
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index f582ace69f0..53d53b4bedd 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -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);
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index edc302cd6e3..1084415d0cf 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -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);
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 8dbf66c108c..80d66532506 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -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);
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index 53a41d58e20..bc873f4e112 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -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)
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 77a800b0e67..d204b114b8e 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -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 {
diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp
index b26ebfd91e1..da563c9c4ec 100644
--- a/intern/cycles/render/integrator.cpp
+++ b/intern/cycles/render/integrator.cpp
@@ -18,9 +18,11 @@
#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);
}
diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h
index afda41a857d..8fb341182b7 100644
--- a/intern/cycles/render/integrator.h
+++ b/intern/cycles/render/integrator.h
@@ -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);
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index e918de990c2..6c03d0859a7 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -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);
}
}
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index fb8684fa59b..3cedde2596e 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -54,6 +54,7 @@ public:
bool cast_shadow;
int shader;
+ int samples;
void tag_update(Scene *scene);
};
diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp
index a5f90bfe34b..45c8a05c27d 100644
--- a/intern/cycles/render/scene.cpp
+++ b/intern/cycles/render/scene.cpp
@@ -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;