Changeset View
Changeset View
Standalone View
Standalone View
intern/cycles/kernel/bvh/bvh_shadow_all.h
| Show All 30 Lines | |||||
| * BVH_MOTION: motion blur rendering | * BVH_MOTION: motion blur rendering | ||||
| */ | */ | ||||
| #ifndef __KERNEL_GPU__ | #ifndef __KERNEL_GPU__ | ||||
| ccl_device | ccl_device | ||||
| #else | #else | ||||
| ccl_device_inline | ccl_device_inline | ||||
| #endif | #endif | ||||
| bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, | bool BVH_FUNCTION_FULL_NAME(BVH)(const KernelGlobals *kg, | ||||
| const Ray *ray, | const Ray *ray, | ||||
| Intersection *isect_array, | Intersection *isect_array, | ||||
| const uint visibility, | const uint visibility, | ||||
| const uint max_hits, | const uint max_hits, | ||||
| uint *num_hits) | uint *num_hits) | ||||
| { | { | ||||
| /* todo: | /* todo: | ||||
| * - likely and unlikely for if() statements | * - likely and unlikely for if() statements | ||||
| Show All 15 Lines | #endif | ||||
| float3 idir = bvh_inverse_direction(dir); | float3 idir = bvh_inverse_direction(dir); | ||||
| int object = OBJECT_NONE; | int object = OBJECT_NONE; | ||||
| float isect_t = tmax; | float isect_t = tmax; | ||||
| #if BVH_FEATURE(BVH_MOTION) | #if BVH_FEATURE(BVH_MOTION) | ||||
| Transform ob_itfm; | Transform ob_itfm; | ||||
| #endif | #endif | ||||
| int num_hits_in_instance = 0; | float t_world_to_instance = 1.0f; | ||||
| *num_hits = 0; | *num_hits = 0; | ||||
| isect_array->t = tmax; | Intersection *isect = isect_array; | ||||
| /* traversal loop */ | /* traversal loop */ | ||||
| do { | do { | ||||
| do { | do { | ||||
| /* traverse internal nodes */ | /* traverse internal nodes */ | ||||
| while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { | while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { | ||||
| int node_addr_child1, traverse_mask; | int node_addr_child1, traverse_mask; | ||||
| float dist[2]; | float dist[2]; | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | #endif | ||||
| bool hit; | bool hit; | ||||
| /* todo: specialized intersect functions which don't fill in | /* todo: specialized intersect functions which don't fill in | ||||
| * isect unless needed and check SD_HAS_TRANSPARENT_SHADOW? | * isect unless needed and check SD_HAS_TRANSPARENT_SHADOW? | ||||
| * might give a few % performance improvement */ | * might give a few % performance improvement */ | ||||
| switch (p_type) { | switch (p_type) { | ||||
| case PRIMITIVE_TRIANGLE: { | case PRIMITIVE_TRIANGLE: { | ||||
| hit = triangle_intersect(kg, isect_array, P, dir, visibility, object, prim_addr); | hit = triangle_intersect( | ||||
| kg, isect, P, dir, isect_t, visibility, object, prim_addr); | |||||
| break; | break; | ||||
| } | } | ||||
| #if BVH_FEATURE(BVH_MOTION) | #if BVH_FEATURE(BVH_MOTION) | ||||
| case PRIMITIVE_MOTION_TRIANGLE: { | case PRIMITIVE_MOTION_TRIANGLE: { | ||||
| hit = motion_triangle_intersect( | hit = motion_triangle_intersect( | ||||
| kg, isect_array, P, dir, ray->time, visibility, object, prim_addr); | kg, isect, P, dir, isect_t, ray->time, visibility, object, prim_addr); | ||||
| break; | break; | ||||
| } | } | ||||
| #endif | #endif | ||||
| #if BVH_FEATURE(BVH_HAIR) | #if BVH_FEATURE(BVH_HAIR) | ||||
| case PRIMITIVE_CURVE_THICK: | case PRIMITIVE_CURVE_THICK: | ||||
| case PRIMITIVE_MOTION_CURVE_THICK: | case PRIMITIVE_MOTION_CURVE_THICK: | ||||
| case PRIMITIVE_CURVE_RIBBON: | case PRIMITIVE_CURVE_RIBBON: | ||||
| case PRIMITIVE_MOTION_CURVE_RIBBON: { | case PRIMITIVE_MOTION_CURVE_RIBBON: { | ||||
| const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr); | const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr); | ||||
| hit = curve_intersect( | hit = curve_intersect(kg, | ||||
| kg, isect_array, P, dir, visibility, object, prim_addr, ray->time, curve_type); | isect, | ||||
| P, | |||||
| dir, | |||||
| isect_t, | |||||
| visibility, | |||||
| object, | |||||
| prim_addr, | |||||
| ray->time, | |||||
| curve_type); | |||||
| break; | break; | ||||
| } | } | ||||
| #endif | #endif | ||||
| default: { | default: { | ||||
| hit = false; | hit = false; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| /* shadow ray early termination */ | /* shadow ray early termination */ | ||||
| if (hit) { | if (hit) { | ||||
| /* Convert intersection distance to world space. */ | |||||
| isect->t /= t_world_to_instance; | |||||
| /* detect if this surface has a shader with transparent shadows */ | /* detect if this surface has a shader with transparent shadows */ | ||||
| /* todo: optimize so primitive visibility flag indicates if | /* todo: optimize so primitive visibility flag indicates if | ||||
| * the primitive has a transparent shadow shader? */ | * the primitive has a transparent shadow shader? */ | ||||
| const int flags = intersection_get_shader_flags(kg, isect_array); | const int flags = intersection_get_shader_flags(kg, isect); | ||||
| /* if no transparent shadows, all light is blocked */ | if (!(flags & SD_HAS_TRANSPARENT_SHADOW) || max_hits == 0) { | ||||
| if (!(flags & SD_HAS_TRANSPARENT_SHADOW)) { | /* If no transparent shadows, all light is blocked and we can | ||||
| return true; | * stop immediately. */ | ||||
| } | |||||
| /* if maximum number of hits reached, block all light */ | |||||
| else if (*num_hits == max_hits) { | |||||
| return true; | return true; | ||||
| } | } | ||||
| /* move on to next entry in intersections array */ | /* Increase the number of hits, possibly beyond max_hits, we will | ||||
| isect_array++; | * simply not record those and only keep the max_hits closest. */ | ||||
| (*num_hits)++; | (*num_hits)++; | ||||
| num_hits_in_instance++; | |||||
| isect_array->t = isect_t; | if (*num_hits >= max_hits) { | ||||
| /* 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_hits, *num_hits); | |||||
| float max_recorded_t = isect_array[0].t; | |||||
| int max_recorded_hit = 0; | |||||
| for (int i = 1; i < num_recorded_hits; i++) { | |||||
| if (isect_array[i].t > max_recorded_t) { | |||||
| max_recorded_t = isect_array[i].t; | |||||
| max_recorded_hit = i; | |||||
| } | |||||
| } | |||||
| isect = isect_array + max_recorded_hit; | |||||
| /* If we already found more hits than we record, we can limit the | |||||
| * ray distance and stop counting hits beyond this, as we are sure to | |||||
| * need to another ray-trace call. */ | |||||
| if (*num_hits > max_hits) { | |||||
| isect_t = max_recorded_t * t_world_to_instance; | |||||
| } | |||||
| } | |||||
| else { | |||||
| /* Still have space for intersection, use next hit. */ | |||||
| isect = isect + 1; | |||||
| } | |||||
| } | } | ||||
| prim_addr++; | prim_addr++; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* instance push */ | /* instance push */ | ||||
| object = kernel_tex_fetch(__prim_object, -prim_addr - 1); | object = kernel_tex_fetch(__prim_object, -prim_addr - 1); | ||||
| #if BVH_FEATURE(BVH_MOTION) | #if BVH_FEATURE(BVH_MOTION) | ||||
| isect_t = bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, isect_t, &ob_itfm); | t_world_to_instance = bvh_instance_motion_push( | ||||
| kg, object, ray, &P, &dir, &idir, &ob_itfm); | |||||
| #else | #else | ||||
| isect_t = bvh_instance_push(kg, object, ray, &P, &dir, &idir, isect_t); | t_world_to_instance = bvh_instance_push(kg, object, ray, &P, &dir, &idir); | ||||
| #endif | #endif | ||||
| num_hits_in_instance = 0; | /* Convert intersection to object space. */ | ||||
| isect_array->t = isect_t; | isect_t *= t_world_to_instance; | ||||
| ++stack_ptr; | ++stack_ptr; | ||||
| kernel_assert(stack_ptr < BVH_STACK_SIZE); | kernel_assert(stack_ptr < BVH_STACK_SIZE); | ||||
| traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL; | traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL; | ||||
| node_addr = kernel_tex_fetch(__object_node, object); | node_addr = kernel_tex_fetch(__object_node, object); | ||||
| } | } | ||||
| } | } | ||||
| } while (node_addr != ENTRYPOINT_SENTINEL); | } while (node_addr != ENTRYPOINT_SENTINEL); | ||||
| if (stack_ptr >= 0) { | if (stack_ptr >= 0) { | ||||
| kernel_assert(object != OBJECT_NONE); | kernel_assert(object != OBJECT_NONE); | ||||
| /* Instance pop. */ | /* Instance pop. */ | ||||
| if (num_hits_in_instance) { | |||||
| float t_fac; | |||||
| #if BVH_FEATURE(BVH_MOTION) | |||||
| bvh_instance_motion_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac, &ob_itfm); | |||||
| #else | |||||
| bvh_instance_pop_factor(kg, object, ray, &P, &dir, &idir, &t_fac); | |||||
| #endif | |||||
| /* scale isect->t to adjust for instancing */ | |||||
| for (int i = 0; i < num_hits_in_instance; i++) { | |||||
| (isect_array - i - 1)->t *= t_fac; | |||||
| } | |||||
| } | |||||
| else { | |||||
| #if BVH_FEATURE(BVH_MOTION) | #if BVH_FEATURE(BVH_MOTION) | ||||
| bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX, &ob_itfm); | bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX, &ob_itfm); | ||||
| #else | #else | ||||
| bvh_instance_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX); | bvh_instance_pop(kg, object, ray, &P, &dir, &idir, FLT_MAX); | ||||
| #endif | #endif | ||||
| } | |||||
| isect_t = tmax; | /* Restore world space ray length. If max number of hits exceeded this | ||||
| isect_array->t = isect_t; | * distance is reduced to recorded only the closest hits. If not use | ||||
| * the original ray length. */ | |||||
| isect_t = (max_hits && *num_hits > max_hits) ? isect->t : tmax; | |||||
| object = OBJECT_NONE; | object = OBJECT_NONE; | ||||
| t_world_to_instance = 1.0f; | |||||
| node_addr = traversal_stack[stack_ptr]; | node_addr = traversal_stack[stack_ptr]; | ||||
| --stack_ptr; | --stack_ptr; | ||||
| } | } | ||||
| } while (node_addr != ENTRYPOINT_SENTINEL); | } while (node_addr != ENTRYPOINT_SENTINEL); | ||||
| return false; | return false; | ||||
| } | } | ||||
| ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, | ccl_device_inline bool BVH_FUNCTION_NAME(const KernelGlobals *kg, | ||||
| const Ray *ray, | const Ray *ray, | ||||
| Intersection *isect_array, | Intersection *isect_array, | ||||
| const uint visibility, | const uint visibility, | ||||
| const uint max_hits, | const uint max_hits, | ||||
| uint *num_hits) | uint *num_hits) | ||||
| { | { | ||||
| return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect_array, visibility, max_hits, num_hits); | return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect_array, visibility, max_hits, num_hits); | ||||
| } | } | ||||
| #undef BVH_FUNCTION_NAME | #undef BVH_FUNCTION_NAME | ||||
| #undef BVH_FUNCTION_FEATURES | #undef BVH_FUNCTION_FEATURES | ||||
| #undef NODE_INTERSECT | #undef NODE_INTERSECT | ||||