Merge branch 'master' into blender2.8
authorCampbell Barton <ideasman42@gmail.com>
Wed, 13 Sep 2017 13:44:13 +0000 (23:44 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 13 Sep 2017 13:44:13 +0000 (23:44 +1000)
45 files changed:
build_files/utils/build_tgz.sh
intern/cycles/kernel/closure/bssrdf.h
intern/cycles/kernel/kernel_accumulate.h
intern/cycles/kernel/kernel_bake.h
intern/cycles/kernel/kernel_emission.h
intern/cycles/kernel/kernel_light.h
intern/cycles/kernel/kernel_passes.h
intern/cycles/kernel/kernel_path.h
intern/cycles/kernel/kernel_path_branched.h
intern/cycles/kernel/kernel_path_state.h
intern/cycles/kernel/kernel_path_subsurface.h
intern/cycles/kernel/kernel_path_surface.h
intern/cycles/kernel/kernel_path_volume.h
intern/cycles/kernel/kernel_random.h
intern/cycles/kernel/kernel_shader.h
intern/cycles/kernel/kernel_shadow.h
intern/cycles/kernel/kernel_types.h
intern/cycles/kernel/kernel_volume.h
intern/cycles/kernel/split/kernel_branched.h
intern/cycles/kernel/split/kernel_buffer_update.h
intern/cycles/kernel/split/kernel_direct_lighting.h
intern/cycles/kernel/split/kernel_do_volume.h
intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
intern/cycles/kernel/split/kernel_indirect_background.h
intern/cycles/kernel/split/kernel_lamp_emission.h
intern/cycles/kernel/split/kernel_scene_intersect.h
intern/cycles/kernel/split/kernel_split_common.h
intern/cycles/kernel/split/kernel_split_data_types.h
release/scripts/startup/bl_operators/object_align.py
source/blender/blenkernel/intern/action.c
source/blender/blenkernel/intern/particle_distribute.c
source/blender/compositor/intern/COM_compositor.cpp
source/blender/compositor/nodes/COM_RenderLayersNode.cpp
source/blender/compositor/nodes/COM_RenderLayersNode.h
source/blender/editors/include/ED_anim_api.h
source/blender/editors/object/object_bake_api.c
source/blender/editors/space_node/drawnode.c
source/blender/makesrna/intern/rna_ID.c
source/blender/makesrna/intern/rna_animation.c
source/blender/makesrna/intern/rna_render.c
source/blender/makesrna/intern/rna_ui.c
source/blender/makesrna/intern/rna_userdef.c
source/blender/render/intern/source/zbuf.c
tests/python/CMakeLists.txt
tests/python/cycles_render_tests.py

index 865df2776053135d275af641856ca3c1cc790208..c568d17db1c2a316b1348e5f3b809fd1cb0d6463 100755 (executable)
@@ -53,7 +53,11 @@ echo "OK"
 # Create the tarball
 cd "$blender_srcdir"
 echo -n "Creating archive:            \"$BASE_DIR/$TARBALL\" ..."
-GZIP=-9 tar --transform "s,^,blender-$VERSION/,g" -zcf "$BASE_DIR/$TARBALL" -T "$BASE_DIR/$MANIFEST"
+tar --transform "s,^,blender-$VERSION/,g" \
+       --use-compress-program="gzip --best" \
+       --create \
+       --file="$BASE_DIR/$TARBALL" \
+       --files-from="$BASE_DIR/$MANIFEST"
 echo "OK"
 
 
index f733ea4c5174e9ef1db14165905071a7a2b3cae6..0622118906022fd99896eb1e8d18b6bd8b44fc87 100644 (file)
@@ -348,8 +348,9 @@ ccl_device_inline Bssrdf *bssrdf_alloc(ShaderData *sd, float3 weight)
 {
        Bssrdf *bssrdf = (Bssrdf*)closure_alloc(sd, sizeof(Bssrdf), CLOSURE_NONE_ID, weight);
 
-       if(!bssrdf)
+       if(bssrdf == NULL) {
                return NULL;
+       }
 
        float sample_weight = fabsf(average(weight));
        bssrdf->sample_weight = sample_weight;
index 82d3c153bf5e0cc97267ec1146bfc6a1b527333e..5e60458655798d87f69aeec1d7ee2129de55fd98 100644 (file)
@@ -226,9 +226,9 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass)
        L->path_total = make_float3(0.0f, 0.0f, 0.0f);
        L->path_total_shaded = make_float3(0.0f, 0.0f, 0.0f);
        L->shadow_background_color = make_float3(0.0f, 0.0f, 0.0f);
-       L->shadow_radiance_sum = make_float3(0.0f, 0.0f, 0.0f);
        L->shadow_throughput = 0.0f;
        L->shadow_transparency = 1.0f;
+       L->has_shadow_catcher = 0;
 #endif
 
 #ifdef __DENOISING_FEATURES__
@@ -279,13 +279,22 @@ ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space
        }
 }
 
-ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 throughput, float3 value, int bounce)
+ccl_device_inline void path_radiance_accum_emission(PathRadiance *L,
+                                                    ccl_addr_space PathState *state,
+                                                    float3 throughput,
+                                                    float3 value)
 {
+#ifdef __SHADOW_TRICKS__
+       if(state->flag & PATH_RAY_SHADOW_CATCHER) {
+               return;
+       }
+#endif
+
 #ifdef __PASSES__
        if(L->use_light_pass) {
-               if(bounce == 0)
+               if(state->bounce == 0)
                        L->emission += throughput*value;
-               else if(bounce == 1)
+               else if(state->bounce == 1)
                        L->direct_emission += throughput*value;
                else
                        L->indirect += throughput*value;
@@ -304,6 +313,18 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L,
                                               float3 bsdf,
                                               float3 ao)
 {
+#ifdef __SHADOW_TRICKS__
+       if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
+               float3 light = throughput * bsdf;
+               L->path_total += light;
+               L->path_total_shaded += ao * light;
+
+               if(state->flag & PATH_RAY_SHADOW_CATCHER) {
+                       return;
+               }
+       }
+#endif
+
 #ifdef __PASSES__
        if(L->use_light_pass) {
                if(state->bounce == 0) {
@@ -321,14 +342,6 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L,
        {
                L->emission += throughput*bsdf*ao;
        }
-
-#ifdef __SHADOW_TRICKS__
-       if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
-               float3 light = throughput * bsdf;
-               L->path_total += light;
-               L->path_total_shaded += ao * light;
-       }
-#endif
 }
 
 ccl_device_inline void path_radiance_accum_total_ao(
@@ -357,6 +370,18 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L,
                                                  float shadow_fac,
                                                  bool is_lamp)
 {
+#ifdef __SHADOW_TRICKS__
+       if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
+               float3 light = throughput * bsdf_eval->sum_no_mis;
+               L->path_total += light;
+               L->path_total_shaded += shadow * light;
+
+               if(state->flag & PATH_RAY_SHADOW_CATCHER) {
+                       return;
+               }
+       }
+#endif
+
 #ifdef __PASSES__
        if(L->use_light_pass) {
                if(state->bounce == 0) {
@@ -383,14 +408,6 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L,
        {
                L->emission += throughput*bsdf_eval->diffuse*shadow;
        }
-
-#ifdef __SHADOW_TRICKS__
-       if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
-               float3 light = throughput * bsdf_eval->sum_no_mis;
-               L->path_total += light;
-               L->path_total_shaded += shadow * light;
-       }
-#endif
 }
 
 ccl_device_inline void path_radiance_accum_total_light(
@@ -417,6 +434,18 @@ ccl_device_inline void path_radiance_accum_background(
         float3 throughput,
         float3 value)
 {
+
+#ifdef __SHADOW_TRICKS__
+       if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
+               L->path_total += throughput * value;
+               L->path_total_shaded += throughput * value * L->shadow_transparency;
+
+               if(state->flag & PATH_RAY_SHADOW_CATCHER) {
+                       return;
+               }
+       }
+#endif
+
 #ifdef __PASSES__
        if(L->use_light_pass) {
                if(state->bounce == 0)
@@ -432,18 +461,31 @@ ccl_device_inline void path_radiance_accum_background(
                L->emission += throughput*value;
        }
 
-#ifdef __SHADOW_TRICKS__
-       if(state->flag & PATH_RAY_STORE_SHADOW_INFO) {
-               L->path_total += throughput * value;
-               L->path_total_shaded += throughput * value * L->shadow_transparency;
-       }
-#endif
-
 #ifdef __DENOISING_FEATURES__
        L->denoising_albedo += state->denoising_feature_weight * value;
 #endif  /* __DENOISING_FEATURES__ */
 }
 
+ccl_device_inline void path_radiance_accum_transparent(
+        PathRadiance *L,
+        ccl_addr_space PathState *state,
+        float3 throughput)
+{
+       L->transparent += average(throughput);
+}
+
+#ifdef __SHADOW_TRICKS__
+ccl_device_inline void path_radiance_accum_shadowcatcher(
+        PathRadiance *L,
+        float3 throughput,
+        float3 background)
+{
+       L->shadow_throughput += average(throughput);
+       L->shadow_background_color += throughput * background;
+       L->has_shadow_catcher = 1;
+}
+#endif
+
 ccl_device_inline void path_radiance_sum_indirect(PathRadiance *L)
 {
 #ifdef __PASSES__
@@ -501,7 +543,36 @@ ccl_device_inline void path_radiance_copy_indirect(PathRadiance *L,
 #endif
 }
 
-ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadiance *L)
+#ifdef __SHADOW_TRICKS__
+ccl_device_inline void path_radiance_sum_shadowcatcher(KernelGlobals *kg,
+                                                       PathRadiance *L,
+                                                       float3 *L_sum,
+                                                       float *alpha)
+{
+       /* Calculate current shadow of the path. */
+       float path_total = average(L->path_total);
+       float shadow;
+
+       if(path_total == 0.0f) {
+               shadow = L->shadow_transparency;
+       }
+       else {
+               float path_total_shaded = average(L->path_total_shaded);
+               shadow = path_total_shaded / path_total;
+       }
+
+       /* Calculate final light sum and transparency for shadow catcher object. */
+       if(kernel_data.background.transparent) {
+               *alpha -= L->shadow_throughput * shadow;
+       }
+       else {
+               L->shadow_background_color *= shadow;
+               *L_sum += L->shadow_background_color;
+       }
+}
+#endif
+
+ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadiance *L, float *alpha)
 {
        float3 L_sum;
        /* Light Passes are used */
@@ -578,8 +649,6 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi
                        L_sum = L_direct + L_indirect;
                }
 #endif
-
-               return L_sum;
        }
 
        /* No Light Passes */
@@ -587,14 +656,24 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi
 #endif
        {
                L_sum = L->emission;
+
+               /* Reject invalid value */
+               float sum = fabsf((L_sum).x) + fabsf((L_sum).y) + fabsf((L_sum).z);
+               if(!isfinite_safe(sum)) {
+                       kernel_assert(!"Non-finite final sum in path_radiance_clamp_and_sum!");
+                       L_sum = make_float3(0.0f, 0.0f, 0.0f);
+               }
        }
 
-       /* Reject invalid value */
-       float sum = fabsf((L_sum).x) + fabsf((L_sum).y) + fabsf((L_sum).z);
-       if(!isfinite_safe(sum)) {
-               kernel_assert(!"Non-finite final sum in path_radiance_clamp_and_sum!");
-               L_sum = make_float3(0.0f, 0.0f, 0.0f);
+       /* Compute alpha. */
+       *alpha = 1.0f - L->transparent;
+
+       /* Add shadow catcher contributions. */
+#ifdef __SHADOW_TRICKS__
+       if(L->has_shadow_catcher) {
+               path_radiance_sum_shadowcatcher(kg, L, &L_sum, alpha);
        }
+#endif  /* __SHADOW_TRICKS__ */
 
        return L_sum;
 }
@@ -627,14 +706,18 @@ ccl_device_inline void path_radiance_split_denoising(KernelGlobals *kg, PathRadi
        *clean = make_float3(0.0f, 0.0f, 0.0f);
 #endif
 
+#ifdef __SHADOW_TRICKS__
+       if(L->has_shadow_catcher) {
+               *noisy += L->shadow_background_color;
+       }
+#endif
+
        *noisy = ensure_finite3(*noisy);
        *clean = ensure_finite3(*clean);
 }
 
-ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance *L_sample, int num_samples)
+ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance *L_sample)
 {
-       float fac = 1.0f/num_samples;
-
 #ifdef __SPLIT_KERNEL__
 #  define safe_float3_add(f, v) \
        do { \
@@ -643,66 +726,35 @@ ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance
                atomic_add_and_fetch_float(p+1, (v).y); \
                atomic_add_and_fetch_float(p+2, (v).z); \
        } while(0)
+#  define safe_float_add(f, v) \
+               atomic_add_and_fetch_float(&(f), (v))
 #else
 #  define safe_float3_add(f, v) (f) += (v)
+#  define safe_float_add(f, v) (f) += (v)
 #endif  /* __SPLIT_KERNEL__ */
 
 #ifdef __PASSES__
-       safe_float3_add(L->direct_diffuse, L_sample->direct_diffuse*fac);
-       safe_float3_add(L->direct_glossy, L_sample->direct_glossy*fac);
-       safe_float3_add(L->direct_transmission, L_sample->direct_transmission*fac);
-       safe_float3_add(L->direct_subsurface, L_sample->direct_subsurface*fac);
-       safe_float3_add(L->direct_scatter, L_sample->direct_scatter*fac);
-
-       safe_float3_add(L->indirect_diffuse, L_sample->indirect_diffuse*fac);
-       safe_float3_add(L->indirect_glossy, L_sample->indirect_glossy*fac);
-       safe_float3_add(L->indirect_transmission, L_sample->indirect_transmission*fac);
-       safe_float3_add(L->indirect_subsurface, L_sample->indirect_subsurface*fac);
-       safe_float3_add(L->indirect_scatter, L_sample->indirect_scatter*fac);
-
-       safe_float3_add(L->background, L_sample->background*fac);
-       safe_float3_add(L->ao, L_sample->ao*fac);
-       safe_float3_add(L->shadow, L_sample->shadow*fac);
-#  ifdef __SPLIT_KERNEL__
-       atomic_add_and_fetch_float(&L->mist, L_sample->mist*fac);
-#  else
-       L->mist += L_sample->mist*fac;
-#  endif  /* __SPLIT_KERNEL__ */
+       safe_float3_add(L->direct_diffuse, L_sample->direct_diffuse);
+       safe_float3_add(L->direct_glossy, L_sample->direct_glossy);
+       safe_float3_add(L->direct_transmission, L_sample->direct_transmission);
+       safe_float3_add(L->direct_subsurface, L_sample->direct_subsurface);
+       safe_float3_add(L->direct_scatter, L_sample->direct_scatter);
+
+       safe_float3_add(L->indirect_diffuse, L_sample->indirect_diffuse);
+       safe_float3_add(L->indirect_glossy, L_sample->indirect_glossy);
+       safe_float3_add(L->indirect_transmission, L_sample->indirect_transmission);
+       safe_float3_add(L->indirect_subsurface, L_sample->indirect_subsurface);
+       safe_float3_add(L->indirect_scatter, L_sample->indirect_scatter);
+
+       safe_float3_add(L->background, L_sample->background);
+       safe_float3_add(L->ao, L_sample->ao);
+       safe_float3_add(L->shadow, L_sample->shadow);
+       safe_float_add(L->mist, L_sample->mist);
 #endif  /* __PASSES__ */
-       safe_float3_add(L->emission, L_sample->emission*fac);
+       safe_float3_add(L->emission, L_sample->emission);
 
+#undef safe_float_add
 #undef safe_float3_add
 }
 
-#ifdef __SHADOW_TRICKS__
-/* Calculate current shadow of the path. */
-ccl_device_inline float path_radiance_sum_shadow(const PathRadiance *L)
-{
-       float path_total = average(L->path_total);
-       float path_total_shaded = average(L->path_total_shaded);
-       if(path_total != 0.0f) {
-               return path_total_shaded / path_total;
-       }
-       return L->shadow_transparency;
-}
-
-/* Calculate final light sum and transparency for shadow catcher object. */
-ccl_device_inline float3 path_radiance_sum_shadowcatcher(KernelGlobals *kg,
-                                                         const PathRadiance *L,
-                                                         float* alpha)
-{
-       const float shadow = path_radiance_sum_shadow(L);
-       float3 L_sum;
-       if(kernel_data.background.transparent) {
-               *alpha = 1.0f - L->shadow_throughput * shadow;
-               L_sum = L->shadow_radiance_sum;
-       }
-       else {
-               L_sum = L->shadow_background_color * L->shadow_throughput * shadow +
-                       L->shadow_radiance_sum;
-       }
-       return L_sum;
-}
-#endif
-
 CCL_NAMESPACE_END
