Blender V4.3
math_intersect.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#ifndef __UTIL_MATH_INTERSECT_H__
6#define __UTIL_MATH_INTERSECT_H__
7
9
10/* Ray Intersection */
11
13 float3 ray_D,
14 float ray_tmin,
15 float ray_tmax,
16 float3 sphere_P,
17 float sphere_radius,
18 ccl_private float3 *isect_P,
19 ccl_private float *isect_t)
20{
21 const float3 d_vec = sphere_P - ray_P;
22 const float r_sq = sphere_radius * sphere_radius;
23 const float d_sq = dot(d_vec, d_vec);
24 const float d_cos_theta = dot(d_vec, ray_D);
25
26 if (d_sq > r_sq && d_cos_theta < 0.0f) {
27 /* Ray origin outside sphere and points away from sphere. */
28 return false;
29 }
30
31 const float d_sin_theta_sq = len_squared(d_vec - d_cos_theta * ray_D);
32
33 if (d_sin_theta_sq > r_sq) {
34 /* Closest point on ray outside sphere. */
35 return false;
36 }
37
38 /* Law of cosines. */
39 const float t = d_cos_theta - copysignf(sqrtf(r_sq - d_sin_theta_sq), d_sq - r_sq);
40
41 if (t > ray_tmin && t < ray_tmax) {
42 *isect_t = t;
43 *isect_P = ray_P + ray_D * t;
44 return true;
45 }
46
47 return false;
48}
49
51 float3 ray_D,
52 float ray_tmin,
53 float ray_tmax,
54 float3 disk_P,
55 float disk_radius,
56 ccl_private float3 *isect_P,
57 ccl_private float *isect_t)
58{
59 /* Aligned disk normal. */
60 float disk_t;
61 const float3 disk_N = normalize_len(ray_P - disk_P, &disk_t);
62 const float div = dot(ray_D, disk_N);
63 if (UNLIKELY(div == 0.0f)) {
64 return false;
65 }
66 /* Compute t to intersection point. */
67 const float t = -disk_t / div;
68 if (!(t > ray_tmin && t < ray_tmax)) {
69 return false;
70 }
71 /* Test if within radius. */
72 float3 P = ray_P + ray_D * t;
73 if (len_squared(P - disk_P) > disk_radius * disk_radius) {
74 return false;
75 }
76 *isect_P = P;
77 *isect_t = t;
78 return true;
79}
80
82 float3 ray_D,
83 float ray_tmin,
84 float ray_tmax,
85 float3 disk_P,
86 float3 disk_N,
87 float disk_radius,
88 ccl_private float3 *isect_P,
89 ccl_private float *isect_t)
90{
91 const float3 vp = ray_P - disk_P;
92 const float dp = dot(vp, disk_N);
93 const float cos_angle = dot(disk_N, -ray_D);
94 if (dp * cos_angle > 0.f) // front of light
95 {
96 float t = dp / cos_angle;
97 if (t < 0.f) { /* Ray points away from the light. */
98 return false;
99 }
100 float3 P = ray_P + t * ray_D;
101 float3 T = P - disk_P;
102
103 if (dot(T, T) < sqr(disk_radius) && (t > ray_tmin && t < ray_tmax)) {
104 *isect_P = ray_P + t * ray_D;
105 *isect_t = t;
106 return true;
107 }
108 }
109 return false;
110}
111
112/* Custom rcp, cross and dot implementations that match Embree bit for bit. */
114{
115#ifdef __KERNEL_NEON__
116 /* Move scalar to vector register and do rcp. */
117 __m128 a = {0};
118 a = vsetq_lane_f32(x, a, 0);
119 float32x4_t reciprocal = vrecpeq_f32(a);
120 reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
121 reciprocal = vmulq_f32(vrecpsq_f32(a, reciprocal), reciprocal);
122 return vgetq_lane_f32(reciprocal, 0);
123#elif defined(__KERNEL_SSE__)
124 const __m128 a = _mm_set_ss(x);
125 const __m128 r = _mm_rcp_ss(a);
126
127# ifdef __KERNEL_AVX2_
128 return _mm_cvtss_f32(_mm_mul_ss(r, _mm_fnmadd_ss(r, a, _mm_set_ss(2.0f))));
129# else
130 return _mm_cvtss_f32(_mm_mul_ss(r, _mm_sub_ss(_mm_set_ss(2.0f), _mm_mul_ss(r, a))));
131# endif
132#else
133 return 1.0f / x;
134#endif
135}
136
138{
139#if defined(__KERNEL_SSE42__) && defined(__KERNEL_SSE__)
140 return madd(make_float4(a.x),
141 make_float4(b.x),
142 madd(make_float4(a.y), make_float4(b.y), make_float4(a.z) * make_float4(b.z)))[0];
143#else
144 return a.x * b.x + a.y * b.y + a.z * b.z;
145#endif
146}
147
149{
150#if defined(__KERNEL_SSE42__) && defined(__KERNEL_SSE__)
151 return make_float3(
152 msub(make_float4(a.y), make_float4(b.z), make_float4(a.z) * make_float4(b.y))[0],
153 msub(make_float4(a.z), make_float4(b.x), make_float4(a.x) * make_float4(b.z))[0],
154 msub(make_float4(a.x), make_float4(b.y), make_float4(a.y) * make_float4(b.x))[0]);
155#else
156 return make_float3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
157#endif
158}
159
161 const float3 ray_D,
162 const float ray_tmin,
163 const float ray_tmax,
164 const float3 tri_a,
165 const float3 tri_b,
166 const float3 tri_c,
167 ccl_private float *isect_u,
168 ccl_private float *isect_v,
169 ccl_private float *isect_t)
170{
171 /* This implementation matches the Plücker coordinates triangle intersection
172 * in Embree. */
173
174 /* Calculate vertices relative to ray origin. */
175 const float3 v0 = tri_a - ray_P;
176 const float3 v1 = tri_b - ray_P;
177 const float3 v2 = tri_c - ray_P;
178
179 /* Calculate triangle edges. */
180 const float3 e0 = v2 - v0;
181 const float3 e1 = v0 - v1;
182 const float3 e2 = v1 - v2;
183
184 /* Perform edge tests. */
185 const float U = ray_triangle_dot(ray_triangle_cross(e0, v2 + v0), ray_D);
186 const float V = ray_triangle_dot(ray_triangle_cross(e1, v0 + v1), ray_D);
187 const float W = ray_triangle_dot(ray_triangle_cross(e2, v1 + v2), ray_D);
188
189 const float UVW = U + V + W;
190 const float eps = FLT_EPSILON * fabsf(UVW);
191 const float minUVW = min(U, min(V, W));
192 const float maxUVW = max(U, max(V, W));
193
194 if (!(minUVW >= -eps || maxUVW <= eps)) {
195 return false;
196 }
197
198 /* Calculate geometry normal and denominator. */
199 const float3 Ng1 = ray_triangle_cross(e1, e0);
200 const float3 Ng = Ng1 + Ng1;
201 const float den = dot(Ng, ray_D);
202 /* Avoid division by 0. */
203 if (UNLIKELY(den == 0.0f)) {
204 return false;
205 }
206
207 /* Perform depth test. */
208 const float T = dot(v0, Ng);
209 const float t = T / den;
210 if (!(t >= ray_tmin && t <= ray_tmax)) {
211 return false;
212 }
213
214 const float rcp_uvw = (fabsf(UVW) < 1e-18f) ? 0.0f : ray_triangle_rcp(UVW);
215 *isect_u = min(U * rcp_uvw, 1.0f);
216 *isect_v = min(V * rcp_uvw, 1.0f);
217 *isect_t = t;
218 return true;
219}
220
222 const float3 ray_D,
223 const float3 verts[3])
224{
225 /* Matches logic in ray_triangle_intersect, self intersection test to validate
226 * if a ray is going to hit self or might incorrectly hit a neighboring triangle. */
227
228 /* Calculate vertices relative to ray origin. */
229 const float3 v0 = verts[0] - ray_P;
230 const float3 v1 = verts[1] - ray_P;
231 const float3 v2 = verts[2] - ray_P;
232
233 /* Calculate triangle edges. */
234 const float3 e0 = v2 - v0;
235 const float3 e1 = v0 - v1;
236 const float3 e2 = v1 - v2;
237
238 /* Perform edge tests. */
239 const float U = ray_triangle_dot(ray_triangle_cross(v2 + v0, e0), ray_D);
240 const float V = ray_triangle_dot(ray_triangle_cross(v0 + v1, e1), ray_D);
241 const float W = ray_triangle_dot(ray_triangle_cross(v1 + v2, e2), ray_D);
242
243 const float eps = FLT_EPSILON * fabsf(U + V + W);
244 const float minUVW = min(U, min(V, W));
245 const float maxUVW = max(U, max(V, W));
246
247 /* Note the extended epsilon compared to ray_triangle_intersect, to account
248 * for intersections with neighboring triangles that have an epsilon. */
249 return (minUVW >= eps || maxUVW <= -eps);
250}
251
252/* Tests for an intersection between a ray and a quad defined by
253 * its midpoint, normal and sides.
254 * If ellipse is true, hits outside the ellipse that's enclosed by the
255 * quad are rejected.
256 */
258 float3 ray_D,
259 float ray_tmin,
260 float ray_tmax,
261 float3 quad_P,
262 float3 inv_quad_u,
263 float3 inv_quad_v,
264 float3 quad_n,
265 ccl_private float3 *isect_P,
266 ccl_private float *isect_t,
267 ccl_private float *isect_u,
268 ccl_private float *isect_v,
269 bool ellipse)
270{
271 /* Perform intersection test. */
272 float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n);
273 if (!(t > ray_tmin && t < ray_tmax)) {
274 return false;
275 }
276 const float3 hit = ray_P + t * ray_D;
277 const float3 inplane = hit - quad_P;
278 const float u = dot(inplane, inv_quad_u);
279 if (u < -0.5f || u > 0.5f) {
280 return false;
281 }
282 const float v = dot(inplane, inv_quad_v);
283 if (v < -0.5f || v > 0.5f) {
284 return false;
285 }
286 if (ellipse && (u * u + v * v > 0.25f)) {
287 return false;
288 }
289 /* Store the result. */
290 /* TODO(sergey): Check whether we can avoid some checks here. */
291 if (isect_P != NULL)
292 *isect_P = hit;
293 if (isect_t != NULL)
294 *isect_t = t;
295
296 /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
297 if (isect_u != NULL)
298 *isect_u = v + 0.5f;
299 if (isect_v != NULL)
300 *isect_v = -u - v;
301
302 return true;
303}
304
305/* Find the ray segment that lies in the same side as the normal `N` of the plane.
306 * `P` is the vector pointing from any point on the plane to the ray origin. */
308 const float3 P,
309 const float3 ray_D,
310 ccl_private float2 *t_range)
311{
312 const float DN = dot(ray_D, N);
313
314 /* Distance from P to the plane. */
315 const float t = -dot(P, N) / DN;
316
317 /* Limit the range to the positive side. */
318 if (DN > 0.0f) {
319 t_range->x = fmaxf(t_range->x, t);
320 }
321 else {
322 t_range->y = fminf(t_range->y, t);
323 }
324
325 return t_range->x < t_range->y;
326}
327
328/* Find the ray segment inside an axis-aligned bounding box. */
330 const float3 bbox_max,
331 const float3 ray_P,
332 const float3 ray_D,
333 ccl_private float2 *t_range)
334{
335 const float3 inv_ray_D = rcp(ray_D);
336
337 /* Absolute distances to lower and upper box coordinates; */
338 const float3 t_lower = (bbox_min - ray_P) * inv_ray_D;
339 const float3 t_upper = (bbox_max - ray_P) * inv_ray_D;
340
341 /* The four t-intervals (for x-/y-/z-slabs, and ray p(t)). */
342 const float4 tmins = float3_to_float4(min(t_lower, t_upper), t_range->x);
343 const float4 tmaxes = float3_to_float4(max(t_lower, t_upper), t_range->y);
344
345 /* Max of mins and min of maxes. */
346 const float tmin = reduce_max(tmins);
347 const float tmax = reduce_min(tmaxes);
348
349 *t_range = make_float2(tmin, tmax);
350
351 return tmin < tmax;
352}
353
354/* Find the segment of a ray defined by P + D * t that lies inside a cylinder defined by
355 * (x / len_u)^2 + (y / len_v)^2 = 1. */
357 const float3 D,
358 const float len_u,
359 const float len_v,
360 ccl_private float2 *t_range)
361{
362 /* Convert to a 2D problem. */
363 const float2 inv_len = 1.0f / make_float2(len_u, len_v);
364 float2 P_proj = float3_to_float2(P) * inv_len;
365 const float2 D_proj = float3_to_float2(D) * inv_len;
366
367 /* Solve quadratic equation a*t^2 + 2b*t + c = 0. */
368 const float a = dot(D_proj, D_proj);
369 float b = dot(P_proj, D_proj);
370
371 /* Move ray origin closer to the cylinder to prevent precision issue when the ray is far away. */
372 const float t_mid = -b / a;
373 P_proj += D_proj * t_mid;
374
375 /* Recompute b from the shifted origin. */
376 b = dot(P_proj, D_proj);
377 const float c = dot(P_proj, P_proj) - 1.0f;
378
379 float tmin, tmax;
380 const bool valid = solve_quadratic(a, 2.0f * b, c, tmin, tmax);
381
382 return valid && intervals_intersect(t_range, make_float2(tmin, tmax) + t_mid);
383}
384
385/* *
386 * Find the ray segment inside a single-sided cone.
387 *
388 * \param axis: a unit-length direction around which the cone has a circular symmetry
389 * \param P: the vector pointing from the cone apex to the ray origin
390 * \param D: the direction of the ray, does not need to have unit-length
391 * \param cos_angle_sq: `sqr(cos(half_aperture_of_the_cone))`
392 * \param t_range: the lower and upper bounds between which the ray lies inside the cone
393 * \return whether the intersection exists and is in the provided range
394 *
395 * See https://www.geometrictools.com/Documentation/IntersectionLineCone.pdf for illustration
396 */
398 const float3 P,
399 float3 D,
400 const float cos_angle_sq,
401 ccl_private float2 *t_range)
402{
403 if (cos_angle_sq < 1e-4f) {
404 /* The cone is nearly a plane. */
405 return ray_plane_intersect(axis, P, D, t_range);
406 }
407
408 const float inv_len = inversesqrtf(len_squared(D));
409 D *= inv_len;
410
411 const float AD = dot(axis, D);
412 const float AP = dot(axis, P);
413
414 const float a = sqr(AD) - cos_angle_sq;
415 const float b = 2.0f * (AD * AP - cos_angle_sq * dot(D, P));
416 const float c = sqr(AP) - cos_angle_sq * dot(P, P);
417
418 float tmin = 0.0f, tmax = FLT_MAX;
419 bool valid = solve_quadratic(a, b, c, tmin, tmax);
420
421 /* Check if the intersections are in the same hemisphere as the cone. */
422 const bool tmin_valid = AP + tmin * AD > 0.0f;
423 const bool tmax_valid = AP + tmax * AD > 0.0f;
424
425 valid &= (tmin_valid || tmax_valid);
426
427 if (!tmax_valid) {
428 tmax = tmin;
429 tmin = 0.0f;
430 }
431 else if (!tmin_valid) {
432 tmin = tmax;
433 tmax = FLT_MAX;
434 }
435
436 return valid && intervals_intersect(t_range, make_float2(tmin, tmax) * inv_len);
437}
438
440
441#endif /* __UTIL_MATH_INTERSECT_H__ */
#define UNLIKELY(x)
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMVert * v
unsigned int U
Definition btGjkEpa3.h:78
local_group_size(16, 16) .push_constant(Type b
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
#define ccl_device_forceinline
#define ccl_device
#define ccl_private
#define ccl_device_inline
#define CCL_NAMESPACE_END
ccl_device_forceinline float4 make_float4(const float x, const float y, const float z, const float w)
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define NULL
#define fmaxf(x, y)
#define fminf(x, y)
ccl_device_forceinline float2 make_float2(const float x, const float y)
#define copysignf(x, y)
#define fabsf(x)
#define sqrtf(x)
static float verts[][3]
CCL_NAMESPACE_BEGIN ccl_device_inline float madd(const float a, const float b, const float c)
Definition math_fast.h:29
ccl_device_inline float len_squared(const float2 a)
ccl_device_inline float reduce_max(const float2 a)
ccl_device_inline float2 normalize_len(const float2 a, ccl_private float *t)
ccl_device_inline float reduce_min(const float2 a)
ccl_device_inline float3 rcp(const float3 a)
ccl_device_inline float4 msub(const float4 a, const float4 b, const float4 c)
ccl_device bool ray_disk_intersect(float3 ray_P, float3 ray_D, float ray_tmin, float ray_tmax, float3 disk_P, float3 disk_N, float disk_radius, ccl_private float3 *isect_P, ccl_private float *isect_t)
ccl_device_inline bool ray_cone_intersect(const float3 axis, const float3 P, float3 D, const float cos_angle_sq, ccl_private float2 *t_range)
ccl_device_forceinline float ray_triangle_rcp(const float x)
ccl_device bool ray_aabb_intersect(const float3 bbox_min, const float3 bbox_max, const float3 ray_P, const float3 ray_D, ccl_private float2 *t_range)
CCL_NAMESPACE_BEGIN ccl_device bool ray_sphere_intersect(float3 ray_P, float3 ray_D, float ray_tmin, float ray_tmax, float3 sphere_P, float sphere_radius, ccl_private float3 *isect_P, ccl_private float *isect_t)
ccl_device bool ray_aligned_disk_intersect(float3 ray_P, float3 ray_D, float ray_tmin, float ray_tmax, float3 disk_P, float disk_radius, ccl_private float3 *isect_P, ccl_private float *isect_t)
ccl_device_inline bool ray_infinite_cylinder_intersect(const float3 P, const float3 D, const float len_u, const float len_v, ccl_private float2 *t_range)
ccl_device_forceinline bool ray_triangle_intersect(const float3 ray_P, const float3 ray_D, const float ray_tmin, const float ray_tmax, const float3 tri_a, const float3 tri_b, const float3 tri_c, ccl_private float *isect_u, ccl_private float *isect_v, ccl_private float *isect_t)
ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_tmin, float ray_tmax, float3 quad_P, float3 inv_quad_u, float3 inv_quad_v, float3 quad_n, ccl_private float3 *isect_P, ccl_private float *isect_t, ccl_private float *isect_u, ccl_private float *isect_v, bool ellipse)
ccl_device_forceinline bool ray_triangle_intersect_self(const float3 ray_P, const float3 ray_D, const float3 verts[3])
ccl_device_inline float3 ray_triangle_cross(const float3 a, const float3 b)
ccl_device_inline float ray_triangle_dot(const float3 a, const float3 b)
ccl_device bool ray_plane_intersect(const float3 N, const float3 P, const float3 ray_D, ccl_private float2 *t_range)
#define N
const btScalar eps
Definition poly34.cpp:11
#define min(a, b)
Definition sort.c:32
#define FLT_MAX
Definition stdcycles.h:14
float max
ccl_device_inline bool intervals_intersect(ccl_private float2 *first, const float2 second)
Definition util/math.h:1055
ccl_device_inline float sqr(float a)
Definition util/math.h:782
ccl_device_inline float inversesqrtf(float f)
Definition util/math.h:711
ccl_device_inline bool solve_quadratic(const float a, const float b, const float c, ccl_private float &x1, ccl_private float &x2)
Definition util/math.h:1066
ccl_device_inline float4 float3_to_float4(const float3 a)
Definition util/math.h:540
ccl_device_inline float2 float3_to_float2(const float3 a)
Definition util/math.h:530
CCL_NAMESPACE_BEGIN struct Window V