Fix T96165: Incorrect render of barcelone scene with BVH2

Fix T95462: Partly transparent objects appear to glow in the dark

The issue was caused by incorrect check for exceeded number
of transparent bounces: the same maximum distance was used
for picking up N closest intersections and counting overall
intersections count.

Now made it so intersection count is using ray distance which
matches the way how Embree and OptiX implementation works.

Benchmark result:
{F12907888}

There is no big time difference in the pabellon scene. The
Victor scene timing doesn't seem to be very reliable as the
variance in time across different benchmark runs is quite
high.

Differential Revision: https://developer.blender.org/D14280
This commit is contained in:
Sergey Sharybin 2022-03-08 14:43:48 +01:00
parent 801d7b4921
commit 04e89c5b06
Notes: blender-bot 2023-02-14 11:21:43 +01:00
Referenced by issue #96165, Blender 3.2/Blender 3.1 - Incorrect render of barcelone scene with BVH2
Referenced by issue #95462, Partly transparent objects appear to glow in the dark when HDRI environment lighting is present (BVH2/Some GPU rendering backends)
1 changed files with 39 additions and 34 deletions

View File

@ -29,8 +29,8 @@ ccl_device_inline
IntegratorShadowState state,
const uint visibility,
const uint max_hits,
ccl_private uint *num_recorded_hits,
ccl_private float *throughput)
ccl_private uint *r_num_recorded_hits,
ccl_private float *r_throughput)
{
/* todo:
* - likely and unlikely for if() statements
@ -60,15 +60,18 @@ ccl_device_inline
* recorded hits is exceeded and we no longer need to find hits beyond the max
* distance found. */
float t_max_world = ray->t;
/* Equal to t_max_world when traversing top level BVH, transformed into local
* space when entering instances. */
float t_max_current = t_max_world;
/* Current maximum distance to the intersection.
* Is calculated as a ray length, transformed to an object space when entering
* instance node. */
float t_max_current = ray->t;
/* Conversion from world to local space for the current instance if any, 1.0
* otherwise. */
float t_world_to_instance = 1.0f;
*num_recorded_hits = 0;
*throughput = 1.0f;
*r_num_recorded_hits = 0;
*r_throughput = 1.0f;
/* traversal loop */
do {
@ -237,10 +240,10 @@ ccl_device_inline
/* Always use baked shadow transparency for curves. */
if (isect.type & PRIMITIVE_CURVE) {
*throughput *= intersection_curve_shadow_transparency(
*r_throughput *= intersection_curve_shadow_transparency(
kg, isect.object, isect.prim, isect.u);
if (*throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
if (*r_throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
return true;
}
else {
@ -249,37 +252,39 @@ ccl_device_inline
}
if (record_intersection) {
/* Increase the number of hits, possibly beyond max_hits, we will
* simply not record those and only keep the max_hits closest. */
uint record_index = (*num_recorded_hits)++;
/* Test if we need to record this transparent intersection. */
const uint max_record_hits = min(max_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
if (record_index >= max_record_hits - 1) {
/* If maximum number of hits reached, find the intersection with
* the largest distance to potentially replace when another hit
* is found. */
const int num_recorded_hits = min(max_record_hits, record_index);
float max_recorded_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, t);
int max_recorded_hit = 0;
if (*r_num_recorded_hits < max_record_hits || isect.t < t_max_world) {
/* If maximum number of hits was reached, replace the intersection with the
* highest distance. We want to find the N closest intersections. */
const uint num_recorded_hits = min(*r_num_recorded_hits, max_record_hits);
uint isect_index = num_recorded_hits;
if (num_recorded_hits + 1 >= max_record_hits) {
float max_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, t);
uint max_recorded_hit = 0;
for (int i = 1; i < num_recorded_hits; i++) {
const float isect_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, t);
if (isect_t > max_recorded_t) {
max_recorded_t = isect_t;
max_recorded_hit = i;
for (uint i = 1; i < num_recorded_hits; ++i) {
const float isect_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, t);
if (isect_t > max_t) {
max_recorded_hit = i;
max_t = isect_t;
}
}
if (num_recorded_hits >= max_record_hits) {
isect_index = max_recorded_hit;
}
/* Limit the ray distance and stop counting hits beyond this. */
t_max_world = max(isect.t, max_t);
}
if (record_index >= max_record_hits) {
record_index = max_recorded_hit;
}
/* Limit the ray distance and stop counting hits beyond this. */
t_max_world = max(max_recorded_t, isect.t);
t_max_current = t_max_world * t_world_to_instance;
integrator_state_write_shadow_isect(state, &isect, isect_index);
}
integrator_state_write_shadow_isect(state, &isect, record_index);
/* Always increase the number of recorded hits, even beyond the maximum,
* so that we can detect this and trace another ray if needed. */
++(*r_num_recorded_hits);
}
}
}
@ -318,7 +323,7 @@ ccl_device_inline
#endif
/* Restore world space ray length. */
t_max_current = t_max_world;
t_max_current = ray->t;
object = OBJECT_NONE;
t_world_to_instance = 1.0f;