Blender V5.0
cycles/kernel/bvh/util.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "kernel/globals.h"
9#include "kernel/types.h"
10
12
14{
15 /* NOTE: Due to some vectorization code non-finite origin point might
16 * cause lots of false-positive intersections which will overflow traversal
17 * stack.
18 * This code is a quick way to perform early output, to avoid crashes in
19 * such cases.
20 * From production scenes so far it seems it's enough to test first element
21 * only.
22 * Scene intersection may also called with empty rays for conditional trace
23 * calls that evaluate to false, so filter those out.
24 */
25 return isfinite_safe(ray->P.x) && isfinite_safe(ray->D.x) && len_squared(ray->D) != 0.0f;
26}
27
28/* Offset intersection distance by the smallest possible amount, to skip
29 * intersections at this distance. This works in cases where the ray start
30 * position is unchanged and only tmin is updated, since for self
31 * intersection we'll be comparing against the exact same distances.
32 *
33 * Always returns normalized floating point value. */
35{
36 /* This is a simplified version of `nextafterf(t, FLT_MAX)`, only dealing with
37 * non-negative and finite t. */
38 kernel_assert(t >= 0.0f && isfinite_safe(t));
39
40 /* Special handling of zero, which also includes handling of denormal values:
41 * always return smallest normalized value. If a denormalized zero is returned
42 * it will cause false-positive intersection detection with a distance of 0.
43 *
44 * The check relies on the fact that comparison of denormal values with zero
45 * returns true. */
46 if (t == 0.0f) {
47 /* The exact bit value of this should be 0x1p-126, but hex floating point values notation is
48 * not available in CUDA/OptiX. */
49 return FLT_MIN;
50 }
51
52 const uint32_t bits = __float_as_uint(t) + 1;
53 const float result = __uint_as_float(bits);
54
55 /* Assert that the calculated value is indeed considered to be offset from the
56 * original value. */
58
59 return result;
60}
61
62/* Ray offset to avoid self intersection.
63 *
64 * This function can be used to compute a modified ray start position for rays
65 * leaving from a surface. This is from:
66 * "A Fast and Robust Method for Avoiding Self-Intersection"
67 * Ray Tracing Gems, chapter 6.
68 */
70{
71 const float int_scale = 256.0f;
72 const int3 of_i = make_int3(
73 (int)(int_scale * Ng.x), (int)(int_scale * Ng.y), (int)(int_scale * Ng.z));
74
75 const float3 p_i = make_float3(
76 __int_as_float(__float_as_int(P.x) + ((P.x < 0) ? -of_i.x : of_i.x)),
77 __int_as_float(__float_as_int(P.y) + ((P.y < 0) ? -of_i.y : of_i.y)),
78 __int_as_float(__float_as_int(P.z) + ((P.z < 0) ? -of_i.z : of_i.z)));
79 const float origin = 1.0f / 32.0f;
80 const float float_scale = 1.0f / 65536.0f;
81 return make_float3(fabsf(P.x) < origin ? P.x + float_scale * Ng.x : p_i.x,
82 fabsf(P.y) < origin ? P.y + float_scale * Ng.y : p_i.y,
83 fabsf(P.z) < origin ? P.z + float_scale * Ng.z : p_i.z);
84}
85
86#ifndef __KERNEL_GPU__
87ccl_device int intersections_compare(const void *a, const void *b)
88{
89 const Intersection *isect_a = (const Intersection *)a;
90 const Intersection *isect_b = (const Intersection *)b;
91
92 if (isect_a->t < isect_b->t) {
93 return -1;
94 }
95 if (isect_a->t > isect_b->t) {
96 return 1;
97 }
98 return 0;
99}
100#endif
101
102/* For subsurface scattering, only sorting a small amount of intersections
103 * so bubble sort is fine for CPU and GPU. */
106 uint num_hits)
107{
108 bool swapped;
109 do {
110 swapped = false;
111 for (uint j = 0; j < num_hits - 1; ++j) {
112 if (hits[j].t > hits[j + 1].t) {
113 Intersection tmp_hit = hits[j];
114 float3 tmp_Ng = Ng[j];
115 hits[j] = hits[j + 1];
116 Ng[j] = Ng[j + 1];
117 hits[j + 1] = tmp_hit;
118 Ng[j + 1] = tmp_Ng;
119 swapped = true;
120 }
121 }
122 --num_hits;
123 } while (swapped);
124}
125
126/* Utility to quickly get flags from an intersection. */
127
129 const int prim,
130 const int type)
131{
132 int shader = 0;
133
134 if (type & PRIMITIVE_TRIANGLE) {
135 shader = kernel_data_fetch(tri_shader, prim);
136 }
137#ifdef __POINTCLOUD__
138 else if (type & PRIMITIVE_POINT) {
139 shader = kernel_data_fetch(points_shader, prim);
140 }
141#endif
142#ifdef __HAIR__
143 else if (type & PRIMITIVE_CURVE) {
144 shader = kernel_data_fetch(curves, prim).shader_id;
145 }
146#endif
147
148 return kernel_data_fetch(shaders, (shader & SHADER_MASK)).flags;
149}
150
152 const int prim,
153 const int isect_type)
154{
155 int shader = 0;
156
157 if (isect_type & PRIMITIVE_TRIANGLE) {
158 shader = kernel_data_fetch(tri_shader, prim);
159 }
160#ifdef __POINTCLOUD__
161 else if (isect_type & PRIMITIVE_POINT) {
162 shader = kernel_data_fetch(points_shader, prim);
163 }
164#endif
165#ifdef __HAIR__
166 else if (isect_type & PRIMITIVE_CURVE) {
167 shader = kernel_data_fetch(curves, prim).shader_id;
168 }
169#endif
170
171 return shader & SHADER_MASK;
172}
173
179
182{
183 return kernel_data_fetch(object_flag, isect->object);
184}
185
186/* TODO: find a better (faster) solution for this. Maybe store offset per object for
187 * attributes needed in intersection? */
189 const int object,
190 const uint id)
191{
192 uint attr_offset = kernel_data_fetch(objects, object).attribute_map_offset;
193 AttributeMap attr_map = kernel_data_fetch(attributes_map, attr_offset);
194
195 while (attr_map.id != id) {
196 if (UNLIKELY(attr_map.id == ATTR_STD_NONE)) {
197 if (UNLIKELY(attr_map.element == 0)) {
198 return (int)ATTR_STD_NOT_FOUND;
199 }
200 /* Chain jump to a different part of the table. */
201 attr_offset = attr_map.offset;
202 }
203 else {
204 attr_offset += ATTR_PRIM_TYPES;
205 }
206 attr_map = kernel_data_fetch(attributes_map, attr_offset);
207 }
208
209 /* return result */
210 return (attr_map.element == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : attr_map.offset;
211}
212
213/* Transparent Shadows */
214
215/* Cut-off value to stop transparent shadow tracing when practically opaque. */
216#define CURVE_SHADOW_TRANSPARENCY_CUTOFF 0.001f
217
219 KernelGlobals kg, const int object, const int prim, const int type, const float u)
220{
221 /* Find attribute. */
222 const int offset = intersection_find_attribute(kg, object, ATTR_STD_SHADOW_TRANSPARENCY);
223 if (offset == ATTR_STD_NOT_FOUND) {
224 /* If no shadow transparency attribute, assume opaque. */
225 return 0.0f;
226 }
227
228 /* Interpolate transparency between curve keys. */
229 const KernelCurve kcurve = kernel_data_fetch(curves, prim);
230 const int k0 = kcurve.first_key + PRIMITIVE_UNPACK_SEGMENT(type);
231 const int k1 = k0 + 1;
232
233 const float f0 = kernel_data_fetch(attributes_float, offset + k0);
234 const float f1 = kernel_data_fetch(attributes_float, offset + k1);
235
236 return (1.0f - u) * f0 + u * f1;
237}
238
240 const int object,
241 const int prim)
242{
243 return (self.prim == prim) && (self.object == object);
244}
245
247 const int object,
248 const int prim)
249{
250 return ((self.prim == prim) && (self.object == object)) ||
251 ((self.light_prim == prim) && (self.light_object == object));
252}
253
255 const int prim)
256{
257 return (self.prim == prim);
258}
259
260#ifdef __SHADOW_LINKING__
262ray_get_shadow_set_membership(KernelGlobals kg, const ccl_ray_data RaySelfPrimitives &self)
263{
264 if (self.light_object != OBJECT_NONE) {
265 return kernel_data_fetch(objects, self.light_object).shadow_set_membership;
266 }
267
268 return LIGHT_LINK_MASK_ALL;
269}
270#endif
271
274 const int isect_object)
275{
276#ifdef __SHADOW_LINKING__
277 if (!(kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING)) {
278 return false;
279 }
280
281 const uint64_t set_membership = ray_get_shadow_set_membership(kg, self);
282 if (set_membership == LIGHT_LINK_MASK_ALL) {
283 return false;
284 }
285
286 const uint blocker_set = kernel_data_fetch(objects, isect_object).blocker_shadow_set;
287 return ((uint64_t(1) << uint64_t(blocker_set)) & set_membership) == 0;
288#else
289 return false;
290#endif
291}
292
293/* Check whether an intersection denoted by its object and primitive is to be skipped due to it
294 * being already recoded.
295 * The situation when primitive is already recoded happens when BVH spatial splits are used. */
297 const int object,
298 const int prim,
299 const int num_hits)
300{
301 const int num_recorded_hits = min(num_hits, int(INTEGRATOR_SHADOW_ISECT_SIZE));
302 for (int i = 0; i < num_recorded_hits; ++i) {
303 const int isect_object = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, object);
304 const int isect_prim = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, prim);
305 if (object == isect_object && prim == isect_prim) {
306 return true;
307 }
308 }
309 return false;
310}
311
unsigned int uint
#define UNLIKELY(x)
PyObject * self
unsigned long long int uint64_t
ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg, const int prim, const int type)
ccl_device_forceinline bool intersection_skip_shadow_already_recoded(IntegratorShadowState state, const int object, const int prim, const int num_hits)
ccl_device_inline bool intersection_skip_shadow_link(KernelGlobals kg, const ccl_ray_data RaySelfPrimitives &self, const int isect_object)
ccl_device_inline void sort_intersections_and_normals(ccl_private Intersection *hits, ccl_private float3 *Ng, uint num_hits)
ccl_device_inline bool intersection_skip_self_shadow(const ccl_ray_data RaySelfPrimitives &self, const int object, const int prim)
ccl_device_inline bool intersection_skip_self(const ccl_ray_data RaySelfPrimitives &self, const int object, const int prim)
CCL_NAMESPACE_BEGIN ccl_device_inline bool intersection_ray_valid(const ccl_private Ray *ray)
ccl_device_forceinline float intersection_t_offset(const float t)
ccl_device int intersections_compare(const void *a, const void *b)
ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg, const int object, const int prim, const int type, const float u)
ccl_device_inline int intersection_find_attribute(KernelGlobals kg, const int object, const uint id)
ccl_device_forceinline int intersection_get_shader(KernelGlobals kg, const ccl_private Intersection *ccl_restrict isect)
ccl_device_inline float3 ray_offset(const float3 P, const float3 Ng)
ccl_device_forceinline int intersection_get_object_flags(KernelGlobals kg, const ccl_private Intersection *ccl_restrict isect)
ccl_device_forceinline int intersection_get_shader_from_isect_prim(KernelGlobals kg, const int prim, const int isect_type)
ccl_device_inline bool intersection_skip_self_local(const ccl_ray_data RaySelfPrimitives &self, const int prim)
#define kernel_assert(cond)
#define kernel_data
#define ccl_ray_data
#define ccl_restrict
#define ccl_device_forceinline
#define kernel_data_fetch(name, index)
#define PRIMITIVE_UNPACK_SEGMENT(type)
#define INTEGRATOR_SHADOW_ISECT_SIZE
#define OBJECT_NONE
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define KERNEL_FEATURE_SHADOW_LINKING
#define LIGHT_LINK_MASK_ALL
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define __int_as_float(x)
ccl_device_forceinline int3 make_int3(const int x, const int y, const int z)
#define __float_as_int(x)
#define __float_as_uint(x)
#define __uint_as_float(x)
@ PRIMITIVE_CURVE
@ PRIMITIVE_TRIANGLE
@ PRIMITIVE_POINT
@ ATTR_STD_NOT_FOUND
@ ATTR_STD_NONE
@ ATTR_STD_SHADOW_TRANSPARENCY
@ SHADER_MASK
@ ATTR_ELEMENT_NONE
@ ATTR_PRIM_TYPES
ccl_device_inline bool isfinite_safe(const float f)
Definition math_base.h:348
ccl_device_inline float len_squared(const float2 a)
static ulong state[N]
#define fabsf
#define ccl_device
#define min(a, b)
Definition sort.cc:36
IntegratorShadowStateCPU * IntegratorShadowState
Definition state.h:230
#define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member)
Definition state.h:238
uint16_t element
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
i
Definition text_draw.cc:230