index 8af1187213d55a52adaec969e52b43b7f3358da6..b05f6e9ed5ebbd7ef2ebaf53c8692c1056759688 100644 (file)
@@ -70,7 +70,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
                /* sample emission */
                if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) {
                        float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf);
-                       path_radiance_accum_emission(&L_sample, throughput, emission, state.bounce);
+                       path_radiance_accum_emission(&L_sample, &state, throughput, emission);
                }
 
                bool is_sss_sample = false;
@@ -102,7 +102,6 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
                                                             &emission_sd,
                                                             &ray,
                                                             throughput,
-                                                            state.num_samples,
                                                             &state,
                                                             &L_sample);
                                        kernel_path_subsurface_accum_indirect(&ss_indirect, &L_sample);
@@ -121,7 +120,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
                                state.ray_t = 0.0f;
 #endif
                                /* compute indirect light */
-                               kernel_path_indirect(kg, &indirect_sd, &emission_sd, &ray, throughput, 1, &state, &L_sample);
+                               kernel_path_indirect(kg, &indirect_sd, &emission_sd, &ray, throughput, &state, &L_sample);
 
                                /* sum and reset indirect light pass variables for the next samples */
                                path_radiance_sum_indirect(&L_sample);
@@ -141,7 +140,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
                /* sample emission */
                if((pass_filter & BAKE_FILTER_EMISSION) && (sd->flag & SD_EMISSION)) {
                        float3 emission = indirect_primitive_emission(kg, sd, 0.0f, state.flag, state.ray_pdf);
-                       path_radiance_accum_emission(&L_sample, throughput, emission, state.bounce);
+                       path_radiance_accum_emission(&L_sample, &state, throughput, emission);
                }
 
 #ifdef __SUBSURFACE__
@@ -172,7 +171,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg,
 #endif
 
        /* accumulate into master L */
-       path_radiance_accum_sample(L, &L_sample, 1);
+       path_radiance_accum_sample(L, &L_sample);
 }
 
 ccl_device bool is_aa_pass(ShaderEvalType type)
@@ -368,7 +367,8 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input,
                case SHADER_EVAL_COMBINED:
                {
                        if((pass_filter & BAKE_FILTER_COMBINED) == BAKE_FILTER_COMBINED) {
-                               out = path_radiance_clamp_and_sum(kg, &L);
+                               float alpha;
+                               out = path_radiance_clamp_and_sum(kg, &L, &alpha);
                                break;
                        }
 
index 48a8e53be331a226b1170fab2f5e8a093b397d72..13d4759a9ecbcb029f8e541bfec1c3faa44eb1ba 100644 (file)
@@ -37,9 +37,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg,
                ray.D = ls->D;
                ray.P = ls->P;
                ray.t = 1.0f;
-#  ifdef __OBJECT_MOTION__
                ray.time = time;
-#  endif
                ray.dP = differential3_zero();
                ray.dD = dI;
 
index 59db6cbd4306837f5e8593f0f809f7df5bf34331..c806deee8e79def94abb54cecc38a3b38b8502bf 100644 (file)
@@ -396,11 +396,13 @@ ccl_device_inline float3 background_light_sample(KernelGlobals *kg,
                                             + (1.0f - portal_sampling_pdf) * cdf_pdf);
                                }
                                return D;
-                       } else {
+                       }
+                       else {
                                /* Sample map, but with nonzero portal_sampling_pdf for MIS. */
                                randu = (randu - portal_sampling_pdf) / (1.0f - portal_sampling_pdf);
                        }
