From ae440703411486c9219fa0ff54e471eea64afb58 Mon Sep 17 00:00:00 2001 From: William Leeson Date: Thu, 13 Jan 2022 17:20:50 +0100 Subject: Cycles: explicitly skip self-intersection Remember the last intersected primitive and skip any intersections with the same primitive. Ref D12954 --- intern/cycles/bvh/embree.cpp | 52 +++++++++++++++- intern/cycles/device/optix/device_impl.cpp | 2 +- intern/cycles/kernel/bvh/bvh.h | 38 +++++++++--- intern/cycles/kernel/bvh/embree.h | 35 ++++++++++- intern/cycles/kernel/bvh/local.h | 8 +++ intern/cycles/kernel/bvh/metal.h | 3 + intern/cycles/kernel/bvh/shadow_all.h | 3 + intern/cycles/kernel/bvh/traversal.h | 72 ++++++++-------------- intern/cycles/kernel/bvh/util.h | 21 +++++++ intern/cycles/kernel/bvh/volume.h | 6 ++ intern/cycles/kernel/bvh/volume_all.h | 6 ++ intern/cycles/kernel/device/metal/kernel.metal | 54 +++++++++++++--- intern/cycles/kernel/device/optix/kernel.cu | 45 ++++++++++++-- .../cycles/kernel/integrator/intersect_closest.h | 6 ++ intern/cycles/kernel/integrator/intersect_shadow.h | 5 +- .../kernel/integrator/intersect_volume_stack.h | 9 ++- intern/cycles/kernel/integrator/shade_shadow.h | 5 +- intern/cycles/kernel/integrator/shade_surface.h | 13 ++++ intern/cycles/kernel/integrator/shade_volume.h | 7 +++ .../kernel/integrator/shadow_state_template.h | 1 + intern/cycles/kernel/integrator/subsurface.h | 1 - intern/cycles/kernel/integrator/subsurface_disk.h | 4 ++ .../kernel/integrator/subsurface_random_walk.h | 15 ++++- intern/cycles/kernel/light/light.h | 4 +- intern/cycles/kernel/light/sample.h | 6 ++ intern/cycles/kernel/svm/ao.h | 4 ++ intern/cycles/kernel/svm/bevel.h | 4 ++ intern/cycles/kernel/types.h | 9 +++ 28 files changed, 360 insertions(+), 78 deletions(-) diff --git a/intern/cycles/bvh/embree.cpp b/intern/cycles/bvh/embree.cpp index 2e49e29d12b..616b6273e6a 100644 --- a/intern/cycles/bvh/embree.cpp +++ b/intern/cycles/bvh/embree.cpp @@ -61,6 +61,26 @@ static_assert(Object::MAX_MOTION_STEPS == Geometry::MAX_MOTION_STEPS, # define IS_HAIR(x) (x & 1) +/* This gets called by Embree at every valid ray/object intersection. + * Things like recording subsurface or shadow hits for later evaluation + * as well as filtering for volume objects happen here. + * Cycles' own BVH does that directly inside the traversal calls. + */ +static void rtc_filter_intersection_func(const RTCFilterFunctionNArguments *args) +{ + /* Current implementation in Cycles assumes only single-ray intersection queries. */ + assert(args->N == 1); + + RTCHit *hit = (RTCHit *)args->hit; + CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt; + const KernelGlobalsCPU *kg = ctx->kg; + const Ray *cray = ctx->ray; + + if (kernel_embree_is_self_intersection(kg, hit, cray)) { + *args->valid = 0; + } +} + /* This gets called by Embree at every valid ray/object intersection. * Things like recording subsurface or shadow hits for later evaluation * as well as filtering for volume objects happen here. @@ -75,12 +95,16 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args) RTCHit *hit = (RTCHit *)args->hit; CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt; const KernelGlobalsCPU *kg = ctx->kg; + const Ray *cray = ctx->ray; switch (ctx->type) { case CCLIntersectContext::RAY_SHADOW_ALL: { Intersection current_isect; kernel_embree_convert_hit(kg, ray, hit, ¤t_isect); - + if (intersection_skip_self_shadow(cray->self, current_isect.object, current_isect.prim)) { + *args->valid = 0; + return; + } /* 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->num_hits >= ctx->max_hits) { @@ -160,6 +184,10 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args) break; } } + if (intersection_skip_self_local(cray->self, current_isect.prim)) { + *args->valid = 0; + return; + } /* No intersection information requested, just return a hit. */ if (ctx->max_hits == 0) { @@ -225,6 +253,11 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args) if (ctx->num_hits < ctx->max_hits) { Intersection current_isect; kernel_embree_convert_hit(kg, ray, hit, ¤t_isect); + if (intersection_skip_self(cray->self, current_isect.object, current_isect.prim)) { + *args->valid = 0; + return; + } + Intersection *isect = &ctx->isect_s[ctx->num_hits]; ++ctx->num_hits; *isect = current_isect; @@ -236,12 +269,15 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args) } /* This tells Embree to continue tracing. */ *args->valid = 0; - break; } + break; } case CCLIntersectContext::RAY_REGULAR: default: - /* Nothing to do here. */ + if (kernel_embree_is_self_intersection(kg, hit, cray)) { + *args->valid = 0; + return; + } break; } } @@ -257,6 +293,14 @@ static void rtc_filter_func_backface_cull(const RTCFilterFunctionNArguments *arg *args->valid = 0; return; } + + CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt; + const KernelGlobalsCPU *kg = ctx->kg; + const Ray *cray = ctx->ray; + + if (kernel_embree_is_self_intersection(kg, hit, cray)) { + *args->valid = 0; + } } static void rtc_filter_occluded_func_backface_cull(const RTCFilterFunctionNArguments *args) @@ -505,6 +549,7 @@ void BVHEmbree::add_triangles(const Object *ob, const Mesh *mesh, int i) rtcSetGeometryUserData(geom_id, (void *)prim_offset); rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func); + rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_intersection_func); rtcSetGeometryMask(geom_id, ob->visibility_for_tracing()); rtcCommitGeometry(geom_id); @@ -767,6 +812,7 @@ void BVHEmbree::add_curves(const Object *ob, const Hair *hair, int i) rtcSetGeometryUserData(geom_id, (void *)prim_offset); if (hair->curve_shape == CURVE_RIBBON) { + rtcSetGeometryIntersectFilterFunction(geom_id, rtc_filter_intersection_func); rtcSetGeometryOccludedFilterFunction(geom_id, rtc_filter_occluded_func); } else { diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp index 009661b2dec..cb6c36d5ea6 100644 --- a/intern/cycles/device/optix/device_impl.cpp +++ b/intern/cycles/device/optix/device_impl.cpp @@ -226,7 +226,7 @@ bool OptiXDevice::load_kernels(const uint kernel_features) pipeline_options.usesMotionBlur = false; pipeline_options.traversableGraphFlags = OPTIX_TRAVERSABLE_GRAPH_FLAG_ALLOW_SINGLE_LEVEL_INSTANCING; - pipeline_options.numPayloadValues = 6; + pipeline_options.numPayloadValues = 8; pipeline_options.numAttributeValues = 2; /* u, v */ pipeline_options.exceptionFlags = OPTIX_EXCEPTION_FLAG_NONE; pipeline_options.pipelineLaunchParamsVariableName = "__params"; /* See globals.h */ diff --git a/intern/cycles/kernel/bvh/bvh.h b/intern/cycles/kernel/bvh/bvh.h index 67804fb1d0d..1797bf60720 100644 --- a/intern/cycles/kernel/bvh/bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -173,15 +173,16 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg, uint p3 = 0; uint p4 = visibility; uint p5 = PRIMITIVE_NONE; + uint p6 = ((uint64_t)ray) & 0xFFFFFFFF; + uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF; uint ray_mask = visibility & 0xFF; - uint ray_flags = OPTIX_RAY_FLAG_NONE; + uint ray_flags = OPTIX_RAY_FLAG_ENFORCE_ANYHIT; if (0 == ray_mask && (visibility & ~0xFF) != 0) { ray_mask = 0xFF; - ray_flags = OPTIX_RAY_FLAG_ENFORCE_ANYHIT; } else if (visibility & PATH_RAY_SHADOW_OPAQUE) { - ray_flags = OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; + ray_flags |= OPTIX_RAY_FLAG_TERMINATE_ON_FIRST_HIT; } optixTrace(scene_intersect_valid(ray) ? kernel_data.bvh.scene : 0, @@ -200,7 +201,9 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg, p2, p3, p4, - p5); + p5, + p6, + p7); isect->t = __uint_as_float(p0); isect->u = __uint_as_float(p1); @@ -242,6 +245,7 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg, } MetalRTIntersectionPayload payload; + payload.self = ray->self; payload.u = 0.0f; payload.v = 0.0f; payload.visibility = visibility; @@ -309,6 +313,7 @@ ccl_device_intersect bool scene_intersect(KernelGlobals kg, CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_REGULAR); IntersectContext rtc_ctx(&ctx); RTCRayHit ray_hit; + ctx.ray = ray; kernel_embree_setup_rayhit(*ray, ray_hit, visibility); rtcIntersect1(kernel_data.bvh.scene, &rtc_ctx.context, &ray_hit); if (ray_hit.hit.geomID != RTC_INVALID_GEOMETRY_ID && @@ -356,6 +361,9 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg, uint p2 = pointer_pack_to_uint_0(local_isect); uint p3 = pointer_pack_to_uint_1(local_isect); uint p4 = local_object; + uint p6 = ((uint64_t)ray) & 0xFFFFFFFF; + uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF; + /* Is set to zero on miss or if ray is aborted, so can be used as return value. */ uint p5 = max_hits; @@ -379,7 +387,9 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg, p2, p3, p4, - p5); + p5, + p6, + p7); return p5; # elif defined(__METALRT__) @@ -417,6 +427,7 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg, } MetalRTIntersectionLocalPayload payload; + payload.self = ray->self; payload.local_object = local_object; payload.max_hits = max_hits; payload.local_isect.num_hits = 0; @@ -460,6 +471,7 @@ ccl_device_intersect bool scene_intersect_local(KernelGlobals kg, kg, has_bvh ? CCLIntersectContext::RAY_SSS : CCLIntersectContext::RAY_LOCAL); ctx.lcg_state = lcg_state; ctx.max_hits = max_hits; + ctx.ray = ray; ctx.local_isect = local_isect; if (local_isect) { local_isect->num_hits = 0; @@ -532,6 +544,8 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg, uint p3 = max_hits; uint p4 = visibility; uint p5 = false; + uint p6 = ((uint64_t)ray) & 0xFFFFFFFF; + uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF; uint ray_mask = visibility & 0xFF; if (0 == ray_mask && (visibility & ~0xFF) != 0) { @@ -555,7 +569,9 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg, p2, p3, p4, - p5); + p5, + p6, + p7); *num_recorded_hits = uint16_unpack_from_uint_0(p2); *throughput = __uint_as_float(p1); @@ -588,6 +604,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg, } MetalRTIntersectionShadowPayload payload; + payload.self = ray->self; payload.visibility = visibility; payload.max_hits = max_hits; payload.num_hits = 0; @@ -634,6 +651,7 @@ ccl_device_intersect bool scene_intersect_shadow_all(KernelGlobals kg, Intersection *isect_array = (Intersection *)state->shadow_isect; ctx.isect_s = isect_array; ctx.max_hits = max_hits; + ctx.ray = ray; IntersectContext rtc_ctx(&ctx); RTCRay rtc_ray; kernel_embree_setup_ray(*ray, rtc_ray, visibility); @@ -685,6 +703,8 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg, uint p3 = 0; uint p4 = visibility; uint p5 = PRIMITIVE_NONE; + uint p6 = ((uint64_t)ray) & 0xFFFFFFFF; + uint p7 = (((uint64_t)ray) >> 32) & 0xFFFFFFFF; uint ray_mask = visibility & 0xFF; if (0 == ray_mask && (visibility & ~0xFF) != 0) { @@ -708,7 +728,9 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg, p2, p3, p4, - p5); + p5, + p6, + p7); isect->t = __uint_as_float(p0); isect->u = __uint_as_float(p1); @@ -744,6 +766,7 @@ ccl_device_intersect bool scene_intersect_volume(KernelGlobals kg, } MetalRTIntersectionPayload payload; + payload.self = ray->self; payload.visibility = visibility; typename metalrt_intersector_type::result_type intersection; @@ -820,6 +843,7 @@ ccl_device_intersect uint scene_intersect_volume_all(KernelGlobals kg, ctx.isect_s = isect; ctx.max_hits = max_hits; ctx.num_hits = 0; + ctx.ray = ray; IntersectContext rtc_ctx(&ctx); RTCRay rtc_ray; kernel_embree_setup_ray(*ray, rtc_ray, visibility); diff --git a/intern/cycles/kernel/bvh/embree.h b/intern/cycles/kernel/bvh/embree.h index 9edd4f90a7e..19c4b9f6f3d 100644 --- a/intern/cycles/kernel/bvh/embree.h +++ b/intern/cycles/kernel/bvh/embree.h @@ -22,6 +22,8 @@ #include "kernel/device/cpu/compat.h" #include "kernel/device/cpu/globals.h" +#include "kernel/bvh/util.h" + #include "util/vector.h" CCL_NAMESPACE_BEGIN @@ -38,6 +40,9 @@ struct CCLIntersectContext { KernelGlobals kg; RayType type; + /* For avoiding self intersections */ + const Ray *ray; + /* for shadow rays */ Intersection *isect_s; uint max_hits; @@ -56,6 +61,7 @@ struct CCLIntersectContext { { kg = kg_; type = type_; + ray = NULL; max_hits = 1; num_hits = 0; num_recorded_hits = 0; @@ -102,7 +108,34 @@ ccl_device_inline void kernel_embree_setup_rayhit(const Ray &ray, { kernel_embree_setup_ray(ray, rayhit.ray, visibility); rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID; - rayhit.hit.primID = RTC_INVALID_GEOMETRY_ID; + rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID; +} + +ccl_device_inline bool kernel_embree_is_self_intersection(const KernelGlobals kg, + const RTCHit *hit, + const Ray *ray) +{ + bool status = false; + if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) { + const int oID = hit->instID[0] / 2; + if ((ray->self.object == oID) || (ray->self.light_object == oID)) { + RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData( + rtcGetGeometry(kernel_data.bvh.scene, hit->instID[0])); + const int pID = hit->primID + + (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID)); + status = intersection_skip_self_shadow(ray->self, oID, pID); + } + } + else { + const int oID = hit->geomID / 2; + if ((ray->self.object == oID) || (ray->self.light_object == oID)) { + const int pID = hit->primID + (intptr_t)rtcGetGeometryUserData( + rtcGetGeometry(kernel_data.bvh.scene, hit->geomID)); + status = intersection_skip_self_shadow(ray->self, oID, pID); + } + } + + return status; } ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg, diff --git a/intern/cycles/kernel/bvh/local.h b/intern/cycles/kernel/bvh/local.h index 4d0e6aac901..4ef6deef98d 100644 --- a/intern/cycles/kernel/bvh/local.h +++ b/intern/cycles/kernel/bvh/local.h @@ -157,7 +157,11 @@ ccl_device_inline } } + /* Skip self intersection. */ const int prim = kernel_tex_fetch(__prim_index, prim_addr); + if (intersection_skip_self_local(ray->self, prim)) { + continue; + } if (triangle_intersect_local(kg, local_isect, @@ -188,7 +192,11 @@ ccl_device_inline } } + /* Skip self intersection. */ const int prim = kernel_tex_fetch(__prim_index, prim_addr); + if (intersection_skip_self_local(ray->self, prim)) { + continue; + } if (motion_triangle_intersect_local(kg, local_isect, diff --git a/intern/cycles/kernel/bvh/metal.h b/intern/cycles/kernel/bvh/metal.h index 55456d15f50..5ab413d9314 100644 --- a/intern/cycles/kernel/bvh/metal.h +++ b/intern/cycles/kernel/bvh/metal.h @@ -15,6 +15,7 @@ */ struct MetalRTIntersectionPayload { + RaySelfPrimitives self; uint visibility; float u, v; int prim; @@ -25,6 +26,7 @@ struct MetalRTIntersectionPayload { }; struct MetalRTIntersectionLocalPayload { + RaySelfPrimitives self; uint local_object; uint lcg_state; short max_hits; @@ -34,6 +36,7 @@ struct MetalRTIntersectionLocalPayload { }; struct MetalRTIntersectionShadowPayload { + RaySelfPrimitives self; uint visibility; #if defined(__METALRT_MOTION__) float time; diff --git a/intern/cycles/kernel/bvh/shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h index 0fb86bfda77..59a7ba63045 100644 --- a/intern/cycles/kernel/bvh/shadow_all.h +++ b/intern/cycles/kernel/bvh/shadow_all.h @@ -160,6 +160,9 @@ ccl_device_inline kernel_tex_fetch(__prim_object, prim_addr) : object; const int prim = kernel_tex_fetch(__prim_index, prim_addr); + if (intersection_skip_self_shadow(ray->self, prim_object, prim)) { + continue; + } switch (type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { diff --git a/intern/cycles/kernel/bvh/traversal.h b/intern/cycles/kernel/bvh/traversal.h index dc2d1422df6..17cd357a069 100644 --- a/intern/cycles/kernel/bvh/traversal.h +++ b/intern/cycles/kernel/bvh/traversal.h @@ -133,35 +133,29 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg, --stack_ptr; /* primitive intersection */ - switch (type & PRIMITIVE_ALL) { - case PRIMITIVE_TRIANGLE: { - for (; prim_addr < prim_addr2; prim_addr++) { - kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); - - const int prim_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; - const int prim = kernel_tex_fetch(__prim_index, prim_addr); + for (; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + + const int prim_object = (object == OBJECT_NONE) ? + kernel_tex_fetch(__prim_object, prim_addr) : + object; + const int prim = kernel_tex_fetch(__prim_index, prim_addr); + if (intersection_skip_self_shadow(ray->self, prim_object, prim)) { + continue; + } + switch (type & PRIMITIVE_ALL) { + case PRIMITIVE_TRIANGLE: { if (triangle_intersect( kg, isect, P, dir, isect->t, visibility, prim_object, prim, prim_addr)) { /* shadow ray early termination */ if (visibility & PATH_RAY_SHADOW_OPAQUE) return true; } + break; } - break; - } #if BVH_FEATURE(BVH_MOTION) - case PRIMITIVE_MOTION_TRIANGLE: { - for (; prim_addr < prim_addr2; prim_addr++) { - kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); - - const int prim_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; - const int prim = kernel_tex_fetch(__prim_index, prim_addr); - + case PRIMITIVE_MOTION_TRIANGLE: { if (motion_triangle_intersect(kg, isect, P, @@ -176,28 +170,21 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg, if (visibility & PATH_RAY_SHADOW_OPAQUE) return true; } + break; } - break; - } #endif /* BVH_FEATURE(BVH_MOTION) */ #if BVH_FEATURE(BVH_HAIR) - case PRIMITIVE_CURVE_THICK: - case PRIMITIVE_MOTION_CURVE_THICK: - case PRIMITIVE_CURVE_RIBBON: - case PRIMITIVE_MOTION_CURVE_RIBBON: { - for (; prim_addr < prim_addr2; prim_addr++) { + case PRIMITIVE_CURVE_THICK: + case PRIMITIVE_MOTION_CURVE_THICK: + case PRIMITIVE_CURVE_RIBBON: + case PRIMITIVE_MOTION_CURVE_RIBBON: { if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) { const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr); if (ray->time < prim_time.x || ray->time > prim_time.y) { - continue; + break; } } - const int prim_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; - const int prim = kernel_tex_fetch(__prim_index, prim_addr); - const int curve_type = kernel_tex_fetch(__prim_type, prim_addr); const bool hit = curve_intersect( kg, isect, P, dir, isect->t, prim_object, prim, ray->time, curve_type); @@ -206,26 +193,19 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg, if (visibility & PATH_RAY_SHADOW_OPAQUE) return true; } + break; } - break; - } #endif /* BVH_FEATURE(BVH_HAIR) */ #if BVH_FEATURE(BVH_POINTCLOUD) - case PRIMITIVE_POINT: - case PRIMITIVE_MOTION_POINT: { - for (; prim_addr < prim_addr2; prim_addr++) { + case PRIMITIVE_POINT: + case PRIMITIVE_MOTION_POINT: { if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) { const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr); if (ray->time < prim_time.x || ray->time > prim_time.y) { - continue; + break; } } - const int prim_object = (object == OBJECT_NONE) ? - kernel_tex_fetch(__prim_object, prim_addr) : - object; - const int prim = kernel_tex_fetch(__prim_index, prim_addr); - const int point_type = kernel_tex_fetch(__prim_type, prim_addr); const bool hit = point_intersect( kg, isect, P, dir, isect->t, prim_object, prim, ray->time, point_type); @@ -234,10 +214,10 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg, if (visibility & PATH_RAY_SHADOW_OPAQUE) return true; } + break; } - break; - } #endif /* BVH_FEATURE(BVH_POINTCLOUD) */ + } } } else { diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h index bd79c6e19c6..ea86523c0f6 100644 --- a/intern/cycles/kernel/bvh/util.h +++ b/intern/cycles/kernel/bvh/util.h @@ -227,4 +227,25 @@ ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg, return (1.0f - u) * f0 + u * f1; } +ccl_device_inline bool intersection_skip_self(ccl_private const RaySelfPrimitives &self, + const int object, + const int prim) +{ + return (self.prim == prim) && (self.object == object); +} + +ccl_device_inline bool intersection_skip_self_shadow(ccl_private const RaySelfPrimitives &self, + const int object, + const int prim) +{ + return ((self.prim == prim) && (self.object == object)) || + ((self.light_prim == prim) && (self.light_object == object)); +} + +ccl_device_inline bool intersection_skip_self_local(ccl_private const RaySelfPrimitives &self, + const int prim) +{ + return (self.prim == prim); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/bvh/volume.h b/intern/cycles/kernel/bvh/volume.h index c0746c8efc3..95bba4f071d 100644 --- a/intern/cycles/kernel/bvh/volume.h +++ b/intern/cycles/kernel/bvh/volume.h @@ -144,6 +144,9 @@ ccl_device_inline kernel_tex_fetch(__prim_object, prim_addr) : object; const int prim = kernel_tex_fetch(__prim_index, prim_addr); + if (intersection_skip_self(ray->self, prim_object, prim)) { + continue; + } int object_flag = kernel_tex_fetch(__object_flag, prim_object); if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { @@ -164,6 +167,9 @@ ccl_device_inline kernel_tex_fetch(__prim_object, prim_addr) : object; const int prim = kernel_tex_fetch(__prim_index, prim_addr); + if (intersection_skip_self(ray->self, prim_object, prim)) { + continue; + } int object_flag = kernel_tex_fetch(__object_flag, prim_object); if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; diff --git a/intern/cycles/kernel/bvh/volume_all.h b/intern/cycles/kernel/bvh/volume_all.h index a88c9d95d46..9f53e987cf1 100644 --- a/intern/cycles/kernel/bvh/volume_all.h +++ b/intern/cycles/kernel/bvh/volume_all.h @@ -147,6 +147,9 @@ ccl_device_inline kernel_tex_fetch(__prim_object, prim_addr) : object; const int prim = kernel_tex_fetch(__prim_index, prim_addr); + if (intersection_skip_self(ray->self, prim_object, prim)) { + continue; + } int object_flag = kernel_tex_fetch(__object_flag, prim_object); if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; @@ -188,6 +191,9 @@ ccl_device_inline kernel_tex_fetch(__prim_object, prim_addr) : object; const int prim = kernel_tex_fetch(__prim_index, prim_addr); + if (intersection_skip_self(ray->self, prim_object, prim)) { + continue; + } int object_flag = kernel_tex_fetch(__object_flag, prim_object); if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal index 3303b541487..6b77940660f 100644 --- a/intern/cycles/kernel/device/metal/kernel.metal +++ b/intern/cycles/kernel/device/metal/kernel.metal @@ -40,6 +40,27 @@ struct TriangleIntersectionResult enum { METALRT_HIT_TRIANGLE, METALRT_HIT_BOUNDING_BOX }; +ccl_device_inline bool intersection_skip_self(ray_data const RaySelfPrimitives& self, + const int object, + const int prim) +{ + return (self.prim == prim) && (self.object == object); +} + +ccl_device_inline bool intersection_skip_self_shadow(ray_data const RaySelfPrimitives& self, + const int object, + const int prim) +{ + return ((self.prim == prim) && (self.object == object)) || + ((self.light_prim == prim) && (self.light_object == object)); +} + +ccl_device_inline bool intersection_skip_self_local(ray_data const RaySelfPrimitives& self, + const int prim) +{ + return (self.prim == prim); +} + template TReturn metalrt_local_hit(constant KernelParamsMetal &launch_params_metal, ray_data MetalKernelContext::MetalRTIntersectionLocalPayload &payload, @@ -53,8 +74,8 @@ TReturn metalrt_local_hit(constant KernelParamsMetal &launch_params_metal, #ifdef __BVH_LOCAL__ uint prim = primitive_id + kernel_tex_fetch(__object_prim_offset, object); - if (object != payload.local_object) { - /* Only intersect with matching object */ + if ((object != payload.local_object) || intersection_skip_self_local(payload.self, prim)) { + /* Only intersect with matching object and skip self-intersecton. */ result.accept = false; result.continue_search = true; return result; @@ -166,6 +187,11 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal, } # endif + if (intersection_skip_self_shadow(payload.self, object, prim)) { + /* continue search */ + return true; + } + float u = 0.0f, v = 0.0f; int type = 0; if (intersection_type == METALRT_HIT_TRIANGLE) { @@ -322,21 +348,35 @@ inline TReturnType metalrt_visibility_test(constant KernelParamsMetal &launch_pa } # endif -# ifdef __VISIBILITY_FLAG__ uint visibility = payload.visibility; +# ifdef __VISIBILITY_FLAG__ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) { result.accept = false; result.continue_search = true; return result; } +# endif /* Shadow ray early termination. */ if (visibility & PATH_RAY_SHADOW_OPAQUE) { - result.accept = true; - result.continue_search = false; - return result; + if (intersection_skip_self_shadow(payload.self, object, prim)) { + result.accept = false; + result.continue_search = true; + return result; + } + else { + result.accept = true; + result.continue_search = false; + return result; + } + } + else { + if (intersection_skip_self(payload.self, object, prim)) { + result.accept = false; + result.continue_search = true; + return result; + } } -# endif result.accept = true; result.continue_search = true; diff --git a/intern/cycles/kernel/device/optix/kernel.cu b/intern/cycles/kernel/device/optix/kernel.cu index aa210b31a95..8e3d57bff8a 100644 --- a/intern/cycles/kernel/device/optix/kernel.cu +++ b/intern/cycles/kernel/device/optix/kernel.cu @@ -45,6 +45,11 @@ template ccl_device_forceinline T *get_payload_ptr_2() return pointer_unpack_from_uint(optixGetPayload_2(), optixGetPayload_3()); } +template ccl_device_forceinline T *get_payload_ptr_6() +{ + return (T *)(((uint64_t)optixGetPayload_7() << 32) | optixGetPayload_6()); +} + ccl_device_forceinline int get_object_id() { #ifdef __OBJECT_MOTION__ @@ -111,6 +116,12 @@ extern "C" __global__ void __anyhit__kernel_optix_local_hit() return optixIgnoreIntersection(); } + const int prim = optixGetPrimitiveIndex(); + ccl_private Ray *const ray = get_payload_ptr_6(); + if (intersection_skip_self_local(ray->self, prim)) { + return optixIgnoreIntersection(); + } + const uint max_hits = optixGetPayload_5(); if (max_hits == 0) { /* Special case for when no hit information is requested, just report that something was hit */ @@ -149,8 +160,6 @@ extern "C" __global__ void __anyhit__kernel_optix_local_hit() local_isect->num_hits = 1; } - const int prim = optixGetPrimitiveIndex(); - Intersection *isect = &local_isect->hits[hit]; isect->t = optixGetRayTmax(); isect->prim = prim; @@ -185,6 +194,11 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit() } # endif + ccl_private Ray *const ray = get_payload_ptr_6(); + if (intersection_skip_self_shadow(ray->self, object, prim)) { + return optixIgnoreIntersection(); + } + float u = 0.0f, v = 0.0f; int type = 0; if (optixIsTriangleHit()) { @@ -314,6 +328,12 @@ extern "C" __global__ void __anyhit__kernel_optix_volume_test() if ((kernel_tex_fetch(__object_flag, object) & SD_OBJECT_HAS_VOLUME) == 0) { return optixIgnoreIntersection(); } + + const int prim = optixGetPrimitiveIndex(); + ccl_private Ray *const ray = get_payload_ptr_6(); + if (intersection_skip_self(ray->self, object, prim)) { + return optixIgnoreIntersection(); + } } extern "C" __global__ void __anyhit__kernel_optix_visibility_test() @@ -330,18 +350,31 @@ extern "C" __global__ void __anyhit__kernel_optix_visibility_test() # endif #endif -#ifdef __VISIBILITY_FLAG__ const uint object = get_object_id(); const uint visibility = optixGetPayload_4(); +#ifdef __VISIBILITY_FLAG__ if ((kernel_tex_fetch(__objects, object).visibility & visibility) == 0) { return optixIgnoreIntersection(); } +#endif + + const int prim = optixGetPrimitiveIndex(); + ccl_private Ray *const ray = get_payload_ptr_6(); - /* Shadow ray early termination. */ if (visibility & PATH_RAY_SHADOW_OPAQUE) { - return optixTerminateRay(); + if (intersection_skip_self_shadow(ray->self, object, prim)) { + return optixIgnoreIntersection(); + } + else { + /* Shadow ray early termination. */ + return optixTerminateRay(); + } + } + else { + if (intersection_skip_self(ray->self, object, prim)) { + return optixIgnoreIntersection(); + } } -#endif } extern "C" __global__ void __closesthit__kernel_optix_hit() diff --git a/intern/cycles/kernel/integrator/intersect_closest.h b/intern/cycles/kernel/integrator/intersect_closest.h index df710dc1d82..4c5265189fa 100644 --- a/intern/cycles/kernel/integrator/intersect_closest.h +++ b/intern/cycles/kernel/integrator/intersect_closest.h @@ -328,6 +328,12 @@ ccl_device void integrator_intersect_closest(KernelGlobals kg, /* Scene Intersection. */ Intersection isect ccl_optional_struct_init; + isect.object = OBJECT_NONE; + isect.prim = PRIM_NONE; + ray.self.object = last_isect_object; + ray.self.prim = last_isect_prim; + ray.self.light_object = OBJECT_NONE; + ray.self.light_prim = PRIM_NONE; bool hit = scene_intersect(kg, &ray, visibility, &isect); /* TODO: remove this and do it in the various intersection functions instead. */ diff --git a/intern/cycles/kernel/integrator/intersect_shadow.h b/intern/cycles/kernel/integrator/intersect_shadow.h index 90422445fad..1ba8724826b 100644 --- a/intern/cycles/kernel/integrator/intersect_shadow.h +++ b/intern/cycles/kernel/integrator/intersect_shadow.h @@ -156,7 +156,10 @@ ccl_device void integrator_intersect_shadow(KernelGlobals kg, IntegratorShadowSt /* Read ray from integrator state into local memory. */ Ray ray ccl_optional_struct_init; integrator_state_read_shadow_ray(kg, state, &ray); - + ray.self.object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, object); + ray.self.prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, prim); + ray.self.light_object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 1, object); + ray.self.light_prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 1, prim); /* Compute visibility. */ const uint visibility = integrate_intersect_shadow_visibility(kg, state); diff --git a/intern/cycles/kernel/integrator/intersect_volume_stack.h b/intern/cycles/kernel/integrator/intersect_volume_stack.h index 9fa5ff63ad2..aa7be879995 100644 --- a/intern/cycles/kernel/integrator/intersect_volume_stack.h +++ b/intern/cycles/kernel/integrator/intersect_volume_stack.h @@ -38,7 +38,10 @@ ccl_device void integrator_volume_stack_update_for_subsurface(KernelGlobals kg, Ray volume_ray ccl_optional_struct_init; volume_ray.P = from_P; volume_ray.D = normalize_len(to_P - from_P, &volume_ray.t); - + volume_ray.self.object = INTEGRATOR_STATE(state, isect, object); + volume_ray.self.prim = INTEGRATOR_STATE(state, isect, prim); + volume_ray.self.light_object = OBJECT_NONE; + volume_ray.self.light_prim = PRIM_NONE; /* Store to avoid global fetches on every intersection step. */ const uint volume_stack_size = kernel_data.volume_stack_size; @@ -91,6 +94,10 @@ ccl_device void integrator_volume_stack_init(KernelGlobals kg, IntegratorState s * fewest hits. */ volume_ray.D = make_float3(0.0f, 0.0f, 1.0f); volume_ray.t = FLT_MAX; + volume_ray.self.object = OBJECT_NONE; + volume_ray.self.prim = PRIM_NONE; + volume_ray.self.light_object = OBJECT_NONE; + volume_ray.self.light_prim = PRIM_NONE; int stack_index = 0, enclosed_index = 0; diff --git a/intern/cycles/kernel/integrator/shade_shadow.h b/intern/cycles/kernel/integrator/shade_shadow.h index a68fcaa7a64..10ec48c8637 100644 --- a/intern/cycles/kernel/integrator/shade_shadow.h +++ b/intern/cycles/kernel/integrator/shade_shadow.h @@ -83,7 +83,10 @@ ccl_device_inline void integrate_transparent_volume_shadow(KernelGlobals kg, /* Setup shader data. */ Ray ray ccl_optional_struct_init; integrator_state_read_shadow_ray(kg, state, &ray); - + ray.self.object = OBJECT_NONE; + ray.self.prim = PRIM_NONE; + ray.self.light_object = OBJECT_NONE; + ray.self.light_prim = PRIM_NONE; /* Modify ray position and length to match current segment. */ const float start_t = (hit == 0) ? 0.0f : INTEGRATOR_STATE_ARRAY(state, shadow_isect, hit - 1, t); diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h index 9f6077e5d66..3ca9e773591 100644 --- a/intern/cycles/kernel/integrator/shade_surface.h +++ b/intern/cycles/kernel/integrator/shade_surface.h @@ -182,6 +182,11 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg, /* Write shadow ray and associated state to global memory. */ integrator_state_write_shadow_ray(kg, shadow_state, &ray); + // Save memory by storing the light and object indices in the shadow_isect + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, object) = ray.self.object; + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, prim) = ray.self.prim; + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, object) = ray.self.light_object; + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, prim) = ray.self.light_prim; /* Copy state from main path to shadow path. */ const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce); @@ -364,6 +369,10 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg, ray.D = ao_D; ray.t = kernel_data.integrator.ao_bounces_distance; ray.time = sd->time; + ray.self.object = sd->object; + ray.self.prim = sd->prim; + ray.self.light_object = OBJECT_NONE; + ray.self.light_prim = PRIM_NONE; ray.dP = differential_zero_compact(); ray.dD = differential_zero_compact(); @@ -375,6 +384,10 @@ ccl_device_forceinline void integrate_surface_ao(KernelGlobals kg, /* Write shadow ray and associated state to global memory. */ integrator_state_write_shadow_ray(kg, shadow_state, &ray); + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, object) = ray.self.object; + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, prim) = ray.self.prim; + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, object) = ray.self.light_object; + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, prim) = ray.self.light_prim; /* Copy state from main path to shadow path. */ const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce); diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h index 00fa256d894..107d5ec1795 100644 --- a/intern/cycles/kernel/integrator/shade_volume.h +++ b/intern/cycles/kernel/integrator/shade_volume.h @@ -791,6 +791,10 @@ ccl_device_forceinline void integrate_volume_direct_light( /* Write shadow ray and associated state to global memory. */ integrator_state_write_shadow_ray(kg, shadow_state, &ray); + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, object) = ray.self.object; + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 0, prim) = ray.self.prim; + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, object) = ray.self.light_object; + INTEGRATOR_STATE_ARRAY_WRITE(shadow_state, shadow_isect, 1, prim) = ray.self.light_prim; /* Copy state from main path to shadow path. */ const uint16_t bounce = INTEGRATOR_STATE(state, path, bounce); @@ -878,6 +882,9 @@ ccl_device_forceinline bool integrate_volume_phase_scatter( INTEGRATOR_STATE_WRITE(state, ray, dP) = differential_make_compact(sd->dP); INTEGRATOR_STATE_WRITE(state, ray, dD) = differential_make_compact(phase_domega_in); # endif + // Save memory by storing last hit prim and object in isect + INTEGRATOR_STATE_WRITE(state, isect, prim) = sd->prim; + INTEGRATOR_STATE_WRITE(state, isect, object) = sd->object; /* Update throughput. */ const float3 throughput = INTEGRATOR_STATE(state, path, throughput); diff --git a/intern/cycles/kernel/integrator/shadow_state_template.h b/intern/cycles/kernel/integrator/shadow_state_template.h index 625a429d3db..86fcabdcd82 100644 --- a/intern/cycles/kernel/integrator/shadow_state_template.h +++ b/intern/cycles/kernel/integrator/shadow_state_template.h @@ -61,6 +61,7 @@ KERNEL_STRUCT_MEMBER(shadow_ray, packed_float3, D, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER(shadow_ray, float, t, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER(shadow_ray, float, time, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER(shadow_ray, float, dP, KERNEL_FEATURE_PATH_TRACING) +KERNEL_STRUCT_MEMBER(shadow_ray, int, object, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_END(shadow_ray) /*********************** Shadow Intersection result **************************/ diff --git a/intern/cycles/kernel/integrator/subsurface.h b/intern/cycles/kernel/integrator/subsurface.h index 59b0cd2596c..5a09fc51d75 100644 --- a/intern/cycles/kernel/integrator/subsurface.h +++ b/intern/cycles/kernel/integrator/subsurface.h @@ -57,7 +57,6 @@ ccl_device int subsurface_bounce(KernelGlobals kg, /* Pass along object info, reusing isect to save memory. */ INTEGRATOR_STATE_WRITE(state, subsurface, Ng) = sd->Ng; - INTEGRATOR_STATE_WRITE(state, isect, object) = sd->object; uint32_t path_flag = (INTEGRATOR_STATE(state, path, flag) & ~PATH_RAY_CAMERA) | ((sc->type == CLOSURE_BSSRDF_BURLEY_ID) ? PATH_RAY_SUBSURFACE_DISK : diff --git a/intern/cycles/kernel/integrator/subsurface_disk.h b/intern/cycles/kernel/integrator/subsurface_disk.h index cc6f5048cda..f5641d1fa5e 100644 --- a/intern/cycles/kernel/integrator/subsurface_disk.h +++ b/intern/cycles/kernel/integrator/subsurface_disk.h @@ -99,6 +99,10 @@ ccl_device_inline bool subsurface_disk(KernelGlobals kg, ray.dP = ray_dP; ray.dD = differential_zero_compact(); ray.time = time; + ray.self.object = OBJECT_NONE; + ray.self.prim = PRIM_NONE; + ray.self.light_object = OBJECT_NONE; + ray.self.light_prim = OBJECT_NONE; /* Intersect with the same object. if multiple intersections are found it * will use at most BSSRDF_MAX_HITS hits, a random subset of all hits. */ diff --git a/intern/cycles/kernel/integrator/subsurface_random_walk.h b/intern/cycles/kernel/integrator/subsurface_random_walk.h index 7a8b467e199..43676fccfe5 100644 --- a/intern/cycles/kernel/integrator/subsurface_random_walk.h +++ b/intern/cycles/kernel/integrator/subsurface_random_walk.h @@ -195,6 +195,7 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg, const float time = INTEGRATOR_STATE(state, ray, time); const float3 Ng = INTEGRATOR_STATE(state, subsurface, Ng); const int object = INTEGRATOR_STATE(state, isect, object); + const int prim = INTEGRATOR_STATE(state, isect, prim); /* Sample diffuse surface scatter into the object. */ float3 D; @@ -211,6 +212,10 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg, ray.time = time; ray.dP = ray_dP; ray.dD = differential_zero_compact(); + ray.self.object = object; + ray.self.prim = prim; + ray.self.light_object = OBJECT_NONE; + ray.self.light_prim = PRIM_NONE; #ifndef __KERNEL_GPU_RAYTRACING__ /* Compute or fetch object transforms. */ @@ -377,7 +382,15 @@ ccl_device_inline bool subsurface_random_walk(KernelGlobals kg, * If yes, we will later use backwards guided sampling in order to have a decent * chance of connecting to it. * TODO: Maybe use less than 10 times the mean free path? */ - ray.t = (bounce == 0) ? max(t, 10.0f / (min3(sigma_t))) : t; + if (bounce == 0) { + ray.t = max(t, 10.0f / (min3(sigma_t))); + } + else { + ray.t = t; + /* After the first bounce the object can intersect the same surface again */ + ray.self.object = OBJECT_NONE; + ray.self.prim = PRIM_NONE; + } scene_intersect_local(kg, &ray, &ss_isect, object, NULL, 1); hit = (ss_isect.num_hits > 0); diff --git a/intern/cycles/kernel/light/light.h b/intern/cycles/kernel/light/light.h index 6e445f862db..b9c0b533518 100644 --- a/intern/cycles/kernel/light/light.h +++ b/intern/cycles/kernel/light/light.h @@ -418,8 +418,8 @@ ccl_device bool light_sample_from_intersection(KernelGlobals kg, LightType type = (LightType)klight->type; ls->type = type; ls->shader = klight->shader_id; - ls->object = PRIM_NONE; - ls->prim = PRIM_NONE; + ls->object = isect->object; + ls->prim = isect->prim; ls->lamp = lamp; /* todo: missing texture coordinates */ ls->t = isect->t; diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h index 7dbc783b1bb..65e87e77c36 100644 --- a/intern/cycles/kernel/light/sample.h +++ b/intern/cycles/kernel/light/sample.h @@ -257,6 +257,12 @@ ccl_device_inline void shadow_ray_setup(ccl_private const ShaderData *ccl_restri ray->dP = differential_make_compact(sd->dP); ray->dD = differential_zero_compact(); ray->time = sd->time; + + /* Fill in intersection surface and light details. */ + ray->self.prim = sd->prim; + ray->self.object = sd->object; + ray->self.light_prim = ls->prim; + ray->self.light_object = ls->object; } /* Create shadow ray towards light sample. */ diff --git a/intern/cycles/kernel/svm/ao.h b/intern/cycles/kernel/svm/ao.h index 678f49c8ccd..e3abc9d69ff 100644 --- a/intern/cycles/kernel/svm/ao.h +++ b/intern/cycles/kernel/svm/ao.h @@ -74,6 +74,10 @@ ccl_device float svm_ao( ray.D = D.x * T + D.y * B + D.z * N; ray.t = max_dist; ray.time = sd->time; + ray.self.object = sd->object; + ray.self.prim = sd->prim; + ray.self.light_object = OBJECT_NONE; + ray.self.light_prim = PRIM_NONE; ray.dP = differential_zero_compact(); ray.dD = differential_zero_compact(); diff --git a/intern/cycles/kernel/svm/bevel.h b/intern/cycles/kernel/svm/bevel.h index 57c0288a96f..98b663299da 100644 --- a/intern/cycles/kernel/svm/bevel.h +++ b/intern/cycles/kernel/svm/bevel.h @@ -196,6 +196,10 @@ ccl_device float3 svm_bevel( ray.dP = differential_zero_compact(); ray.dD = differential_zero_compact(); ray.time = sd->time; + ray.self.object = OBJECT_NONE; + ray.self.prim = PRIM_NONE; + ray.self.light_object = OBJECT_NONE; + ray.self.light_prim = PRIM_NONE; /* Intersect with the same object. if multiple intersections are found it * will use at most LOCAL_MAX_HITS hits, a random subset of all hits. */ diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 3d9a8b403ac..d4cb22d4af4 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -512,12 +512,21 @@ typedef struct differential { /* Ray */ +typedef struct RaySelfPrimitives { + int prim; /* Primitive the ray is starting from */ + int object; /* Instance prim is a part of */ + int light_prim; /* Light primitive */ + int light_object; /* Light object */ +} RaySelfPrimitives; + typedef struct Ray { float3 P; /* origin */ float3 D; /* direction */ float t; /* length of the ray */ float time; /* time (for motion blur) */ + RaySelfPrimitives self; + #ifdef __RAY_DIFFERENTIALS__ float dP; float dD; -- cgit v1.2.3