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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbuild_files/utils/build_tgz.sh6
-rw-r--r--intern/cycles/kernel/closure/bssrdf.h3
-rw-r--r--intern/cycles/kernel/kernel_accumulate.h232
-rw-r--r--intern/cycles/kernel/kernel_bake.h12
-rw-r--r--intern/cycles/kernel/kernel_emission.h2
-rw-r--r--intern/cycles/kernel/kernel_light.h57
-rw-r--r--intern/cycles/kernel/kernel_passes.h30
-rw-r--r--intern/cycles/kernel/kernel_path.h901
-rw-r--r--intern/cycles/kernel/kernel_path_branched.h136
-rw-r--r--intern/cycles/kernel/kernel_path_state.h34
-rw-r--r--intern/cycles/kernel/kernel_path_subsurface.h4
-rw-r--r--intern/cycles/kernel/kernel_path_surface.h11
-rw-r--r--intern/cycles/kernel/kernel_path_volume.h33
-rw-r--r--intern/cycles/kernel/kernel_random.h11
-rw-r--r--intern/cycles/kernel/kernel_shader.h10
-rw-r--r--intern/cycles/kernel/kernel_shadow.h66
-rw-r--r--intern/cycles/kernel/kernel_types.h13
-rw-r--r--intern/cycles/kernel/kernel_volume.h8
-rw-r--r--intern/cycles/kernel/split/kernel_branched.h1
-rw-r--r--intern/cycles/kernel/split/kernel_buffer_update.h3
-rw-r--r--intern/cycles/kernel/split/kernel_direct_lighting.h5
-rw-r--r--intern/cycles/kernel/split/kernel_do_volume.h1
-rw-r--r--intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h146
-rw-r--r--intern/cycles/kernel/split/kernel_indirect_background.h32
-rw-r--r--intern/cycles/kernel/split/kernel_lamp_emission.h23
-rw-r--r--intern/cycles/kernel/split/kernel_scene_intersect.h44
-rw-r--r--intern/cycles/kernel/split/kernel_split_common.h2
-rw-r--r--intern/cycles/kernel/split/kernel_split_data_types.h1
-rw-r--r--release/scripts/startup/bl_operators/object_align.py5
-rw-r--r--source/blender/blenkernel/intern/action.c12
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c13
-rw-r--r--source/blender/compositor/intern/COM_compositor.cpp16
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.cpp173
-rw-r--r--source/blender/compositor/nodes/COM_RenderLayersNode.h12
-rw-r--r--source/blender/editors/include/ED_anim_api.h9
-rw-r--r--source/blender/editors/object/object_bake_api.c4
-rw-r--r--source/blender/editors/space_node/drawnode.c11
-rw-r--r--source/blender/makesrna/intern/rna_ID.c7
-rw-r--r--source/blender/makesrna/intern/rna_animation.c5
-rw-r--r--source/blender/makesrna/intern/rna_render.c5
-rw-r--r--source/blender/makesrna/intern/rna_ui.c20
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c5
-rw-r--r--source/blender/render/intern/source/zbuf.c15
-rw-r--r--tests/python/CMakeLists.txt1
-rwxr-xr-xtests/python/cycles_render_tests.py64
45 files changed, 1042 insertions, 1162 deletions
diff --git a/build_files/utils/build_tgz.sh b/build_files/utils/build_tgz.sh
index 865df277605..c568d17db1c 100755
--- a/build_files/utils/build_tgz.sh
+++ b/build_files/utils/build_tgz.sh
@@ -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"
diff --git a/intern/cycles/kernel/closure/bssrdf.h b/intern/cycles/kernel/closure/bssrdf.h
index f733ea4c517..06221189060 100644
--- a/intern/cycles/kernel/closure/bssrdf.h
+++ b/intern/cycles/kernel/closure/bssrdf.h
@@ -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;
diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h
index 82d3c153bf5..5e604586557 100644
--- a/intern/cycles/kernel/kernel_accumulate.h
+++ b/intern/cycles/kernel/kernel_accumulate.h
@@ -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
diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h
index 8af1187213d..b05f6e9ed5e 100644
--- a/intern/cycles/kernel/kernel_bake.h
+++ b/intern/cycles/kernel/kernel_bake.h
@@ -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;
}
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
index 48a8e53be33..13d4759a9ec 100644
--- a/intern/cycles/kernel/kernel_emission.h
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -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;
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
index 59db6cbd430..c806deee8e7 100644
--- a/intern/cycles/kernel/kernel_light.h
+++ b/intern/cycles/kernel/kernel_light.h
@@ -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);
diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h
index d454cce6e30..fff7f4cfdb7 100644
--- a/intern/cycles/kernel/kernel_passes.h
+++ b/intern/cycles/kernel/kernel_passes.h
@@ -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,
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
index 3319e2c2435..fc157feb28c 100644
--- a/intern/cycles/kernel/kernel_path.h
+++ b/intern/cycles/kernel/kernel_path.h
@@ -50,6 +50,294 @@
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__ */
diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h
index dde40674ee6..3994d8d4954 100644
--- a/intern/cycles/kernel/kernel_path_branched.h
+++ b/intern/cycles/kernel/kernel_path_branched.h
@@ -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);
}
}
diff --git a/intern/cycles/kernel/kernel_path_state.h b/intern/cycles/kernel/kernel_path_state.h
index b539224db31..bb09b4ac080 100644
--- a/intern/cycles/kernel/kernel_path_state.h
+++ b/intern/cycles/kernel/kernel_path_state.h
@@ -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
diff --git a/intern/cycles/kernel/kernel_path_subsurface.h b/intern/cycles/kernel/kernel_path_subsurface.h
index 9bccc9201e0..619d57e71fb 100644
--- a/intern/cycles/kernel/kernel_path_subsurface.h
+++ b/intern/cycles/kernel/kernel_path_subsurface.h
@@ -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;
}
diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h
index 6c3a444e48a..e798fcc6a2c 100644
--- a/intern/cycles/kernel/kernel_path_surface.h
+++ b/intern/cycles/kernel/kernel_path_surface.h
@@ -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 */
diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h
index c9c7f447c42..e7e24f853c2 100644
--- a/intern/cycles/kernel/kernel_path_volume.h
+++ b/intern/cycles/kernel/kernel_path_volume.h
@@ -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)) {
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
index 221d92f5de1..b35ed3bd279 100644
--- a/intern/cycles/kernel/kernel_random.h
+++ b/intern/cycles/kernel/kernel_random.h
@@ -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)
{
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
index dd64f5b05ba..5964aca0c78 100644
--- a/intern/cycles/kernel/kernel_shader.h
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -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__
diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h
index 22e085e94da..3a534bbb6be 100644
--- a/intern/cycles/kernel/kernel_shadow.h
+++ b/intern/cycles/kernel/kernel_shadow.h
@@ -16,6 +16,39 @@
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.
*
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index 8f65c00491c..1b4e926ca28 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -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;
diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h
index 42094a9c3f8..d8e8e192ab2 100644
--- a/intern/cycles/kernel/kernel_volume.h
+++ b/intern/cycles/kernel/kernel_volume.h
@@ -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 */
diff --git a/intern/cycles/kernel/split/kernel_branched.h b/intern/cycles/kernel/split/kernel_branched.h
index 9fe4ec18e9e..2c390593ba1 100644
--- a/intern/cycles/kernel/split/kernel_branched.h
+++ b/intern/cycles/kernel/split/kernel_branched.h
@@ -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;
diff --git a/intern/cycles/kernel/split/kernel_buffer_update.h b/intern/cycles/kernel/split/kernel_buffer_update.h
index 3b61319e349..7b4d1299c12 100644
--- a/intern/cycles/kernel/split/kernel_buffer_update.h
+++ b/intern/cycles/kernel/split/kernel_buffer_update.h
@@ -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);
}
diff --git a/intern/cycles/kernel/split/kernel_direct_lighting.h b/intern/cycles/kernel/split/kernel_direct_lighting.h
index 8e3f7555550..2aac66ecb84 100644
--- a/intern/cycles/kernel/split/kernel_direct_lighting.h
+++ b/intern/cycles/kernel/split/kernel_direct_lighting.h
@@ -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;
diff --git a/intern/cycles/kernel/split/kernel_do_volume.h b/intern/cycles/kernel/split/kernel_do_volume.h
index 478d83d633e..2975aa20004 100644
--- a/intern/cycles/kernel/split/kernel_do_volume.h
+++ b/intern/cycles/kernel/split/kernel_do_volume.h
@@ -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
diff --git a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
index 253b78526e7..9036b1e473d 100644
--- a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
+++ b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h
@@ -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);
}
}
diff --git a/intern/cycles/kernel/split/kernel_indirect_background.h b/intern/cycles/kernel/split/kernel_indirect_background.h
index 04d5769ef0d..437043a5971 100644
--- a/intern/cycles/kernel/split/kernel_indirect_background.h
+++ b/intern/cycles/kernel/split/kernel_indirect_background.h
@@ -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
diff --git a/intern/cycles/kernel/split/kernel_lamp_emission.h b/intern/cycles/kernel/split/kernel_lamp_emission.h
index c669d79ddcd..448456d167d 100644
--- a/intern/cycles/kernel/split/kernel_lamp_emission.h
+++ b/intern/cycles/kernel/split/kernel_lamp_emission.h
@@ -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);
}
}
diff --git a/intern/cycles/kernel/split/kernel_scene_intersect.h b/intern/cycles/kernel/split/kernel_scene_intersect.h
index d0afd39ef29..f5378bc172b 100644
--- a/intern/cycles/kernel/split/kernel_scene_intersect.h
+++ b/intern/cycles/kernel/split/kernel_scene_intersect.h
@@ -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;
diff --git a/intern/cycles/kernel/split/kernel_split_common.h b/intern/cycles/kernel/split/kernel_split_common.h
index 08f0124b529..558d327bc76 100644
--- a/intern/cycles/kernel/split/kernel_split_common.h
+++ b/intern/cycles/kernel/split/kernel_split_common.h
@@ -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);
diff --git a/intern/cycles/kernel/split/kernel_split_data_types.h b/intern/cycles/kernel/split/kernel_split_data_types.h
index 3eae884d479..e08afc22b20 100644
--- a/intern/cycles/kernel/split/kernel_split_data_types.h
+++ b/intern/cycles/kernel/split/kernel_split_data_types.h
@@ -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;
diff --git a/release/scripts/startup/bl_operators/object_align.py b/release/scripts/startup/bl_operators/object_align.py
index 1539ffb3545..b7d3866989d 100644
--- a/release/scripts/startup/bl_operators/object_align.py
+++ b/release/scripts/startup/bl_operators/object_align.py
@@ -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]
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 00b9e0a283b..6f7b3286e40 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -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;
}
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
index ac9c60e8999..fe84504327c 100644
--- a/source/blender/blenkernel/intern/particle_distribute.c
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -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;
}
diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp
index e3dfd69d8ec..40db5efda27 100644
--- a/source/blender/compositor/intern/COM_compositor.cpp
+++ b/source/blender/compositor/intern/COM_compositor.cpp
@@ -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;
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
index 75128de2d84..9a11ddbbceb 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cpp
@@ -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
*/
@@ -25,16 +25,22 @@
#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);
+ }
}
diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.h b/source/blender/compositor/nodes/COM_RenderLayersNode.h
index 1f733a9f4bb..5c6c5e17d1f 100644
--- a/source/blender/compositor/nodes/COM_RenderLayersNode.h
+++ b/source/blender/compositor/nodes/COM_RenderLayersNode.h
@@ -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;
};
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index f9c90713f40..797262c685b 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -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) */
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index eb2d1117f1e..0a4989ebad4 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -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;
}
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index bee2379cd81..67584fbe1f1 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -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();
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 1c6172ef667..90b7ffd71bb 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -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;
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 9745d8fae56..1f5ddddb74f 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -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;
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 7bcf116d6b7..130dbad8b93 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -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};
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index 12af5dc8287..08038b0b1ff 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -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};
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index a2cc808f90b..6a8b42913bd 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -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};
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 68707f163af..0b6d31ef902 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -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;
diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt
index 4d5c0934cf2..a3460823e69 100644
--- a/tests/python/CMakeLists.txt
+++ b/tests/python/CMakeLists.txt
@@ -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)
diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py
index ba4c04f7cf3..fde0b6bdcba 100755
--- a/tests/python/cycles_render_tests.py
+++ b/tests/python/cycles_render_tests.py
@@ -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 = (