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:
-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;