diff options
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 = ( |