-               } else {
+               }
+               else {
                        /* We can't sample a portal.
                         * Check if we can sample the map instead.
                         */
@@ -772,7 +774,8 @@ ccl_device_inline bool triangle_world_space_vertices(KernelGlobals *kg, int obje
        if(object_flag & SD_OBJECT_HAS_VERTEX_MOTION && time >= 0.0f) {
                motion_triangle_vertices(kg, object, prim, time, V);
                has_motion = true;
-       } else {
+       }
+       else {
                triangle_vertices(kg, prim, V);
        }
 
@@ -839,13 +842,15 @@ ccl_device_forceinline float triangle_light_pdf(KernelGlobals *kg, ShaderData *s
                /* pdf_triangles is calculated over triangle area, but we're not sampling over its area */
                if(UNLIKELY(solid_angle == 0.0f)) {
                        return 0.0f;
-               } else {
+               }
+               else {
                        float area = 1.0f;
                        if(has_motion) {
                                /* get the center frame vertices, this is what the PDF was calculated from */
                                triangle_world_space_vertices(kg, sd->object, sd->prim, -1.0f, V);
                                area = triangle_area(V[0], V[1], V[2]);
-                       } else {
+                       }
+                       else {
                                area = 0.5f * len(N);
                        }
                        const float pdf = area * kernel_data.integrator.pdf_triangles;
@@ -965,19 +970,25 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals *kg, int prim, i
                ls->D = z * B + safe_sqrtf(1.0f - z*z) * safe_normalize(C_ - dot(C_, B) * B);
 
                /* calculate intersection with the planar triangle */
-               ray_triangle_intersect(P, ls->D, FLT_MAX,
+               if(!ray_triangle_intersect(P, ls->D, FLT_MAX,
 #if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__)
-                                      (ssef*)V,
+                                          (ssef*)V,
 #else
-                                      V[0], V[1], V[2],
+                                          V[0], V[1], V[2],
 #endif
-                                      &ls->u, &ls->v, &ls->t);
+                                          &ls->u, &ls->v, &ls->t)) {
+                       ls->pdf = 0.0f;
+                       return;
+               }
+
                ls->P = P + ls->D * ls->t;
 
                /* pdf_triangles is calculated over triangle area, but we're sampling over solid angle */
                if(UNLIKELY(solid_angle == 0.0f)) {
                        ls->pdf = 0.0f;
-               } else {
+                       return;
+               }
+               else {
                        if(has_motion) {
                                /* get the center frame vertices, this is what the PDF was calculated from */
                                triangle_world_space_vertices(kg, object, prim, -1.0f, V);
@@ -1013,20 +1024,21 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals *kg, int prim, i
 
 /* Light Distribution */
 
-ccl_device int light_distribution_sample(KernelGlobals *kg, float randt)
+ccl_device int light_distribution_sample(KernelGlobals *kg, float *randu)
 {
-       /* this is basically std::upper_bound as used by pbrt, to find a point light or
+       /* This is basically std::upper_bound as used by pbrt, to find a point light or
         * triangle to emit from, proportional to area. a good improvement would be to
         * also sample proportional to power, though it's not so well defined with
-        * OSL shaders. */
+        * arbitrary shaders. */
        int first = 0;
        int len = kernel_data.integrator.num_distribution + 1;
+       float r = *randu;
 
        while(len > 0) {
                int half_len = len >> 1;
                int middle = first + half_len;
 
-               if(randt < kernel_tex_fetch(__light_distribution, middle).x) {
+               if(r < kernel_tex_fetch(__light_distribution, middle).x) {
                        len = half_len;
                }
                else {
@@ -1035,9 +1047,17 @@ ccl_device int light_distribution_sample(KernelGlobals *kg, float randt)
                }
        }
 
-       /* clamping should not be needed but float rounding errors seem to
-        * make this fail on rare occasions */
-       return clamp(first-1, 0, kernel_data.integrator.num_distribution-1);
+       /* Clamping should not be needed but float rounding errors seem to
+        * make this fail on rare occasions. */
+       int index = clamp(first-1, 0, kernel_data.integrator.num_distribution-1);
+
+       /* Rescale to reuse random number. this helps the 2D samples within
+        * each area light be stratified as well. */
+       float distr_min = kernel_tex_fetch(__light_distribution, index).x;
+       float distr_max = kernel_tex_fetch(__light_distribution, index+1).x;
+       *randu = (r - distr_min)/(distr_max - distr_min);
+
+       return index;
 }
 
 /* Generic Light */
@@ -1049,7 +1069,6 @@ ccl_device bool light_select_reached_max_bounces(KernelGlobals *kg, int index, i
 }
 
 ccl_device_noinline bool light_sample(KernelGlobals *kg,
-                                      float randt,
                                       float randu,
                                       float randv,
                                       float time,
@@ -1058,7 +1077,7 @@ ccl_device_noinline bool light_sample(KernelGlobals *kg,
                                       LightSample *ls)
 {
        /* sample index */
-       int index = light_distribution_sample(kg, randt);
+       int index = light_distribution_sample(kg, &randu);
 
        /* fetch light data */
        float4 l = kernel_tex_fetch(__light_distribution, index);
index d454cce6e304b5677b23c6b968c08f43e7ec2e83..fff7f4cfdb750198960e330840b55276fe6afade 100644 (file)
@@ -225,7 +225,7 @@ ccl_device_inline void kernel_write_debug_passes(KernelGlobals *kg,
 #endif /* __KERNEL_DEBUG__ */
 
 ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global float *buffer, PathRadiance *L,
-       ShaderData *sd, int sample, ccl_addr_space PathState *state, float3 throughput)
+       ShaderData *sd, ccl_addr_space PathState *state, float3 throughput)
 {
 #ifdef __PASSES__
        int path_flag = state->flag;
@@ -243,6 +243,7 @@ ccl_device_inline void kernel_write_data_passes(KernelGlobals *kg, ccl_global fl
                   kernel_data.film.pass_alpha_threshold == 0.0f ||
                   average(shader_bsdf_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold)
                {
+                       int sample = state->sample;
 
                        if(sample == 0) {
                                if(flag & PASS_DEPTH) {
@@ -364,21 +365,11 @@ ccl_device_inline void kernel_write_light_passes(KernelGlobals *kg, ccl_global f
 }
 
 ccl_device_inline void kernel_write_result(KernelGlobals *kg, ccl_global float *buffer,
-       int sample, PathRadiance *L, bool is_shadow_catcher)
+       int sample, PathRadiance *L)
 {
        if(L) {
-               float3 L_sum;
-               float alpha = 1.0f - L->transparent;
-
-#ifdef __SHADOW_TRICKS__
-               if(is_shadow_catcher) {
-                       L_sum = path_radiance_sum_shadowcatcher(kg, L, &alpha);
-               }
-               else
-#endif  /* __SHADOW_TRICKS__ */
-               {
-                       L_sum = path_radiance_clamp_and_sum(kg, L);
-               }
+               float alpha;
+               float3 L_sum = path_radiance_clamp_and_sum(kg, L, &alpha);
 
                kernel_write_pass_float4(buffer, sample, make_float4(L_sum.x, L_sum.y, L_sum.z, alpha));
 
@@ -393,16 +384,7 @@ ccl_device_inline void kernel_write_result(KernelGlobals *kg, ccl_global float *
 #  endif
                        if(kernel_data.film.pass_denoising_clean) {
                                float3 noisy, clean;
-#ifdef __SHADOW_TRICKS__
-                               if(is_shadow_catcher) {
-                                       noisy = L_sum;
-                                       clean = make_float3(0.0f, 0.0f, 0.0f);
-                               }
-                               else
-#endif  /* __SHADOW_TRICKS__ */
-                               {
-                                       path_radiance_split_denoising(kg, L, &noisy, &clean);
-                               }
+                               path_radiance_split_denoising(kg, L, &noisy, &clean);
                                kernel_write_pass_float3_variance(buffer + kernel_data.film.pass_denoising_data + DENOISING_PASS_COLOR,
                                                                  sample, noisy);
                                kernel_write_pass_float3_unaligned(buffer + kernel_data.film.pass_denoising_clean,
index 3319e2c2435b05e3d046862af18252c8aabf89df..fc157feb28c5d2c43cec9ae608bcafc33267b646 100644 (file)
 
 CCL_NAMESPACE_BEGIN
 
+ccl_device_forceinline bool kernel_path_scene_intersect(
+       KernelGlobals *kg,
+       ccl_addr_space PathState *state,
+       Ray *ray,
+       Intersection *isect,
+       PathRadiance *L)
+{
+       uint visibility = path_state_ray_visibility(kg, state);
+
+#ifdef __HAIR__
+       float difl = 0.0f, extmax = 0.0f;
+       uint lcg_state = 0;
+
+       if(kernel_data.bvh.have_curves) {
+               if((kernel_data.cam.resolution == 1) && (state->flag & PATH_RAY_CAMERA)) {
+                       float3 pixdiff = ray->dD.dx + ray->dD.dy;
+                       /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/
+                       difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f;
+               }
+
+               extmax = kernel_data.curve.maximum_width;
+               lcg_state = lcg_state_init_addrspace(state, 0x51633e2d);
+       }
+
+       if(path_state_ao_bounce(kg, state)) {
+               visibility = PATH_RAY_SHADOW;
+               ray->t = kernel_data.background.ao_distance;
+       }
+
+       bool hit = scene_intersect(kg, *ray, visibility, isect, &lcg_state, difl, extmax);
+#else
+       bool hit = scene_intersect(kg, *ray, visibility, isect, NULL, 0.0f, 0.0f);
+#endif  /* __HAIR__ */
+
+#ifdef __KERNEL_DEBUG__
+       if(state->flag & PATH_RAY_CAMERA) {
+               L->debug_data.num_bvh_traversed_nodes += isect->num_traversed_nodes;
+               L->debug_data.num_bvh_traversed_instances += isect->num_traversed_instances;
+               L->debug_data.num_bvh_intersections += isect->num_intersections;
+       }
+       L->debug_data.num_ray_bounces++;
+#endif  /* __KERNEL_DEBUG__ */
+
+       return hit;
+}
+
+ccl_device_forceinline void kernel_path_lamp_emission(
+       KernelGlobals *kg,
+       ccl_addr_space PathState *state,
+       Ray *ray,
+       float3 throughput,
+       ccl_addr_space Intersection *isect,
+       ShaderData *emission_sd,
+       PathRadiance *L)
+{
+#ifdef __LAMP_MIS__
+       if(kernel_data.integrator.use_lamp_mis && !(state->flag & PATH_RAY_CAMERA)) {
+               /* ray starting from previous non-transparent bounce */
+               Ray light_ray;
+
+               light_ray.P = ray->P - state->ray_t*ray->D;
+               state->ray_t += isect->t;
+               light_ray.D = ray->D;
+               light_ray.t = state->ray_t;
+               light_ray.time = ray->time;
+               light_ray.dD = ray->dD;
+               light_ray.dP = ray->dP;
+
+               /* intersect with lamp */
+               float3 emission;
+
+               if(indirect_lamp_emission(kg, emission_sd, state, &light_ray, &emission))
+                       path_radiance_accum_emission(L, state, throughput, emission);
+       }
+#endif  /* __LAMP_MIS__ */
+}
+
+ccl_device_forceinline void kernel_path_background(
+       KernelGlobals *kg,
+       ccl_addr_space PathState *state,
+       ccl_addr_space Ray *ray,
+       float3 throughput,
+       ShaderData *emission_sd,
+       PathRadiance *L)
+{
+       /* eval background shader if nothing hit */
+       if(kernel_data.background.transparent && (state->flag & PATH_RAY_CAMERA)) {
+               L->transparent += average(throughput);
+
+#ifdef __PASSES__
+               if(!(kernel_data.film.pass_flag & PASS_BACKGROUND))
+#endif  /* __PASSES__ */
+                       return;
+       }
+
+#ifdef __BACKGROUND__
+       /* sample background shader */
+       float3 L_background = indirect_background(kg, emission_sd, state, ray);
+       path_radiance_accum_background(L, state, throughput, L_background);
+#endif  /* __BACKGROUND__ */
+}
+
+#ifndef __SPLIT_KERNEL__
+
+ccl_device_forceinline VolumeIntegrateResult kernel_path_volume(
+       KernelGlobals *kg,
+       ShaderData *sd,
+       PathState *state,
+       Ray *ray,
+       float3 *throughput,
+       ccl_addr_space Intersection *isect,
+       bool hit,
+       ShaderData *emission_sd,
+       PathRadiance *L)
+{
+#ifdef __VOLUME__
+       /* Sanitize volume stack. */
+       if(!hit) {
+               kernel_volume_clean_stack(kg, state->volume_stack);
+       }
+       /* volume attenuation, emission, scatter */
+       if(state->volume_stack[0].shader != SHADER_NONE) {
+               Ray volume_ray = *ray;
+               volume_ray.t = (hit)? isect->t: FLT_MAX;
+
+               bool heterogeneous = volume_stack_is_heterogeneous(kg, state->volume_stack);
+
+#  ifdef __VOLUME_DECOUPLED__
+               int sampling_method = volume_stack_sampling_method(kg, state->volume_stack);
+               bool direct = (state->flag & PATH_RAY_CAMERA) != 0;
+               bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, direct, sampling_method);
+
+               if(decoupled) {
+                       /* cache steps along volume for repeated sampling */
+                       VolumeSegment volume_segment;
+
+                       shader_setup_from_volume(kg, sd, &volume_ray);
+                       kernel_volume_decoupled_record(kg, state,
+                               &volume_ray, sd, &volume_segment, heterogeneous);
+
+                       volume_segment.sampling_method = sampling_method;
+
+                       /* emission */
+                       if(volume_segment.closure_flag & SD_EMISSION)
+                               path_radiance_accum_emission(L, state, *throughput, volume_segment.accum_emission);
+
+                       /* scattering */
+                       VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED;
+
+                       if(volume_segment.closure_flag & SD_SCATTER) {
+                               int all = kernel_data.integrator.sample_all_lights_indirect;
+
+                               /* direct light sampling */
+                               kernel_branched_path_volume_connect_light(kg, sd,
+                                       emission_sd, *throughput, state, L, all,
+                                       &volume_ray, &volume_segment);
+
+                               /* indirect sample. if we use distance sampling and take just
+                                * one sample for direct and indirect light, we could share
+                                * this computation, but makes code a bit complex */
+                               float rphase = path_state_rng_1D_for_decision(kg, state, PRNG_PHASE);
+                               float rscatter = path_state_rng_1D_for_decision(kg, state, PRNG_SCATTER_DISTANCE);
+
+                               result = kernel_volume_decoupled_scatter(kg,
+                                       state, &volume_ray, sd, throughput,
+                                       rphase, rscatter, &volume_segment, NULL, true);
+                       }
+
+                       /* free cached steps */
+                       kernel_volume_decoupled_free(kg, &volume_segment);
+
+                       if(result == VOLUME_PATH_SCATTERED) {
+                               if(kernel_path_volume_bounce(kg, sd, throughput, state, L, ray))
+                                       return VOLUME_PATH_SCATTERED;
+                               else
+                                       return VOLUME_PATH_MISSED;
+                       }
+                       else {
+                               *throughput *= volume_segment.accum_transmittance;
+                       }
+               }
+               else
+#  endif  /* __VOLUME_DECOUPLED__ */
+               {
+                       /* integrate along volume segment with distance sampling */
+                       VolumeIntegrateResult result = kernel_volume_integrate(
+                               kg, state, sd, &volume_ray, L, throughput, heterogeneous);
+
+#  ifdef __VOLUME_SCATTER__
+                       if(result == VOLUME_PATH_SCATTERED) {
+                               /* direct lighting */
+                               kernel_path_volume_connect_light(kg, sd, emission_sd, *throughput, state, L);
+
+                               /* indirect light bounce */
+                               if(kernel_path_volume_bounce(kg, sd, throughput, state, L, ray))
+                                       return VOLUME_PATH_SCATTERED;
+                               else
+                                       return VOLUME_PATH_MISSED;
+                       }
+#  endif  /* __VOLUME_SCATTER__ */
+               }
+       }
+#endif  /* __VOLUME__ */
+
+       return VOLUME_PATH_ATTENUATED;
+}
+
+#endif /* __SPLIT_KERNEL__ */
+
+ccl_device_forceinline bool kernel_path_shader_apply(
+       KernelGlobals *kg,
+       ShaderData *sd,
+       ccl_addr_space PathState *state,
+       ccl_addr_space Ray *ray,
+       float3 throughput,
+       ShaderData *emission_sd,
+       PathRadiance *L,
+       ccl_global float *buffer)
+{
+#ifdef __SHADOW_TRICKS__
+       if((sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) {
+               if(state->flag & PATH_RAY_CAMERA) {
+                       state->flag |= (PATH_RAY_SHADOW_CATCHER |
+                                                  PATH_RAY_STORE_SHADOW_INFO);
+
+                       float3 bg = make_float3(0.0f, 0.0f, 0.0f);
+                       if(!kernel_data.background.transparent) {
+                               bg = indirect_background(kg, emission_sd, state, ray);
+                       }
+                       path_radiance_accum_shadowcatcher(L, throughput, bg);
+               }
+       }
+       else if(state->flag & PATH_RAY_SHADOW_CATCHER) {
+               /* Only update transparency after shadow catcher bounce. */
+               L->shadow_transparency *=
+                               average(shader_bsdf_transparency(kg, sd));
+       }
+#endif  /* __SHADOW_TRICKS__ */
+
+       /* holdout */
+#ifdef __HOLDOUT__
+       if(((sd->flag & SD_HOLDOUT) ||
+               (sd->object_flag & SD_OBJECT_HOLDOUT_MASK)) &&
+          (state->flag & PATH_RAY_CAMERA))
+       {
+               if(kernel_data.background.transparent) {
+                       float3 holdout_weight;
+                       if(sd->object_flag & SD_OBJECT_HOLDOUT_MASK) {
+                               holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
+                       }
+                       else {
+                               holdout_weight = shader_holdout_eval(kg, sd);
+                       }
+                       /* any throughput is ok, should all be identical here */
+                       L->transparent += average(holdout_weight*throughput);
+               }
+
+               if(sd->object_flag & SD_OBJECT_HOLDOUT_MASK) {
+                       return false;
+               }
+       }
+#endif  /* __HOLDOUT__ */
+
+       /* holdout mask objects do not write data passes */
+       kernel_write_data_passes(kg, buffer, L, sd, state, throughput);
+
+       /* 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*state->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_primitive_emission(kg, sd, sd->ray_length, state->flag, state->ray_pdf);
+               path_radiance_accum_emission(L, state, throughput, emission);
+       }
+#endif  /* __EMISSION__ */
+
+       return true;
+}
+
 ccl_device_noinline void kernel_path_ao(KernelGlobals *kg,
                                         ShaderData *sd,
                                         ShaderData *emission_sd,
@@ -78,9 +366,7 @@ ccl_device_noinline void kernel_path_ao(KernelGlobals *kg,
                light_ray.P = ray_offset(sd->P, sd->Ng);
                light_ray.D = ao_D;
                light_ray.t = kernel_data.background.ao_distance;
-#ifdef __OBJECT_MOTION__
                light_ray.time = sd->time;
-#endif  /* __OBJECT_MOTION__ */
                light_ray.dP = sd->dP;
                light_ray.dD = differential3_zero();
 
@@ -102,203 +388,46 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
                                      ShaderData *emission_sd,
                                      Ray *ray,
                                      float3 throughput,
-                                     int num_samples,
                                      PathState *state,
                                      PathRadiance *L)
 {
        /* path iteration */
        for(;;) {
-               /* intersect scene */
+               /* Find intersection with objects in scene. */
                Intersection isect;
-               uint visibility = path_state_ray_visibility(kg, state);
-               if(state->bounce > kernel_data.integrator.ao_bounces) {
-                       visibility = PATH_RAY_SHADOW;
-                       ray->t = kernel_data.background.ao_distance;
-               }
-               bool hit = scene_intersect(kg,
-                                          *ray,
-                                          visibility,
-                                          &isect,
-                                          NULL,
-                                          0.0f, 0.0f);
-
-#ifdef __LAMP_MIS__
-               if(kernel_data.integrator.use_lamp_mis && !(state->flag & PATH_RAY_CAMERA)) {
-                       /* ray starting from previous non-transparent bounce */
-                       Ray light_ray;
-
-                       light_ray.P = ray->P - state->ray_t*ray->D;
-                       state->ray_t += isect.t;
-                       light_ray.D = ray->D;
-                       light_ray.t = state->ray_t;
-                       light_ray.time = ray->time;
-                       light_ray.dD = ray->dD;
-                       light_ray.dP = ray->dP;
-
-                       /* intersect with lamp */
-                       float3 emission;
-                       if(indirect_lamp_emission(kg, emission_sd, state, &light_ray, &emission)) {
-                               path_radiance_accum_emission(L,
-                                                            throughput,
-                                                            emission,
-                                                            state->bounce);
-                       }
-               }
-#endif  /* __LAMP_MIS__ */
-
-#ifdef __VOLUME__
-               /* Sanitize volume stack. */
-               if(!hit) {
-                       kernel_volume_clean_stack(kg, state->volume_stack);
-               }
-               /* volume attenuation, emission, scatter */
-               if(state->volume_stack[0].shader != SHADER_NONE) {
-                       Ray volume_ray = *ray;
-                       volume_ray.t = (hit)? isect.t: FLT_MAX;
-
-                       bool heterogeneous =
-                               volume_stack_is_heterogeneous(kg,
-                                                             state->volume_stack);
-
-#  ifdef __VOLUME_DECOUPLED__
-                       int sampling_method =
-                               volume_stack_sampling_method(kg,
-                                                            state->volume_stack);
-                       bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, false, sampling_method);
-
-                       if(decoupled) {
-                               /* cache steps along volume for repeated sampling */
-                               VolumeSegment volume_segment;
-
-                               shader_setup_from_volume(kg,
-                                                        sd,
-                                                        &volume_ray);
-                               kernel_volume_decoupled_record(kg,
-                                                              state,
-                                                              &volume_ray,
-                                                              sd,
-                                                              &volume_segment,
-                                                              heterogeneous);
-
-                               volume_segment.sampling_method = sampling_method;
-
-                               /* emission */
-                               if(volume_segment.closure_flag & SD_EMISSION) {
-                                       path_radiance_accum_emission(L,
-                                                                    throughput,
-                                                                    volume_segment.accum_emission,
-                                                                    state->bounce);
-                               }
-
-                               /* scattering */
-                               VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED;
-
-                               if(volume_segment.closure_flag & SD_SCATTER) {
-                                       int all = kernel_data.integrator.sample_all_lights_indirect;
-
-                                       /* direct light sampling */
-                                       kernel_branched_path_volume_connect_light(kg,
-                                                                                 sd,
-                                                                                 emission_sd,
-                                                                                 throughput,
-                                                                                 state,
-                                                                                 L,
-                                                                                 all,
-                                                                                 &volume_ray,
-                                                                                 &volume_segment);
-
-                                       /* indirect sample. if we use distance sampling and take just
-                                        * one sample for direct and indirect light, we could share
-                                        * this computation, but makes code a bit complex */
-                                       float rphase = path_state_rng_1D_for_decision(kg, state, PRNG_PHASE);
-                                       float rscatter = path_state_rng_1D_for_decision(kg, state, PRNG_SCATTER_DISTANCE);
-
-                                       result = kernel_volume_decoupled_scatter(kg,
-                                                                                state,
-                                                                                &volume_ray,
-                                                                                sd,
-                                                                                &throughput,
-                                                                                rphase,
-                                                                                rscatter,
-                                                                                &volume_segment,
-                                                                                NULL,
-                                                                                true);
-                               }
-
-                               /* free cached steps */
-                               kernel_volume_decoupled_free(kg, &volume_segment);
-
-                               if(result == VOLUME_PATH_SCATTERED) {
-                                       if(kernel_path_volume_bounce(kg,
-                                                                    sd,
-                                                                    &throughput,
-                                                                    state,
-                                                                    L,
-                                                                    ray))
-                                       {
-                                               continue;
-                                       }
-                                       else {
-                                               break;
-                                       }
-                               }
-                               else {
-                                       throughput *= volume_segment.accum_transmittance;
-                               }
-                       }
-                       else
-#  endif  /* __VOLUME_DECOUPLED__ */
-                       {
-                               /* integrate along volume segment with distance sampling */
-                               VolumeIntegrateResult result = kernel_volume_integrate(
-                                       kg, state, sd, &volume_ray, L, &throughput, heterogeneous);
-
-#  ifdef __VOLUME_SCATTER__
-                               if(result == VOLUME_PATH_SCATTERED) {
-                                       /* direct lighting */
-                                       kernel_path_volume_connect_light(kg,
-                                                                        sd,
-                                                                        emission_sd,
-                                                                        throughput,
-                                                                        state,
-                                                                        L);
-
-                                       /* indirect light bounce */
-                                       if(kernel_path_volume_bounce(kg,
-                                                                    sd,
-                                                                    &throughput,
-                                                                    state,
-                                                                    L,
-                                                                    ray))
-                                       {
-                                               continue;
-                                       }
-                                       else {
-                                               break;
-                                       }
-                               }
-#  endif  /* __VOLUME_SCATTER__ */
-                       }
+               bool hit = kernel_path_scene_intersect(kg, state, ray, &isect, L);
+
+               /* Find intersection with lamps and compute emission for MIS. */
+               kernel_path_lamp_emission(kg, state, ray, throughput, &isect, emission_sd, L);
+
+               /* Volume integration. */
+               VolumeIntegrateResult result = kernel_path_volume(kg,
+                                                                  sd,
+                                                                  state,
+                                                                  ray,
+                                                                  &throughput,
+                                                                  &isect,
+                                                                  hit,
+                                                                  emission_sd,
+                                                                  L);
+
+               if(result == VOLUME_PATH_SCATTERED) {
+                       continue;
+               }
+               else if(result == VOLUME_PATH_MISSED) {
+                       break;
                }
-#endif  /* __VOLUME__ */
 
+               /* Shade background. */
                if(!hit) {
-#ifdef __BACKGROUND__
-                       /* sample background shader */
-                       float3 L_background = indirect_background(kg, emission_sd, state, ray);
-                       path_radiance_accum_background(L,
-                                                      state,
-                                                      throughput,
-                                                      L_background);
-#endif  /* __BACKGROUND__ */
-
+                       kernel_path_background(kg, state, ray, throughput, emission_sd, L);
                        break;
                }
-               else if(state->bounce > kernel_data.integrator.ao_bounces) {
+               else if(path_state_ao_bounce(kg, state)) {
                        break;
                }
 
-               /* setup shading */
+               /* Setup and evaluate shader. */
                shader_setup_from_ray(kg,
                                      sd,
                                      &isect,
@@ -309,46 +438,23 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
                shader_merge_closures(sd);
 #endif  /* __BRANCHED_PATH__ */
 
-#ifdef __SHADOW_TRICKS__
-               if(!(sd->object_flag & SD_OBJECT_SHADOW_CATCHER) &&
-                  (state->flag & PATH_RAY_SHADOW_CATCHER))
+               /* Apply shadow catcher, holdout, emission. */
+               if(!kernel_path_shader_apply(kg,
+                                            sd,
+                                            state,
+                                            ray,
+                                            throughput,
+                                            emission_sd,
+                                            L,
+                                            NULL))
                {
-                       /* Only update transparency after shadow catcher bounce. */
-                       L->shadow_transparency *=
-                               average(shader_bsdf_transparency(kg, sd));
-               }
-#endif  /* __SHADOW_TRICKS__ */
-
-               /* 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*state->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_primitive_emission(kg,
-                                                                     sd,
-                                                                     isect.t,
-                                                                     state->flag,
-                                                                     state->ray_pdf);
-                       path_radiance_accum_emission(L, throughput, emission, state->bounce);
+                       break;
                }
-#endif  /* __EMISSION__ */
 
                /* 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_continuation_probability(kg,
-                                                        state,
-                                                        throughput*num_samples);
+               float probability = path_state_continuation_probability(kg, state, throughput);
 
                if(probability == 0.0f) {
                        break;
@@ -424,26 +530,17 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg,
 
 #endif /* defined(__BRANCHED_PATH__) || defined(__BAKING__) */
 
-ccl_device_inline void kernel_path_integrate(KernelGlobals *kg,
-                                             uint rng_hash,
-                                             int sample,
-                                             Ray ray,
-                                             ccl_global float *buffer,
-                                             PathRadiance *L,
-                                             bool *is_shadow_catcher)
+ccl_device_forceinline void kernel_path_integrate(
+       KernelGlobals *kg,
+       PathState *state,
+       float3 throughput,
+       Ray *ray,
+       PathRadiance *L,
+       ccl_global float *buffer,
+       ShaderData *emission_sd)
 {
-       /* initialize */
-       float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
-
-       path_radiance_init(L, kernel_data.film.use_light_pass);
-
-       /* shader data memory used for both volumes and surfaces, saves stack space */
+       /* Shader data memory used for both volumes and surfaces, saves stack space. */
        ShaderData sd;
-       /* shader data used by emission, shadows, volume stacks */
-       ShaderData emission_sd;
-
-       PathState state;
-       path_state_init(kg, &emission_sd, &state, rng_hash, sample, &ray);
 
 #ifdef __SUBSURFACE__
        SubsurfaceIndirectRays ss_indirect;
@@ -454,270 +551,80 @@ ccl_device_inline void kernel_path_integrate(KernelGlobals *kg,
 
        /* path iteration */
        for(;;) {
-               /* intersect scene */
+               /* Find intersection with objects in scene. */
                Intersection isect;
-               uint visibility = path_state_ray_visibility(kg, &state);
-
-#ifdef __HAIR__
-               float difl = 0.0f, extmax = 0.0f;
-               uint lcg_state = 0;
-
-               if(kernel_data.bvh.have_curves) {
-                       if((kernel_data.cam.resolution == 1) && (state.flag & PATH_RAY_CAMERA)) {       
-                               float3 pixdiff = ray.dD.dx + ray.dD.dy;
-                               /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/
-                               difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f;
-                       }
-
-                       extmax = kernel_data.curve.maximum_width;
-                       lcg_state = lcg_state_init(&state, 0x51633e2d);
-               }
-
-               if(state.bounce > kernel_data.integrator.ao_bounces) {
-                       visibility = PATH_RAY_SHADOW;
-                       ray.t = kernel_data.background.ao_distance;
-               }
-
-               bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax);
-#else
-               bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f);
-#endif  /* __HAIR__ */
-
-#ifdef __KERNEL_DEBUG__
-               if(state.flag & PATH_RAY_CAMERA) {
-                       L->debug_data.num_bvh_traversed_nodes += isect.num_traversed_nodes;
-                       L->debug_data.num_bvh_traversed_instances += isect.num_traversed_instances;
-                       L->debug_data.num_bvh_intersections += isect.num_intersections;
-               }
-               L->debug_data.num_ray_bounces++;
-#endif  /* __KERNEL_DEBUG__ */
-
-#ifdef __LAMP_MIS__
-               if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) {
-                       /* ray starting from previous non-transparent bounce */
-                       Ray light_ray;
-
-                       light_ray.P = ray.P - state.ray_t*ray.D;
-                       state.ray_t += isect.t;
-                       light_ray.D = ray.D;
-                       light_ray.t = state.ray_t;
-                       light_ray.time = ray.time;
-                       light_ray.dD = ray.dD;
-                       light_ray.dP = ray.dP;
-
-                       /* intersect with lamp */
-                       float3 emission;
-
-                       if(indirect_lamp_emission(kg, &emission_sd, &state, &light_ray, &emission))
-                               path_radiance_accum_emission(L, throughput, emission, state.bounce);
-               }
-#endif  /* __LAMP_MIS__ */
-
-#ifdef __VOLUME__
-               /* Sanitize volume stack. */
-               if(!hit) {
-                       kernel_volume_clean_stack(kg, state.volume_stack);
-               }
-               /* volume attenuation, emission, scatter */
-               if(state.volume_stack[0].shader != SHADER_NONE) {
-                       Ray volume_ray = ray;
-                       volume_ray.t = (hit)? isect.t: FLT_MAX;
-
-                       bool heterogeneous = volume_stack_is_heterogeneous(kg, state.volume_stack);
-
-#  ifdef __VOLUME_DECOUPLED__
-                       int sampling_method = volume_stack_sampling_method(kg, state.volume_stack);
-                       bool decoupled = kernel_volume_use_decoupled(kg, heterogeneous, true, sampling_method);
-
-                       if(decoupled) {
-                               /* cache steps along volume for repeated sampling */
-                               VolumeSegment volume_segment;
-
-                               shader_setup_from_volume(kg, &sd, &volume_ray);
-                               kernel_volume_decoupled_record(kg, &state,
-                                       &volume_ray, &sd, &volume_segment, heterogeneous);
-
-                               volume_segment.sampling_method = sampling_method;
-
-                               /* emission */
-                               if(volume_segment.closure_flag & SD_EMISSION)
-                                       path_radiance_accum_emission(L, throughput, volume_segment.accum_emission, state.bounce);
-
-                               /* scattering */
-                               VolumeIntegrateResult result = VOLUME_PATH_ATTENUATED;
-
-                               if(volume_segment.closure_flag & SD_SCATTER) {
-                                       int all = false;
-
-                                       /* direct light sampling */
-                                       kernel_branched_path_volume_connect_light(kg, &sd,
-                                               &emission_sd, throughput, &state, L, all,
-                                               &volume_ray, &volume_segment);
-
-                                       /* indirect sample. if we use distance sampling and take just
-                                        * one sample for direct and indirect light, we could share
-                                        * this computation, but makes code a bit complex */
-                                       float rphase = path_state_rng_1D_for_decision(kg, &state, PRNG_PHASE);
-                                       float rscatter = path_state_rng_1D_for_decision(kg, &state, PRNG_SCATTER_DISTANCE);
-
-                                       result = kernel_volume_decoupled_scatter(kg,
-                                               &state, &volume_ray, &sd, &throughput,
-                                               rphase, rscatter, &volume_segment, NULL, true);
-                               }
-
-                               /* free cached steps */
-                               kernel_volume_decoupled_free(kg, &volume_segment);
-
-                               if(result == VOLUME_PATH_SCATTERED) {
-                                       if(kernel_path_volume_bounce(kg, &sd, &throughput, &state, L, &ray))
-                                               continue;
-                                       else
-                                               break;
-                               }
-                               else {
-                                       throughput *= volume_segment.accum_transmittance;
-                               }
-                       }
-                       else
-#  endif  /* __VOLUME_DECOUPLED__ */
-                       {
-                               /* integrate along volume segment with distance sampling */
-                               VolumeIntegrateResult result = kernel_volume_integrate(
-                                       kg, &state, &sd, &volume_ray, L, &throughput, heterogeneous);
-
-#  ifdef __VOLUME_SCATTER__
-                               if(result == VOLUME_PATH_SCATTERED) {
-                                       /* direct lighting */
-                                       kernel_path_volume_connect_light(kg, &sd, &emission_sd, throughput, &state, L);
-
-                                       /* indirect light bounce */
-                                       if(kernel_path_volume_bounce(kg, &sd, &throughput, &state, L, &ray))
-                                               continue;
-                                       else
-                                               break;
-                               }
-#  endif  /* __VOLUME_SCATTER__ */
-                       }
+               bool hit = kernel_path_scene_intersect(kg, state, ray, &isect, L);
+
+               /* Find intersection with lamps and compute emission for MIS. */
+               kernel_path_lamp_emission(kg, state, ray, throughput, &isect, emission_sd, L);
+
+               /* Volume integration. */
+               VolumeIntegrateResult result = kernel_path_volume(kg,
+                                                                  &sd,
+                                                                  state,
+                                                                  ray,
+                                                                  &throughput,
+                                                                  &isect,
+                                                                  hit,
+                                                                  emission_sd,
+                                                                  L);
+
+               if(result == VOLUME_PATH_SCATTERED) {
+                       continue;
+               }
+               else if(result == VOLUME_PATH_MISSED) {
+                       break;
                }
-#endif  /* __VOLUME__ */
 
+               /* Shade background. */
                if(!hit) {
-                       /* eval background shader if nothing hit */
-                       if(kernel_data.background.transparent && (state.flag & PATH_RAY_CAMERA)) {
-                               L->transparent += average(throughput);
-
-#ifdef __PASSES__
-                               if(!(kernel_data.film.pass_flag & PASS_BACKGROUND))
-#endif  /* __PASSES__ */
-                                       break;
-                       }
-
-#ifdef __BACKGROUND__
-                       /* sample background shader */
-                       float3 L_background = indirect_background(kg, &emission_sd, &state, &ray);
-                       path_radiance_accum_background(L, &state, throughput, L_background);
-#endif  /* __BACKGROUND__ */
-
+                       kernel_path_background(kg, state, ray, throughput, emission_sd, L);
                        break;
                }
-               else if(state.bounce > kernel_data.integrator.ao_bounces) {
+               else if(path_state_ao_bounce(kg, state)) {
                        break;
                }
 
-               /* setup shading */
-               shader_setup_from_ray(kg, &sd, &isect, &ray);
-               float rbsdf = path_state_rng_1D_for_decision(kg, &state, PRNG_BSDF);
-               shader_eval_surface(kg, &sd, &state, rbsdf, state.flag);
-
-#ifdef __SHADOW_TRICKS__
-               if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) {
-                       if(state.flag & PATH_RAY_CAMERA) {
-                               state.flag |= (PATH_RAY_SHADOW_CATCHER |
-                                              PATH_RAY_STORE_SHADOW_INFO);
-                               if(!kernel_data.background.transparent) {
-                                       L->shadow_background_color =
-                                               indirect_background(kg, &emission_sd, &state, &ray);
-                               }
-                               L->shadow_radiance_sum = path_radiance_clamp_and_sum(kg, L);
-                               L->shadow_throughput = average(throughput);
-                       }
-               }
-               else if(state.flag & PATH_RAY_SHADOW_CATCHER) {
-                       /* Only update transparency after shadow catcher bounce. */
-                       L->shadow_transparency *=
-                               average(shader_bsdf_transparency(kg, &sd));
-               }
-#endif  /* __SHADOW_TRICKS__ */
-
-               /* holdout */
-#ifdef __HOLDOUT__
-               if(((sd.flag & SD_HOLDOUT) ||
-                   (sd.object_flag & SD_OBJECT_HOLDOUT_MASK)) &&
-                  (state.flag & PATH_RAY_CAMERA))
+               /* Setup and evaluate shader. */
+               shader_setup_from_ray(kg, &sd, &isect, ray);
+               float rbsdf = path_state_rng_1D_for_decision(kg, state, PRNG_BSDF);
+               shader_eval_surface(kg, &sd, state, rbsdf, state->flag);
+
+               /* Apply shadow catcher, holdout, emission. */
+               if(!kernel_path_shader_apply(kg,
+                                            &sd,
+                                            state,
+                                            ray,
+                                            throughput,
+                                            emission_sd,
+                                            L,
+                                            buffer))
                {
-                       if(kernel_data.background.transparent) {
-                               float3 holdout_weight;
-                               if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) {
-                                       holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
-                               }
-                               else {
-                                       holdout_weight = shader_holdout_eval(kg, &sd);
-                               }
-                               /* any throughput is ok, should all be identical here */
-                               L->transparent += average(holdout_weight*throughput);
-                       }
-
-                       if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) {
-                               break;
-                       }
-               }
-#endif  /* __HOLDOUT__ */
-
-               /* holdout mask objects do not write data passes */
-               kernel_write_data_passes(kg, buffer, L, &sd, sample, &state, throughput);
-
-               /* 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*state.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) {
-                       /* todo: is isect.t wrong here for transparent surfaces? */
-                       float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf);
-                       path_radiance_accum_emission(L, throughput, emission, state.bounce);
+                       break;
                }
-#endif  /* __EMISSION__ */
 
                /* 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_continuation_probability(kg, &state, throughput);
+               float probability = path_state_continuation_probability(kg, state, throughput);
 
                if(probability == 0.0f) {
                        break;
                }
                else if(probability != 1.0f) {
-                       float terminate = path_state_rng_1D_for_decision(kg, &state, PRNG_TERMINATE);
+                       float terminate = path_state_rng_1D_for_decision(kg, state, PRNG_TERMINATE);
                        if(terminate >= probability)
                                break;
 
                        throughput /= probability;
                }
 
-               kernel_update_denoising_features(kg, &sd, &state, L);
+               kernel_update_denoising_features(kg, &sd, state, L);
 
 #ifdef __AO__
                /* ambient occlusion */
                if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) {
-                       kernel_path_ao(kg, &sd, &emission_sd, L, &state, throughput, shader_bsdf_alpha(kg, &sd));
+                       kernel_path_ao(kg, &sd, emission_sd, L, state, throughput, shader_bsdf_alpha(kg, &sd));
                }
 #endif  /* __AO__ */
 
@@ -727,10 +634,10 @@ ccl_device_inline void kernel_path_integrate(KernelGlobals *kg,
                if(sd.flag & SD_BSSRDF) {
                        if(kernel_path_subsurface_scatter(kg,
                                                          &sd,
-                                                         &emission_sd,
+                                                         emission_sd,
                                                          L,
-                                                         &state,
-                                                         &ray,
+                                                         state,
+                                                         ray,
                                                          &throughput,
                                                          &ss_indirect))
                        {
@@ -740,10 +647,10 @@ ccl_device_inline void kernel_path_integrate(KernelGlobals *kg,
 #endif  /* __SUBSURFACE__ */
 
                /* direct lighting */
-               kernel_path_surface_connect_light(kg, &sd, &emission_sd, throughput, &state, L);
+               kernel_path_surface_connect_light(kg, &sd, emission_sd, throughput, state, L);
 
                /* compute direct lighting and next bounce */
-               if(!kernel_path_surface_bounce(kg, &sd, &throughput, &state, L, &ray))
+               if(!kernel_path_surface_bounce(kg, &sd, &throughput, state, L, ray))
                        break;
        }
 
@@ -756,8 +663,8 @@ ccl_device_inline void kernel_path_integrate(KernelGlobals *kg,
                if(ss_indirect.num_rays) {
                        kernel_path_subsurface_setup_indirect(kg,
                                                              &ss_indirect,
-                                                             &state,
-                                                             &ray,
+                                                             state,
+                                                             ray,
                                                              L,
                                                              &throughput);
                }
@@ -766,10 +673,6 @@ ccl_device_inline void kernel_path_integrate(KernelGlobals *kg,
                }
        }
 #endif  /* __SUBSURFACE__ */
-
-#ifdef __SHADOW_TRICKS__
-       *is_shadow_catcher = (state.flag & PATH_RAY_SHADOW_CATCHER) != 0;
-#endif  /* __SHADOW_TRICKS__ */
 }
 
 ccl_device void kernel_path_trace(KernelGlobals *kg,
@@ -783,23 +686,37 @@ ccl_device void kernel_path_trace(KernelGlobals *kg,
        rng_state += index;
        buffer += index*pass_stride;
 
-       /* initialize random numbers and ray */
+       /* Initialize random numbers and sample ray. */
        uint rng_hash;
        Ray ray;
 
        kernel_path_trace_setup(kg, rng_state, sample, x, y, &rng_hash, &ray);
 
-       /* integrate */
+       if(ray.t == 0.0f) {
+               kernel_write_result(kg, buffer, sample, NULL);
+               return;
+       }
+
+       /* Initialize state. */
+       float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
+
        PathRadiance L;
-       bool is_shadow_catcher;
+       path_radiance_init(&L, kernel_data.film.use_light_pass);
 
-       if(ray.t != 0.0f) {
-               kernel_path_integrate(kg, rng_hash, sample, ray, buffer, &L, &is_shadow_catcher);
-               kernel_write_result(kg, buffer, sample, &L, is_shadow_catcher);
-       }
-       else {
-               kernel_write_result(kg, buffer, sample, NULL, false);
-       }
+       ShaderData emission_sd;
+       PathState state;
+       path_state_init(kg, &emission_sd, &state, rng_hash, sample, &ray);
+
+       /* Integrate. */
+       kernel_path_integrate(kg,
+                             &state,
+                             throughput,
+                             &ray,
+                             &L,
+                             buffer,
+                             &emission_sd);
+
+       kernel_write_result(kg, buffer, sample, &L);
 }
 
 #endif  /* __SPLIT_KERNEL__ */
index dde40674ee615f3fae76f75dd57b8e7533b3cfea..3994d8d49546b949a60149f8c32429a272ae3bb2 100644 (file)
@@ -48,9 +48,7 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg,
                        light_ray.P = ray_offset(sd->P, sd->Ng);
                        light_ray.D = ao_D;
                        light_ray.t = kernel_data.background.ao_distance;
-#ifdef __OBJECT_MOTION__
                        light_ray.time = sd->time;
-#endif  /* __OBJECT_MOTION__ */
                        light_ray.dP = sd->dP;
                        light_ray.dD = differential3_zero();
 
@@ -144,7 +142,6 @@ ccl_device_noinline void kernel_branched_path_surface_indirect_light(KernelGloba
                                             emission_sd,
                                             &bsdf_ray,
                                             tp*num_samples_inv,
-                                            num_samples,
                                             &ps,
                                             L);
 
@@ -271,8 +268,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
                                                int sample,
                                                Ray ray,
                                                ccl_global float *buffer,
-                                               PathRadiance *L,
-                                               bool *is_shadow_catcher)
+                                               PathRadiance *L)
 {
        /* initialize */
        float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
@@ -292,36 +288,9 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
         * Indirect bounces are handled in kernel_branched_path_surface_indirect_light().
         */
        for(;;) {
-               /* intersect scene */
+               /* Find intersection with objects in scene. */
                Intersection isect;
-               uint visibility = path_state_ray_visibility(kg, &state);
-
-#ifdef __HAIR__
-               float difl = 0.0f, extmax = 0.0f;
-               uint lcg_state = 0;
-
-               if(kernel_data.bvh.have_curves) {
-                       if(kernel_data.cam.resolution == 1) {
-                               float3 pixdiff = ray.dD.dx + ray.dD.dy;
-                               /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/
-                               difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f;
-                       }
-
-                       extmax = kernel_data.curve.maximum_width;
-                       lcg_state = lcg_state_init(&state, 0x51633e2d);
-               }
-
-               bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax);
-#else
-               bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f);
-#endif  /* __HAIR__ */
-
-#ifdef __KERNEL_DEBUG__
-               L->debug_data.num_bvh_traversed_nodes += isect.num_traversed_nodes;
-               L->debug_data.num_bvh_traversed_instances += isect.num_traversed_instances;
-               L->debug_data.num_bvh_intersections += isect.num_intersections;
-               L->debug_data.num_ray_bounces++;
-#endif  /* __KERNEL_DEBUG__ */
+               bool hit = kernel_path_scene_intersect(kg, &state, &ray, &isect, L);
 
 #ifdef __VOLUME__
                /* Sanitize volume stack. */
@@ -376,10 +345,8 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
                                        VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
                                                &ps, &pray, &sd, &tp, rphase, rscatter, &volume_segment, NULL, false);
 
-                                       (void)result;
-                                       kernel_assert(result == VOLUME_PATH_SCATTERED);
-
-                                       if(kernel_path_volume_bounce(kg,
+                                       if(result == VOLUME_PATH_SCATTERED &&
+                                          kernel_path_volume_bounce(kg,
                                                                     &sd,
                                                                     &tp,
                                                                     &ps,
@@ -391,7 +358,6 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
                                                                     &emission_sd,
                                                                     &pray,
                                                                     tp*num_samples_inv,
-                                                                    num_samples,
                                                                     &ps,
                                                                     L);
 
@@ -405,7 +371,7 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
 
                        /* emission and transmittance */
                        if(volume_segment.closure_flag & SD_EMISSION)
-                               path_radiance_accum_emission(L, throughput, volume_segment.accum_emission, state.bounce);
+                               path_radiance_accum_emission(L, &state, throughput, volume_segment.accum_emission);
                        throughput *= volume_segment.accum_transmittance;
 
                        /* free cached steps */
@@ -447,7 +413,6 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
                                                                     &emission_sd,
                                                                     &pray,
                                                                     tp,
-                                                                    num_samples,
                                                                     &ps,
                                                                     L);
 
@@ -466,79 +431,29 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
                }
 #endif  /* __VOLUME__ */
 
+               /* Shade background. */
                if(!hit) {
-                       /* 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  /* __PASSES__ */
-                                       break;
-                       }
-
-#ifdef __BACKGROUND__
-                       /* sample background shader */
-                       float3 L_background = indirect_background(kg, &emission_sd, &state, &ray);
-                       path_radiance_accum_background(L, &state, throughput, L_background);
-#endif  /* __BACKGROUND__ */
-
+                       kernel_path_background(kg, &state, &ray, throughput, &emission_sd, L);
                        break;
                }
 
-               /* setup shading */
+               /* Setup and evaluate shader. */
                shader_setup_from_ray(kg, &sd, &isect, &ray);
                shader_eval_surface(kg, &sd, &state, 0.0f, state.flag);
                shader_merge_closures(&sd);
 
-#ifdef __SHADOW_TRICKS__
-               if((sd.object_flag & SD_OBJECT_SHADOW_CATCHER)) {
-                       state.flag |= (PATH_RAY_SHADOW_CATCHER |
-                                      PATH_RAY_STORE_SHADOW_INFO);
-                       if(!kernel_data.background.transparent) {
-                               L->shadow_background_color =
-                                       indirect_background(kg, &emission_sd, &state, &ray);
-                       }
-                       L->shadow_radiance_sum = path_radiance_clamp_and_sum(kg, L);
-                       L->shadow_throughput = average(throughput);
-               }
-               else if(state.flag & PATH_RAY_SHADOW_CATCHER) {
-                       /* Only update transparency after shadow catcher bounce. */
-                       L->shadow_transparency *=
-                               average(shader_bsdf_transparency(kg, &sd));
-               }
-#endif  /* __SHADOW_TRICKS__ */
-
-               /* holdout */
-#ifdef __HOLDOUT__
-               if((sd.flag & SD_HOLDOUT) || (sd.object_flag & SD_OBJECT_HOLDOUT_MASK)) {
-                       if(kernel_data.background.transparent) {
-                               float3 holdout_weight;
-                               if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) {
-                                       holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
-                               }
-                               else {
-                                       holdout_weight = shader_holdout_eval(kg, &sd);
-                               }
-                               /* any throughput is ok, should all be identical here */
-                               L->transparent += average(holdout_weight*throughput);
-                       }
-                       if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) {
-                               break;
-                       }
-               }
-#endif  /* __HOLDOUT__ */
-
-               /* holdout mask objects do not write data passes */
-               kernel_write_data_passes(kg, buffer, L, &sd, sample, &state, throughput);
-
-#ifdef __EMISSION__
-               /* emission */
-               if(sd.flag & SD_EMISSION) {
-                       float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf);
-                       path_radiance_accum_emission(L, throughput, emission, state.bounce);
+               /* Apply shadow catcher, holdout, emission. */
+               if(!kernel_path_shader_apply(kg,
+                                            &sd,
+                                            &state,
+                                            &ray,
+                                            throughput,
+                                            &emission_sd,
+                                            L,
+                                            buffer))
+               {
+                       break;
                }
-#endif  /* __EMISSION__ */
 
                /* transparency termination */
                if(state.flag & PATH_RAY_TRANSPARENT) {
@@ -620,10 +535,6 @@ ccl_device void kernel_branched_path_integrate(KernelGlobals *kg,
                kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack);
 #endif  /* __VOLUME__ */
        }
-
-#ifdef __SHADOW_TRICKS__
-       *is_shadow_catcher = (state.flag & PATH_RAY_SHADOW_CATCHER) != 0;
-#endif  /* __SHADOW_TRICKS__ */
 }
 
 ccl_device void kernel_branched_path_trace(KernelGlobals *kg,
@@ -645,14 +556,13 @@ ccl_device void kernel_branched_path_trace(KernelGlobals *kg,
 
        /* integrate */
        PathRadiance L;
-       bool is_shadow_catcher;
 
        if(ray.t != 0.0f) {
-               kernel_branched_path_integrate(kg, rng_hash, sample, ray, buffer, &L, &is_shadow_catcher);
-               kernel_write_result(kg, buffer, sample, &L, is_shadow_catcher);
+               kernel_branched_path_integrate(kg, rng_hash, sample, ray, buffer, &L);
+               kernel_write_result(kg, buffer, sample, &L);
        }
        else {
-               kernel_write_result(kg, buffer, sample, NULL, false);
+               kernel_write_result(kg, buffer, sample, NULL);
        }
 }
 
index b539224db31402aa0130cba02e97b7f4472920af..bb09b4ac08036e4dc2d73dadc84f1b5cb18ed67c 100644 (file)
@@ -29,6 +29,7 @@ ccl_device_inline void path_state_init(KernelGlobals *kg,
        state->rng_offset = PRNG_BASE_NUM;
        state->sample = sample;
        state->num_samples = kernel_data.integrator.aa_samples;
+       state->branch_factor = 1.0f;
 
        state->bounce = 0;
        state->diffuse_bounce = 0;
@@ -143,7 +144,7 @@ ccl_device_inline void path_state_next(KernelGlobals *kg, ccl_addr_space PathSta
 #endif
 }
 
-ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, PathState *state)
+ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, ccl_addr_space PathState *state)
 {
        uint flag = state->flag & PATH_RAY_ALL_VISIBILITY;
 
@@ -157,7 +158,9 @@ ccl_device_inline uint path_state_ray_visibility(KernelGlobals *kg, PathState *s
        return flag;
 }
 
-ccl_device_inline float path_state_continuation_probability(KernelGlobals *kg, ccl_addr_space PathState *state, const float3 throughput)
+ccl_device_inline float path_state_continuation_probability(KernelGlobals *kg,
+                                                            ccl_addr_space PathState *state,
+                                                            const float3 throughput)
 {
        if(state->flag & PATH_RAY_TRANSPARENT) {
                /* Transparent rays are treated separately with own max bounces. */
@@ -201,7 +204,7 @@ ccl_device_inline float path_state_continuation_probability(KernelGlobals *kg, c
 
        /* Probalistic termination: use sqrt() to roughly match typical view
         * transform and do path termination a bit later on average. */
-       return sqrtf(max3(fabs(throughput)));
+       return min(sqrtf(max3(fabs(throughput)) * state->branch_factor), 1.0f);
 }
 
 /* TODO(DingTo): Find more meaningful name for this */
@@ -214,5 +217,30 @@ ccl_device_inline void path_state_modify_bounce(ccl_addr_space PathState *state,
                state->bounce -= 1;
 }
 
+ccl_device_inline bool path_state_ao_bounce(KernelGlobals *kg, ccl_addr_space PathState *state)
+{
+    if(state->bounce <= kernel_data.integrator.ao_bounces) {
+        return false;
+    }
+
+    int bounce = state->bounce - state->transmission_bounce - (state->glossy_bounce > 0);
+    return (bounce > kernel_data.integrator.ao_bounces);
+}
+
+ccl_device_inline void path_state_branch(ccl_addr_space PathState *state,
+                                         int branch,
+                                         int num_branches)
+{
+       state->rng_offset += PRNG_BOUNCE_NUM;
+
+       if(num_branches > 1) {
+               /* Path is splitting into a branch, adjust so that each branch
+                * still gets a unique sample from the same sequence. */
+               state->sample = state->sample*num_branches + branch;
+               state->num_samples = state->num_samples*num_branches;
+               state->branch_factor *= num_branches;
+       }
+}
+
 CCL_NAMESPACE_END
 
index 9bccc9201e0a0491d4f6e85e54a047bbdd1bbae3..619d57e71fb8ad56b18d312e4e2bc7d0e44f4a7d 100644 (file)
@@ -124,7 +124,7 @@ bool kernel_path_subsurface_scatter(
                                ss_indirect->num_rays++;
                        }
                        else {
-                               path_radiance_accum_sample(L, hit_L, 1);
+                               path_radiance_accum_sample(L, hit_L);
                        }
                }
                return true;
@@ -145,7 +145,7 @@ ccl_device void kernel_path_subsurface_accum_indirect(
 {
        if(ss_indirect->tracing) {
                path_radiance_sum_indirect(L);
-               path_radiance_accum_sample(&ss_indirect->direct_L, L, 1);
+               path_radiance_accum_sample(&ss_indirect->direct_L, L);
                if(ss_indirect->num_rays == 0) {
                        *L = ss_indirect->direct_L;
                }
index 6c3a444e48aed7896e2c87a8140936c1169b6b2f..e798fcc6a2cec2fa5c6b8e630c5d1254fbb1553d 100644 (file)
@@ -85,17 +85,16 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(
                        float num_samples_inv = num_samples_adjust/num_samples;
 
                        for(int j = 0; j < num_samples; j++) {
-                               float light_t = path_branched_rng_1D(kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT);
                                float light_u, light_v;
                                path_branched_rng_2D(kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
                                float terminate = path_branched_rng_light_termination(kg, state->rng_hash, state, j, num_samples);
 
                                /* only sample triangle lights */
                                if(kernel_data.integrator.num_all_lights)
-                                       light_t = 0.5f*light_t;
+                                       light_u = 0.5f*light_u;
 
                                LightSample ls;
-                               if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+                               if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
                                        /* Same as above, probability needs to be corrected since the sampling was forced to select a mesh light. */
                                        if(kernel_data.integrator.num_all_lights)
                                                ls.pdf *= 2.0f;
@@ -118,13 +117,12 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(
        }
        else {
                /* sample one light at random */
-               float light_t = path_state_rng_1D(kg, state, PRNG_LIGHT);
                float light_u, light_v;
                path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
                float terminate = path_state_rng_light_termination(kg, state);
 
                LightSample ls;
-               if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+               if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
                        /* sample random light */
                        if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
                                /* trace shadow ray */
@@ -238,7 +236,6 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg,
 #endif
 
        /* sample illumination from lights to find path contribution */
-       float light_t = path_state_rng_1D(kg, state, PRNG_LIGHT);
        float light_u, light_v;
        path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
 
@@ -251,7 +248,7 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg,
 #endif
 
        LightSample ls;
-       if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+       if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
                float terminate = path_state_rng_light_termination(kg, state);
                if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
                        /* trace shadow ray */
index c9c7f447c42e9de35067a85bbda3ab3cac58fb32..e7e24f853c2caba551ac2796b7e863b54c1ff0fb 100644 (file)
@@ -31,7 +31,6 @@ ccl_device_inline void kernel_path_volume_connect_light(
                return;
 
        /* sample illumination from lights to find path contribution */
-       float light_t = path_state_rng_1D(kg, state, PRNG_LIGHT);
        float light_u, light_v;
        path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
 
@@ -41,11 +40,9 @@ ccl_device_inline void kernel_path_volume_connect_light(
        bool is_lamp;
 
        /* connect to light from given point where shader has been evaluated */
-#  ifdef __OBJECT_MOTION__
        light_ray.time = sd->time;
-#  endif
 
-       if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls))
+       if(light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls))
        {
                float terminate = path_state_rng_light_termination(kg, state);
                if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
@@ -135,9 +132,7 @@ ccl_device void kernel_branched_path_volume_connect_light(
        BsdfEval L_light;
        bool is_lamp;
 
-#  ifdef __OBJECT_MOTION__
        light_ray.time = sd->time;
-#  endif
 
        if(sample_all_lights) {
                /* lamp sampling */
@@ -166,11 +161,9 @@ ccl_device void kernel_branched_path_volume_connect_light(
                                VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
                                        state, ray, sd, &tp, rphase, rscatter, segment, (ls.t != FLT_MAX)? &ls.P: NULL, false);
 
-                               (void)result;
-                               kernel_assert(result == VOLUME_PATH_SCATTERED);
-
                                /* todo: split up light_sample so we don't have to call it again with new position */
-                               if(lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls)) {
+                               if(result == VOLUME_PATH_SCATTERED &&
+                                  lamp_light_sample(kg, i, light_u, light_v, sd->P, &ls)) {
                                        if(kernel_data.integrator.pdf_triangles != 0.0f)
                                                ls.pdf *= 2.0f;
 
@@ -195,16 +188,15 @@ ccl_device void kernel_branched_path_volume_connect_light(
 
                        for(int j = 0; j < num_samples; j++) {
                                /* sample random position on random triangle */
-                               float light_t = path_branched_rng_1D_for_decision(kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT);
                                float light_u, light_v;
                                path_branched_rng_2D(kg, state->rng_hash, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v);
 
                                /* only sample triangle lights */
                                if(kernel_data.integrator.num_all_lights)
-                                       light_t = 0.5f*light_t;
+                                       light_u = 0.5f*light_u;
 
                                LightSample ls;
-                               light_sample(kg, light_t, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
+                               light_sample(kg, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
 
                                float3 tp = throughput;
 
@@ -215,11 +207,9 @@ ccl_device void kernel_branched_path_volume_connect_light(
                                VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
                                        state, ray, sd, &tp, rphase, rscatter, segment, (ls.t != FLT_MAX)? &ls.P: NULL, false);
                                        
-                               (void)result;
-                               kernel_assert(result == VOLUME_PATH_SCATTERED);
-
                                /* todo: split up light_sample so we don't have to call it again with new position */
-                               if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+                               if(result == VOLUME_PATH_SCATTERED &&
+                                  light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
                                        if(kernel_data.integrator.num_all_lights)
                                                ls.pdf *= 2.0f;
 
@@ -239,12 +229,11 @@ ccl_device void kernel_branched_path_volume_connect_light(
        }
        else {
                /* sample random position on random light */
-               float light_t = path_state_rng_1D(kg, state, PRNG_LIGHT);
                float light_u, light_v;
                path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
 
                LightSample ls;
-               light_sample(kg, light_t, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
+               light_sample(kg, light_u, light_v, sd->time, ray->P, state->bounce, &ls);
 
                float3 tp = throughput;
 
@@ -255,11 +244,9 @@ ccl_device void kernel_branched_path_volume_connect_light(
                VolumeIntegrateResult result = kernel_volume_decoupled_scatter(kg,
                        state, ray, sd, &tp, rphase, rscatter, segment, (ls.t != FLT_MAX)? &ls.P: NULL, false);
                        
-               (void)result;
-               kernel_assert(result == VOLUME_PATH_SCATTERED);
-
                /* todo: split up light_sample so we don't have to call it again with new position */
-               if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
+               if(result == VOLUME_PATH_SCATTERED &&
+                  light_sample(kg, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) {
                        /* sample random light */
                        float terminate = path_state_rng_light_termination(kg, state);
                        if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) {
index 221d92f5de1b897d6265b5be129226c20c387917..b35ed3bd27965168c789cc794b9833715c83db5a 100644 (file)
@@ -296,17 +296,6 @@ ccl_device_inline float path_branched_rng_light_termination(
        return 0.0f;
 }
 
-ccl_device_inline void path_state_branch(ccl_addr_space PathState *state,
-                                         int branch,
-                                         int num_branches)
-{
-       /* path is splitting into a branch, adjust so that each branch
-        * still gets a unique sample from the same sequence */
-       state->rng_offset += PRNG_BOUNCE_NUM;
-       state->sample = state->sample*num_branches + branch;
-       state->num_samples = state->num_samples*num_branches;
-}
-
 ccl_device_inline uint lcg_state_init(PathState *state,
                                       uint scramble)
 {
index dd64f5b05baf6dd6fac8bcdf628474b5fbcb0765..5964aca0c78b2cd9e049297b7d771f8c78bc175b 100644 (file)
@@ -66,8 +66,8 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg,
        /* matrices and time */
 #ifdef __OBJECT_MOTION__
        shader_setup_object_transforms(kg, sd, ray->time);
-       sd->time = ray->time;
 #endif
+       sd->time = ray->time;
 
        sd->prim = kernel_tex_fetch(__prim_index, isect->prim);
        sd->ray_length = isect->t;
@@ -271,17 +271,17 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg,
        sd->u = u;
        sd->v = v;
 #endif
+       sd->time = time;
        sd->ray_length = t;
 
        sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
        sd->object_flag = 0;
        if(sd->object != OBJECT_NONE) {
                sd->object_flag |= kernel_tex_fetch(__object_flag,
-                                                              sd->object);
+                                                   sd->object);
 
 #ifdef __OBJECT_MOTION__
                shader_setup_object_transforms(kg, sd, time);
-               sd->time = time;
        }
        else if(lamp != LAMP_NONE) {
                sd->ob_tfm  = lamp_fetch_transform(kg, lamp, false);
@@ -385,9 +385,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat
        sd->shader = kernel_data.background.surface_shader;
        sd->flag = kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE);
        sd->object_flag = 0;
-#ifdef __OBJECT_MOTION__
        sd->time = ray->time;
-#endif
        sd->ray_length = 0.0f;
 
 #ifdef __INSTANCING__
@@ -427,9 +425,7 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s
        sd->shader = SHADER_NONE;
        sd->flag = 0;
        sd->object_flag = 0;
-#ifdef __OBJECT_MOTION__
        sd->time = ray->time;
-#endif
        sd->ray_length = 0.0f; /* todo: can we set this to some useful value? */
 
 #ifdef __INSTANCING__
index 22e085e94da7c780c1c15d3b3d90403b74391b50..3a534bbb6be98583e0f00c6dbcc4e4f67d8effa6 100644 (file)
 
 CCL_NAMESPACE_BEGIN
 
+#ifdef __VOLUME__
+typedef struct VolumeState {
+#  ifdef __SPLIT_KERNEL__
+#  else
+       PathState ps;
+#  endif
+} VolumeState;
+
+/* Get PathState ready for use for volume stack evaluation. */
+ccl_device_inline PathState *shadow_blocked_volume_path_state(
+        KernelGlobals *kg,
+        VolumeState *volume_state,
+        ccl_addr_space PathState *state,
+        ShaderData *sd,
+        Ray *ray)
+{
+#  ifdef __SPLIT_KERNEL__
+       ccl_addr_space PathState *ps =
+               &kernel_split_state.state_shadow[ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0)];
+#  else
+       PathState *ps = &volume_state->ps;
+#  endif
+       *ps = *state;
+       /* We are checking for shadow on the "other" side of the surface, so need
+        * to discard volume we are currently at.
+        */
+       if(dot(sd->Ng, ray->D) < 0.0f) {
+               kernel_volume_stack_enter_exit(kg, sd, ps->volume_stack);
+       }
+       return ps;
+}
+#endif  /* __VOLUME__ */
+
 /* Attenuate throughput accordingly to the given intersection event.
  * Returns true if the throughput is zero and traversal can be aborted.
  */
@@ -119,39 +152,6 @@ ccl_device bool shadow_blocked_opaque(KernelGlobals *kg,
 
 #    define SHADOW_STACK_MAX_HITS 64
 
-#    ifdef __VOLUME__
-struct VolumeState {
-#      ifdef __SPLIT_KERNEL__
-#      else
-               PathState ps;
-#      endif
-};
-
-/* Get PathState ready for use for volume stack evaluation. */
-ccl_device_inline PathState *shadow_blocked_volume_path_state(
-        KernelGlobals *kg,
-        VolumeState *volume_state,
-        ccl_addr_space PathState *state,
-        ShaderData *sd,
-        Ray *ray)
-{
-#      ifdef __SPLIT_KERNEL__
-       ccl_addr_space PathState *ps =
-               &kernel_split_state.state_shadow[ccl_global_id(1) * ccl_global_size(0) + ccl_global_id(0)];
-#      else
-       PathState *ps = &volume_state->ps;
-#      endif
-       *ps = *state;
-       /* We are checking for shadow on the "other" side of the surface, so need
-        * to discard volume we are currently at.
-        */
-       if(dot(sd->Ng, ray->D) < 0.0f) {
-               kernel_volume_stack_enter_exit(kg, sd, ps->volume_stack);
-       }
-       return ps;
-}
-#endif  //   __VOLUME__
-
 /* Actual logic with traversal loop implementation which is free from device
  * specific tweaks.
  *
index 8f65c00491c8979d9ab79c34a06877ed2a532fd9..1b4e926ca2872b1695d52fa378376246324d06f0 100644 (file)
@@ -292,7 +292,7 @@ enum PathTraceDimension {
        PRNG_BSDF_U = 0,
        PRNG_BSDF_V = 1,
        PRNG_BSDF = 2,
-       PRNG_LIGHT = 3,
+       PRNG_UNUSED3 = 3,
        PRNG_LIGHT_U = 4,
        PRNG_LIGHT_V = 5,
        PRNG_LIGHT_TERMINATE = 6,
@@ -535,11 +535,13 @@ typedef ccl_addr_space struct PathRadiance {
        /* Path radiance sum and throughput at the moment when ray hits shadow
         * catcher object.
         */
-       float3 shadow_radiance_sum;
        float shadow_throughput;
 
        /* Accumulated transparency along the path after shadow catcher bounce. */
        float shadow_transparency;
+
+       /* Indicate if any shadow catcher data is set. */
+       int has_shadow_catcher;
 #endif
 
 #ifdef __DENOISING_FEATURES__
@@ -1006,9 +1008,10 @@ typedef struct PathState {
 
        /* random number generator state */
        uint rng_hash;          /* per pixel hash */
-       int rng_offset;                 /* dimension offset */
-       int sample;                     /* path sample number */
-       int num_samples;                /* total number of times this path will be sampled */
+       int rng_offset;         /* dimension offset */
+       int sample;             /* path sample number */
+       int num_samples;        /* total number of times this path will be sampled */
+       float branch_factor;    /* number of branches in indirect paths */
 
        /* bounce counting */
        int bounce;
index 42094a9c3f80d077a55c222fc9c22f0e91599788..d8e8e192ab25208b558cb8ee8a14491e4a8f6549 100644 (file)
@@ -438,7 +438,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_homogeneous(
                float3 sigma_t = coeff.sigma_a + coeff.sigma_s;
                float3 transmittance = volume_color_transmittance(sigma_t, ray->t);
                float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, ray->t);
-               path_radiance_accum_emission(L, *throughput, emission, state->bounce);
+               path_radiance_accum_emission(L, state, *throughput, emission);
        }
 
        /* modify throughput */
@@ -558,7 +558,7 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance(
                        /* integrate emission attenuated by absorption */
                        if(L && (closure_flag & SD_EMISSION)) {
                                float3 emission = kernel_volume_emission_integrate(&coeff, closure_flag, transmittance, dt);
-                               path_radiance_accum_emission(L, tp, emission, state->bounce);
+                               path_radiance_accum_emission(L, state, tp, emission);
                        }
 
                        /* modify throughput */
@@ -997,8 +997,8 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter(
                        mis_weight = 2.0f*power_heuristic(pdf, distance_pdf);
                }
        }
-       if(sample_t < 1e-6f || pdf == 0.0f) {
-               return VOLUME_PATH_SCATTERED;
+       if(sample_t < 0.0f || pdf == 0.0f) {
+               return VOLUME_PATH_MISSED;
        }
 
        /* compute transmittance up to this step */
index 9fe4ec18e9eb9d533419b9fccf8158f17e0e1504..2c390593ba1458844745167f48c3bc599589076f 100644 (file)
@@ -188,7 +188,6 @@ ccl_device_noinline bool kernel_split_branched_path_surface_indirect_light_iter(
                        /* update state for next iteration */
                        branched_state->next_closure = i;
                        branched_state->next_sample = j+1;
-                       branched_state->num_samples = num_samples;
 
                        /* start the indirect path */
                        *tp *= num_samples_inv;
index 3b61319e349c79950b8cdb979b657c22149e3106..7b4d1299c120c59424b6f722dcd7370c274f92fb 100644 (file)
@@ -94,8 +94,7 @@ ccl_device void kernel_buffer_update(KernelGlobals *kg,
                buffer += (kernel_split_params.offset + pixel_x + pixel_y*stride) * kernel_data.film.pass_stride;
 
                /* accumulate result in output buffer */
-               bool is_shadow_catcher = (state->flag & PATH_RAY_SHADOW_CATCHER);
-               kernel_write_result(kg, buffer, sample, L, is_shadow_catcher);
+               kernel_write_result(kg, buffer, sample, L);
 
                ASSIGN_RAY_STATE(ray_state, ray_index, RAY_TO_REGENERATE);
        }
index 8e3f755555006e0b943c87fb0ed00f817c95f228..2aac66ecb84213ba2ace887b1fc2280bb87e57a6 100644 (file)
@@ -81,23 +81,20 @@ ccl_device void kernel_direct_lighting(KernelGlobals *kg,
 
                if(flag) {
                        /* Sample illumination from lights to find path contribution. */
-                       float light_t = path_state_rng_1D(kg, state, PRNG_LIGHT);
                        float light_u, light_v;
                        path_state_rng_2D(kg, state, PRNG_LIGHT_U, &light_u, &light_v);
                        float terminate = path_state_rng_light_termination(kg, state);
 
                        LightSample ls;
                        if(light_sample(kg,
-                                       light_t, light_u, light_v,
+                                       light_u, light_v,
                                        sd->time,
                                        sd->P,
                                        state->bounce,
                                        &ls)) {
 
                                Ray light_ray;
-#  ifdef __OBJECT_MOTION__
                                light_ray.time = sd->time;
-#  endif
 
                                BsdfEval L_light;
                                bool is_lamp;
index 478d83d633e3b9babdde5daa1d5dfaf2165f6328..2975aa200045de3ee30ea048151b0e276705947d 100644 (file)
@@ -72,7 +72,6 @@ ccl_device_noinline bool kernel_split_branched_path_volume_indirect_light_iter(K
                        /* start the indirect path */
                        branched_state->next_closure = 0;
                        branched_state->next_sample = j+1;
-                       branched_state->num_samples = num_samples;
 
                        /* Attempting to share too many samples is slow for volumes as it causes us to
                         * loop here more and have many calls to kernel_volume_integrate which evaluates
index 253b78526e78376898df89b7081b1ae505210950..9036b1e473d5ccc1897a1a07ab5575244dbad8e8 100644 (file)
@@ -94,161 +94,63 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao(
 
        ccl_global PathState *state = 0x0;
        float3 throughput;
-       uint sample;
 
        ccl_global char *ray_state = kernel_split_state.ray_state;
        ShaderData *sd = &kernel_split_state.sd[ray_index];
-       ccl_global float *buffer = kernel_split_params.buffer;
 
        if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
                uint work_index = kernel_split_state.work_array[ray_index];
-               sample = get_work_sample(kg, work_index, ray_index) + kernel_split_params.start_sample;
-
                uint pixel_x, pixel_y, tile_x, tile_y;
                get_work_pixel_tile_position(kg, &pixel_x, &pixel_y,
                                        &tile_x, &tile_y,
                                        work_index,
                                        ray_index);
 
+               ccl_global float *buffer = kernel_split_params.buffer;
                buffer += (kernel_split_params.offset + pixel_x + pixel_y * stride) * kernel_data.film.pass_stride;
 
+               ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
+               ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index];
+               PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
+
                throughput = kernel_split_state.throughput[ray_index];
                state = &kernel_split_state.path_state[ray_index];
 
-#ifdef __SHADOW_TRICKS__
-               if((sd->object_flag & SD_OBJECT_SHADOW_CATCHER)) {
-                       if(state->flag & PATH_RAY_CAMERA) {
-                               PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
-                               state->flag |= (PATH_RAY_SHADOW_CATCHER |
-                                               PATH_RAY_STORE_SHADOW_INFO);
-                               if(!kernel_data.background.transparent) {
-                                       ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
-                                       L->shadow_background_color = indirect_background(
-                                               kg,
-                                               &kernel_split_state.sd_DL_shadow[ray_index],
-                                               state,
-                                               ray);
-                               }
-                               L->shadow_radiance_sum = path_radiance_clamp_and_sum(kg, L);
-                               L->shadow_throughput = average(throughput);
-                       }
-               }
-               else if(state->flag & PATH_RAY_SHADOW_CATCHER) {
-                       /* Only update transparency after shadow catcher bounce. */
-                       PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
-                       L->shadow_transparency *= average(shader_bsdf_transparency(kg, sd));
-               }
-#endif  /* __SHADOW_TRICKS__ */
-
-               /* holdout */
-#ifdef __HOLDOUT__
-               if(((sd->flag & SD_HOLDOUT) ||
-                   (sd->object_flag & SD_OBJECT_HOLDOUT_MASK)) &&
-                  (state->flag & PATH_RAY_CAMERA))
+               if(!kernel_path_shader_apply(kg,
+                                            sd,
+                                            state,
+                                            ray,
+                                            throughput,
+                                            emission_sd,
+                                            L,
+                                            buffer))
                {
-                       if(kernel_data.background.transparent) {
-                               float3 holdout_weight;
-                               if(sd->object_flag & SD_OBJECT_HOLDOUT_MASK) {
-                                       holdout_weight = make_float3(1.0f, 1.0f, 1.0f);
-                               }
-                               else {
-                                       holdout_weight = shader_holdout_eval(kg, sd);
-                               }
-                               /* any throughput is ok, should all be identical here */
-                               PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
-                               L->transparent += average(holdout_weight*throughput);
-                       }
-                       if(sd->object_flag & SD_OBJECT_HOLDOUT_MASK) {
-                               kernel_split_path_end(kg, ray_index);
-                       }
+                       kernel_split_path_end(kg, ray_index);
                }
-#endif  /* __HOLDOUT__ */
        }
 
        if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
-               PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
-
-#ifdef __BRANCHED_PATH__
-               if(!IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT))
-#endif  /* __BRANCHED_PATH__ */
-               {
-                       /* Holdout mask objects do not write data passes. */
-                       kernel_write_data_passes(kg,
-                                                    buffer,
-                                                    L,
-                                                    sd,
-                                                    sample,
-                                                    state,
-                                                    throughput);
-               }
-
-               /* Blurring of bsdf after bounces, for rays that have a small likelihood
-                * of following this particular path (diffuse, rough glossy.
-                */
-#ifndef __BRANCHED_PATH__
-               if(kernel_data.integrator.filter_glossy != FLT_MAX)
-#else
-               if(kernel_data.integrator.filter_glossy != FLT_MAX &&
-                  (!kernel_data.integrator.branched || IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)))
-#endif  /* __BRANCHED_PATH__ */
-               {
-                       float blur_pdf = kernel_data.integrator.filter_glossy*state->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) {
-                       /* TODO(sergey): is isect.t wrong here for transparent surfaces? */
-                       float3 emission = indirect_primitive_emission(
-                               kg,
-                               sd,
-                               kernel_split_state.isect[ray_index].t,
-                               state->flag,
-                               state->ray_pdf);
-                       path_radiance_accum_emission(L, throughput, emission, state->bounce);
-               }
-#endif  /* __EMISSION__ */
-
                /* 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.
                 */
-#ifndef __BRANCHED_PATH__
                float probability = path_state_continuation_probability(kg, state, throughput);
-#else
-               float probability = 1.0f;
-
-               if(!kernel_data.integrator.branched) {
-                       probability = path_state_continuation_probability(kg, state, throughput);
-               }
-               else if(IS_FLAG(ray_state, ray_index, RAY_BRANCHED_INDIRECT)) {
-                       int num_samples = kernel_split_state.branched_state[ray_index].num_samples;
-                       probability = path_state_continuation_probability(kg, state, throughput*num_samples);
-               }
-               else if(state->flag & PATH_RAY_TRANSPARENT) {
-                       probability = path_state_continuation_probability(kg, state, throughput);
-               }
-#endif
 
                if(probability == 0.0f) {
                        kernel_split_path_end(kg, ray_index);
                }
-
-               if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
-                       if(probability != 1.0f) {
-                               float terminate = path_state_rng_1D_for_decision(kg, state, PRNG_TERMINATE);
-                               if(terminate >= probability) {
-                                       kernel_split_path_end(kg, ray_index);
-                               }
-                               else {
-                                       kernel_split_state.throughput[ray_index] = throughput/probability;
-                               }
+               else if(probability < 1.0f) {
+                       float terminate = path_state_rng_1D_for_decision(kg, state, PRNG_TERMINATE);
+                       if(terminate >= probability) {
+                               kernel_split_path_end(kg, ray_index);
                        }
+                       else {
+                               kernel_split_state.throughput[ray_index] = throughput/probability;
+                       }
+               }
 
+               if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
+                       PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
                        kernel_update_denoising_features(kg, sd, state, L);
                }
        }
index 04d5769ef0db233b2c7dc1ffc7c75fdbed65ce06..437043a59717d26245173da3670b15da86a1ca7e 100644 (file)
@@ -33,7 +33,7 @@ ccl_device void kernel_indirect_background(KernelGlobals *kg)
                if(ray_index != QUEUE_EMPTY_SLOT) {
                        if(IS_STATE(ray_state, ray_index, RAY_ACTIVE)) {
                                ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
-                               if(state->bounce > kernel_data.integrator.ao_bounces) {
+                               if(path_state_ao_bounce(kg, state)) {
                                        kernel_split_path_end(kg, ray_index);
                                }
                        }
@@ -50,32 +50,16 @@ ccl_device void kernel_indirect_background(KernelGlobals *kg)
                return;
        }
 
-       ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
-       PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
-       ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
-       ccl_global float3 *throughput = &kernel_split_state.throughput[ray_index];
-
        if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) {
-               /* eval background shader if nothing hit */
-               if(kernel_data.background.transparent && (state->flag & PATH_RAY_CAMERA)) {
-                       L->transparent += average((*throughput));
-#ifdef __PASSES__
-                       if(!(kernel_data.film.pass_flag & PASS_BACKGROUND))
-#endif
-                               kernel_split_path_end(kg, ray_index);
-               }
+               ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
+               PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
+               ccl_global Ray *ray = &kernel_split_state.ray[ray_index];
+               float3 throughput = kernel_split_state.throughput[ray_index];
+               ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index];
 
-               if(IS_STATE(ray_state, ray_index, RAY_HIT_BACKGROUND)) {
-#ifdef __BACKGROUND__
-                       /* sample background shader */
-                       float3 L_background = indirect_background(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, ray);
-                       path_radiance_accum_background(L, state, (*throughput), L_background);
-#endif
-                       kernel_split_path_end(kg, ray_index);
-               }
+               kernel_path_background(kg, state, ray, throughput, emission_sd, L);
+               kernel_split_path_end(kg, ray_index);
        }
-
-
 }
 
 CCL_NAMESPACE_END
index c669d79ddcd70c730e710c8f346f6e019cba70fa..448456d167d689aa25d56b2629b10db3d90a01da 100644 (file)
@@ -57,27 +57,10 @@ ccl_device void kernel_lamp_emission(KernelGlobals *kg)
 
                float3 throughput = kernel_split_state.throughput[ray_index];
                Ray ray = kernel_split_state.ray[ray_index];
+               ccl_global Intersection *isect = &kernel_split_state.isect[ray_index];
+               ShaderData *emission_sd = &kernel_split_state.sd_DL_shadow[ray_index];
 
-#ifdef __LAMP_MIS__
-               if(kernel_data.integrator.use_lamp_mis && !(state->flag & PATH_RAY_CAMERA)) {
-                       /* ray starting from previous non-transparent bounce */
-                       Ray light_ray;
-
-                       light_ray.P = ray.P - state->ray_t*ray.D;
-                       state->ray_t += kernel_split_state.isect[ray_index].t;
-                       light_ray.D = ray.D;
-                       light_ray.t = state->ray_t;
-                       light_ray.time = ray.time;
-                       light_ray.dD = ray.dD;
-                       light_ray.dP = ray.dP;
-                       /* intersect with lamp */
-                       float3 emission;
-
-                       if(indirect_lamp_emission(kg, &kernel_split_state.sd_DL_shadow[ray_index], state, &light_ray, &emission)) {
-                               path_radiance_accum_emission(L, throughput, emission, state->bounce);
-                       }
-               }
-#endif  /* __LAMP_MIS__ */
+               kernel_path_lamp_emission(kg, state, &ray, throughput, isect, emission_sd, L);
        }
 }
 
index d0afd39ef296850505841ab2f1234665d13bead6..f5378bc172b2caff958c941b2f423d85082f16d6 100644 (file)
@@ -59,49 +59,13 @@ ccl_device void kernel_scene_intersect(KernelGlobals *kg)
                return;
        }
 
-       Intersection isect;
-       PathState state = kernel_split_state.path_state[ray_index];
+       ccl_global PathState *state = &kernel_split_state.path_state[ray_index];
        Ray ray = kernel_split_state.ray[ray_index];
-
-       /* intersect scene */
-       uint visibility = path_state_ray_visibility(kg, &state);
-
-       if(state.bounce > kernel_data.integrator.ao_bounces) {
-               visibility = PATH_RAY_SHADOW;
-               ray.t = kernel_data.background.ao_distance;
-       }
-
-#ifdef __HAIR__
-       float difl = 0.0f, extmax = 0.0f;
-       uint lcg_state = 0;
-
-       if(kernel_data.bvh.have_curves) {
-               if((kernel_data.cam.resolution == 1) && (state.flag & PATH_RAY_CAMERA)) {
-                       float3 pixdiff = ray.dD.dx + ray.dD.dy;
-                       /*pixdiff = pixdiff - dot(pixdiff, ray.D)*ray.D;*/
-                       difl = kernel_data.curve.minimum_width * len(pixdiff) * 0.5f;
-               }
-
-               extmax = kernel_data.curve.maximum_width;
-               lcg_state = lcg_state_init(&state, 0x51633e2d);
-       }
-
-       bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax);
-#else
-       bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f);
-#endif
-       kernel_split_state.isect[ray_index] = isect;
-
-#ifdef __KERNEL_DEBUG__
        PathRadiance *L = &kernel_split_state.path_radiance[ray_index];
 
-       if(state.flag & PATH_RAY_CAMERA) {
-               L->debug_data.num_bvh_traversed_nodes += isect.num_traversed_nodes;
-               L->debug_data.num_bvh_traversed_instances += isect.num_traversed_instances;
-               L->debug_data.num_bvh_intersections += isect.num_intersections;
-       }
-       L->debug_data.num_ray_bounces++;
-#endif
+       Intersection isect;
+       bool hit = kernel_path_scene_intersect(kg, state, &ray, &isect, L);
+       kernel_split_state.isect[ray_index] = isect;
 
        if(!hit) {
                /* Change the state of rays that hit the background;
index 08f0124b529205e6f7660e2ac18aca88406cf7e0..558d327bc76d9585c0c1e000b570bbe7ba51ccd2 100644 (file)
@@ -63,7 +63,7 @@ ccl_device_inline void kernel_split_path_end(KernelGlobals *kg, int ray_index)
                PathRadiance *orig_ray_L = &kernel_split_state.path_radiance[orig_ray];
 
                path_radiance_sum_indirect(L);
-               path_radiance_accum_sample(orig_ray_L, L, 1);
+               path_radiance_accum_sample(orig_ray_L, L);
 
                atomic_fetch_and_dec_uint32((ccl_global uint*)&kernel_split_state.branched_state[orig_ray].shared_sample_count);
 
index 3eae884d47955b4d56288febe102cf481b450394..e08afc22b20cf8320bea8f84866c8b763f7350f4 100644 (file)
@@ -72,7 +72,6 @@ typedef ccl_global struct SplitBranchedState {
        /* indirect loop state */
        int next_closure;
        int next_sample;
-       int num_samples;
 
 #ifdef __SUBSURFACE__
        int ss_next_closure;
index 1539ffb3545888aed99b1239114911aab30fdd12..b7d3866989d6bf8c486d59fa30d0654a7ff41d18 100644 (file)
@@ -131,6 +131,11 @@ def align_objects(context,
 
     cursor = (space if space and space.type == 'VIEW_3D' else scene).cursor_location
 
+    # We are accessing runtime data such as evaluated bounding box, so we need to
+    # be sure it is properly updated and valid (bounding box might be lost on operator
+    # redo).
+    scene.update()
+
     Left_Front_Up_SEL = [0.0, 0.0, 0.0]
     Right_Back_Down_SEL = [0.0, 0.0, 0.0]
 
index 00b9e0a283b109d241ae568409b824079a16afce..6f7b3286e40a45fb3466a15604ef4065e1bee318 100644 (file)
@@ -1135,9 +1135,13 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
                        if (fcu->totvert) {
                                float nmin, nmax;
                                
-                               /* get extents for this curve */
-                               /* TODO: allow enabling/disabling this? */
-                               calc_fcurve_range(fcu, &nmin, &nmax, false, true);
+                               /* get extents for this curve
+                                * - no "selected only", since this is often used in the backend
+                                * - no "minimum length" (we will apply this later), otherwise
+                                *   single-keyframe curves will increase the overall length by
+                                *   a phantom frame (T50354)
+                                */
+                               calc_fcurve_range(fcu, &nmin, &nmax, false, false);
                                
                                /* compare to the running tally */
                                min = min_ff(min, nmin);
@@ -1190,7 +1194,9 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_
        }
        
        if (foundvert || foundmod) {
+               /* ensure that action is at least 1 frame long (for NLA strips to have a valid length) */
                if (min == max) max += 1.0f;
+               
                *start = min;
                *end = max;
        }
index ac9c60e8999ac1f876740ee05f50ce3c0e0a9e0a..fe84504327c4e149fb49247ff9cebae63fc558ea 100644 (file)
@@ -1092,13 +1092,10 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
                /* This is to address tricky issues with vertex-emitting when user tries (and expects) exact 1-1 vert/part
                 * distribution (see T47983 and its two example files). It allows us to consider pos as
                 * 'midpoint between v and v+1' (or 'p and p+1', depending whether we have more vertices than particles or not),
-                * and avoid stumbling over float imprecisions in element_sum. */
-               if (from == PART_FROM_VERT) {
-                       pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5;  /* We choose the smaller step. */
-               }
-               else {
-                       pos = 0.0;
-               }
+                * and avoid stumbling over float imprecisions in element_sum.
+                * Note: moved face and volume distribution to this as well (instead of starting at zero),
+                * for the same reasons, see T52682. */
+               pos = (totpart < totmapped) ? 0.5 / (double)totmapped : step * 0.5;  /* We choose the smaller step. */
 
                for (i = 0, p = 0; p < totpart; p++, pos += step) {
                        for ( ; (i < totmapped - 1) && (pos > (double)element_sum[i]); i++);
@@ -1137,7 +1134,7 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti
                
                if (jitlevel == 0) {
                        jitlevel= totpart/totelem;
-                       if (part->flag & PART_EDISTR) jitlevel*= 2;     /* looks better in general, not very scietific */
+                       if (part->flag & PART_EDISTR) jitlevel*= 2;     /* looks better in general, not very scientific */
                        if (jitlevel<3) jitlevel= 3;
                }
                
index e3dfd69d8ecca89d3ff22a72a2c9e97546a34f89..40db5efda279c81cb5511fef612b79a801c26e1c 100644 (file)
@@ -64,9 +64,21 @@ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rende
        /* Make sure node tree has previews.
         * Don't create previews in advance, this is done when adding preview operations.
         * Reserved preview size is determined by render output for now.
+        *
+        * We fit the aspect into COM_PREVIEW_SIZE x COM_PREVIEW_SIZE image to avoid
+        * insane preview resolution, which might even overflow preview dimensions.
         */
-       float aspect = rd->xsch > 0 ? (float)rd->ysch / (float)rd->xsch : 1.0f;
-       BKE_node_preview_init_tree(editingtree, COM_PREVIEW_SIZE, (int)(COM_PREVIEW_SIZE * aspect), false);
+       const float aspect = rd->xsch > 0 ? (float)rd->ysch / (float)rd->xsch : 1.0f;
+       int preview_width, preview_height;
+       if (aspect < 1.0f) {
+               preview_width = COM_PREVIEW_SIZE;
+               preview_height = (int)(COM_PREVIEW_SIZE * aspect);
+       }
+       else {
+               preview_width = (int)(COM_PREVIEW_SIZE / aspect);
+               preview_height = COM_PREVIEW_SIZE;
+       }
+       BKE_node_preview_init_tree(editingtree, preview_width, preview_height, false);
 
        /* initialize workscheduler, will check if already done. TODO deinitialize somewhere */
        bool use_opencl = (editingtree->flag & NTREE_COM_OPENCL) != 0;
index 75128de2d846bc8777ca11512f27817805bd8bd8..9a11ddbbceb40942887d4c874d49d48820cc2460 100644 (file)
@@ -15,8 +15,8 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
- * Contributor: 
- *             Jeroen Bakker 
+ * Contributor:
+ *             Jeroen Bakker
  *             Monique Dewanchand
  */
 
 #include "COM_TranslateOperation.h"
 #include "COM_RotateOperation.h"
 #include "COM_ScaleOperation.h"
+#include "COM_SetColorOperation.h"
 #include "COM_SetValueOperation.h"
+#include "COM_SetVectorOperation.h"
 
 RenderLayersNode::RenderLayersNode(bNode *editorNode) : Node(editorNode)
 {
        /* pass */
 }
 
-void RenderLayersNode::testSocketLink(NodeConverter &converter, const CompositorContext &context,
-                                      NodeOutput *output, RenderLayersProg *operation,
-                                      Scene *scene, int layerId, bool is_preview) const
+void RenderLayersNode::testSocketLink(NodeConverter &converter,
+                                      const CompositorContext &context,
+                                      NodeOutput *output,
+                                      RenderLayersProg *operation,
+                                      Scene *scene,
+                                      int layerId,
+                                      bool is_preview) const
 {
        operation->setScene(scene);
        operation->setLayerId(layerId);
@@ -43,45 +49,140 @@ void RenderLayersNode::testSocketLink(NodeConverter &converter, const Compositor
 
        converter.mapOutputSocket(output, operation->getOutputSocket());
        converter.addOperation(operation);
-       
+
        if (is_preview) /* only for image socket */
                converter.addPreview(operation->getOutputSocket());
 }
 
-void RenderLayersNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+void RenderLayersNode::testRenderLink(NodeConverter &converter,
+                                      const CompositorContext &context,
+                                      Render *re) const
 {
        Scene *scene = (Scene *)this->getbNode()->id;
-       short layerId = this->getbNode()->custom1;
-       Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL;
-       int numberOfOutputs = this->getNumberOfOutputSockets();
-       
-       if (re) {
-               RenderResult *rr = RE_AcquireResultRead(re);
-               if (rr) {
-                       SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, layerId);
-                       if (srl) {
-                               RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
-                               if (rl) {
-                                       for (int i = 0; i < numberOfOutputs; i++) {
-                                               NodeOutput *output = this->getOutputSocket(i);
-                                               NodeImageLayer *storage = (NodeImageLayer*) output->getbNodeSocket()->storage;
-                                               RenderPass *rpass = (RenderPass*) BLI_findstring(&rl->passes, storage->pass_name, offsetof(RenderPass, name));
-                                               if (rpass) {
-                                                       if (STREQ(rpass->name, RE_PASSNAME_COMBINED) && STREQ(output->getbNodeSocket()->name, "Alpha")) {
-                                                               testSocketLink(converter, context, output, new RenderLayersAlphaProg(rpass->name, COM_DT_VALUE, rpass->channels), scene, layerId, false);
-                                                       }
-                                                       else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
-                                                               testSocketLink(converter, context, output, new RenderLayersDepthProg(rpass->name, COM_DT_VALUE, rpass->channels), scene, layerId, false);
-                                                       }
-                                                       else {
-                                                               DataType type = ((rpass->channels == 4)? COM_DT_COLOR : ((rpass->channels == 3)? COM_DT_VECTOR : COM_DT_VALUE));
-                                                               testSocketLink(converter, context, output, new RenderLayersProg(rpass->name, type, rpass->channels), scene, layerId, STREQ(output->getbNodeSocket()->name, "Image"));
-                                                       }
-                                               }
-                                       }
-                               }
+       const short layerId = this->getbNode()->custom1;
+       RenderResult *rr = RE_AcquireResultRead(re);
+       if (rr == NULL) {
+               missingRenderLink(converter);
+               return;
+       }
+       SceneRenderLayer *srl = (SceneRenderLayer *)BLI_findlink(&scene->r.layers, layerId);
+       if (srl == NULL) {
+               missingRenderLink(converter);
+               return;
+       }
+       RenderLayer *rl = RE_GetRenderLayer(rr, srl->name);
+       if (rl == NULL) {
+               missingRenderLink(converter);
+               return;
+       }
+       const int num_outputs = this->getNumberOfOutputSockets();
+       for (int i = 0; i < num_outputs; i++) {
+               NodeOutput *output = this->getOutputSocket(i);
+               NodeImageLayer *storage = (NodeImageLayer*) output->getbNodeSocket()->storage;
+               RenderPass *rpass = (RenderPass*) BLI_findstring(
+                       &rl->passes,
+                       storage->pass_name,
+                       offsetof(RenderPass, name));
+               if (rpass == NULL) {
+                       missingSocketLink(converter, output);
+                       continue;
+               }
+               RenderLayersProg *operation;
+               bool is_preview;
+               if (STREQ(rpass->name, RE_PASSNAME_COMBINED) &&
+                   STREQ(output->getbNodeSocket()->name, "Alpha"))
+               {
+                       operation = new RenderLayersAlphaProg(rpass->name,
+                                                             COM_DT_VALUE,
+                                                             rpass->channels);
+                       is_preview = false;
+               }
+               else if (STREQ(rpass->name, RE_PASSNAME_Z)) {
+                       operation = new RenderLayersDepthProg(rpass->name,
+                                                             COM_DT_VALUE,
+                                                             rpass->channels);
+                       is_preview = false;
+               }
+               else {
+                       DataType type;
+                       switch (rpass->channels) {
+                               case 4: type = COM_DT_COLOR; break;
+                               case 3: type = COM_DT_VECTOR; break;
+                               case 1: type = COM_DT_VALUE; break;
+                               default:
+                                       BLI_assert(!"Unexpected number of channels for pass");
+                                       type = COM_DT_VALUE;
+                                       break;
                        }
+                       operation = new RenderLayersProg(rpass->name,
+                                                        type,
+                                                        rpass->channels);
+                       is_preview = STREQ(output->getbNodeSocket()->name, "Image");
+               }
+               testSocketLink(converter,
+                              context,
+                              output,
+                              operation,
+                              scene,
+                              layerId,
+                              is_preview);
+       }
+}
+
+void RenderLayersNode::missingSocketLink(NodeConverter &converter,
+                                         NodeOutput *output) const
+{
+       NodeOperation *operation;
+       switch (output->getDataType()) {
+               case COM_DT_COLOR:
+               {
+                       const float color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+                       SetColorOperation *color_operation = new SetColorOperation();
+                       color_operation->setChannels(color);
+                       operation = color_operation;
+                       break;
+               }
+               case COM_DT_VECTOR:
+               {
+                       const float vector[3] = {0.0f, 0.0f, 0.0f};
+                       SetVectorOperation *vector_operation = new SetVectorOperation();
+                       vector_operation->setVector(vector);
+                       operation = vector_operation;
+                       break;
+               }
+               case COM_DT_VALUE:
+               {
+                       SetValueOperation *value_operation = new SetValueOperation();
+                       value_operation->setValue(0.0f);
+                       operation = value_operation;
+                       break;
                }
+       }
+
+       converter.mapOutputSocket(output, operation->getOutputSocket());
+       converter.addOperation(operation);
+}
+
+void RenderLayersNode::missingRenderLink(NodeConverter &converter) const
+{
+       const int num_outputs = this->getNumberOfOutputSockets();
+       for (int i = 0; i < num_outputs; i++) {
+               NodeOutput *output = this->getOutputSocket(i);
+               missingSocketLink(converter, output);
+       }
+}
+
+void RenderLayersNode::convertToOperations(NodeConverter &converter,
+                                           const CompositorContext &context) const
+{
+       Scene *scene = (Scene *)this->getbNode()->id;
+       Render *re = (scene) ? RE_GetRender(scene->id.name) : NULL;
+
+       if (re != NULL) {
+               testRenderLink(converter, context, re);
                RE_ReleaseResult(re);
        }
+       else {
+               missingRenderLink(converter);
+       }
 }
index 1f733a9f4bb3f00ef30658c210e18dca37074f7f..5c6c5e17d1f909fceea9d6d35341d0a89c08f541 100644 (file)
@@ -24,6 +24,8 @@
 #include "DNA_node_types.h"
 #include "COM_RenderLayersProg.h"
 
+struct Render;
+
 /**
  * @brief RenderLayersNode
  * @ingroup Node
@@ -31,7 +33,8 @@
 class RenderLayersNode : public Node {
 public:
        RenderLayersNode(bNode *editorNode);
-       void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
+       void convertToOperations(NodeConverter &converter,
+                                const CompositorContext &context) const;
 private:
        void testSocketLink(NodeConverter &converter,
                            const CompositorContext &context,
@@ -40,4 +43,11 @@ private:
                            Scene *scene,
                            int layerId,
                            bool is_preview) const;
+       void testRenderLink(NodeConverter &converter,
+                           const CompositorContext &context,
+                           Render *re) const;
+
+       void missingSocketLink(NodeConverter &converter,
+                              NodeOutput *output) const;
+       void missingRenderLink(NodeConverter &converter) const;
 };
index f9c90713f400654af6f6c8d7f2c083d840f1b930..797262c685be3fc7d93ad4782b444d84b3b80684 100644 (file)
@@ -125,6 +125,15 @@ typedef struct bAnimListElem {
        void   *key_data;       /* motion data - mostly F-Curves, but can be other types too */
        
        
+       /* NOTE: id here is the "IdAdtTemplate"-style datablock (e.g. Object, Material, Texture, NodeTree)
+        *       from which evaluation of the RNA-paths takes place. It's used to figure out how deep
+        *       channels should be nested (e.g. for Textures/NodeTrees) in the tree, and allows property
+        *       lookups (e.g. for sliders and for inserting keyframes) to work. If we had instead used
+        *       bAction or something similar, none of this would be possible: although it's trivial
+        *       to use an IdAdtTemplate type to find the source action a channel (e.g. F-Curve) comes from
+        *       (i.e. in the AnimEditors, it *must* be the active action, as only that can be edited),
+        *       it's impossible to go the other way (i.e. one action may be used in multiple places).
+        */
        struct ID *id;          /* ID block that channel is attached to */
        struct AnimData *adt;   /* source of the animation data attached to ID block (for convenience) */
        
index eb2d1117f1ece9bb32e961c81c5e3f59d468f0f0..0a4989ebad43c872b9aeb963c4020305a3e58d18 100644 (file)
@@ -627,7 +627,9 @@ static Mesh *bake_mesh_new_from_object(EvaluationContext *eval_ctx, Main *bmain,
                ED_object_editmode_load(ob);
 
        Mesh *me = BKE_mesh_new_from_object(eval_ctx, bmain, scene, ob, 1, 2, 0, 0);
-       BKE_mesh_split_faces(me, true);
+       if (me->flag & ME_AUTOSMOOTH) {
+               BKE_mesh_split_faces(me, true);
+       }
 
        return me;
 }
index bee2379cd8195523fc6dc2fd23f5648ea9bf8f6f..67584fbe1f152667d9106bc43ac406a384758d18 100644 (file)
@@ -2154,8 +2154,9 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo
        if (node->custom1 == 0) {
                const float backdropWidth = backdrop->x;
                const float backdropHeight = backdrop->y;
-               const float cx  = x + snode->zoom * backdropWidth * node->custom3;
+               const float cx = x + snode->zoom * backdropWidth  * node->custom3;
                const float cy = y + snode->zoom * backdropHeight * node->custom4;
+               const float cross_size = 12 * U.pixelsize;
 
                Gwn_VertFormat *format = immVertexFormat();
                unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
@@ -2165,10 +2166,10 @@ static void node_composit_backdrop_viewer(SpaceNode *snode, ImBuf *backdrop, bNo
                immUniformColor3f(1.0f, 1.0f, 1.0f);
 
                immBegin(GWN_PRIM_LINES, 4);
-               immVertex2f(pos, cx - 25, cy - 25);
-               immVertex2f(pos, cx + 25, cy + 25);
-               immVertex2f(pos, cx + 25, cy - 25);
-               immVertex2f(pos, cx - 25, cy + 25);
+               immVertex2f(pos, cx - cross_size, cy - cross_size);
+               immVertex2f(pos, cx + cross_size, cy + cross_size);
+               immVertex2f(pos, cx + cross_size, cy - cross_size);
+               immVertex2f(pos, cx - cross_size, cy + cross_size);
                immEnd();
 
                immUnbindProgram();
index 1c6172ef667ca36369da8e2330ad2d2c738d830c..90b7ffd71bb8f54ec565b481f8a50ddb2de4c320 100644 (file)
@@ -267,9 +267,10 @@ void rna_PropertyGroup_unregister(Main *UNUSED(bmain), StructRNA *type)
        RNA_struct_free(&BLENDER_RNA, type);
 }
 
-StructRNA *rna_PropertyGroup_register(Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier,
-                                      StructValidateFunc validate, StructCallbackFunc UNUSED(call),
-                                      StructFreeFunc UNUSED(free))
+StructRNA *rna_PropertyGroup_register(
+        Main *UNUSED(bmain), ReportList *reports, void *data, const char *identifier,
+        StructValidateFunc validate, StructCallbackFunc UNUSED(call),
+        StructFreeFunc UNUSED(free))
 {
        PointerRNA dummyptr;
 
index 9745d8fae56c48d47aae8932a791af9c21c674a6..1f5ddddb74fc091be9fc964fc53fbb5fd849461c 100644 (file)
@@ -247,8 +247,9 @@ static void rna_KeyingSetInfo_unregister(Main *bmain, StructRNA *type)
        ANIM_keyingset_info_unregister(bmain, ksi);
 }
 
-static StructRNA *rna_KeyingSetInfo_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
-                                             StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_KeyingSetInfo_register(
+        Main *bmain, ReportList *reports, void *data, const char *identifier,
+        StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
 {
        KeyingSetInfo dummyksi = {NULL};
        KeyingSetInfo *ksi;
index 7bcf116d6b770dbb932e1d5de0148f13502384c8..130dbad8b930f225537be655504be429e9ee27f2 100644 (file)
@@ -310,8 +310,9 @@ static void rna_RenderEngine_unregister(Main *UNUSED(bmain), StructRNA *type)
        BLI_freelinkN(&R_engines, et);
 }
 
-static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
-                                            StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_RenderEngine_register(
+        Main *bmain, ReportList *reports, void *data, const char *identifier,
+        StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
 {
        RenderEngineType *et, dummyet = {NULL};
        RenderEngine dummyengine = {NULL};
index 12af5dc828743decb164e05e6aa2f3bb1649d6c4..08038b0b1ffd71feb3e0dd4010fb178dcf5708ff 100644 (file)
@@ -185,8 +185,9 @@ static void rna_Panel_unregister(Main *UNUSED(bmain), StructRNA *type)
        WM_main_add_notifier(NC_WINDOW, NULL);
 }
 
-static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
-                                     StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_Panel_register(
+        Main *bmain, ReportList *reports, void *data, const char *identifier,
+        StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
 {
        ARegionType *art;
        PanelType *pt, dummypt = {NULL};
@@ -469,8 +470,9 @@ static void rna_UIList_unregister(Main *UNUSED(bmain), StructRNA *type)
        WM_main_add_notifier(NC_WINDOW, NULL);
 }
 
-static StructRNA *rna_UIList_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
-                                      StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_UIList_register(
+        Main *bmain, ReportList *reports, void *data, const char *identifier,
+        StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
 {
        uiListType *ult, dummyult = {NULL};
        uiList dummyuilist = {NULL};
@@ -571,8 +573,9 @@ static void rna_Header_unregister(Main *UNUSED(bmain), StructRNA *type)
        WM_main_add_notifier(NC_WINDOW, NULL);
 }
 
-static StructRNA *rna_Header_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
-                                      StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_Header_register(
+        Main *bmain, ReportList *reports, void *data, const char *identifier,
+        StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
 {
        ARegionType *art;
        HeaderType *ht, dummyht = {NULL};
@@ -699,8 +702,9 @@ static void rna_Menu_unregister(Main *UNUSED(bmain), StructRNA *type)
        WM_main_add_notifier(NC_WINDOW, NULL);
 }
 
-static StructRNA *rna_Menu_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
-                                    StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_Menu_register(
+        Main *bmain, ReportList *reports, void *data, const char *identifier,
+        StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
 {
        MenuType *mt, dummymt = {NULL};
        Menu dummymenu = {NULL};
index a2cc808f90b870c374e0be6f48ca02f100cbe019..6a8b42913bd640cfbab999ec066a21d9e098dba9 100644 (file)
@@ -591,8 +591,9 @@ static void rna_AddonPref_unregister(Main *UNUSED(bmain), StructRNA *type)
        WM_main_add_notifier(NC_WINDOW, NULL);
 }
 
-static StructRNA *rna_AddonPref_register(Main *bmain, ReportList *reports, void *data, const char *identifier,
-                                         StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
+static StructRNA *rna_AddonPref_register(
+        Main *bmain, ReportList *reports, void *data, const char *identifier,
+        StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free)
 {
        bAddonPrefType *apt, dummyapt = {{'\0'}};
        bAddon dummyaddon = {NULL};
index 68707f163afc294eef2a8c72ceda259207a7d92f..0b6d31ef90281225274c96d7cdfc0530aaf24f4b 100644 (file)
@@ -1564,20 +1564,13 @@ void zspan_scanconvert(ZSpan *zspan, void *handle, float *v1, float *v2, float *
        vy0= ((double)my2)*vyd + (double)xx1;
        
        /* correct span */
-       sn1= (my0 + my2)/2;
-       if (zspan->span1[sn1] < zspan->span2[sn1]) {
-               span1= zspan->span1+my2;
-               span2= zspan->span2+my2;
-       }
-       else {
-               span1= zspan->span2+my2;
-               span2= zspan->span1+my2;
-       }
+       span1= zspan->span1+my2;
+       span2= zspan->span2+my2;
        
        for (i = 0, y = my2; y >= my0; i++, y--, span1--, span2--) {
                
-               sn1= floor(*span1);
-               sn2= floor(*span2);
+               sn1= floor(min_ff(*span1, *span2));
+               sn2= floor(max_ff(*span1, *span2));
                sn1++; 
                
                if (sn2>=rectx) sn2= rectx-1;
index 4d5c0934cf26071fd8d467d151b8f1a2c6fe279e..a3460823e69496d22dae7170a6a74afc532394b5 100644 (file)
@@ -534,6 +534,7 @@ if(WITH_CYCLES)
                if(WITH_OPENGL_TESTS)
                        add_cycles_render_test(opengl)
                endif()
+               add_cycles_render_test(bake)
                add_cycles_render_test(denoise)
                add_cycles_render_test(displacement)
                add_cycles_render_test(image_data_types)
index ba4c04f7cf306db9b33b8aade6276d9b15f4368f..fde0b6bdcba27c756b08eafd31f06c455413f25c 100755 (executable)
@@ -77,6 +77,22 @@ def render_file(filepath):
             '--python', os.path.join(basedir,
                                      "util",
                                      "render_opengl.py")]
+    elif subject == 'bake':
+        command = [
+            BLENDER,
+            "-b",
+            "-noaudio",
+            "--factory-startup",
+            "--enable-autoexec",
+            filepath,
+            "-E", "CYCLES"]
+        command += custom_args
+        command += [
+            "-o", TEMP_FILE_MASK,
+            "-F", "PNG",
+            '--python', os.path.join(basedir,
+                                     "util",
+                                     "render_bake.py")]
     else:
         command = [
             BLENDER,
@@ -142,7 +158,7 @@ def test_get_images(filepath):
         os.makedirs(diff_dirpath)
     diff_img = os.path.join(diff_dirpath, testname + ".diff.png")
 
-    return ref_img, new_img, diff_img
+    return old_img, ref_img, new_img, diff_img
 
 
 class Report:
@@ -239,7 +255,7 @@ class Report:
         name = test_get_name(filepath)
         name = name.replace('_', ' ')
 
-        ref_img, new_img, diff_img = test_get_images(filepath)
+        old_img, ref_img, new_img, diff_img = test_get_images(filepath)
 
         status = error if error else ""
         style = """ style="background-color: #f99;" """ if error else ""
@@ -266,7 +282,7 @@ class Report:
 
 
 def verify_output(report, filepath):
-    ref_img, new_img, diff_img = test_get_images(filepath)
+    old_img, ref_img, new_img, diff_img = test_get_images(filepath)
 
     # copy new image
     if os.path.exists(new_img):
@@ -274,25 +290,35 @@ def verify_output(report, filepath):
     if os.path.exists(TEMP_FILE):
         shutil.copy(TEMP_FILE, new_img)
 
+    update = os.getenv('CYCLESTEST_UPDATE')
+
+    if os.path.exists(ref_img):
+        # diff test with threshold
+        command = (
+            IDIFF,
+            "-fail", "0.016",
+            "-failpercent", "1",
+            ref_img,
+            TEMP_FILE,
+            )
+        try:
+            subprocess.check_output(command)
+            failed = False
+        except subprocess.CalledProcessError as e:
+            if VERBOSE:
+                print_message(e.output.decode("utf-8"))
+            failed = e.returncode != 1
+    else:
+        if not update:
+            return False
 
-    if not os.path.exists(ref_img):
-        return False
+        failed = True
 
-    # diff test with threshold
-    command = (
-        IDIFF,
-        "-fail", "0.016",
-        "-failpercent", "1",
-        ref_img,
-        TEMP_FILE,
-        )
-    try:
-        subprocess.check_output(command)
+    if failed and update:
+        # update reference
+        shutil.copy(new_img, ref_img)
+        shutil.copy(new_img, old_img)
         failed = False
-    except subprocess.CalledProcessError as e:
-        if VERBOSE:
-            print_message(e.output.decode("utf-8"))
-        failed = e.returncode != 1
 
     # generate diff image
     command = (