diff options
author | Brecht Van Lommel <brecht@blender.org> | 2021-09-20 17:16:11 +0300 |
---|---|---|
committer | Brecht Van Lommel <brecht@blender.org> | 2021-10-19 16:11:09 +0300 |
commit | fd77a28031daff3122ded3a1cb37a7fb44feedf6 (patch) | |
tree | f54967b7f5f1175555aa21d613137fe436d7fc8c /intern/cycles/bvh/bvh_embree.cpp | |
parent | d06828f0b8ebb083de59fd2cb8c5f8fe6af1da22 (diff) |
Cycles: bake transparent shadows for hair
These transparent shadows can be expansive to evaluate. Especially on the
GPU they can lead to poor occupancy when only some pixels require many kernel
launches to trace and evaluate many layers of transparency.
Baked transparency allows tracing a single ray in many cases by accumulating
the throughput directly in the intersection program without recording hits
or evaluating shaders. Transparency is baked at curve vertices and
interpolated, for most shaders this will look practically the same as actual
shader evaluation.
Fixes T91428, performance regression with spring demo file due to transparent
hair, and makes it render significantly faster than Blender 2.93.
Differential Revision: https://developer.blender.org/D12880
Diffstat (limited to 'intern/cycles/bvh/bvh_embree.cpp')
-rw-r--r-- | intern/cycles/bvh/bvh_embree.cpp | 45 |
1 files changed, 31 insertions, 14 deletions
diff --git a/intern/cycles/bvh/bvh_embree.cpp b/intern/cycles/bvh/bvh_embree.cpp index 343d62dedf4..cd19e009bf3 100644 --- a/intern/cycles/bvh/bvh_embree.cpp +++ b/intern/cycles/bvh/bvh_embree.cpp @@ -80,31 +80,49 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args) Intersection current_isect; kernel_embree_convert_hit(kg, ray, hit, ¤t_isect); - /* If no transparent shadows, all light is blocked. */ + /* If no transparent shadows or max number of hits exceeded, all light is blocked. */ const int flags = intersection_get_shader_flags(kg, current_isect.prim, current_isect.type); - if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->max_hits == 0) { + if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->num_hits >= ctx->max_hits) { ctx->opaque_hit = true; return; } + ++ctx->num_hits; + + /* Always use baked shadow transparency for curves. */ + if (current_isect.type & PRIMITIVE_ALL_CURVE) { + ctx->throughput *= intersection_curve_shadow_transparency( + kg, current_isect.object, current_isect.prim, current_isect.u); + + if (ctx->throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) { + ctx->opaque_hit = true; + return; + } + else { + *args->valid = 0; + return; + } + } + /* Test if we need to record this transparent intersection. */ - if (ctx->num_hits < ctx->max_hits || ray->tfar < ctx->max_t) { + const uint max_record_hits = min(ctx->max_hits, INTEGRATOR_SHADOW_ISECT_SIZE); + if (ctx->num_recorded_hits < max_record_hits || ray->tfar < ctx->max_t) { /* If maximum number of hits was reached, replace the intersection with the * highest distance. We want to find the N closest intersections. */ - const int num_recorded_hits = min(ctx->num_hits, ctx->max_hits); - int isect_index = num_recorded_hits; - if (num_recorded_hits + 1 >= ctx->max_hits) { + const uint num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits); + uint isect_index = num_recorded_hits; + if (num_recorded_hits + 1 >= max_record_hits) { float max_t = ctx->isect_s[0].t; - int max_recorded_hit = 0; + uint max_recorded_hit = 0; - for (int i = 1; i < num_recorded_hits; ++i) { + for (uint i = 1; i < num_recorded_hits; ++i) { if (ctx->isect_s[i].t > max_t) { max_recorded_hit = i; max_t = ctx->isect_s[i].t; } } - if (num_recorded_hits >= ctx->max_hits) { + if (num_recorded_hits >= max_record_hits) { isect_index = max_recorded_hit; } @@ -118,10 +136,9 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args) ctx->isect_s[isect_index] = current_isect; } - /* Always increase the number of hits, even beyond ray.max_hits so that - * the caller can detect this as and consider it opaque, or trace another - * ray. */ - ++ctx->num_hits; + /* Always increase the number of recorded hits, even beyond the maximum, + * so that we can detect this and trace another ray if needed. */ + ++ctx->num_recorded_hits; /* This tells Embree to continue tracing. */ *args->valid = 0; @@ -160,7 +177,7 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args) if (ctx->lcg_state) { /* See triangle_intersect_subsurface() for the native equivalent. */ - for (int i = min(ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) { + for (int i = min((int)ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) { if (local_isect->hits[i].t == ray->tfar) { /* This tells Embree to continue tracing. */ *args->valid = 0; |