This change fixes the remaining failing tests with SSS when using HIP-RT. This includes crash when SSS is used on curves, and objects with motion blur and SSS rendering black. The root cause for both cases was the fact that traversal was always assuming regular BVH (built for triangles), while curves and motion triangles are using custom primitives, which requires specialized BVH traversal. This change includes: - Early output from `scene_intersect_local()` for non-triangle and non-motion-triangle primitives. This fixes `sss_hair.blend` test, and also avoids unnecessary BVH traversal when the local intersection is requested from curve object. The same early-output could be added to other BVH traversal implementation. - Use `hiprtGeomCustomTraversalAnyHitCustomStack` for motion triangles primitives. This fixes motion blur on objects with SSS render black. Fixes #135856 Co-authored-by: Sahar A. Kashi <sahar.alipourkashi@amd.com> Co-authored-by: Sergey Sharybin <sergey@blender.org> Pull Request: https://projects.blender.org/blender/blender/pulls/135943
248 lines
7.8 KiB
C++
248 lines
7.8 KiB
C++
/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 */
|
|
|
|
#pragma once
|
|
|
|
#include "kernel/device/hiprt/common.h"
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
ccl_device_inline bool scene_intersect_valid(const ccl_private Ray *ray)
|
|
{
|
|
return isfinite_safe(ray->P.x) && isfinite_safe(ray->D.x) && len_squared(ray->D) != 0.0f;
|
|
}
|
|
|
|
ccl_device_intersect bool scene_intersect(KernelGlobals kg,
|
|
const ccl_private Ray *ray,
|
|
const uint visibility,
|
|
ccl_private Intersection *isect)
|
|
{
|
|
isect->t = ray->tmax;
|
|
isect->u = 0.0f;
|
|
isect->v = 0.0f;
|
|
isect->prim = PRIM_NONE;
|
|
isect->object = OBJECT_NONE;
|
|
isect->type = PRIMITIVE_NONE;
|
|
if (!scene_intersect_valid(ray)) {
|
|
isect->t = ray->tmax;
|
|
isect->type = PRIMITIVE_NONE;
|
|
return false;
|
|
}
|
|
|
|
if (kernel_data.device_bvh == 0)
|
|
return false;
|
|
|
|
hiprtRay ray_hip;
|
|
|
|
SET_HIPRT_RAY(ray_hip, ray)
|
|
|
|
RayPayload payload;
|
|
payload.self = ray->self;
|
|
payload.kg = kg;
|
|
payload.visibility = visibility;
|
|
payload.prim_type = PRIMITIVE_NONE;
|
|
payload.ray_time = ray->time;
|
|
|
|
hiprtHit hit = {};
|
|
|
|
GET_TRAVERSAL_STACK()
|
|
|
|
if (visibility & PATH_RAY_SHADOW_OPAQUE) {
|
|
GET_TRAVERSAL_ANY_HIT(table_closest_intersect, 0, ray->time)
|
|
hit = traversal.getNextHit();
|
|
}
|
|
else {
|
|
GET_TRAVERSAL_CLOSEST_HIT(table_closest_intersect, 0, ray->time)
|
|
hit = traversal.getNextHit();
|
|
}
|
|
if (hit.hasHit()) {
|
|
set_intersect_point(kg, hit, isect);
|
|
if (isect->type > 1) { // should be applied only for curves
|
|
isect->type = payload.prim_type;
|
|
isect->prim = hit.primID;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ccl_device_intersect bool scene_intersect_shadow(KernelGlobals kg,
|
|
const ccl_private Ray *ray,
|
|
const uint visibility)
|
|
{
|
|
Intersection isect;
|
|
return scene_intersect(kg, ray, visibility, &isect);
|
|
}
|
|
|
|
#ifdef __BVH_LOCAL__
|
|
template<bool single_hit = false>
|
|
ccl_device_intersect bool scene_intersect_local(KernelGlobals kg,
|
|
const ccl_private Ray *ray,
|
|
ccl_private LocalIntersection *local_isect,
|
|
const int local_object,
|
|
ccl_private uint *lcg_state,
|
|
const int max_hits)
|
|
{
|
|
if (local_isect != nullptr) {
|
|
local_isect->num_hits = 0;
|
|
}
|
|
|
|
if (!scene_intersect_valid(ray)) {
|
|
return false;
|
|
}
|
|
|
|
const int primitive_type = kernel_data_fetch(objects, local_object).primitive_type;
|
|
if (!(primitive_type & PRIMITIVE_TRIANGLE)) {
|
|
/* Local intersection functions are only considering triangle and motion triangle orimitives.
|
|
* If the local intersection is requested from other primitives (curve or point cloud) perform
|
|
* an early return to avoid tree travsersal with no primitive intersection. */
|
|
return false;
|
|
}
|
|
|
|
float3 P = ray->P;
|
|
float3 dir = bvh_clamp_direction(ray->D);
|
|
float3 idir = bvh_inverse_direction(dir);
|
|
|
|
const int object_flag = kernel_data_fetch(object_flag, local_object);
|
|
if (!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
|
|
# if BVH_FEATURE(BVH_MOTION)
|
|
bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir);
|
|
# else
|
|
bvh_instance_push(kg, local_object, ray, &P, &dir, &idir);
|
|
# endif
|
|
}
|
|
|
|
hiprtRay ray_hip;
|
|
ray_hip.origin = P;
|
|
ray_hip.direction = dir;
|
|
ray_hip.maxT = ray->tmax;
|
|
ray_hip.minT = ray->tmin;
|
|
|
|
LocalPayload payload = {0};
|
|
payload.kg = kg;
|
|
payload.self = ray->self;
|
|
payload.ray_time = ray->time;
|
|
payload.local_object = local_object;
|
|
payload.max_hits = max_hits;
|
|
payload.lcg_state = lcg_state;
|
|
payload.local_isect = local_isect;
|
|
|
|
GET_TRAVERSAL_STACK()
|
|
|
|
void *local_geom = (void *)(kernel_data_fetch(blas_ptr, local_object));
|
|
|
|
hiprtHit hit;
|
|
if (primitive_type == PRIMITIVE_MOTION_TRIANGLE) {
|
|
/* Motion triangle BVH uses custom primitives which requires custom traversal. */
|
|
hiprtGeomCustomTraversalAnyHitCustomStack<Stack> traversal((hiprtGeometry)local_geom,
|
|
ray_hip,
|
|
stack,
|
|
hiprtTraversalHintDefault,
|
|
&payload,
|
|
kernel_params.table_local_intersect,
|
|
2);
|
|
hit = traversal.getNextHit();
|
|
}
|
|
else {
|
|
hiprtGeomTraversalAnyHitCustomStack<Stack> traversal((hiprtGeometry)local_geom,
|
|
ray_hip,
|
|
stack,
|
|
hiprtTraversalHintDefault,
|
|
&payload,
|
|
kernel_params.table_local_intersect,
|
|
2);
|
|
hit = traversal.getNextHit();
|
|
}
|
|
|
|
return hit.hasHit();
|
|
}
|
|
#endif //__BVH_LOCAL__
|
|
|
|
#ifdef __SHADOW_RECORD_ALL__
|
|
ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg,
|
|
IntegratorShadowState state,
|
|
const ccl_private Ray *ray,
|
|
const uint visibility,
|
|
const uint max_hits,
|
|
ccl_private uint *num_recorded_hits,
|
|
ccl_private float *throughput)
|
|
{
|
|
*throughput = 1.0f;
|
|
*num_recorded_hits = 0;
|
|
|
|
if (!scene_intersect_valid(ray)) {
|
|
return false;
|
|
}
|
|
|
|
hiprtRay ray_hip;
|
|
|
|
SET_HIPRT_RAY(ray_hip, ray)
|
|
ShadowPayload payload;
|
|
payload.kg = kg;
|
|
payload.self = ray->self;
|
|
payload.in_state = state;
|
|
payload.max_hits = max_hits;
|
|
payload.visibility = visibility;
|
|
payload.prim_type = PRIMITIVE_NONE;
|
|
payload.ray_time = ray->time;
|
|
payload.num_hits = 0;
|
|
payload.r_num_recorded_hits = num_recorded_hits;
|
|
payload.r_throughput = throughput;
|
|
GET_TRAVERSAL_STACK()
|
|
GET_TRAVERSAL_ANY_HIT(table_shadow_intersect, 1, ray->time)
|
|
hiprtHit hit = traversal.getNextHit();
|
|
num_recorded_hits = payload.r_num_recorded_hits;
|
|
throughput = payload.r_throughput;
|
|
return hit.hasHit();
|
|
}
|
|
#endif /* __SHADOW_RECORD_ALL__ */
|
|
|
|
#ifdef __VOLUME__
|
|
ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg,
|
|
const ccl_private Ray *ray,
|
|
ccl_private Intersection *isect,
|
|
const uint visibility)
|
|
{
|
|
isect->t = ray->tmax;
|
|
isect->u = 0.0f;
|
|
isect->v = 0.0f;
|
|
isect->prim = PRIM_NONE;
|
|
isect->object = OBJECT_NONE;
|
|
isect->type = PRIMITIVE_NONE;
|
|
|
|
if (!scene_intersect_valid(ray)) {
|
|
return false;
|
|
}
|
|
|
|
hiprtRay ray_hip;
|
|
|
|
SET_HIPRT_RAY(ray_hip, ray)
|
|
|
|
RayPayload payload;
|
|
payload.self = ray->self;
|
|
payload.kg = kg;
|
|
payload.visibility = visibility;
|
|
payload.prim_type = PRIMITIVE_NONE;
|
|
payload.ray_time = ray->time;
|
|
|
|
GET_TRAVERSAL_STACK()
|
|
|
|
GET_TRAVERSAL_CLOSEST_HIT(table_volume_intersect, 3, ray->time)
|
|
hiprtHit hit = traversal.getNextHit();
|
|
// return hit.hasHit();
|
|
if (hit.hasHit()) {
|
|
set_intersect_point(kg, hit, isect);
|
|
if (isect->type > 1) { // should be applied only for curves
|
|
isect->type = payload.prim_type;
|
|
isect->prim = hit.primID;
|
|
}
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
#endif /* __VOLUME__ */
|
|
|
|
CCL_NAMESPACE_END
|